大会我们需要结局吗? [复制]

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 的内置汇编器(正确地)拒绝模棱两可的指令。

以上是关于大会我们需要结局吗? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

蛞蝓 Django 领域;我们需要这个吗? [复制]

一个熟悉的场景,RabbitMQ给你不一样的结局

FRB数据库:不同类型的CNV 5年长期结局也会不同吗? —隐匿型CNV和经典型CNV 5年长期治疗结局

电子女孩运行崩溃

Dart - null 感知运算符,为啥!需要吗? [复制]

nodejs 8导入模块-需要还是导入? [复制]