简单内联汇编程序在GCC 5.0下触发Segmentation Fault:11的修复方案
修复GCC内联汇编square函数的段错误问题
环境与原始代码
在配备Core 2 Duo的iMac(Mac OS X 10.7系统)上,使用GCC 5.0.0编译以下代码:
#include <stdio.h> int square (int n) { __asm__("mov %eax, n" "mul %eax"); } int main(void) { printf("\nSquare of 4 is %i", square(4)); /* Calling square gives Segmentation fault: 11 error */ return 0; }
编译与运行报错
编译命令:gcc -o assem -DDEBUG=9 -ansi -pedantic -Wall -g assem.c
编译时出现警告:
assem.c: In function ‘square’: assem.c:6:1: warning: control reaches end of non-void function [-Wreturn-type] } ^ assem.c:4:Can't relocate expression. Absolute 0 assumed. Compilation finished at Mon Jul 25 18:23:47
运行程序触发Segmentation fault:11错误,用户查阅10余个相关问题未解决。
后续尝试
- 将内联汇编改为
asm ("imul %0, %0" : "+r"(n)); return n;时编译器报错,修改为asm ("imul %0, %0" : "+r"(n));仍有类似错误。 - 使用Clang 3.7.1(带
-fasm-blocks参数)编译特定代码时,触发语法错误。
需求说明
修复square函数代码,要求不改变基本结构——将n移入寄存器、用mul指令自乘、尽量不使用return语句返回结果,拒绝重写式方案。
修复后的代码
#include <stdio.h> int square(int n) { __asm__ __volatile__ ( "movl %1, %%eax\n\t" // 把参数n移入EAX寄存器 "mull %%eax\n\t" // EAX自乘,结果低32位保留在EAX中 : "=a"(n) // 告知编译器EAX中的结果对应返回值(关联变量n) : "r"(n) // 指定输入参数n可放在任意通用寄存器 : "%eax" // 声明EAX会被修改,避免编译器寄存器冲突 ); // 无需显式return,x86平台int返回值默认取自EAX,编译器会自动处理 } int main(void) { printf("\nSquare of 4 is %i", square(4)); return 0; }
关键修复点
- 修正AT&T汇编语法:原代码
mov %eax, n操作数顺序颠倒,AT&T语法是「源在前,目的在后」,改为movl %1, %%eax;同时用%%表示实际寄存器,%1对应输入约束的参数n。 - 添加约束关联:通过
"=a"(n)告诉编译器EAX寄存器的内容是函数返回值(关联到n),"r"(n)让编译器自动分配输入参数的寄存器,避免直接引用变量导致重定位错误。 - 遵循调用约定:x86平台C语言返回int类型时,默认将结果存在EAX寄存器,因此无需显式写return语句,符合需求。
- 避免编译器优化:添加
__volatile__确保汇编块不会被编译器优化掉,保证执行逻辑。
编译原命令即可正常编译运行,无警告和段错误。
内容的提问来源于stack exchange,提问作者Lars Malmsteen
相关产品推荐
相关产品推荐

