在C中调用NASM数据段db字符串触发段错误
问题根源与解决方案
问题分析
段错误的核心是C代码与汇编代码的类型不匹配:
- 汇编中
foo: db "bar", 0定义的是直接存储在.data段的字符串,foo是该字符串的起始地址(本身就是字符数组的首地址)。 - 但C代码里声明
extern char *foo,表示foo是一个指向字符的指针变量,而非字符数组/字符串本身。
程序运行时,puts(foo)会把foo的值当作指针访问内存。而foo对应的字符串内容是"bar"(ASCII码为0x62 0x61 0x72 0x00),小端模式下系统会把低64位0x00726162当作指针地址,这个地址属于非法内存区域,直接触发段错误。gdb输出的$1 = 0x726162 <error: Cannot access memory at address 0x726162>也验证了这一点——程序把字符串内容当成了指针地址。
两种修复方案
方案1:修改C代码的声明,匹配汇编实际类型
将C里的extern char *foo改为extern char foo[](或extern const char foo[],字符串建议放只读段,更安全):
#include <stdio.h> extern char foo[]; // 声明为字符数组,而非指针 int main() { puts(foo); }
方案2:修改汇编代码,定义指针变量指向字符串
如果必须在C里保留char *foo的指针声明,汇编中需要定义一个指针变量指向字符串地址:
global foo section .rodata ; 字符串建议放只读段,避免意外修改 str_bar: db "bar", 0 section .data foo: dq str_bar ; 64位系统下定义8字节指针,指向str_bar的地址
额外建议
- 字符串常量推荐放在
.rodata段(汇编)或用const修饰(C),提升安全性。 - 编译时添加
-Wall参数,比如gcc -Wall main.c foo.o,会触发类型不匹配的警告,帮助快速定位问题:warning: initialization of ‘char *’ from incompatible pointer type ‘char *’ [-Wincompatible-pointer-types]
内容的提问来源于stack exchange,提问作者MyNameIsTrez
相关产品推荐
相关产品推荐

