大会我们需要结局吗? [复制]
Posted
技术标签:
【中文标题】大会我们需要结局吗? [复制]【英文标题】:Assembly do we need the endings? [duplicate] 【发布时间】:2021-05-25 15:23:11 【问题描述】:在汇编 (att) 中,以下是合法的:
mov %rax, %rbx
等于:
movq %rax, %rbx
其中q表示第一个参数是64位,我的问题是:
这个 q(或其他结尾)是否仅用于人类阅读的简单性,或者在某些情况下,不写 q 会给出错误的答案或与预期不同的结果,甚至会导致代码崩溃(非法命令),请如果可能的话,给我一个例子。
【问题讨论】:
movq $1, (%rbx)
需要 Q 来确定内存操作数的大小。
我认为还有其他副本,以及我链接的副本,但可能仅适用于 NASM。 (对于所有的汇编器都是一样的,除了那些对于模棱两可的情况有一些随机默认值的坏的汇编器)。我链接的那个确实在 Cody 的回答中提到了 AT&T 语法。
【参考方案1】:
您是在询问操作数大小后缀。有两种情况:
对于许多指令,操作数的大小可以从操作数本身推断出来,通常是因为它们是特定大小的寄存器。这就像您的示例:mov %rax, %rbx
必须具有 64 位操作数大小,因为 %rax, %rbx
是 64 位寄存器。在这种情况下,后缀是可选的,无论你写mov %rax, %rbx
还是movq %rax, %rbx
,都会生成相同的机器码(48 89 c3
)。是否选择包含它纯粹是风格问题(尽管人们肯定对哪种方式更好有意见)。
如果您提供的后缀与操作数不一致,例如movl %rax, %rbx
,汇编器会给出警告或错误。
在其他情况下,无法推断操作数大小。最常见的情况是一个操作数是立即数,而另一个是内存引用。如果您从 cmets 为 ecm 的示例编写 mov $1, (%rbx)
,这是模棱两可的:汇编器应该发出指令来存储一个字节(机器代码 c6 03 01
),还是一个字(两个字节,66 c7 03 01 00
),还是一个长 (四个字节,c7 03 01 00 00 00
),还是一个四字节(八个字节,48 c7 03 01 00 00 00
)?所以在这种情况下需要一个后缀:你必须写movb $1, (%rbx)
或movw $1, (%rbx)
等等。
如果您在这种情况下省略后缀,最新的汇编器版本至少应该会警告您。然后有些会因错误而中止;其他人可能会猜测操作数大小或使用一些内置默认值,如下面的 Peter cmets。一些较旧的汇编器版本实际上会在没有警告的情况下恢复为默认值。
所以原则上,是的,省略后缀可能会导致“错误”代码,在某些情况下和某些汇编程序。但是,目前广泛使用的 AT&T 语法汇编器版本至少会警告您。
然而,还有另一种可能发生这种情况的方法:假设您想将 5 添加到 32 位寄存器 eax
(addl $5, %eax
),但您打错了字并省略了 e
。如果你有使用后缀的习惯,你会写addl $5, %ax
并得到一个汇编错误,提醒你你的错误。如果你的风格是省略它们,你会写 add $5, %ax
并且代码会完美构建但会“错误”。
【讨论】:
有趣的事实:对于mov
以外的模棱两可的指令,GAS 默认为 dword:例如add $1, (%rax)
组装成 83 00 01 add DWORD PTR [rax],0x1
。在过去一年多的时间里,GAS 终于加了一个警告:Warning: no instruction mnemonic suffix given and no register operands;使用“添加”的默认值。我不知道 GAS 是如何以这种糟糕的设计结束的,或者为什么它直到最近的版本才发出警告。 (我有as
2.35.1),虽然我读过一些关于 Unix 汇编器具有 dword 默认值的内容。 clang 的内置汇编器(正确地)拒绝模棱两可的指令。以上是关于大会我们需要结局吗? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
FRB数据库:不同类型的CNV 5年长期结局也会不同吗? —隐匿型CNV和经典型CNV 5年长期治疗结局