Linux下x86_64汇编声明时字符串长度的参数传递异常问题
搞定这个x86_64汇编的奇怪数值问题
嘿,这个坑我踩过好多次了!你遇到的无意义大数值问题,根源是x86_64架构下64位寄存器和32位数据定义的不匹配,具体拆解给你看:
- Linux x86_64的
sys_write系统调用要求第三个参数(存在%rdx寄存器里)是64位的长度值,但你定义的len1用的是.long——这是32位整数类型,只占4字节内存。 - 当你直接把
len1加载到64位的%rdx时,汇编器会执行64位的内存读取操作,相当于把len1的4字节有效数据,加上它后面内存里随机的4字节垃圾数据,拼成了一个8字节的超大数,也就是你看到的那个无意义长串。 - 至于
sys_exit的%rdi寄存器看起来正常?那多半是巧合——要么len1后面的内存恰好是0,要么你用了32位加载(比如mov edi, len1),这种情况下x86_64会自动把32位值零扩展到64位,所以结果正常,但这不是靠谱的写法。
两种靠谱的修复方法
方法1:把长度变量改成64位类型
直接把.long换成.quad(x86_64下的64位整数类型),这样内存里存的就是完整的64位长度值,加载到%rdx时自然不会读入垃圾数据:
.section .data string1: .string "test\n" len1: .quad .-string1 # 用.quad替代.long,定义64位长度 string2: .string "another string\n" len2: .quad .-string2
方法2:加载时做零扩展(保留32位定义的话)
如果非要保留.long的定义,那加载的时候要明确用32位寄存器做中转,x86_64会自动把32位值零扩展到64位寄存器的高位,避免读取多余的内存垃圾:
# 错误写法:直接读64位,带垃圾数据 # mov rdx, len1 # 正确写法:先加载到32位edx,自动零扩展到rdx mov edx, len1
验证小技巧
你可以用objdump -d foo.o反汇编你的目标文件,看看加载len1的指令:
- 如果是
mov rdx,0xXXXXXX这种,就是64位读取,肯定会带垃圾数据; - 如果是
mov edx,0xXXXXXX,就是32位读取,自动零扩展,结果就对了。
内容的提问来源于stack exchange,提问作者Lourenco
相关产品推荐
相关产品推荐

