作家
登录

函数调用中堆栈的个人理解

作者: 来源: 2017-07-28 09:50:33 阅读 我要评论

call:将下一条指令的地址压入当前调用函数的┞坊中(将PC指令压入栈中,因为在大年夜内存中掏出call指令时,PC指令已经主动增长),然后改变PC指令的为call的function的地址,法度榜样指针跳转到新function。

这是我的第一篇博客,因为公司项目须要,将临时拜别C说话一段时光。所以在此记录一下本身之前进修C说话的一些心得领会,欲望可以分享给大年夜家,也可以记录下本身进修过程中碰到的问题以及存在的困惑(其实就是本身进修过程中不解的处所)。好了,废话不多说,开端微博内容了,O(∩_∩)O哈哈~

用gcc -S main.c 生成汇编文件main.s, 个中function的汇编代码如下:

复制代码

    接下来精晓过下面几个问题解析函数调用中对客栈懂得:

  • 函数调用过程中客栈在内存中存放的构造若何?
  • 汇编说话中call,ret,leave等具体操作时若何?
  • linux中义务的客栈,数据存放是若何?

    1. 函数调用过程中客栈在内存中存放的构造若何?

    计算机,嵌入式设备,智能设备等其实都是有软件和硬件两部分构成,具体实现也许复杂,但整体的构造也就如斯。软件运行在硬件上,告诉硬件该干什么。操作体系软件是在启动过程中经由BIOS,bootloarder等(如不雅有这些过程的话)大年夜磁盘加载到内存中,而自定义软件则是编写存放稻磁逄中,只有经由过程加载才会到内存中运行。

    起首我们来看一下什么是堆、栈还有客栈,我们经常说客栈其实它是等同于栈的概念。

    可以通俗意义上如许懂得堆,堆是一段异常大年夜的内存空间,供不合的法度榜样员大年夜个中掏出一段供本身应用,应用之后要由法度榜样员本身释放,如不雅不释放的话,这部分存储空间将不克不及被其他法度榜样应用。堆的存储空间是不持续的,因为会因为不应时光,不合大年夜小的堆空间的申请导致其不持续性。堆的发展是大年夜低地址向高地址增长的。

    对栈的懂得是,栈是一段存储空间,供体系或者操作体系应用,对法度榜样员来说一般是弗成见的,除非大年夜一开端由法度榜样员本身经由过程汇编等本身构建栈,栈会由体系治理单位本身申请释放。栈是大年夜高地址向低地址发展的,既栈底在高地址,栈顶低地址。

    其次我们看一下应用法度榜样的加载,应用法度榜样被加载进内存后,由操作体系为其分派客栈,法度榜样的人口函数会是main函数。不过main函数也不是第一个被调用的函数,我们经由过程简单的例子讲解。

复制代码
#include <stdio.h>#include <string.h>int function(int arg){    return arg;}int main(void){    int i = 10;    int j;    j = function(i);    printf("%d\n",j);    return 0;}
复制代码
function:.LFB0:    .cfi_startproc    pushq    %rbp    .cfi_def_cfa_offset 16    .cfi_offset 6, -16    movq    %rsp, %rbp    .cfi_def_cfa_register 6    movl    %edi, -4(%rbp)    movl    -4(%rbp), %eax    popq    %rbp    .cfi_def_cfa 7, 8    ret    .cfi_endproc
复制代码

看以看到当函数被调用时,起首会把调用函数的┞坊底压栈到本身函数的┞坊中(pushq %rbp),然后将本来函数栈顶rsp作为当前函数的┞坊底(movq %rsp, %rbp)。函数运行完成时,会将压入栈中的rbp从新出栈到rbp中(popq %rbp)。当前function汇编函数没有显示出栈顶的变更(rsp的变更),我们可以经由过程main函数来看栈顶的变更,汇编代码如下:

复制代码
main:.LFB1:    .cfi_startproc    pushq    %rbp    .cfi_def_cfa_offset 16    .cfi_offset 6, -16    movq    %rsp, %rbp    .cfi_def_cfa_register 6    subq    $16, %rsp    movl    $10, -4(%rbp)    movl    -4(%rbp), %eax    movl    %eax, %edi    call    function    movl    %eax, -8(%rbp)    movl    -8(%rbp), %eax    movl    %eax, %esi    movl    $.LC0, %edi    movl    $0, %eax    call    printf    movl    $0, %eax    leave    .cfi_def_cfa 7, 8    ret    .cfi_endproc
复制代码

大年夜膳绫擎的汇编代码可以看到起首也是压栈和设置新栈底的过程,大年夜此可以看出main函数也是被调用的函数,而不是第一个调用函数。代码中的黄色部分是当前栈顶变更,大年夜应用的subq可以知道,栈顶的地址要小于栈底的地址,所以栈是大年夜高地址向低地址发展。

    接下来可能有点绕,慢慢读,将用说话描述函数调用过程,调用函数会将被调用函数的实参大年夜右往左的次序压入调用函数的┞坊中,经由过程call指令调用被调用函数,起首将return address(也就是call指令的后一条指令的地址)压入调用函数栈中,这时rsp存放器中存储的地址是存放return address内存地址的下一地址值,这时调用函数的┞坊构造形成,然后就会进入被调用函数的感化域中。被调用函数起首将调用函数的rbp压入被调用函数栈中(其拭魅这个地址就是rsp存放器中存储的地址),接下来将会将这个地址作为被调用函数的rbp地址,才会有movq %rsp, %rbp指令设置被调用函数的┞坊底。如上所描述的构成了函数调用的客栈构造如下图所示。


  推荐阅读

  9个开发人员的秘密可能会让您的业务陷入困境

应用法度榜样开辟可以成为您营业的关键身分,而可促进开辟出市场主导的移动端应用法度榜样的奇才或只是能编写精确的定制代率攀来使营业成长起来的奇才,这些人都异常值得公司进行投入。但>>>详细阅读


本文标题:函数调用中堆栈的个人理解

地址:http://www.17bianji.com/lsqh/36443.html

关键词: 探索发现

乐购科技部分新闻及文章转载自互联网,供读者交流和学习,若有涉及作者版权等问题请及时与我们联系,以便更正、删除或按规定办理。感谢所有提供资讯的网站,欢迎各类媒体与乐购科技进行文章共享合作。

网友点评
自媒体专栏

评论

热度

精彩导读
栏目ID=71的表不存在(操作类型=0)