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

x86_64 Linux(FASM)下向C函数传参报错及参数遍历方法问询

问题分析与解决方案

1. 段错误的核心原因

你遇到的段错误,大概率是argv数组没有以NULL指针结尾,或者栈未满足x86_64 SysV ABI的16字节对齐要求:

  • C标准明确要求argv数组的最后一个元素必须是NULL,arg_test遍历参数时会依赖这个终止符判断结束,若未添加,函数会越界访问非法内存触发段错误。
  • x86_64 Linux下的SysV ABI规定,调用函数前栈指针RSP必须是16字节对齐(call指令会压入8字节返回地址,因此调用前RSP需为16的倍数),未对齐可能导致函数内部操作出错。

2. 正确传递参数的FASM实现示例

步骤1:构造字符串与argv数组

将参数字符串放在只读数据段,构造argv数组时必须添加NULL终止符:

section .rodata
    arg0 db './test', 0   ; argv[0]:程序自身路径
    arg1 db 'hello', 0    ; argv[1]:第一个自定义参数
    argv dq arg0, arg1, 0 ; argv数组:最后一个元素为NULL终止符

步骤2:满足栈对齐并调用C函数

以_start为入口时,先调整栈到16字节对齐,再按SysV ABI规则传递参数(前6个参数用寄存器rdi、rsi、rdx等):

section .text
    global _start
    extern arg_test

_start:
    ; 调整栈到16字节对齐:_start入口时RSP指向返回地址,减8字节完成对齐
    sub rsp, 8
    ; 设置参数:rdi存argc,rsi存argv指针
    mov rdi, 2        ; 参数数量为2(argv[0] + argv[1])
    mov rsi, argv     ; 传入argv数组地址
    call arg_test     ; 调用C函数
    ; 调用exit系统调用安全退出,避免返回后触发未知错误
    mov rax, 60
    mov rdi, 0
    syscall

步骤3:编译链接指令

分别编译汇编与C代码,再链接为可执行文件:

# 编译C代码为目标文件
gcc -c arg_test.c -o arg_test.o
# 编译汇编代码
fasm test.asm test.o
# 链接生成可执行文件
gcc test.o arg_test.o -o test

3. 正确遍历argv的C函数写法

确保arg_test按标准逻辑遍历参数,既可以用argc控制循环,也可以依赖NULL终止符:

#include <stdio.h>

void arg_test(int argc, char *argv[]) {
    printf("arg count: %d\n", argc);
    
    // 方法1:用argc控制遍历范围
    for (int i = 0; i < argc; i++) {
        printf("argv[%d]: %s\n", i, argv[i]);
    }

    // 方法2:依赖NULL终止符遍历
    // char **ptr = argv;
    // while (*ptr) {
    //     printf("%s\n", *ptr);
    //     ptr++;
    // }
}

常见误区排查

  • 绝对不能省略argv数组的NULL终止符,这是触发段错误的最常见原因。
  • 严格遵守x86_64的栈对齐要求,否则函数内部使用SSE等指令会引发异常。
  • 所有传递给C的字符串必须以0结尾,否则printf等函数会越界读取内存。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 06:31:09