如何在x86_64 AT&T语法汇编的数据段定义函数静态局部变量
汇编实现函数静态局部变量(pi)的正确方式
你的代码存在两个核心问题:
- 重复定义全局符号
pi:两个函数里的pi都是全局可见的符号,链接时会触发重复定义错误 - 错误使用
.data段:不管你把.data插在函数内还是全局位置,最终都会合并到全局数据区,无法实现变量的函数局部可见性
要实现C语言中静态局部变量的效果(仅对所属函数可见,初始化一次),可以用GAS汇编的**局部符号(以.L开头)**配合只读数据段(因为pi是常量,适合放在.rodata),具体修改如下:
.data radius: .double 10.0 .text .global main main: pushq %rbp movq %rsp, %rbp call circle movq %rbp, %rsp popq %rbp ret .type circle, @function circle: pushq %rbp movq %rsp, %rbp # 计算面积 call area movl $1, %eax movq $fmtare, %rdi call printf # 计算周长 call circum movl $1, %eax movq $fmtcir, %rdi call printf movq %rbp, %rsp popq %rbp ret .type area, @function area: # 定义area函数专属的静态局部pi(只读,局部符号) .section .rodata, "a", @progbits .Lpi_area: .double 3.14 .section .text, "ax", @progbits pushq %rbp movq %rsp, %rbp movsd .Lpi_area(%rip), %xmm0 # 使用RIP相对寻址访问局部符号 mulsd radius(%rip), %xmm0 mulsd radius(%rip), %xmm0 movq %rbp, %rsp popq %rbp ret .type circum, @function circum: # 定义circum函数专属的静态局部pi(只读,局部符号) .section .rodata, "a", @progbits .Lpi_circum: .double 3.141592 .section .text, "ax", @progbits pushq %rbp movq %rsp, %rbp movsd radius(%rip), %xmm0 addsd radius(%rip), %xmm0 mulsd .Lpi_circum(%rip), %xmm0 movq %rbp, %rsp popq %rbp ret # 全局格式字符串 .section .rodata fmtare: .asciz "The area is %g\n" fmtcir: .asciz "The circumference is %g\n"
关键说明:
- 局部符号
.Lpi_area/.Lpi_circum:以.L开头的符号是汇编器局部符号,不会被导出到目标文件的符号表,因此其他函数无法访问,实现了局部可见性 - RIP相对寻址:
symbol(%rip)是x86-64下的位置无关寻址方式,适合访问静态数据,避免硬编码地址 .rodata段:pi是常量,放在只读数据段更合理,避免意外修改,同时节省内存(只读数据可以被多个进程共享)
如果需要的是可修改的静态局部变量(而非常量),只需把.rodata换成.data段,同样用.L前缀的局部符号即可。
内容的提问来源于stack exchange,提问作者arka
相关产品推荐
相关产品推荐

