本文共 2047 字,大约阅读时间需要 6 分钟。
运行环境:实验楼
/*main.c*/int g(int x){ return x + 3;}int f(int x){ return g(x);}int main(void){ return f(8) + 1;}
/*Makefile*/all: gcc –S –o main.s main.c -m32
/*main.s*/ .file "main.c" .text .globl g .type g, @functiong:.LFB0: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 movl 8(%ebp), %eax addl $3, %eax popl %ebp .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc.LFE0: .size g, .-g .globl f .type f, @functionf:.LFB1: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 subl $4, %esp movl 8(%ebp), %eax movl %eax, (%esp) call g leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc.LFE1: .size f, .-f .globl main .type main, @functionmain:.LFB2: .cfi_startproc pushl %ebp //将栈底压栈 .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp //将栈顶的值赋给栈底 .cfi_def_cfa_register 5 subl $4, %esp //栈顶 movl $8, (%esp) //将8赋给栈顶 call f addl $1, %eax leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc.LFE2: .size main, .-main .ident "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2" .section .note.GNU-stack,"",@progbits
gcc –o main main.c -m32 //可以编译为可执行文件//然后在命令行下./main 就开始执行了//这个过程大概是bash解析了命令行.并fork并exec了main将main从设备块中读取到高速缓冲块中,然后拷贝到用户空间的对应段上.?,并建立栈顶esp和栈底ebp和eip//栈顶在栈底下面,中间无间隔,eip指向main中的 pushl %ebp然后从main开始运行,在栈内?//栈内的哪个地址?假设栈内的地址为0xbfe5 d38f,栈向下增长
/*用户栈*//*从高到*/主程序的参数主程序调用后的返回地址第0帧地址局部变量fun1的参数fun1调用后的返回地址第1帧地址局部变量
##汇编代码解析
###main
下面的图表示是上面的语句执行完之后的状态即下图表示的是 pushl %ebp 后的状态
###f
该行没有改变栈,只是将(ebp-8)地址内的值(8)付给了eax
###g
该行没有改变栈,只是将(ebp-8)地址内的值(8)付给了eax
改行没有改变栈,只是将eax加了3,此时为11
###f
###main
此时没改变堆栈,只是将eax中的值加了3,此时为14
####注意:
这里面需要注意的是%eax是独立于栈存在的,所以不会消失,所以返回值都存在%eax寄存器中栈分为四种,这里面分析的栈是满减栈,另外还有空减栈,满增栈,满减栈