x86汇编实现1D Stencil时栈缓冲区溢出问题求助
问题原因分析与修复方案
错误根源
你遇到的栈缓冲区溢出错误,由两个核心问题导致:
1. 调用约定参数处理错误
Windows x64平台采用fastcall调用约定,函数前三个参数通过寄存器传递:RCX(第一个参数X)、RDX(第二个参数Y)、R8(第三个参数n)。但你的汇编代码错误地从栈帧(rbp+16、rbp+24)读取参数,导致X和Y的指针指向非法内存,后续数组访问直接越界。
2. 循环范围错误导致数组越界
你的Stencil计算式要求i的有效范围是 3 ≤ i ≤ n-4(因为i-3 ≥ 0且i+3 < n),但原汇编循环从ecx=0开始,一直执行到ecx == n,会触发两种越界:
- 当
ecx < 3时,访问X[i-3](比如i=0时访问X[-3]),属于数组前越界; - 当
ecx > n-4时(比如i=7时,i+3=10超出X[0..9]的索引范围),属于数组后越界;
这种越界直接破坏了编译器添加的栈保护cookie,触发溢出检测报错。
修复后的汇编代码
section .text global stencil_function stencil_function: push rbp mov rbp, rsp ; 保存非易失性寄存器(符合Windows x64调用约定规范) push rbx push rsi push rdi ; 从调用约定寄存器获取参数 mov rdi, rcx ; X = RCX mov rsi, rdx ; Y = RDX mov rbx, r8 ; n = R8 ; 设置有效循环范围:i从3开始,到n-4结束 mov ecx, 3 mov edx, ebx sub edx, 4 ; edx = n-4 stencil_loop: cmp ecx, edx jg end_loop ; i > n-4时退出循环 ; 执行Stencil计算 mov eax, dword [rdi + rcx*4 - 12] ; X[i-3] add eax, dword [rdi + rcx*4 - 8] ; +X[i-2] add eax, dword [rdi + rcx*4 - 4] ; +X[i-1] add eax, dword [rdi + rcx*4] ; +X[i] add eax, dword [rdi + rcx*4 + 4] ; +X[i+1] add eax, dword [rdi + rcx*4 + 8] ; +X[i+2] add eax, dword [rdi + rcx*4 + 12] ; +X[i+3] mov dword [rsi + rcx*4], eax ; 结果存入Y[i] inc ecx jmp stencil_loop end_loop: ; 恢复寄存器 pop rdi pop rsi pop rbx pop rbp ret
修复说明
- 修正参数传递:直接使用Windows x64约定的寄存器获取
X、Y、n,避免栈帧读取错误; - 限制循环范围:只处理有效的
i值,彻底杜绝数组越界; - 符合调用约定:保存并恢复非易失性寄存器(
RBX、RSI、RDI),避免破坏调用者的寄存器状态。
运行修复后的代码,将正常输出Y = 28 35 42,对应Y[3]=1+2+3+4+5+6+7=28、Y[4]=2+3+4+5+6+7+8=35、Y[5]=3+4+5+6+7+8+9=42,与预期一致。
内容的提问来源于stack exchange,提问作者Stephanie Joy Relles
相关产品推荐
相关产品推荐

