16(%esp)
与[esp+16]
相比真的违反直觉的人吗?不是更多逻辑:
eax = 5
mov eax, 5
at& t是:
mov 5, eax
5 = a (? wait what ?)
注意: 我不是想乱跑。我只是不明白他们所做的设计选择,我想知道他们为什么做了他们所做的事。
答案 0 :(得分:26)
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')后缀 。请注意,后缀并非总是 required 。例如,您可以写:
mov %al, (%ebx)
让GNU汇编程序“弄清楚”,因为你在谈论'%al',所以移动是针对单个字节的。真的行 !然而,我仍然发现更好地指定大小(它确实有助于读者,而程序员本身也是他自己代码的首要读者)。
对于“倒置”:反之亦然。英特尔语法模仿C中发生的事情,其中值在右侧计算,然后写入左侧的值。因此,考虑到从左到右的阅读,写作在“反向”方向上从右到左。 AT& T语法恢复到“正常”方向。至少他们考虑过这样;因为无论如何他们决定使用他们自己的语法,他们认为他们可以在他们认为的“正确的顺序”中使用操作数。这主要是一个惯例,但不是一个不合逻辑的惯例。 C约定模仿数学符号,除了数学是关于定义值(“让x是值5”)而不关于分配值(“我们写值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系统中,它们应该由OS供应商提供。此外,英特尔在Unix世界中并不是一个重要的参与者;大系统主要使用VAX或Motorola 680x0衍生产品。 20年后,没有人发现MS-Dos PC将成为台式机和服务器领域的主导架构。
答案 1 :(得分:9)
1-2,5:他们可能选择为寄存器加前缀,以便更容易解析;你直接知道第一个字符是什么样的标记。
4:不。
6:同样,可能是为了让解析器更容易找出要输出的指令。
7:实际上这在语法意义上更有意义,将 移动到 。也许 mov 指令应该是 ld 指令。
不要误会我的意思,我认为AT& T语法很糟糕。
答案 2 :(得分:7)
GNU汇编程序的AT& T语法的起源是Unix汇编程序 1 ,它本身的输入语法主要来自PDP-11 PAL-11汇编程序(约1970年)。
有人可以向我解释为什么AT& T语法中的每个常量都在它前面有一个'$'吗?
它允许区分立即常量和内存地址。英特尔语法反过来,内存引用为[foo]
。
顺便说一句,MASM(Microsoft Assembler)不需要在语法级别上进行区分,因为它可以判断操作数是符号常量还是标签。 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
提到b
。
这只是让我做了很多蹩脚打字的另一种尝试吗?
不。
另外,我是唯一一个发现:16(%esp)与[esp + 16]相比真的违反直觉吗?
这来自PDP-11 索引寻址模式,其中通过将寄存器的内容与指令之后的索引字相加来形成存储器地址。
我知道它编译成同样的东西,但为什么有人想要输入很多'$'和'%'而不需要? - 为什么GNU选择 这种语法是默认的吗?
它来自PDP-11。
天然气通常可以搞清楚。其他装配工在特定情况下也需要帮助。另一件事,为什么at& t语法中的每条指令前面都有一个:l? - 我知道它的操作数大小,但为什么不让它 汇编人员说出来了吗? (我会不想做一个电影 不是那么大的操作数?)
PDP-11将CLR
用于字节指令,例如:CLRB
vs l
。其他后缀出现在VAX-11中:w
为长,f
为单词,d
为浮点数,q
为双,Last thing: why are the mov arguments inverted?
为四字, ...
{{1}}
可以说,由于PDP-11早于英特尔微处理器,它就是另一种方式。
答案 3 :(得分:2)
与英特尔相比,AT& T语法颠倒操作数顺序的原因很可能是因为最初开发Unix的PDP-11使用相同的操作数顺序。
英特尔和DEC只是选择了相反的订单。