繁体   English   中英

设计 AT&T 汇编语法的最初原因是什么?

[英]What was the original reason for the design of AT&T assembly syntax?

在x86 或amd64 上使用汇编指令时,程序员可以使用“Intel”(即nasm编译器)或“AT&T”(即gas编译器)汇编语法。 “Intel”语法在 Windows 上更流行,但“AT&T”在 UNIX(类)系统上更流行。

但是 Intel 和 AMD 手册,即芯片创建者创建的手册,都使用“Intel”语法。

我想知道,“AT&T”语法设计背后的最初想法是什么? 远离处理器创建者使用的符号有什么好处?

长期以来,UNIX 是在 PDP-11 上开发的,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,如果有一个两字节索引和m是3,如果代替存储器操作数,使用一个寄存器。 如果存在两个操作数,则另一个操作数始终是一个寄存器并以r位编码。 否则, r对操作码的另外三位进行编码。

在这种寻址方案中,立即数是不可能的,所有采用立即数的指令都在其操作码中编码该事实。 立即数拼写为$imm就像在 PDP-11 语法中一样。

虽然 Intel 的汇编器总是使用dst, src操作数顺序,但没有特别令人信服的理由来适应这种约定,并且 UNIX 汇编器被编写为使用 PDP11 中已知的src, dst操作数顺序。

他们在 8087 浮点指令的实现中与这种顺序存在一些不一致,可能是因为英特尔为非交换浮点指令的两个可能方向提供了不同的助记符,这些助记符与 AT&T 语法使用的操作数顺序不匹配。

PDP11 指令jmp (跳转)和jsr (跳转到子程序)跳转到它们操作数的地址。 因此, jmp foo会跳转到foojmp *foo会跳转到存储在变量foo的地址,类似于lea在 8086 中的工作方式。

x86 的jmpcall指令的语法被设计为好像这些指令在 PDP11 上工作一样,这就是为什么jmp foo跳转到foo并且jmp *foo跳转到地址foo处的值,即使 8086 实际上没有延迟寻址。 这具有在语法上区分直接跳转和间接跳转的优点和便利,而不需要每个直接跳转目标的$前缀,但在逻辑上没有多大意义。

语法被扩展为使用冒号指定段前缀:

seg:addr

引入 80386 时,该方案使用四部分通用寻址模式适应其新的 SIB 寻址模式:

disp(base,index,scale)

其中disp是位移,base 是基址寄存器, index是一个索引寄存器, scale是 1、2、4 或 8,以按这些数量之一缩放索引寄存器。 这等同于 Intel 语法:

[disp+base+index*scale]

PDP-11 的另一个显着特点是大多数指令都以字节和字的形式提供。 您使用的哪个由操作码的bw后缀表示,它直接切换操作码的第一位:

 010001   movw r0,r1
 110001   movb r0,r1

这也适用于 AT&T 语法,因为大多数 8086 指令确实也可用于字节模式和字模式。 后来 80386 和 AMD K6 引入了 32 位指令(后缀l表示long )和 64 位指令(后缀q表示 quad)。

最后但并非最不重要的一点是,最初的约定是在 C 语言符号前面加上下划线(在 Windows 上仍然如此),这样您就可以将名为ax的 C 函数与寄存器ax区分开来。 当 Unix System Laboratories 开发 ELF 二进制格式时,他们决定摆脱这种装饰。 由于无法区分直接地址和寄存器,因此每个寄存器都添加了%前缀:

mov direct,%eax # move memory at direct to %eax

这就是我们如何获得今天的 AT&T 语法。

汇编语言是由汇编程序定义的,汇编程序是解析汇编语言的软件。 唯一的“标准”是机器代码,它必须与处理器相匹配,但是如果你让 100 名程序员给他们机器代码标准(没有任何汇编语言提示),你最终会得到 1 到 100 种不同的汇编语言. 只要它们制作出适合工具链的完整工具,对于该处理器的所有用例(裸机、操作系统、应用程序工作),它们都可以完美运行。

创建描述指令集的文档和汇编程序(您需要的第一个工具)符合指令集(机器代码)创建者的最大利益。 他们可以将其外包或在内部制造,无论哪种方式都没有关系,但是拥有一个带有语法的汇编器和一个机器代码文档,它使用汇编器的语法来连接两者之间的点,会给任何人可能感兴趣的那个处理器是一个起点。 就像英特尔和 8086/88 的情况一样。 但这并不意味着 masm 和 tasm 与 intels 汇编程序完全兼容。 即使每条指令的语法匹配,每条指令的语法只是汇编语言的一部分,还有很多非指令类型的语法、指令、宏语言等。 那是从 DOS 世界末日开始的UNIX 结束,因此 AT&T。 当时的 gnu 人是 unix 世界末日,所以他们使用 AT&T 语法或派生的语法是完全合理的,因为他们通常在移植过程中搞砸了汇编语言。 也许有一个例外。

nasm 和其他一些类似的尝试继续使用 masm 语法,因为 masm 是一个封闭源代码的 Microsoft 工具(就像 tasm 和 Borland C 的任何东西,如果那不是 tasm 也是如此)。 这些现在可能是开源的,但没有必要,从头开始编写一个比尝试移植该代码更容易,我假设是用现代编译器构建的,并且 nasm 已经存在。

为什么的问题就像问我为什么选择今天早上或任何一天选择的那双袜子一样。 你的袜子对世界其他地方的影响可能没有那么大,但这个问题同样无关紧要和/或无法回答。 部分答案可以追溯到要求 100 名程序员为相同的机器代码定义制作一个汇编程序。 这些程序员中的一些可能对汇编语言有经验,并且可能会选择按照他们以前使用过的语言创建一种汇编语言,这意味着他们中的一些人将使一种看起来非常相似。 但是他们之前使用的一个或多个可能不同,因此会有这些相似但仍然不同的组。 然后让我们说 30 年问这 100 个人中的每一个人为什么问题......如果他们还活着......就像问我为什么你选择在你 30 年前编写的程序中以你所做的方式声明一个变量它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM