精华内容
下载资源
问答
  • C++ 函数调用压栈过程
    2021-12-29 21:31:19
    1. 将函数参数压入栈中,可以发现参数的压栈顺序是从右向左的。
    2. 将call指令后面一条指令的地址压入栈中,函数返回后会跳转到该地址。将调用方栈底地址压入栈中。将EBX,ESI,EDI压入栈中,这也就是我们常说的函数中断前的“保护现场”,EBX,ESI,EDI分别为基址寄存器,源变址寄存器,目的变址寄存器。
    3. 通过call指令跳转到函数的起始地址,将函数内部的变量去堆栈上开辟空间,执行函数功能。
    4. 函数执行完成后,取出保存在栈中的寄存器数值,将寄存器的值也恢复到了函数调用之前,并取回函数返回地址,函数返回。
    更多相关内容
  •  本篇文章着重写的是系统中栈的工作原理,以及函数调用过程中栈帧的产生与释放的过程,有可能名字过大,如果不合适我可以换一个名字,希望大家能够指正,小丁虚心求教!如果有哪里写的不清楚的或者错误的地方请及时...

    (转自:https://blog.csdn.net/u011555996/article/details/70211315

    1.开篇

      本篇文章着重写的是系统中栈的工作原理,以及函数调用过程中栈帧的产生与释放的过程,有可能名字过大,如果不合适我可以换一个名字,希望大家能够指正,小丁虚心求教!如果有哪里写的不清楚的或者错误的地方请及时更正,小丁再次谢过了。文章里面有错别字,也可能会有好友说寄存器的32、16位的区别其实我感觉这里主要讲的还是些原理性的东西,后续会将文章图片错别字进行调整.(图片里面的posh改为push)

    2.内存的不同用途

      根据不同的操作系统,一个进程可能被分配到不同的内存区域去执行。但是不管什么样的操作系统、什么样的计算机架构,进程使用的内存都可以按照功能大致分为以下4个部分:

      (1)代码区:这个区域存储着被装入执行的二进制机器代码,处理器会到这个区域取指并执行。

      (2)数据区:用于存储全局变量等。

      (3)堆区:进程可以在堆区动态地请求一定大小的内存,并在用完之后归还给堆区。动态分配和回收是堆区的特点。

      (4)栈区:用于动态地存储函数之间的关系,以保证被调用函数在返回时恢复到母函数中继续执行。

      在Windows平台下,高级语言写出的程序经过编译链接,最终会变成PE文件。当PE文件被装载运行后,就成了所谓的进程。

      PE文件代码段中包含的二进制级别的机器代码会被装入内存的代码区(.text),处理器将到内存的这个区域一条一条地取出指令和操作数,并送入运算逻辑单元进行运算;如果代码中请求开辟动态内存,则会在内存的堆区分配一块大小合适的区域返回给代码区的代码使用;当函数调用发生时,函数的调用关系等信息会动态地保存在内存的栈区,以供处理器在执行完被调用函数的代码时,返回母函数。

      如果把计算机看成一个有条不紊的工厂,我们可以得到如下类比:

        < CPU是完成工作的工人。

        < 数据区、堆区、栈区等则是用来存放原料、半成品、成品等各种东西的场所。

        < 存放在代码区的指令则告诉CPU要做什么,怎么做,到哪里去领原材料,用什么工具来做,做完以后把成品放到哪个货 仓去。

        < 值得一提的是,栈除了扮演存放原料、半成品的仓库之外,它还是车间调度主任的办公室。

    3.栈与系统栈

      从计算机科学的角度来看,栈指的是一种数据结构,是一种先进后出的数据表。栈的最常见操作有两种:压栈(PUSH)、弹栈(POP);

      用于标识栈的属性也有两个:栈顶(TOP)、栈底(BASE)。

      栈在内存中的存放是高地址是栈底(Base),低地址是栈顶(Top)。

      下面来演示下栈的工作原理:

      首先我们先以这段汇编指令来进行操作:

          

    mov ax,0123H  
      
    push ax  
      
    mov bx 2244H  
      
    push bx  
      
    pop ax  
      
    pop bx  
    

      首先我们先将10000H-1000FH这段内存空间来当做栈来使用,首先执行的操作是push ax,会将0123H压入到栈中,SP=SP-2,SS:SP指向当前栈顶当前的单元,以当前的单元为新的栈顶,将ax的数据送到SS:SP指向的内存单元中,SS:SP此时指向新的栈顶。此时ax的数值是0123H;详细请见下图

      接来下进行第二部操作:push bx,操作同上;

      接下来我们要演示的是pop操作,请注意pop操作的细节,比如到了栈底的时候指针是在哪里?这些都是要进行关注的。

      CPU执行pop ax时,SP=SP+2,SS:SP指向1000EH,pop操作栈顶元素,1000CH处的2266H依然存在,但是它在栈中不存在了,当再次push等入栈指令后,SS:SP移至1000CH,并在里面写入新的数据,将其覆盖。详细看下图操作:

     

            当再次进行pop给bx时,这是SP=SP+2,这时候指针就超出了栈底,就变成了SP=10H,所以我们得出一个结论就是当栈为空时,SS=1000H,SP=10H。详细看下面操作:

      内存的栈区实际上指的就是系统栈。系统栈由系统自动维护,它用于实现高级语言中函数的调用。对于类似C语言这样的高级语言,系统栈的PUSH、POP等堆栈平衡细节是透明的。一般说来,只有在使用汇编语言开发程序的时候,才需要和它直接打交道。

    4.函数调用约定与相关指令

         函数调用约定描述了函数传递参数方式和栈帧同工作的技术细节。不同的操作系统、不同的语言、不同的编译器在实现函数调用时的原理虽然基本相同,但具体的调用约定还是有差别的。这包括参数传递方式,参数入栈顺序是从右向左还是从左向右,函数返回时恢复堆栈平衡的操作在子函数中进行还是在母函数中进行。
      调用方式之间的差异

      具体的,对于Visual C++来说,可支持以下3种函数调用约定:

      

      如果要明确使用某一种调用约定,只需要在函数前加上调用约定的声明即可,否则默认情况下,VC会使用_stdcall的调用方式。 除了参数入栈方向和恢复栈平衡操作位置的不同之外,参数传递有时也会有所不同。例如,每一个C++类成员函数都有一个this指针,在Windows平台中,这个指针一般是用ECX寄存器来传递的,但如果用GCC编译器来编译,这个指针会作为最后一个参数压入栈中。

      注意:同一段代码用不同的编译选项、不同的编译器编译链接后,得到的可执行文件会有很多不同。

      函数调用大概包括以下几个步骤:

       (1)参数入栈:将参数从右向左依次压入系统栈中。

       (2)返回地址入栈:将当前代码区调用指令的下一条指令地址压入栈中,供函数返回时继续执行。

       (3)代码区跳转:处理器从当前代码区跳转到被调用函数的入口处。

       (4)栈帧调整:具体包括:

          <1>保存当前栈帧状态值,已备后面恢复本栈帧时使用(EBP入栈)。

          <2>将当前栈帧切换到新栈帧(将ESP值装入EBP,更新栈帧底部)。

          <3>给新栈帧分配空间(把ESP减去所需空间的大小,抬高栈顶)。

          <4>对于_stdcall调用约定,函数调用时用到的指令序列大致如下:

          push 参数3      ;假设该函数有3个参数,将从右向做依次入栈

          push 参数2

          push 参数1

          call 函数地址   ;call指令将同时完成两项工作:a)向栈中压入当前指令地址的下一个指令地址,即保存返回地址。 b)跳转到所调用函数的入口处。

          push  ebp        ;保存旧栈帧的底部

          mov  ebp,esp     ;设置新栈帧的底部 (栈帧切换)

          sub   esp,xxx     ;设置新栈帧的顶部 (抬高栈顶,为新栈帧开辟空间)

      函数返回的步骤如下:

       <1>保存返回值,通常将函数的返回值保存在寄存器EAX中。

       <2>弹出当前帧,恢复上一个栈帧。具体包括:

          (1)在堆栈平衡的基础上,给ESP加上栈帧的大小,降低栈顶,回收当前栈帧的空间。

          (2)将当前栈帧底部保存的前栈帧EBP值弹入EBP寄存器,恢复出上一个栈帧。

          (3)将函数返回地址弹给EIP寄存器。

       <3>跳转:按照函数返回地址跳回母函数中继续执行。

       还是以C语言和Win32平台为例,函数返回时的相关的指令序列如下:

       add esp,xxx     ;降低栈顶,回收当前的栈帧

       pop ebp         ;将上一个栈帧底部位置恢复到ebp

       retn            ;a)弹出当前栈顶元素,即弹出栈帧中的返回地址,至此,栈帧恢复到上一个栈帧工作完成。b)让处理器跳转到弹出的返回地址,恢复调用前代码区

    5.寄存器与函数栈帧

      每一个函数独占自己的栈帧空间。当前正在运行的函数的栈帧总是在栈顶。Win32系统提供两个特殊的寄存器用于标识位于系统栈顶端的栈帧。

      (1)ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。

      (2)EBP:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。 

      【寄存器对栈的标识作用见(图1)】

      函数栈帧:ESP和EBP之间的内存空间为当前栈帧,EBP标识了当前栈帧的底部,ESP标识了当前栈帧的顶部。

      在函数栈帧中,一般包含以下几类重要信息。

      (1)局部变量:为函数局部变量开辟的内存空间。

      (2)栈帧状态值:保存前栈帧的顶部和底部(实际上只保存前栈帧的底部,前栈帧的顶部可以通过栈帧平衡计算得到),用于在本栈被弹出后恢复出上一个栈帧。

      (3)函数返回地址:保存当前函数调用前的“断点”信息,也就是函数调用前的指令位置,以便在函数返回时能够恢复到函数被调用前的代码区中继续执行指令。

      注:函数栈帧的大小并不固定,一般与其对应函数的局部变量多少有关。函数运行过程中,其栈帧大小也是在不停变化的。除了与栈相关的寄存器外,我们还需要记住另一个至关重要的寄存器。

      EIP:指令寄存器(extended instruction pointer),其内存放着一个指针,该指针永远指向下一条等待执行的指令地址。 可以说如果控制了EIP寄存器的内容,就控制了进程——我们让EIP指向哪里,CPU就会去执行哪里的指令。这里不多说EIP的作用,我个人认为王爽老是的汇编里面讲EIP讲的已经是挺好的了~这里不想多写关于EIP的事情。

    6.结束语

      本文是针对上面两篇文章的一个基础性的补充~希望大家能够喜欢和指正其中的不足之处。

    展开全文
  • C/C++函数调用压栈模型

    千次阅读 2018-05-18 19:18:29
    函数调用压栈模型对于我们学习C语言非常重要,最直观的体现在我们后面要学的函数的递归,函数的递归就充分利用的函数的压栈模型 当函数从入口函数main函数开始执行时,编译器将我们操作系统的运行状态,main...

           函数调用的压栈模型对于我们学习C语言非常重要,最直观的体现在我们后面要学的函数的递归,函数的递归就充分利用的函数的压栈模型

            

            当函数从入口函数main函数开始执行时,编译器会将我们操作系统的运行状态,main函数的返回地址、main的参数、mian函数中的变量、进行依次压栈;当main函数开始调用fa()函数时,编译器此时会将main函数的运行状态进行压栈,再将fa()含糊的返回地址、fa函数的参数、fa定义变量依次压栈;当fa调用fb的时候,编译器此时会将fa函数的运行状态进行压栈,再将fb含糊的返回地址、fb函数的参数、fb定义变量依次压栈。

            

            当函数fb运行完成后,fb所有的压栈都会被编译器释放掉,编译器再从栈中接收到fa函数的运行状态后,衔接调用fb函数之前的操作,继续执行,同理,fa执行完后,编译器对mian函数的处理也相同。

            一个函数可以在栈上分配内存,也可以在堆上分配内存,更可以在全局区域分配内存,因此理解内存从哪里来,对于我们函数参数的传递,变量的调用异常重要。

            fb函数在栈上分配的内存,不能被fa和mian函数所调用,因为它会在fb函数执行完后被编译器释放掉;而 fb函数使用new或者malloc在堆上分配的内存或者在全局区分配的内存,只要不被程序员自己释放掉,是可以可以被fa和main函数所调用的。


    展开全文
  • 函数调用 压栈的工作原理

    万次阅读 多人点赞 2017-04-17 15:11:48
     本篇文章着重写的是系统中栈的工作原理,以及函数调用过程中栈帧的产生与释放的过程,有可能名字过大,如果不合适我可以换一个名字,希望大家能够指正,小丁虚心求教!如果有哪里写的不清楚的或者错误的地方请及时...
    


     
    1.开篇

      本篇文章着重写的是系统中栈的工作原理,以及函数调用过程中栈帧的产生与释放的过程,有可能名字过大,如果不合适我可以换一个名字,希望大家能够指正,小丁虚心求教!如果有哪里写的不清楚的或者错误的地方请及时更正,小丁再次谢过了。文章里面有错别字,也可能会有好友说寄存器的32、16位的区别其实我感觉这里主要讲的还是些原理性的东西,后续会将文章图片错别字进行调整.(图片里面的posh改为push)

    2.内存的不同用途

      根据不同的操作系统,一个进程可能被分配到不同的内存区域去执行。但是不管什么样的操作系统、什么样的计算机架构,进程使用的内存都可以按照功能大致分为以下4个部分:

      (1)代码区:这个区域存储着被装入执行的二进制机器代码,处理器会到这个区域取指并执行。

      (2)数据区:用于存储全局变量等。

      (3)堆区:进程可以在堆区动态地请求一定大小的内存,并在用完之后归还给堆区。动态分配和回收是堆区的特点。

      (4)栈区:用于动态地存储函数之间的关系,以保证被调用函数在返回时恢复到母函数中继续执行。

      在Windows平台下,高级语言写出的程序经过编译链接,最终会变成PE文件。当PE文件被装载运行后,就成了所谓的进程。

      PE文件代码段中包含的二进制级别的机器代码会被装入内存的代码区(.text),处理器将到内存的这个区域一条一条地取出指令和操作数,并送入运算逻辑单元进行运算;如果代码中请求开辟动态内存,则会在内存的堆区分配一块大小合适的区域返回给代码区的代码使用;当函数调用发生时,函数的调用关系等信息会动态地保存在内存的栈区,以供处理器在执行完被调用函数的代码时,返回母函数。

      如果把计算机看成一个有条不紊的工厂,我们可以得到如下类比:

        < CPU是完成工作的工人。

        < 数据区、堆区、栈区等则是用来存放原料、半成品、成品等各种东西的场所。

        < 存放在代码区的指令则告诉CPU要做什么,怎么做,到哪里去领原材料,用什么工具来做,做完以后把成品放到哪个货 仓去。

        < 值得一提的是,栈除了扮演存放原料、半成品的仓库之外,它还是车间调度主任的办公室。

    3.栈与系统栈

      从计算机科学的角度来看,栈指的是一种数据结构,是一种先进后出的数据表。栈的最常见操作有两种:压栈(PUSH)、弹栈(POP);

      用于标识栈的属性也有两个:栈顶(TOP)、栈底(BASE)。

      栈在内存中的存放是高地址是栈底(Base),低地址是栈顶(Top)。

      下面来演示下栈的工作原理:

      首先我们先以这段汇编指令来进行操作:

          

    1. mov ax,0123H  
    2.   
    3. push ax  
    4.   
    5. mov bx 2244H  
    6.   
    7. push bx  
    8.   
    9. pop ax  
    10.   
    11. pop bx  
    mov ax,0123H
    
    push ax
    
    mov bx 2244H
    
    push bx
    
    pop ax
    
    pop bx

      首先我们先将10000H-1000FH这段内存空间来当做栈来使用,首先执行的操作是push ax,会将0123H压入到栈中,SP=SP-2,SS:SP指向当前栈顶当前的单元,以当前的单元为新的栈顶,将ax的数据送到SS:SP指向的内存单元中,SS:SP此时指向新的栈顶。此时ax的数值是0123H;详细请见下图

      接来下进行第二部操作:push bx,操作同上;

      接下来我们要演示的是pop操作,请注意pop操作的细节,比如到了栈底的时候指针是在哪里?这些都是要进行关注的。

      CPU执行pop ax时,SP=SP+2,SS:SP指向1000EH,pop操作栈顶元素,1000CH处的2266H依然存在,但是它在栈中不存在了,当再次push等入栈指令后,SS:SP移至1000CH,并在里面写入新的数据,将其覆盖。详细看下图操作:


            当再次进行pop给bx时,这是SP=SP+2,这时候指针就超出了栈底,就变成了SP=10H,所以我们得出一个结论就是当栈为空时,SS=1000H,SP=10H。详细看下面操作:

      内存的栈区实际上指的就是系统栈。系统栈由系统自动维护,它用于实现高级语言中函数的调用。对于类似C语言这样的高级语言,系统栈的PUSH、POP等堆栈平衡细节是透明的。一般说来,只有在使用汇编语言开发程序的时候,才需要和它直接打交道。

    4.函数调用约定与相关指令

         函数调用约定描述了函数传递参数方式和栈帧同工作的技术细节。不同的操作系统、不同的语言、不同的编译器在实现函数调用时的原理虽然基本相同,但具体的调用约定还是有差别的。这包括参数传递方式,参数入栈顺序是从右向左还是从左向右,函数返回时恢复堆栈平衡的操作在子函数中进行还是在母函数中进行。
      调用方式之间的差异

      具体的,对于Visual C++来说,可支持以下3种函数调用约定:

      

      如果要明确使用某一种调用约定,只需要在函数前加上调用约定的声明即可,否则默认情况下,VC会使用_stdcall的调用方式。 除了参数入栈方向和恢复栈平衡操作位置的不同之外,参数传递有时也会有所不同。例如,每一个C++类成员函数都有一个this指针,在Windows平台中,这个指针一般是用ECX寄存器来传递的,但如果用GCC编译器来编译,这个指针会作为最后一个参数压入栈中。

      注意:同一段代码用不同的编译选项、不同的编译器编译链接后,得到的可执行文件会有很多不同。

      函数调用大概包括以下几个步骤:

       (1)参数入栈:将参数从右向左依次压入系统栈中。

       (2)返回地址入栈:将当前代码区调用指令的下一条指令地址压入栈中,供函数返回时继续执行。

       (3)代码区跳转:处理器从当前代码区跳转到被调用函数的入口处。

       (4)栈帧调整:具体包括:

          <1>保存当前栈帧状态值,已备后面恢复本栈帧时使用(EBP入栈)。

          <2>将当前栈帧切换到新栈帧(将ESP值装入EBP,更新栈帧底部)。

          <3>给新栈帧分配空间(把ESP减去所需空间的大小,抬高栈顶)。

          <4>对于_stdcall调用约定,函数调用时用到的指令序列大致如下:

          push 参数3      ;假设该函数有3个参数,将从右向做依次入栈

          push 参数2

          push 参数1

          call 函数地址   ;call指令将同时完成两项工作:a)向栈中压入当前指令地址的下一个指令地址,即保存返回地址。 b)跳转到所调用函数的入口处。

          push  ebp        ;保存旧栈帧的底部

          mov  ebp,esp     ;设置新栈帧的底部 (栈帧切换)

          sub   esp,xxx     ;设置新栈帧的顶部 (抬高栈顶,为新栈帧开辟空间)

      函数返回的步骤如下:

       <1>保存返回值,通常将函数的返回值保存在寄存器EAX中。

       <2>弹出当前帧,恢复上一个栈帧。具体包括:

          (1)在堆栈平衡的基础上,给ESP加上栈帧的大小,降低栈顶,回收当前栈帧的空间。

          (2)将当前栈帧底部保存的前栈帧EBP值弹入EBP寄存器,恢复出上一个栈帧。

          (3)将函数返回地址弹给EIP寄存器。

       <3>跳转:按照函数返回地址跳回母函数中继续执行。

       还是以C语言和Win32平台为例,函数返回时的相关的指令序列如下:

       add esp,xxx     ;降低栈顶,回收当前的栈帧

       pop ebp         ;将上一个栈帧底部位置恢复到ebp

       retn            ;a)弹出当前栈顶元素,即弹出栈帧中的返回地址,至此,栈帧恢复到上一个栈帧工作完成。b)让处理器跳转到弹出的返回地址,恢复调用前代码区

    5.寄存器与函数栈帧

      每一个函数独占自己的栈帧空间。当前正在运行的函数的栈帧总是在栈顶。Win32系统提供两个特殊的寄存器用于标识位于系统栈顶端的栈帧。

      (1)ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。

      (2)EBP:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。 

      【寄存器对栈的标识作用见(图1)】

      函数栈帧:ESP和EBP之间的内存空间为当前栈帧,EBP标识了当前栈帧的底部,ESP标识了当前栈帧的顶部。

      在函数栈帧中,一般包含以下几类重要信息。

      (1)局部变量:为函数局部变量开辟的内存空间。

      (2)栈帧状态值:保存前栈帧的顶部和底部(实际上只保存前栈帧的底部,前栈帧的顶部可以通过栈帧平衡计算得到),用于在本栈被弹出后恢复出上一个栈帧。

      (3)函数返回地址:保存当前函数调用前的“断点”信息,也就是函数调用前的指令位置,以便在函数返回时能够恢复到函数被调用前的代码区中继续执行指令。

      注:函数栈帧的大小并不固定,一般与其对应函数的局部变量多少有关。函数运行过程中,其栈帧大小也是在不停变化的。除了与栈相关的寄存器外,我们还需要记住另一个至关重要的寄存器。

      EIP:指令寄存器(extended instruction pointer),其内存放着一个指针,该指针永远指向下一条等待执行的指令地址。 可以说如果控制了EIP寄存器的内容,就控制了进程——我们让EIP指向哪里,CPU就会去执行哪里的指令。这里不多说EIP的作用,我个人认为王爽老是的汇编里面讲EIP讲的已经是挺好的了~这里不想多写关于EIP的事情。

    6.结束语

      本文是针对上面两篇文章的一个基础性的补充~希望大家能够喜欢和指正其中的不足之处。

    展开全文
  • 假如函数在调用它之前定义... 您可能感兴趣的文章:深入理解C++中public、protected及private用法C/C++函数调用的几种方式总结浅析C语言中堆和栈的区别关于C语言中参数的传值问题浅谈C语言函数调用参数压栈的相关问题
  • 函数参数压栈顺序

    千次阅读 2019-03-15 09:02:43
    大家困惑的参数压栈顺序也是调用约定的范畴,即上文所言“参数、返回值、返回地址、域指针等的存储位置”与“如何发起函数调用和调用结束后如何恢复” 既然调用约定是编译器级别的方案,那么不同编译器应该就有...
  • 分析: push就是压栈 pop就是出栈 函数调用的跳转,在对应函数的指令执行完之后,还需要再回到函数调用的地方,继续执行call之后的指令。 问题来了: 这种情况下,有没有办法可以不跳转回原来的地方,实现函数的...
  • 但是这种情况应该注意:如果中断子程序中调用子函 数,且函数需要参数和返回值,则被调用子函数和中断子程序要使用 相同的寄存器组,否则出现不可预料的后果。以一个温度测试系统为 例。系统采用 8051作为处理器...
  •  本篇文章着重写的是系统中栈的工作原理,以及函数调用过程中栈帧的产生与释放的过程,有可能名字过大,如果不合适我可以换一个名字,希望大家能够指正,小丁虚心求教!如果有哪里写的不清楚的或者错误的地方请及时...
  • C/C++ 函数调用方式与栈原理是 C/C++ 开发必须要掌握的基础知识,也是高级技术岗位面试中高频题。我真的真的真的建议无论是使用 C/C++ 的学生还是广大 C/C++ 开发者,都该掌握此回答中所介绍的知识。 如果你看不懂...
  • ARM架构下,函数参数是通过r0~r4寄存器传递的,如果参数超过4个,就要借助于栈进行参数传递。 int func(int a1, int a2, int a3, int a4, int a5, int a6) { return a1 + a2 + a3 + a4 + a5; } int main(void)...
  • C函数调用过程原理和栈分析

    千次阅读 2018-07-13 12:01:57
    在编程中,相信每个人对函数都不陌生,那么你真正理解函数调用过程吗?当一个c函数调用时,一个栈帧(stack frame)是如何被建立,又如何被消除的。本文主要就是来解决这些问题的,不同的操作系统和编译器可能有所...
  • 栈的基础知识 eip寄存器 存放的指针指向程序即将执行到的地址 esp(32位)/rsp(64位)寄存器 存放函数的栈顶指针 ...•在函数调用结束时,栈顶的函数(callee)状态被弹出,栈顶恢复到调用函数(caller
  • 在现代的开发工作中,相信绝大部分的同学手头的项目...还记得我们团队有位开发同学当时问过我一个问题,我们用xx框架这么重,一个用户请求过来即使什么也不干,都已经进行了那么多次的函数调用了,适合用来做接口开...
  • ARM体系函数调用过程分析

    千次阅读 2019-03-06 11:16:32
    一、背景: 1、栈描叙:  栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。... 进函数需要压栈操作,保存需要的信息;出函数时需要出栈操作,恢复现场。 2、特殊寄存...
  • 函数调用标准(Procedure Call Standard,PCS)用来描述父/子函数是如何编译、链接的,特别是父函数和子函数之间调用关系的约定,如栈的布局、参数的传递等。每个处理器架构都有不同的函数调用标准,本章重点介绍ARM...
  • 在 C/C++ 程序中,函数调用是十分常见的操作。那么,这一操作的底层原理是怎样的?编译器帮我们做了哪些操作?CPU 中各寄存器及内存堆栈在函数调用时是如何被使用的?栈帧的创建和恢复是如何完成的?针对上述问题,...
  • 调用子函数fun,开辟子函数fun的栈帧,先将y的值赋值给b,b=20入栈,然后将x的值赋值给a,a=10入栈,然后将主函数的栈底指针入栈,然后将主函数z=fun(x,y);后的指令地址也进行入栈,称为现场保护。然后将a+b的值30...
  • 汇编:函数调用

    千次阅读 2019-07-18 18:57:33
    让我们再回忆一下脑海中关于函数调用的概念,也许是这个样子: 这里的“控制流转移”又是如何发生的呢?在解释这个之前,也许我们需要科普一点有关于汇编的知识。 2. 函数调用中的一些细节说明 2.1 函数调用中的...
  • 函数调用

    2021-07-05 04:55:24
    中文名函数调用外文名function reference一般形式在程序中通过对函数的调用来包括内容函数表达式嵌套调用C语言中不允许作嵌套的函数定义函数调用一般形式语音在程序中通过对函数的调用来执行函数体,其过程与其它...
  • 1.main函数调用sum,sum执行完以后,怎么知道回到哪个函数中? 2.sum函数执行完,回到main以后,怎么知道从哪一行指令继续运行的? int sum(int a,int b) { int temp = 0; temp = a + b; return temp; } int main()...
  • 或许习惯于用高级语言编程的大部分同学都会忽略了函数调用的具体过程是怎样的,如果想知道这个过程就不得不从汇编入手,但汇编语言又晦涩难懂。在这里谨以一个简单的例子说说我对函数调用过程的学习心得。先上C语言...
  • 然而可能许多人还不知道函数调用的一些深层问题,所以我写的这篇文章一来是应了一个好朋友的要求而写,二来希望一些朋友能够从我这篇文章了解函数调用的机制。但是并不是每个人都可以完全读懂这文章,想完全读懂此文...
  • 栈:简单来说,栈就是一个先进后出的数据结构,这个和函数调用过程一样,调用时,调用函数在前,被调用函数在后,返回时,被调用函数先返回,调用函数在后。 正好符合先进后出的结构。我们先来看看栈的push,和pop...
  • 汇编函数调用原理

    2022-04-06 21:56:15
    在程序中,函数调用是非常普遍的操作,那么C语言程序在函数调用的过程中,底层执行的汇编代码是怎么样的?寄存器和栈发生了哪些操作呢?
  • 一切的函数调用都要将不同的数据、地址压入或者弹出栈。因此,为了更好地理解函数的调用,我们需要先来看看栈是怎么工作的。 栈是什么? 简单来说,栈是一种LIFO形式的数据结构,所有的数据都是后进先出。这种形式...
  • 从汇编的角度解析函数调用过程看看下面这个简单函数的调用过程:1 int Add(int x,inty)2 {3 int sum = 0;4 sum = x +y;5 returnsum;6 }78 intmain ()9 {10 int a = 10;11 int b = 12;12 int ret = 0;13 ret =Add(a,b...
  • 8051 单片机内存十分有限,没有软件堆栈,函数调用不通过堆栈来传递形参,而硬件堆栈空间也十分有限,程序里所有的局部变量以及全局变量都是编译的时候固定存储在某个地址的存储空间的,函数调用的时候就不用压栈了...
  • 函数调用过程

    万次阅读 多人点赞 2018-01-31 09:21:19
    今天突然看到有人私信我说一直没写函数调用过程(栈帧的形成和销毁过程)这篇博文,赶紧补上。 刚看的栈帧内容时,我很迷惑,我觉得栈帧创建和销毁很麻烦,几句话根本说不完,而且我好像描述不清楚他的过程,所以...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 16,195
精华内容 6,478
关键字:

子函数调用是否会压栈