NASM编写调用printf的汇编代码编译失败,加-fPIE仍报错求助
NASM调用printf编译错误修复
问题背景
编写了调用printf的NASM汇编代码,编译时遇到标签警告和PIE重定位错误,添加-fPIE选项无效,直接用ld链接出现段错误。
原汇编代码
section .text global main extern printf main: endbr64 push rbp mov rdi, [array + 1 * 4] mov rsi, specifer mov rax, 0 call printf pop rbp mov rax, 0 ret section .data array db 1,2,3,4,5,6,7,8,9,1 arrlen equ $ - array specifer db '%d',0xa,0 speclen equ $ - specifer
编译命令
nasm -f elf64 arrays.asm gcc arrays.o
错误信息
arrays.asm:6: warning: label alone on a line without a colon might be in error [-w+orphan-labels] /usr/bin/ld: arrays.o: relocation R_X86_64_32S against `.data' can not be used when making a PIE object; recompile with -fPIE collect2: error: ld returned 1 exit status
工具版本
- NASM: 2.14.02
- GCC: 9.4.0
- ld: 2.34
错误原因与修复方案
1. 标签警告修复
错误提示的endbr64是CET(控制流强制技术)指令,部分旧版NASM可能无法正确识别该指令,导致误判为无冒号的标签。
- 直接删除
endbr64行即可消除警告(如果不需要CET功能); - 若需保留该指令,可用字节码替代:
db 0xf3, 0x0f, 0x1e, 0xfa。
2. PIE重定位错误修复
64位Linux下GCC默认生成PIE(位置独立可执行文件),这类程序要求访问数据段时必须使用RIP相对寻址,原代码使用的绝对寻址会触发重定位错误。同时原代码存在数据宽度错误:
array是单字节数组(db),原代码mov rdi, [array + 1*4]会读取8字节数据,导致内存越界,需用movzx零扩展单字节到64位寄存器;- 访问数据符号前需加
rel前缀,生成RIP相对地址。
修正后的汇编代码
section .text global main extern printf main: push rbp ; 取array偏移4的单字节元素,零扩展到rdi(printf第一个参数) movzx rdi, byte [rel array + 4] ; 加载格式字符串的RIP相对地址到rsi(printf第二个参数) mov rsi, rel specifer mov rax, 0 call printf pop rbp mov rax, 0 ret section .data array db 1,2,3,4,5,6,7,8,9,1 arrlen equ $ - array specifer db '%d',0xa,0 speclen equ $ - specifer
正确编译命令
直接使用原命令即可,无需额外添加-fPIE:
nasm -f elf64 arrays.asm gcc arrays.o -o arrays
若需明确指定PIE编译,可添加-fPIE选项:
nasm -f elf64 arrays.asm gcc -fPIE arrays.o -o arrays
关于ld链接段错误的说明
ld不会自动链接C标准库和启动代码(如crt0.o),而printf依赖C标准库,因此必须用GCC完成链接,它会自动处理这些依赖项。
内容的提问来源于stack exchange,提问作者raging-loon
相关产品推荐
相关产品推荐

