深入理解计算机程序,《深入理解计算机系统》-程序的机器级表示

在高级语言横行的现在,能看懂机器语言的程序员并不多。了解了寄存器,汇编等知识后,才能对进程,线程有更深的认识,而不仅仅只是一个Thread类。

寄存器

8199711bcd9a

寄存器.png

一个CPU包含一组8个存储32位值寄存器。这些寄存器用来保存整数数据和指针。访问寄存器的速度比访问内存的速度快。特别留意下%esp和%ebp这两个寄存器分别保存指向程序栈的栈顶位置的指针和指向程序栈栈底位置的指针。下面规定%eax表示图中%eax方法中的值,是个32位整数。其他寄存器同理。

函数的汇编实现

文中有这么一个例子:

8199711bcd9a

过程.png

这例子中有两个函数caller()和swap_add(),下面左边的图是caller()的栈帧,右边的图是调用swap_add()后,在caller()栈帧下建了swap_add的栈帧。

我们看下caller的汇编代码,看下它被调用时是如何建立自己的栈帧和swap_add的栈帧并为swap_add准备好参数的:

8199711bcd9a

caller对应的汇编.png

第2行:保存%ebp指向内存的值到栈顶

第3行:将%esp中的值赋给%ebp

第4行:将%esp-24,也就是将栈指针下移24个字节

第5行:将%ebp-4内存处赋值为534,也就是arg1

第6行:将%ebp-8内存处赋值为1057,也就是arg2

第7行,8:将arg2的地址(&arg1)赋值给%esp+4指向的内存

第9行,10:将arg1的地址(&arg2)赋值给%esp指向的内存,也就是栈顶

第11行:调用swap_add方法

经过这段汇编代码,就形成了上面的左图。再来看下建立swap_add栈帧的过程:

8199711bcd9a

swap_add栈帧建立.png

第2行:保存%ebp到栈顶

第3行:更新%ebp也指向栈顶,到这里新的栈帧已经建立

第4行:%ebx保存着caller函数中的值,在调用swap_add时可能覆盖%ebx,所以要先将%ebx里面的值保存到栈上,退出swap_add时要,恢复%ebx的值,这样才不会影响返回到caller后,caller正常执行。到这里就形成了上面右边的栈帧结构。

swap_add的栈帧建立好后,我们看下swap_add内部的汇编代码:

8199711bcd9a

swap_add内部实现.png

第5行:将参数&arg1保存到%edx

第6行:将参数&arg2保存到%ecx

第7行:将arg1保存到%ebx

第8行:将arg2保存到%eax

第9行:将%eax的值保存到%edx指向的内存处

第10行:将%ebx的值保存到%ecx指向的内存处,到这里实现了arg1和arg2值的交换

第11行:将%ebx加到%eax中,%eax规定为保存返回值的寄存器

这个函数中,我们交换了arg1和arg2的值,并且将它们的和保存在寄存器%eax中。

我们最后看下swap_add是如何返回到caller中的:

8199711bcd9a

swap_add返回caller.png

第12行:将上面保存在栈中的%ebx的值重新保存到%ebx中

第13行:%ebp指向caller的栈底

第14行:通知程序计数器回到caller中swap_add方法后面的那条指令,到这里又回到了caller的栈帧(上面左图的栈帧),好像swap_add没有调用过一样。

总结

熟悉了这个过程,我们对局部变量,指针,栈溢出这些名词肯定会更深刻的理解。下一节,我们看下虚拟存储器。

参考:《深入理解计算机系统》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值