基于GDB分析树莓派3(ARM)基础C程序汇编指令的技术问询
ARM栈帧与汇编细节答疑(树莓派3环境)
嘿,看你在树莓派3的ARM架构上调试C程序,研究栈帧和内存段的汇编细节,刚好我对这块熟,来给你逐个解答疑问:
疑问1:前三条涉及栈指针的指令是否为main函数建立栈帧?
完全正确!这三条就是ARM标准的栈帧建立流程:
push {r11}:把调用者的帧指针(FP,也就是r11寄存器)压入栈中保存,因为接下来我们要把r11改成当前main函数的帧指针add r11, sp, #0:将当前栈指针(SP)的值赋值给r11,此时r11就成为了main函数的帧指针,用来标记当前栈帧的起始位置sub sp, sp, #12:调整栈指针,为局部变量和栈对齐要求预留12字节的空间(你的代码里两个int变量占8字节,多出来的4字节是ARM的栈对齐规则要求)
疑问2:0x10414处使用age的值,是否是局部变量作为栈帧部分入栈?
没错,这里就是把局部变量age存在栈帧里:
mov r3, #30:把常量30加载到r3寄存器str r3, [r11, #-8]:把r3的值存储到帧指针r11偏移-8的位置,这个位置就在刚才预留的栈空间里,也就是局部变量age的存储地址。另外那个未赋值的salary应该在[r11, #-4]的位置,只是因为没赋值所以汇编里没相关操作。
疑问3:0x1041c处是否是我所假设的作为栈帧部分入栈的返回值?
这个理解有点偏差哦!这里是在设置函数的返回值,但并不是存在栈帧里:
mov r3, #0:把返回值0加载到r3寄存器mov r0, r3:把r3的值传到r0寄存器——在ARM的函数调用约定里,函数的返回值是通过r0寄存器传递的,而不是存在栈帧中。这两步是在为main函数的返回值0做准备,之后通过bx lr返回给调用者。
疑问4:函数末尾栈何时被清理?
栈的清理是在函数末尾的两条指令完成的:
add sp, r11, #0:把栈指针SP重置为帧指针r11的值,这一步直接释放了之前预留的12字节栈空间,相当于清理了局部变量占用的栈内存pop {r11}:把之前保存的调用者的帧指针从栈里恢复到r11寄存器,恢复调用者的栈帧环境
等这两步完成后,bx lr跳回调用者的代码,整个main函数的栈帧就完全清理完毕了
你的C代码
int main () { int age = 30; int salary; return 0; }
对应的汇编指令
0x10408 <main> push {r11} ; (str r11, [sp, #-4]!) 0x1040c <main+4> add r11, sp, #0 0x10410 <main+8> sub sp, sp, #12 0x10414 <main+12> mov r3, #30 0x10418 <main+16> str r3, [r11, #-8] 0x1041c <main+20> mov r3, #0 0x10420 <main+24> mov r0, r3 0x10424 <main+28> add sp, r11, #0 0x10428 <main+32> pop {r11} ; (ldr r11, [sp], #4) 0x1042c <main+36> bx lr
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

