在x86或amd64上使用汇编指令时,程序员可以使用" Intel" (即nasm
编译器)或" AT& T" (即gas
编译器)汇编语法。 "英特尔"语法在Windows上更受欢迎,但" AT& T"在UNIX(类似)系统上更受欢迎。
但是英特尔和AMD的手册,以及芯片创建者创建的手册都使用了"英特尔"语法。
我想知道," AT& T"设计背后的原始理念是什么?句法?浮动处理器创建者使用的符号有什么好处?
答案 0 :(得分:11)
UNIX很长一段时间是在PDP-11上开发的,这是一台来自DEC的16位计算机,它具有相当简单的指令集。几乎每条指令都有两个操作数,每个操作数可以有以下八种寻址模式之一,这里用MACRO 16汇编语言显示:
0n Rn register
1n (Rn) deferred
2n (Rn)+ autoincrement
3n @(Rn)+ autoincrement deferred
4n -(Rn) autodecrement
5n @-(Rn) autodecrement deferred
6n X(Rn) index
7n @X(Rn) index deferred
可以通过在程序计数器R7上巧妙地重复使用某些寻址模式来编码中间地址和直接地址:
27 #imm immediate
37 @#imm absolute
67 addr relative
77 @addr relative deferred
由于UNIX tty驱动程序使用@
和#
作为控制字符,$
替换#
而*
替换为@
。
PDP11指令字中的第一个操作数是指源操作数,而第二个操作数是指目的地。这反映在汇编语言的操作数顺序中,即源,然后是目标。例如,操作码
011273
指的是指令
mov (R2),R3
将R2
指向的单词移动到R3
。
此语法适用于8086 CPU及其寻址模式:
mr0 X(bx,si) bx + si indexed
mr1 X(bx,di) bx + di indexed
mr2 X(bp,si) bp + si indexed
mr3 X(bp,di) bp + di indexed
mr4 X(si) si indexed
mr5 X(di) di indexed
mr6 X(bp) bp indexed
mr7 X(bx) bx indexed
3rR R register
0r6 addr direct
如果没有索引,m
为0,如果存在单字节索引,则m
为1,如果存在双字节索引则m
为2且{如果使用寄存器而不是内存操作数,则{1}}为3。如果存在两个操作数,则另一个操作数始终是寄存器并以m
数字编码。否则,r
将对操作码的另外三位进行编码。
在这种寻址方案中,无法使用immediates,所有采用immediates的指令都会在其操作码中编码该事实。 Immediates拼写r
就像在PDP-11语法中一样。
虽然英特尔总是对其汇编程序使用$imm
操作数排序,但没有特别令人信服的理由来调整此约定,并且编写UNIX汇编程序以使用PDP11中已知的dst, src
操作数排序。
他们在实现8087浮点指令时与这种排序有一些不一致,可能是因为英特尔给出了非交换浮点指令的两个可能方向,这些指令与AT& T&#使用的操作数排序不匹配。 39; s语法。
PDP11指令src, dst
(跳转)和jmp
(跳转到子程序)跳转到其操作数的地址。因此,jsr
会跳转到jmp foo
,foo
会跳转到存储在变量jmp *foo
中的地址,类似于foo
在8086中的工作方式。< / p>
x86的lea
和jmp
指令的语法设计就像这些指令在PDP11上的工作方式一样,这就是call
跳转到jmp foo
的原因}和foo
跳转到地址jmp *foo
的值,即使8086实际上没有延迟寻址。这具有在语法上区分直接跳转和间接跳转的优点和便利,而不需要为每个直接跳转目标设置foo
前缀,但在逻辑上没有多少意义。
扩展语法以使用冒号指定段前缀:
$
当引入80386时,该方案采用四部分通用寻址模式适应其新的SIB寻址模式:
seg:addr
其中disp(base,index,scale)
是位移,base是基址寄存器,disp
是索引寄存器,index
是1,2,4或8,用于将索引寄存器缩放为这些金额。这等同于Intel语法:
scale
PDP-11的另一个显着特点是大多数指令都有字节和字变体。你使用哪一个用操作码的[disp+base+index*scale]
或b
后缀表示,它直接切换操作码的第一位:
w
这也适用于AT&amp; T语法,因为大多数8086指令确实也可用于字节模式和字模式。后来80386和AMD K6引入了32位指令( 010001 movw r0,r1
110001 movb r0,r1
后缀为l
)和64位指令(后缀long
为quad)。
最后但并非最不重要的是,最初的惯例是使用下划线为C语言符号添加前缀(在Windows上仍然如此),因此您可以将名为q
的C函数与寄存器ax
区分开来。当Unix系统实验室开发出ELF二进制格式时,他们决定摆脱这种装饰。由于无法区分直接地址和寄存器,否则会在每个寄存器中添加ax
前缀:
%
这就是我们今天获得AT&amp; T语法的方式。
答案 1 :(得分:-3)
汇编语言由汇编程序定义,汇编程序是解析汇编语言的软件。唯一的“标准”是机器代码,它必须与处理器匹配,但是如果您需要100个程序员并给它们机器代码标准(没有任何汇编语言提示),那么最终会有1到100种不同的汇编语言。对于该处理器的所有用例(裸机,操作系统,应用程序工作),只要它们构成一个适合工具链的完整工具,它们都能很好地工作。
指令集的创建者(机器代码)的最大利益是创建描述指令集的文档和汇编程序,这是您需要的第一个工具。无论哪种方式无关紧要,它们都可以将其收缩或者内置,但是使用汇编程序,语法和机器代码文档,使用汇编程序的语法连接两者之间的点,将给任何人可能对该处理器感兴趣的一个起点。与英特尔和8086/88的情况一样。但这并不意味着masm和tasm与intels汇编程序完全兼容。即使每个指令的语法匹配,每个指令语法只是汇编语言的一部分,有很多非指令类型的语法,指令,宏语言等等。那是来自DOS世界末日,有UNIX端,因此AT&amp; T. gnu当时的人们都是unix世界末日,因此他们使用AT&amp; T语法或衍生词是完全合理的,因为它们通常在端口期间搞乱汇编语言。也许有一个例外。
nasm和其他一些类似的尝试继续使用masm语法,因为masm是一个封闭的源代码Microsoft工具(如同那样,并且无论如何都是Borland C)。这些可能现在是开源的,但是没有必要,从头开始编写比尝试移植代码更容易,我假设使用现代编译器构建,并且nasm已经存在。
为什么问题就像问我为什么选择今天早上或任何特定日子选择的那双袜子。你的袜子可能不会对世界其他地方造成太大的影响,但这个问题同样无关紧要和/或无法回答。答案可以部分归结为要求100位程序员为相同的机器代码定义制作汇编程序。这些程序员中的一些人可能对汇编语言有经验,并且可能选择在他们之前使用过的图像中创建汇编语言,这意味着他们中的一些将使一个看起来非常相似的汇编语言。但是他们之前使用的一个或多个可能是不同的,所以会有这些相似但仍然不同的组。然后让我们说30年来问这100个人中的每一个人为什么问题...如果他们还活着......就像问我为什么你选择在30年前以你所做的方式写的程序中声明一个变量它