内联汇编操作局部数组触发段错误,求问题原因分析
解决局部数组内联汇编的段错误问题
嘿,我帮你定位到了这个段错误的核心原因,还有两种靠谱的修复方案:
问题到底出在哪?
你用的是32位寄存器(ebx、esi、eax)写的内联汇编,但如果是在64位系统上编译,默认会生成64位程序——这就出问题了:
- 局部数组存在栈上,64位系统的栈地址都是高地址(比如
0x7ffexxxxxx),是64位的。但ebx是32位寄存器,只能存下地址的低32位,直接截断后就变成了无效内存地址,执行mov eax, [ebx+4*esi]时自然触发段错误。 - 全局变量为啥没问题?因为全局变量存在进程的低地址数据段(比如
0x40xxxxxx),它的地址低32位本身就是有效的,就算被截断也能正常访问,所以不会报错。
另外还有个小细节:GCC内联汇编里的"b"约束在64位模式下对应的是64位寄存器rbx,但你写的是32位的ebx,等于只用到了rbx的低32位,这也加剧了地址错误。
两种修复方案任你选
方案1:编译成32位程序
如果你想继续用现有的32位汇编代码,编译时加上-m32和-masm=intel选项,强制生成32位程序:
gcc -m32 -masm=intel your_code.c -o your_program
这样数组地址是32位的,ebx能完整存储,栈地址访问就不会出问题了。
方案2:修改汇编适配64位模式
把汇编里的32位寄存器换成对应的64位版本,约束不用改(GCC会自动把"b"映射到rbx,"S"映射到rsi):
void myfunc() { int array[10] = {1,2,3,4,5,6,7,8,9,10}; printArray(array,10); for (int i = 0; i < 10; i++) { asm volatile ( "mov rax, [rbx+4*rsi];" // 替换为64位寄存器 "lea rax, [rax+8*rax];" "mov [rbx+4*rsi], rax" : : "b" (array), "S" (i) : "memory", "rax" ); } printArray(array,10); }
然后用64位模式编译:
gcc -masm=intel your_code.c -o your_program
修复后的预期输出
不管用哪种方案,运行程序都会得到:
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 18, 27, 36, 45, 54, 63, 72, 81, 90,
完全符合预期,因为lea rax, [rax+8*rax]就是把元素值乘以9的操作~
内容的提问来源于stack exchange,提问作者Behrooz Ns
相关产品推荐
相关产品推荐

