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
相关产品推荐
相关产品推荐

