通过汇编一个简单的C程序,理解计算机如何工作

本文通过一个简单的C语言程序实例,详细解析了函数调用过程中的内存分配与释放,以及参数传递的方式。从main函数出发,逐步深入到f和g函数的调用细节,展示了如何使用GCC生成汇编代码,并解释了每一行汇编指令的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

秣陵+ 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

//文件名 main.c
int g(int x)
{   
    return x+12;
}
int f(int x)
{
    return g(x)
}
int main()
return f(21)+36

汇编命令
gcc -S -o main.s main.c -m32 // m32为编译为32位的选项
用VIM打开main.s删除所有以点开头的行
:g/^\s\?\.\+/d
//得到汇编代码如下
g:
    pushl   %ebp
    movl    %esp, %ebp
    movl    8(%ebp), %eax
    addl    $12, %eax
    popl    %ebp
    ret
f:
    pushl   %ebp
    movl    %esp, %ebp
    pushl   8(%ebp)
    call    g
    addl    $4, %esp
    leave
    ret
main:
    pushl   %ebp
    movl    %esp, %ebp
    pushl   $21
    call    f
    addl    $4, %esp
    addl    $36, %eax
    leave
    ret

C代码
汇编码

汇编码解读

程序从main开始,假设此时 ebp=esp=64 内存[]

main:
pushl   %ebp
movl    %esp, %ebp

建立一个新的堆栈a,新栈基址为60

ebp=60,esp=60

[64]

pushl   $21

将21入栈

ebp=60,esp=56

[64,21]

call    f

将eip入栈,把f传入eip

ebp=60,esp=52

[64,21,main_call_next]

f:
pushl   %ebp
movl    %esp, %ebp

在堆栈a上建立新栈b,基址为48

esp=48,ebp=48

[64,21,main_call_next,60]

pushl   8(%ebp)

将(ebp+8)处的值压栈即将21压栈,esp为44

ebp=48,esp=44

[64,21,main_call_next,60,21]

call    g

将eip入栈,把g传入eip

ebp=48,esp=40

[64,21,main_call_next,60,21,f_call_next]

g:
pushl   %ebp
movl    %esp, %ebp

在建立新栈c,基址为36

esp=36,ebp=36

[64,21,main_call_next,60,21,f_call_next,48]

movl    8(%ebp), %eax

将(ebp+8)处的值传入eax,即eax=21

esp=36,ebp=36

[64,21,main_call_next,60,21,f_call_next,48]

addl    $12, %eax

将eax中的值与12相加并保存到eax中,即eax=21+12 eax=33

esp=36,ebp=36

[64,21,main_call_next,60,21,f_call_next,48]

popl %ebp

对堆栈C进行出栈操作

ebp=48,esp=40

[64,21,main_call_next,60,21,f_call_next]

ret
即:
    popl %eip 对堆栈b进行出栈操作,出栈到eip,

ebp=48,esp=44

[64,21,main_call_next,60,21]

addl    $4, %esp

ebp=48,esp=48

[64,21,main_call_next,60]

leave
相当于:
    movl %ebp%esp
    popl %ebp

epb=60,esp=52

[64,21,main_call_next]

ret
即:
    popl %eip 对堆栈a进行出栈操作,出栈到eip,

epb=60, esp=56

[64,21]

addl    $4, %esp

esp=60,esp=60

[64]

addl    $36, %eax

eax = 36 + 33 = 69

esp=60,esp=60

[64]

leave
相当于:
    movl %ebp%esp
    popl %ebp

ebp=64,esp=60

[]

ret
即:
    popl %eip 对堆栈a进行出栈操作,出栈到eip

ebp=64,esp=64

[]
内存示意图
内存示意图

总结

程序按总是顺序执行,当遇到跳转时,会保存当前的地址,跳转后总是先新建一个堆栈以免破坏之前的堆栈防止丢失回去的路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值