【问题标题】:curious gcc compiler code for x |= 128 when x is uint8x 为 uint8 时 x |= 128 的好奇 gcc 编译器代码
【发布时间】:2017-09-29 16:07:04
【问题描述】:

我最近偶然发现了一个我不理解的有趣的编译器代码。 取以下代码:

unsigned char x;
...
x |= 127;
x |= 128;

对于第一条语句,编译器生成:

or eax, 0x7f.

但是,对于第二个语句,它变成:

or eax, 0xffffff80

似乎对于小于 127 的值,使用 1 字节值,而 128 之后的 dword 是首选。

有人知道为什么会这样吗? 我复制了这个 gcc 6.2(我认为是最新的)。

我尝试在 gcc 邮件列表(gcc-bugs@gcc.gnu.org 或 gcc-help@gcc.gnu.org)上发帖,但我只收到了投递失败。

【问题讨论】:

  • 我怀疑这只是您的反汇编程序格式化数字的一种伪影(0x80 如果解释为有符号数字,则为负数)。
  • 我正在使用 gdb。这是它在控制台中打印值的方式pastebin.com/0A2SXUNU
  • 我还用 -S 编译了代码,得到了这个:pastebin.com/g8aSn9iy
  • 如果使用 gcc -S 编译,生成的 .s 文件有orl $-128, %eax。对于邮件列表,通常失败带有解释(通常,您尝试发送 html 电子邮件而不是纯文本)。
  • 两条指令都执行 32 位“双字”大小的 OR 运算,并且两条指令都使用符号扩展为 32 位的 8 位立即操作数进行编码。

标签: c gcc assembly compiler-optimization cpu-registers


【解决方案1】:

从反汇编输出中可以看出,两条指令都是 3 字节宽:

 83 c8 7f                or     $0x7f,%eax
 83 c8 80                or     $0xffffff80,%eax

83 / 1 是32-bit register / memory with 8-bit sign-extended immediate value:

83 /1 ib    OR r/m32,imm8   r/m32 OR imm8 (sign-extended).

因此实际上它确实改变了 32 位寄存器的不可见部分,但这并不重要。它的效率不低于任何其他方法。也没有任何指令对 8 位立即数进行符号扩展,除了那些使用 8 位寄存器半/四分之一操作的指令。但是使用此指令使其与其他寄存器的工作方式相同,这些寄存器可通过r/m32 寻址但不能作为单个字节访问(例如edi、esi)。

【讨论】:

  • 你是如何生成这种形式的汇编指令的?
  • -c编译成目标文件(我有64位电脑,所以我用-m32编译);然后从.o 文件中查看objdump -d
  • 好的,好消息是汇编代码很好。但是看看这些显示方式有什么问题会很有趣。
  • 没什么错,只是编译器的大小优化。使用 0x00000080 需要更长的 5 字节指令。
  • @SterpuMihai 没有错。 0x80 解释为 8 位有符号整数值是 -128,表示为 32 位有符号整数值时等于 0xFFFFFF80。因此机器代码使用 8 位形式存储值,反汇编程序显示扩展的 32 位值,or 计算本身将使用该值,节省您将 0x80 从 8 位转换为 32 的工作量位以完全理解计算。 eax 的高位 24b 会被它损坏,但这没关系,因为 xchar,所以只有低 8 位值是相关的。
猜你喜欢
  • 1970-01-01
  • 2017-08-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-18
  • 1970-01-01
  • 2010-12-31
  • 2013-01-06
相关资源
最近更新 更多