GNU汇编中如何在偏移量中使用立即数?求助解决相关错误
问题分析与解决建议
错误原因拆解
第一个代码的编译错误
你写的movq $50, mem($3)是错误的AT&T语法:
- x86_64 AT&T语法中,直接指定偏移量访问符号地址的正确格式是
mem+3(或3+mem),而非mem($3)。 - 另外,你要写入的是单个字节,用
movq会一次性写入8字节,覆盖后续7个字节,应该用movb指令。
第二个代码的段错误
movq mem, %rbx是错误的:
- AT&T语法中,不加
$表示访问该地址的内容,而非取地址。mem在.bss段初始值为0,这条指令会把0加载到%rbx,后续访问3(%rbx)就是访问虚拟地址3,属于非法内存,触发段错误。 - 正确取地址的写法是
movq $mem, %rbx(加$表示立即数,即mem的地址)。 - 同样,写入单个字节应该用
movb而非movq。
正确实现方案
方案1:直接用符号+偏移量(无需寄存器,符合你的需求)
利用x86_64的PC相对寻址,直接通过符号+偏移访问内存,无需额外寄存器:
.bss mem: .zero 30000 # 30KB空字节串 .text .globl main main: pushq %rbp movq %rsp, %rbp movb $50, mem+2 # 注:字节索引从0开始,第3个字节对应偏移2;若你是从1计数的第3个字节,此处用+2 movzbl mem+2, %edi # 读取该字节并零扩展到%edi(putchar需要int类型参数) call putchar leave ret # main函数需返回,补充ret指令避免未定义行为
方案2:用寄存器保存地址(适合多次复用地址的场景)
如果需要多次访问mem,可以先把地址存入寄存器,注意正确的取地址写法和字节操作:
.bss mem: .zero 30000 .text .globl main main: pushq %rbp movq %rsp, %rbp movq $mem, %rbx # 把mem的地址加载到%rbx(加$表示立即数) movb $50, 2(%rbx) # 写入第3个字节(偏移2) movzbl 2(%rbx), %edi call putchar leave ret
关键注意点
- AT&T语法中,立即数必须加
$,符号地址取地址时也要加$,否则是访问该地址的内容。 - 操作单个字节用
movb,操作双字用movl,四字用movq,避免不必要的内存覆盖。 main函数最后必须加ret指令返回,否则会导致未定义行为。
内容的提问来源于stack exchange,提问作者Angela Riley
相关产品推荐
相关产品推荐

