You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

gcc/g++中变长数组arr在栈上的位置及与rbp寄存器的关系

变长数组arr与rbp寄存器的栈位置关联分析

核心逻辑:栈帧与rbp的作用

rbp(基址指针寄存器)是函数栈帧的"锚点"——函数调用时,它会固定当前栈帧的基地址,栈上所有变量(参数、局部变量、返回地址等)都通过rbp的偏移量来寻址。注意栈的生长方向是高地址→低地址,所以变量的偏移量大多是负数(从rbp向低地址方向计算)。

你的代码对应汇编的栈帧处理(以x86-64架构为例)

用g++ -S生成的汇编中,test_func的栈帧构建和数组分配逻辑大致如下:

  1. 函数进入时,先保存上一层栈帧的rbp:push rbp,然后把当前栈顶指针rsp的值赋给rbp:mov rbp, rsp——这一步完成当前栈帧的基址初始化。
  2. 根据参数m计算数组大小(m * sizeof(int)),然后调整栈顶指针rsp来分配数组空间:sub rsp, <数组字节数>。因为栈向低地址生长,sub操作相当于在栈上开辟出数组的内存。
  3. 此时arr的起始地址要么是调整后的rsp(如果没有其他局部变量占用空间),要么是rbp减去一个固定偏移量(这个偏移包含旧rbp、返回地址、已保存的参数等占用的字节)。

简化后的汇编片段参考:

test_func:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16                     ; 先预留基础空间存储参数
        mov     DWORD PTR [rbp-4], edi      ; 参数m存在rbp-4的位置
        mov     DWORD PTR [rbp-8], esi      ; 参数n存在rbp-8的位置
        mov     eax, DWORD PTR [rbp-4]
        imul    eax, eax, 4                 ; 计算数组总字节数:m*4(int占4字节)
        sub     rsp, eax                    ; 为arr分配栈空间,此时rsp指向arr起始地址
        ; 后续arr[i]的访问会被编译为*(rsp + i*4) 或 *(rbp - 偏移量 + i*4)

arr在栈上的具体位置

从高地址到低地址的栈帧结构大致为:

返回地址 → 旧rbp → 保存的函数参数(m、n) → 其他局部变量 → 变长数组arr起始地址(对应调整后的rsp) → 栈顶

简单说,arr的起始地址 = rbp - 固定偏移(旧rbp、参数等占用的字节) - m*sizeof(int),或者直接等于调整后的rsp值。对数组元素arr[i]的访问,本质是通过rbp或rsp加上i*sizeof(int)的偏移来寻址。

GDB查看的正确姿势

之前没收获大概率是操作问题,试试这几步:

  • 编译时带调试信息:g++ -g test.cpp -o test
  • 启动GDB后,在test_func的数组赋值处打断点:b test_func:4
  • 运行到断点后,用info frame查看当前栈帧的rbp值
  • 用x/30x $rbp-120(30个int占120字节)查看栈内存,就能看到arr的元素;也可以直接用p &arr打印数组起始地址,对比rbp的值就能算出偏移量

内容的提问来源于stack exchange,提问作者Frank

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 06:09:56