You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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位程序

  1. 编译C代码为目标文件:
gcc -m32 -c somefunc.c -o somefunc.o

-m32指定生成32位代码,-c表示只编译不链接。

  1. 编译汇编代码为目标文件:
nasm -f elf32 main_assembly_code.asm -o main.o

-f elf32指定生成32位ELF目标文件。

  1. 链接生成可执行文件:
  • 用_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。
  • 栈对齐:64位下调用函数前栈必须对齐到16字节,否则可能触发错误;32位无强制要求,但保持对齐更稳妥。
  • C运行时初始化:用_start作为入口会跳过C运行时初始化,若C函数涉及全局变量、malloc等操作,建议用main作为入口。

内容的提问来源于stack exchange,提问作者yercekimi31

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 22:13:19