为何执行psubd xmm, memory操作会触发段错误?
段错误原因分析与解决办法
这问题我之前帮人排查过类似的,核心是SSE指令的对齐要求坑了你——触发段错误的根本原因是**psubd这类SSE指令对内存操作数有严格的16字节对齐要求,而你用.lcomm LABELX,16定义的变量没有保证16字节对齐**。
为什么对齐会导致段错误?
在x86架构下,绝大多数SSE指令访问内存时,要求目标内存地址必须是16字节对齐的。如果地址未对齐,CPU会抛出对齐检查异常(#AC),操作系统会把这个异常转化为段错误(SIGSEGV)直接终止程序。
你用.lcomm定义变量时,GAS汇编器的默认对齐规则是跟着目标平台走的(比如x86-64上默认是8字节对齐),不会因为你分配了16字节空间就自动改成16字节对齐。所以LABELX的地址大概率是8字节对齐,但不满足SSE指令的要求,这就触发了错误。
额外的操作数顺序说明
顺便提一句,你用的是AT&T语法,psubd LABELX, %xmm11的实际行为是:
将
%xmm11中的4个32位双字,分别减去LABELX指向内存中的4个32位双字,结果存回%xmm11
这和你“用XMM11减去LABELX低32位”的意图是匹配的,但psubd会同时处理所有4个双字。如果你只需要操作低32位,其实可以用普通通用寄存器指令(比如movl LABELX, %eax; subl %eax, %r11d),这样既不需要对齐,也更贴合你的需求。
解决办法
有两种简单方式可以修复对齐问题:
- 方式一:显式指定
.lcomm的对齐参数
修改你的bss段定义,在.lcomm中加入第三个参数指定16字节对齐:.section .bss .lcomm LABELX, 16, 16 # 第三个参数为对齐字节数 - 方式二:用
.align指令强制对齐
在定义LABELX之前添加.align 16指令,确保后续变量满足16字节对齐:.section .bss .align 16 .lcomm LABELX, 16
内容的提问来源于stack exchange,提问作者masec
相关产品推荐
相关产品推荐

