今天在进行汇编程序调用 C 函数的时候出现了几个问题罗列如下:
1. ld 链接问题
ld: 当搜索用于 //usr/lib/x86_64-linux-gnu/libc.so 时跳过不兼容的 -lc
ld: 当搜索用于 //usr/lib/x86_64-linux-gnu/libc.a 时跳过不兼容的 -lc
ld: 找不到 -lc
使用的链接命令为:
ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o output_file -lc input_file.o
当时以为错误出在系统没有正确的生成 32 位代码加了-m elf_i386
选项,结果发现命令中指定加载的是 32 位动态库,系统默认链接的是 64 位目标代码,产生不兼容错误.正确的链接方式应该是:
ld --dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc -o output_file input_file.o
PS: 在汇编中调用 C 函数需要采用静态链接或动态链接的方法. 静态链接会把函数目标代码直接连接到应用程序的可执行文件中. 动态链接使用库方式,使得可以在应用程序中引用函数,运行时由操作系统调用动态链接库. 调用链接库的选项为-l
选项-lc
指调用libc.*
库
2. 调用时传参问题
编译成功后运行,报错段错误(核心已转储)使用 gdb 调试发现错误出现在函数调用时,查阅一番后发现:原代码是采用堆栈方式传参
这种方式是在 32 位环境下使用的方法,64 位环境采用寄存器传参方式
规则为:
当参数少于 7 个时, 参数从左到右对应寄存器: rdi, rsi, rdx, rcx, r8, r9.
当参数为 7 个以上时,多出参数依次压入堆栈.
RAX 放置函数返回值
调用者负责平衡栈
一些代码因为采用堆栈传参
函数调用后会对 esp 执行 addl 指令恢复堆栈指针
在改动相关代码时要留意删除该指令