汇编代码中addr32前缀含义及双addr32出现原因
addr32前缀的含义 先贴对应反汇编片段:
adcx %r13,%r13 #! PC = 0x55555557d9fb adox %rcx,%r10 #! PC = 0x55555557da01 adcx %r14,%r14 #! PC = 0x55555557da07 addr32 mulx %rdx,%rcx,%rbp #! PC = 0x55555557da0d mov 0x98(%rsi),%rdx #! EA = L0x7fffffffdc68; Value = 0x0000000000000000; PC = 0x55555557da13 adox %rax,%r11 #! PC = 0x55555557da1a adcx %r15,%r15 #! PC = 0x55555557da20 adox %rcx,%r12 #! PC = 0x55555557da26 mov $0x20,%rsi #! PC = 0x55555557da2c adox %rbp,%r13 #! PC = 0x55555557da33 addr32 addr32 mulx %rdx,%rcx,%rax #! PC = 0x55555557da39
单addr32的具体含义
addr32对应机器码字节0x67,是x86架构定义的地址长度覆盖前缀。64位长模式下默认内存寻址使用64位规则计算有效地址,当指令前携带0x67前缀时,会强制切换为32位寻址宽度计算内存操作数的有效地址。
你这段代码里的addr32和寻址宽度修改没有任何关系:此处mulx的操作数全是通用寄存器,不存在内存访问,自然没有切换寻址宽度的需求。这个前缀是编译器插入的冗余对齐填充字节,目的是把后续指令的起始地址凑到对齐边界(通常是16字节或缓存行起始位置),提升CPU取指和执行效率。GDB反汇编时没有把这个填充字节识别为对齐nop,就直接按前缀对应的助记符打印成了addr32。
连续两个addr32的成因
最后一行出现两个addr32,本质是编译器在这条mulx指令前连续插入了两个0x67字节凑对齐长度。
x86架构允许指令前存在不改变指令行为的冗余前缀,只要整条指令(含前缀)总长度不超过15字节的硬件限制,CPU执行时会直接忽略这些冗余前缀,不会抛出异常。反汇编工具只是逐字节解析机器码,遇到一个0x67就打印一个addr32,遇到两个就打印两个,不会主动做省略处理。
可以通过地址差直接验证:带单个addr32的mulx从0xda0d起始,到下一条指令0xda13总长度为6字节,比无冗余前缀的同形式mulx刚好多1字节,就是那个0x67填充字节;带双addr32的mulx从0xda39起始,两个0x67字节刚好把指令长度凑到对齐需要的数值。
这类冗余前缀的显示效果和反汇编工具版本有关,新版objdump、IDA等工具会把纯用于对齐的冗余前缀识别为填充数据,不会显示为
addr32助记符。
内容的提问来源于stack exchange,提问作者Alex Lai

