x86汇编中栈分配的两个数组为何出现互相覆盖问题
错误定位与修复方案
核心错误点
- names_ptr赋值错误
你在分配姓名数组的代码中,执行完栈对齐操作后,错误将值为0的rax赋值给names_ptr,而非当前栈指针rsp:
原错误代码:
- names_ptr赋值错误
and rsp, -16 mov [names_ptr], rax ; rax此时为0,names_ptr被错误设为0地址
正确写法应为mov [names_ptr], rsp。
- 数组索引逻辑错误
names_ptr和grades_ptr是存储数组基地址的指针变量,你直接对变量本身的地址做偏移计算,相当于在指针变量所在的内存区域读写数据,而非读写指针指向的数组内存:
原错误索引代码:
- 数组索引逻辑错误
lea rsi, [names_ptr+rbx*8] ; 取names_ptr变量自身地址加偏移,不是数组地址偏移
正确索引逻辑需要先取出指针存储的基地址,再计算偏移:
mov rsi, [names_ptr] lea rsi, [rsi + rbx*8]
成绩数组的索引逻辑存在同样的错误,需要同步修正。
- 错误修改rbp寄存器
main函数开头已经将原始栈顶存入rbp用于后续栈恢复,但你在分配成绩数组前又执行了mov rbp, rsp覆盖了原始rbp值,会导致函数退出时栈恢复错误,直接删除这行多余的赋值即可。
- 错误修改rbp寄存器
- 姓名数组元素大小不匹配
你使用%10s格式读取字符串,10个字符加结束符共需要11字节存储空间,但你每个数组元素仅分配8字节,会导致缓冲区溢出。可以选择两种修复方式:
- 将数组元素大小调整为16字节,计算数组总大小的时候用
shl rdi, 4代替shl rdi, 3 - 将字符串读取格式改为
%7s,保证输入的字符串加结束符不超过8字节
- 姓名数组元素大小不匹配
- 指针变量分配冗余
bss段中names_ptr和grades_ptr各分配了2个8字节空间,实际只需要存储1个指针,改为resq 1即可。
- 指针变量分配冗余
修正后的栈分配核心代码示例
mov rdi, [num_students] shl rdi, 3 ; 若调整姓名元素大小为16则改为shl rdi,4 sub rsp, rdi and rsp, -16 mov [names_ptr], rsp ; 修正为给names_ptr赋rsp值 mov rdi, [num_students] shl rdi, 3 sub rsp, rdi and rsp, -16 mov [grades_ptr], rsp
修正后的数组读取示例
_get_student: call _prompt_name xor rax, rax mov rdi, stud_name_format mov rsi, [names_ptr] ; 先取数组基地址 lea rsi, [rsi + rbx*8] ; 计算元素偏移,元素大小调整的话对应修改乘数 call scanf call _prompt_grade xor rax, rax mov rdi, int_format mov rsi, [grades_ptr] ; 先取成绩数组基地址 lea rsi, [rsi + rbx*8] call scanf inc rbx cmp rbx, [num_students] jl _get_student
内容的提问来源于stack exchange,提问作者Charles Buchanan
相关产品推荐
相关产品推荐

