x86-64 AT&T汇编中标签与变量的mov指令差异咨询
x86-64 AT&T汇编寻址问题解答
问题1:test_label 相关三条mov指令的差异
先明确AT&T汇编的基础寻址规则:
- 带
$前缀的符号代表符号的地址本身(立即数),赋值过程不涉及内存读写 - 不带前缀的符号默认代表符号对应内存地址的存储内容,属于直接内存寻址
- 括号
()代表间接寻址逻辑,会把括号内的值作为内存地址,访问该地址的存储内容
三条指令的具体行为:
mov test_label,%eax#1:直接内存寻址操作。获取test_label对应的内存地址,读取该地址处的4字节数据写入%eax寄存器,等价于C逻辑eax = *(uint32_t *)test_labelmov (test_label),%eax#2:绝对间接内存寻址操作。将test_label对应的地址值作为内存访问基地址,读取该地址处的4字节数据写入%eax。在GNU汇编器(gas)默认配置下,这条指令和#1执行效果完全一致——因为test_label是编译链接阶段就确定的常量地址,两种写法最终都会解析为访问test_label地址处的内存。mov $test_label,%eax#3:立即数寻址操作。直接将test_label对应的内存地址本身作为立即数写入%eax寄存器,全程没有内存读操作,等价于C逻辑eax = (uint32_t)test_label
地址、值读取维度差异:
- 地址维度:#1、#2实际访问的内存地址为
test_label的地址值;#3不访问内存,直接将test_label的地址值作为赋值内容 - 值读取维度:#1、#2读取的是
test_label指向的内存存储的业务数据;#3读取的是test_label本身的地址常量值
问题2:.data段int变量var相关三条mov指令的差异
前提:var是.data段定义的4字节int类型变量,链接后对应固定内存地址,地址内存储的是变量的int值。
三条指令的具体差异:
mov var,%eax#4:直接内存寻址,读取变量var存储的4字节int值写入%eax,等价于C逻辑eax = varmov (var),%eax#5:绝对间接内存寻址,和#4的执行效果完全相同。因为var对应的地址是编译链接确定的常量,两种写法都会解析为访问var地址处的内存数据,无实际差异。mov $var,%eax#6:立即数寻址,直接将变量var的内存地址本身作为立即数写入%eax,等价于C逻辑eax = (uint32_t)&var
注意:以上等价逻辑仅针对常量地址的场景,如果是寄存器间接寻址(比如
mov (%rbx),%eax),括号的作用会完全不同:该指令是把%rbx存储的值作为内存地址,读取对应地址的4字节到%eax,和不带括号的mov %rbx,%eax(直接把%rbx的低32位赋值给%eax)有本质区别,不要混淆。
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

