C语言在源码级别如何理解生成的文件在系统内是如何运行的?也就是各个函数是如何执行并调用,调用后返回到哪里?这里提到了 一个过程活动记录。
解决函数的调用的经典机制--堆栈中的过程活动记录。
过程活动记录是一种数据结构,记录了调用结束及返回调用点所需要的全部信息。
需要预习的知识:汇编指令、某处理器架构的寄存器、堆栈结构
inter的CPU架构寄存器:
4个32位通用寄存器(EAX、EBX、ECX和EDX)
2个32位变址和指针寄存器(ESI和EDI) 2个32位指针寄存器(ESP和EBP)
6个[16位(段选择符)+隐藏部分(描述符缓冲)]段寄存器(ES、CS、SS、DS、FS和GS)
1个32位指令指针寄存器(EIP) 1个32位标志寄存器(EFlags)
2个48位系统表寄存器(GDTR、IDTR)和2个[16位(选择符)+隐藏部分(描述符缓冲)](LDTR、TR)
5个32位控制寄存器(CR0~ CR4),CR4是从Pentium CPU开始出现的
8个32位调试寄存器(DR0~ DR7)
8个32位测试寄存器(TR0~TR7)
arm的CPU架构寄存器:
汇编指令:pushl、movl、subl、leal、leave、ret
堆栈结构:先进后出。用到的指针寄存器是EIP、ESP、EBP。
案例:
#include "stdio.h"int aa(int a,int b)
{
int c = 0;
c = a + b;
return c;
}
int main(int argc,char**argv)
{
int d = 0;
int a = 1;
int b = 2;
d = aa(a,b);
return d;
}
gcc-4.5.1 x86的汇编代码
.file "test.c"//文件名
.text//代码段
.globl aa//全局符号
.type aa, @function//定义aa为函数
aa:
pushl %ebp //ebp中的内容压入堆栈(保护ebp中内容,上一个esp)
movl %esp, %ebp //esp中的内容传入ebp中(esp中的内容等于ebp),此时esp是什么?待定?
subl $16, %esp //esp中的内容减去16,并存入esp,也就是esp向下偏移16个字节,为什么是减?因为堆栈的生长方向和实际的物理地址的关系。向上生长的堆栈的实际物理地址在递减
movl $0, -4(%ebp) //ebp中的地址小4个偏移,写入0
movl 12(%ebp), %eax //
movl 8(%ebp), %edx
leal (%edx,%eax), %eax //leal指令mov (%eax,%eax,4), %edx 就是把5这个地址里面的数读出来到edx ,lea (%eax,%eax,4), %edx 就是把5这个地址给edx,事实上就是一个算术运算。这里是把%edx+%eax赋值给%eax
movl %eax, -4(%ebp) //计算结果入栈
movl -4(%ebp), %eax //保存返回值
leave //恢复ESP、EBP
ret //POP IP
.size aa, .-aa
.globl main
.type main, @function
main:
pushl %ebp //ebp压栈,保存上一个调用的ebp,也就是上一个esp
movl %esp, %ebp //esp中的内容保存在ebp中,暂存此时的esp
subl $24, %esp //栈顶指针下沉24个字节,也就是6个双字,该空间是用来保存参数的?此时ESP在位置是EBP-24
movl $0, -4(%ebp) // 依次将临时变量存入栈中,
movl $1, -8(%ebp)
movl $2, -12(%ebp)
movl -12(%ebp), %eax //将其中一个传输给eax
movl %eax, 4(%esp) //第一个实参
movl -8(%ebp), %eax
movl %eax, (%esp) //第二个实参
call aa
movl %eax, -4(%ebp)//aa的返回值(存在eax)存入(-4)ebp
movl -4(%ebp), %eax//保存返回值?
leave
ret
.size main, .-main
.ident "GCC: (GNU) 4.5.1 20100924 (Red Hat 4.5.1-4)"
.section .note.GNU-stack,"",@progbits
arm-linux-gcc-4.5.1 arm的汇编代码
.cpu arm1176jzf-s
.eabi_attribute 27, 3
.fpu vfp
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 2
.eabi_attribute 30, 6
.eabi_attribute 18, 4
.file "test.c"
.text
.align 2
.global aa
.type aa, %function
aa:
@ args = 0, pretend = 0, frame = 16
@ frame_needed = 1, uses_anonymous_args = 0
@ link register save eliminated.
str fp, [sp, #-4]!
add fp, sp, #0
sub sp, sp, #20
str r0, [fp, #-16]
str r1, [fp, #-20]
mov r3, #0
str r3, [fp, #-8]
ldr r2, [fp, #-16]
ldr r3, [fp, #-20]
add r3, r2, r3
str r3, [fp, #-8]
ldr r3, [fp, #-8]
mov r0, r3
add sp, fp, #0
ldmfd sp!, {fp}
bx lr
.size aa, .-aa
.align 2
.global main
.type main, %function
main:
@ args = 0, pretend = 0, frame = 24
@ frame_needed = 1, uses_anonymous_args = 0
stmfd sp!, {fp, lr}
add fp, sp, #4
sub sp, sp, #24
str r0, [fp, #-24]
str r1, [fp, #-28]
mov r3, #0
str r3, [fp, #-8]
mov r3, #1
str r3, [fp, #-12]
mov r3, #2
str r3, [fp, #-16]
ldr r0, [fp, #-12]
ldr r1, [fp, #-16]
bl aa
str r0, [fp, #-8]
ldr r3, [fp, #-8]
mov r0, r3
sub sp, fp, #4
ldmfd sp!, {fp, pc}
.size main, .-main
.ident "GCC: (ctng-1.8.1-FA) 4.5.1"
.section .note.GNU-stack,"",%progbits