23
  1. 谁能向我解释为什么 AT&T 语法中的每个常量前面都有一个“$”?
  2. 为什么所有寄存器都有一个'%'?
  3. 这只是让我做很多蹩脚打字的另一种尝试吗?
  4. 另外,我是唯一一个发现:16(%esp)与 相比真的违反直觉[esp+16]吗?
  5. 我知道它编译成同样的东西,但为什么有人想要输入很多'$'和'%'而不需要呢?- 为什么 GNU 选择这种语法作为默认语法?
  6. 另一件事,为什么 at&t 语法中的每条指令前面都有一个:l?- 我确实知道它的操作数大小,但是为什么不让汇编器弄清楚呢?(我会想对不是那么大的操作数做一个 movl 吗?)
  7. 最后一件事:为什么 mov 参数倒置了?

是不是合乎逻辑:

eax = 5
mov eax, 5

at&t 是:

mov 5, eax
5 = a (? wait what ?)

注意:我不是要拖钓。我只是不明白他们所做的设计选择,我试图了解他们为什么要这样做。

4

4 回答 4

30

1、2、3和5:符号有点多余,但我发现在汇编开发时这是一件好事。冗余有助于阅读。“让汇编程序自己弄清楚”这一点很容易变成“让阅读代码的程序员自己弄清楚”,而我不喜欢当我是阅读代码的人时。编程不是只写任务;甚至程序员自己也必须阅读自己的代码,语法冗余也有很大帮助。

另一点是 '%' 和 '$' 意味着可以在不破坏向后兼容性的情况下添加新寄存器:添加例如名为 的寄存器没有问题xmm4,因为它会写成%xmm4,不能与变量混淆调用xmm4它将不带“%”写入。

至于打字量:通常,在汇编中编程时,瓶颈是大脑,而不是手。如果 '$' 和 '%' 减慢了你的速度,那么要么你的思考速度比通常认为对人类可行的要快,或者更有可能是你手头的任务过于机械化,不应该在部件; 它应该留给自动代码生成器,俗称“C编译器”。

添加了“l”后缀以处理汇编程序“无法”解决的某些情况。例如,这段代码:

mov  [esp], 10

是模棱两可的,因为它不知道您是要写入值 10 的字节,还是要写入具有相同数值的 32 位字。然后,英特尔语法要求:

mov  byte ptr [esp], 10

当您考虑时,这很丑陋。AT&T 的人想让事情变得更理性,所以他们想出了:

movb   $10, (%esp)

他们更喜欢系统化,并且到处都有“b”(或“l”或“w”)后缀。请注意,后缀并不总是必需的。例如,您可以编写:

mov   %al, (%ebx)

并让 GNU 汇编器“弄清楚”,因为你在谈论 '%al',所以移动是针对单个字节的。真的行 !然而,我仍然觉得指定大小更好(这对读者很有帮助,程序员本人是他自己代码的第一个也是最重要的读者)。

对于“反转”:相反。英特尔语法模仿 C 中发生的情况,其中值在右侧计算,然后写入左侧。因此,考虑到阅读是从左到右的,写作从右到左,在“反向”方向上。AT&T 语法恢复到“正常”方向。至少他们是这么认为的;因为他们决定无论如何都要使用自己的语法,所以他们认为可以按照他们认为的“正确顺序”来使用操作数。这主要是一种约定,但不是不合逻辑的约定。C 约定模仿数学符号,除了数学是关于定义值(“让 x 是值 5”)而不是关于分配值(“一个名为“x”的插槽)。AT&T 的选择是有道理的。只有当您将 C 代码转换为汇编时,它才会令人困惑,该任务通常应该留给 C 编译器。

从历史的角度来看,问题 5 的最后一部分很有趣。x86 的 GNU 工具遵循 AT&T 语法,因为当时它们正试图在 Unix 世界中占据一席之地(“GNU”的意思是“GNU 不是 Unix”)并与 Unix 工具竞争;Unix 由 AT&T 控制。这是在 Linux 甚至 Windows 3.0 出现之前;PC 是 16 位系统。Unix 使用 AT&T 语法,因此 GNU 使用 AT&T 语法。

那么好问题是:为什么 AT&T 发现发明自己的语法很聪明?如上所述,他们有一些理由,这些理由并非没有道理。当然,使用您自己的语法的代价是它限制了互操作性。在那些日子里,C 编译器或汇编器作为一个单独的工具并没有真正的意义:在 Unix 系统中,它们应该由操作系统供应商提供。此外,英特尔在 Unix 世界中并不是一个大玩家。大型系统大多使用 VAX 或摩托罗拉 680x0 衍生产品。没有人想到 MS-Dos PC 会在 20 年后成为桌面和服务器世界的主导架构。

于 2010-11-16T13:25:40.493 回答
11

1-2, 5:他们可能选择在寄存器前加上前缀,以便更容易解析;您可以直接在第一个字符处知道它是什么类型的标记。

4:没有。

6:同样,可能是为了让解析器更容易弄清楚要输出什么指令。

7:实际上这在语法上更有意义,将什么移到哪里。也许mov指令应该是ld指令。

不要误会我的意思,我认为 AT&T 语法很糟糕。

于 2010-11-16T12:03:30.407 回答
9

GNU 汇编器的 AT&T 语法可以追溯到 Unix 汇编器1,它本身的输入语法主要来自 PDP-11 PAL-11 汇编器(约 1970 年)。

谁能向我解释为什么 AT&T 语法中的每个常量前面都有一个“$”?

它允许将立即常量与内存地址区分开来。英特尔语法则相反,内存引用为[foo].

顺便说一句,MASM(Microsoft 汇编程序)不需要在语法级别进行区分,因为它可以判断操作数是符号常量还是标签。x86 的其他汇编器积极避免这种猜测,因为它们可能会让读者感到困惑,例如:IDEAL 模式下的 TASM(它警告不在括号中的内存引用)、nasm、fasm。

PAL-11 用于#立即寻址模式,其中操作数跟随指令。#一个没有表示相对寻址模式的常量,其中相对地址跟随指令。

Unix 使用与 DEC 汇编程序相同的寻址模式语法,用*而不是@,和$而不是#,因为@#显然不方便键入2

为什么所有寄存器都有一个'%'?

在 PAL-11 中,寄存器定义为 R0=%0, R1=%1, ... R6 也称为 SP,R7 也称为 PC。DEC MACRO-11 宏汇编器允许将寄存器称为%x,其中x可以是任意表达式,例如%3+1称为%4

这只是让我做很多蹩脚打字的另一种尝试吗?

没有。

另外,我是唯一一个发现:16(%esp) 与 [esp+16] 相比真的违反直觉的人吗?

这来自 PDP-11索引寻址模式,其中存储器地址是通过将寄存器的内容和指令后的索引字相加形成的。

我知道它编译成同样的东西,但为什么有人想要输入很多'$'和'%'而不需要呢?- 为什么 GNU 选择这种语法作为默认语法?

它来自 PDP-11。

另一件事,为什么 at&t 语法中的每条指令前面都有一个:l?- 我确实知道它的操作数大小,但是为什么不让汇编器弄清楚呢?(我会想对不是那么大的操作数做一个 movl 吗?)

气一般都能算出来。在特定情况下,其他汇编程序也需要帮助。

PDP-11 将b用于字节指令,例如:CLRvs CLRB. VAX-11 中还出现了其他后缀:lfor long、wfor word、ffor float、dfor double、qfor quad-word、...

Last thing: why are the mov arguments inverted?

可以说,由于 PDP-11 早于英特尔微处理器,因此情况正好相反。


  1. 根据gas info-page,通过BSD 4.2汇编器。
  2. Unix 汇编程序参考手册 §8.1 - Dennis M. Ritchie
于 2016-03-05T17:49:42.753 回答
2

与 Intel 相比,AT&T 语法反转操作数顺序的原因很可能是因为最初开发 Unix 的 PDP-11 使用相同的操作数顺序。

英特尔和 DEC 只是选择了相反的订单。

于 2015-09-18T14:28:24.087 回答