Linux下如何混合使用NASM汇编与C语言?含调用及编译方法
在Linux下用NASM汇编调用C函数的实现与编译方法
一、修正代码结构
你的示例存在几个关键问题:C函数实现不应放在头文件中(头文件仅用于声明)、汇编文件后缀建议用.asm而非.h、还要注意不同位宽下C函数名的修饰规则。
1. C代码拆分(声明+实现)
somefunc.h(头文件,仅做函数声明)
#ifndef SOMEFUNC_H #define SOMEFUNC_H // 声明要被汇编调用的函数 int int_func(); float float_func(); #endif
somefunc.c(实现文件,编写函数逻辑)
#include "somefunc.h" int int_func() { // 示例:返回整数42 return 42; } float float_func() { // 示例:返回浮点数3.14 return 3.14f; }
2. 汇编代码调整
32位版本(注意函数名带下划线前缀)
32位Linux下,gcc会给C函数名自动加上下划线前缀,汇编中需用extern声明外部函数:
section .text global _start ; 程序入口,或改用main(推荐) extern _int_func, _float_func ; 声明外部C函数 _start: ; 调用int_func,返回值存储在eax寄存器 call _int_func push eax ; 可选:保存整数返回值到栈 ; 调用float_func,返回值存储在xmm0寄存器(gcc默认SSE模式) call _float_func movss [float_result], xmm0 ; 保存浮点数到内存 ; 退出程序,返回0给系统 mov eax, 1 ; sys_exit系统调用号 mov ebx, 0 ; 返回码 int 0x80 ; 触发系统调用 section .bss float_result resb 4 ; 预留存储float返回值的内存空间
推荐用main作为入口(自动初始化C运行时)
如果C函数涉及全局变量、动态内存分配等,用main作为入口能自动完成C运行时初始化:
section .text global main extern _int_func, _float_func main: call _int_func push eax ; 保存整数返回值 call _float_func movss [float_result], xmm0 ; 保存浮点数返回值 mov eax, 0 ; main函数返回0 ret section .bss float_result resb 4
64位版本(函数名无下划线前缀)
64位Linux下无函数名前缀,遵循System V AMD64调用约定:
section .text global main extern int_func, float_func main: call int_func ; 返回值在eax寄存器中 call float_func ; 返回值在xmm0寄存器中 mov eax, 0 ret
二、编译与链接步骤
情况1:32位程序
- 编译C代码为目标文件:
gcc -m32 -c somefunc.c -o somefunc.o
-m32指定生成32位代码,-c表示只编译不链接。
- 编译汇编代码为目标文件:
nasm -f elf32 main_assembly_code.asm -o main.o
-f elf32指定生成32位ELF目标文件。
- 链接生成可执行文件:
- 用
_start作为入口:需跳过C运行时启动代码
gcc -m32 -nostartfiles main.o somefunc.o -o program
- 用
main作为入口:直接链接即可
gcc -m32 main.o somefunc.o -o program
情况2:64位程序
无需指定-m32,直接编译链接:
# 编译C代码 gcc -c somefunc.c -o somefunc.o # 编译汇编代码 nasm -f elf64 main_assembly_code.asm -o main.o # 链接生成可执行文件 gcc main.o somefunc.o -o program
三、关键注意事项
- 调用约定:
- 32位用
cdecl:参数从右往左压栈,调用者负责清理栈;int返回值在eax,float返回值在xmm0(SSE模式)。 - 64位用System V AMD64 ABI:前6个整数参数存在
rdi, rsi, rdx, rcx, r8, r9,浮点参数存在xmm0-xmm7;返回值int在rax,float在xmm0。
- 32位用
- 栈对齐:64位下调用函数前栈必须对齐到16字节,否则可能触发错误;32位无强制要求,但保持对齐更稳妥。
- C运行时初始化:用
_start作为入口会跳过C运行时初始化,若C函数涉及全局变量、malloc等操作,建议用main作为入口。
内容的提问来源于stack exchange,提问作者yercekimi31
相关产品推荐
相关产品推荐

