x86_64 AT&T汇编调用printf执行报错:required file not found
64位ELF汇编调用printf报错排查与修正
问题描述
开发编译器时生成x86_64 AT&T汇编代码,试图调用libc的printf函数,目标架构为64位ELF。使用以下命令编译链接生成可执行文件:
as --64 examples/out/test.S -o examples/out/test.o && ld -lc examples/out/test.o -o examples/out/test
运行./examples/out/test时出现错误:
bash: examples/out/test: cannot execute: required file not found
原汇编代码test.S内容如下:
;#; This file was generated by the MZ compiler. .section .data b: .space 8 a: .space 8 fmt: .asciz "%lld" .global _start .section .text _start: push %rbp mov %rsp, %rbp lea a(%rip), %rax movq $420, (%rax) lea b(%rip), %rax movq $42, (%rax) movq $42069, %rdx lea fmt(%rip), %rcx call printf pop %rbp movl $0, %ebx movl $1, %eax int $0x80
报错原因分析
- 动态链接器路径缺失:直接用
ld -lc链接时,未指定64位系统的动态链接器路径,导致系统无法找到运行时所需的动态链接器,进而无法加载依赖的libc库。 - 调用约定违反规范:x86_64 System V ABI调用约定中,
printf的第一个参数(格式串)应放入%rdi寄存器,第二个参数(输出数值)应放入%rsi寄存器。原代码错误地将格式串放入%rcx、数值放入%rdx,完全违反调用约定,会导致函数调用行为异常。 - 栈未对齐:x86_64架构要求函数调用前栈保持16字节对齐。原代码中
push %rbp后栈指针偏移8字节,调用printf前未调整栈对齐,会触发运行时错误。 - 退出方式错误:
int $0x80是32位Linux系统调用接口,在64位程序中使用会导致系统调用参数传递错误,无法正常退出程序。
修正方案
1. 修正后的汇编代码
;#; This file was generated by the MZ compiler. .section .data b: .space 8 a: .space 8 fmt: .asciz "%lld\n" # 添加换行符,让输出更规范 .global _start .section .text _start: push %rbp mov %rsp, %rbp # 示例数据赋值(保留原逻辑) lea a(%rip), %rax movq $420, (%rax) lea b(%rip), %rax movq $42, (%rax) # 调整栈对齐:push %rbp后栈偏移8字节,sub $8凑16字节对齐 sub $8, %rsp # 按照x86_64 System V ABI传递printf参数 movq $42069, %rsi # 第二个参数:要输出的数值 lea fmt(%rip), %rdi # 第一个参数:格式串 call printf # 恢复栈 add $8, %rsp pop %rbp # 使用64位系统调用退出程序 mov $60, %rax # exit系统调用号(64位) mov $0, %rdi # 退出码 syscall
2. 正确的编译链接命令
方式一:用gcc自动处理链接细节(推荐)
gcc会自动处理动态链接器、libc依赖和栈对齐等问题:
as --64 examples/out/test.S -o examples/out/test.o && gcc -no-pie examples/out/test.o -o examples/out/test
或直接用gcc编译汇编文件:
gcc -no-pie examples/out/test.S -o examples/out/test
方式二:手动用ld指定动态链接器
若必须用ld,需明确指定64位动态链接器路径(WSL Kali中通常为/lib64/ld-linux-x86-64.so.2):
as --64 examples/out/test.S -o examples/out/test.o && ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc examples/out/test.o -o examples/out/test
验证
运行修正后的可执行文件,会输出42069,程序正常退出,无报错。
内容的提问来源于stack exchange,提问作者Mihir Patel
相关产品推荐
相关产品推荐

