使用GCC编译汇编代码遇_start重复定义及R_X86_64_32重定位错误
这两个错误其实都是GCC默认行为和你的汇编代码预期不匹配导致的,咱们一个个拆解解决:
1. 解决multiple definition of _start错误
问题根源
GCC编译时默认会链接C标准库的启动代码(比如Scrt1.o),这套启动代码已经定义了_start作为程序的入口点;而你的汇编代码里又自己定义了_start,直接导致符号重复定义冲突。
两种解决思路
思路一:让GCC跳过C运行时启动代码
如果你不需要C标准库的初始化逻辑(比如环境变量、标准IO的初始化),可以直接告诉GCC不要链接CRT(C运行时),这样就不会有自带的_start和你写的冲突了。编译命令改成:
gcc -nostdlib cpuid.s -o cpuid
思路二:把汇编入口改成main,适配GCC默认流程
如果希望保留C运行时的功能,只需要把汇编里的_start换成main,让GCC的启动代码自动调用你的main函数。比如:
原汇编开头:
.global _start _start: # 你的代码逻辑
修改后:
.global main main: # 你的代码逻辑 # 注意:用main作为入口时,最后需要通过exit系统调用返回,保证程序正常退出 mov $60, %rax # x86_64下exit系统调用号为60 xor %rdi, %rdi # 返回值设为0 syscall
然后用原本的命令编译即可:
gcc cpuid.s -o cpuid
2. 解决relocation R_X86_64_32 against .data错误
问题根源
x86_64系统下,GCC默认会生成位置无关可执行文件(PIE)——这种模式要求程序能加载到任意内存地址,而你汇编里用了32位绝对地址访问.data段,不符合PIE的位置无关要求,因此触发重定位错误。
两种解决思路
思路一:禁用PIE编译
直接告诉GCC生成传统的非位置无关可执行文件,这样32位绝对寻址就能正常使用了。结合之前的场景,命令如下:
- 用
-nostdlib的场景:
gcc -nostdlib -no-pie cpuid.s -o cpuid
- 用
main作为入口的场景:
gcc -no-pie cpuid.s -o cpuid
思路二:修改汇编代码,使用64位位置无关寻址
如果想保留PIE的安全特性,可以把汇编里访问.data的代码改成RIP相对寻址(x86_64下位置无关代码的标准写法)。比如:
原代码(32位绝对寻址,报错):
mov $my_data, %rax
修改后(RIP相对寻址):
lea my_data(%rip), %rax
如果是直接读取数据到寄存器:
原代码:
mov my_data, %eax
修改后:
mov my_data(%rip), %eax
修改完成后,用默认GCC命令编译就不会报错了:
gcc cpuid.s -o cpuid
总结选择
根据你的需求组合方案即可:
- 完全自定义程序入口、不需要C运行时:
gcc -nostdlib -no-pie cpuid.s -o cpuid - 适配C运行时、不想改汇编入口:修改汇编为
main入口 +gcc -no-pie cpuid.s -o cpuid - 想保留PIE特性:修改汇编为RIP相对寻址 +
gcc cpuid.s -o cpuid
内容的提问来源于stack exchange,提问作者Miracle Huang
相关产品推荐
相关产品推荐

