函数调用的细节实现

函数调用的细节实现

这个问题当时感觉答得还可以,不过很多细节记不清晰了。所以下面反汇编一段小程序,进行分析,因为我比较熟悉的是arm汇编,所以我选择了一台安装了交叉工具链的ubuntu,而没有使用之前的centos。所以可能画风会有些不同。

下图是我写了一个简单的程序和makefile。程序中是由main函数调用fun()函数。

编译程序,生成可执行文件,并对其进行反汇编,将反汇编之后的信息写入dump文件,打开dump文件,分析其中的关键源码。

可以看出函数调用的过程如下:

1.传递参数,如果参数小于四个,则使用R0-R3 4个寄存器传递,多余4个的通过压栈传输,而压栈选择压变量e而不是选择压变量a,则说明了压栈是从右向左的。

2.使用跳转指令,跳转到相应的函数段。

3.增加栈帧,保存现在的栈基址指针fp,然后重新给栈基址指针fp和栈顶指针sp赋予新值。

4.将通过寄存器传递进来的参数保存入栈。

来自为知笔记(Wiz)

时间: 2024-10-15 17:02:44

函数调用的细节实现的相关文章

第15课 缔造程序兼容的合约(下)

1. ABI规定桢栈结构 (1)栈帧的内存布局(以Linux为例) (2)栈帧的形成方式 (3)栈帧的销毁方式 2. ebp寄存器 (1)ebp为当前栈帧的基准(存储上一个栈帧的ebp值) (2)通过ebp能够获取返回值地址.参数和局部变量等. 3. 函数调用发生时的细节 (1)调用者通过call指令调用函数,将返回地址压入栈中 (2)函数所需要的栈空间大小由编译器确定,表现为字面常量 (3)函数结束时,leave指令恢复上一个栈帧的esp和ebp(mov ebp, esp; pop ebp)

Linux江湖08:使用GCC和GNU Binutils编写能在x86实模式运行的16位代码

不可否认,这次的标题有点长.之所以把标题写得这么详细,主要是为了搜索引擎能够准确地把确实需要了解GCC生成16位实模式代码方法的朋友带到我的博客.先说一下背景,编写能在x86实模式下运行的16位代码,这个话题确实有点复古,所以能找到的资料也相应较少.要运行x86实模式的程序,目前我知道的只有两种方式,一种是使用DOS系统,另一种是把它写成引导扇区的代码,在系统启动时直接运行.很显然,许多讲自己实现操作系统的书籍都会讲到x86实模式,也只有自己实现操作系统引导的朋友需要用到x86实模式,所以我这篇

Linux 桌面玩家指南:08. 使用 GCC 和 GNU Binutils 编写能在 x86 实模式运行的 16 位代码

特别说明:要在我的随笔后写评论的小伙伴们请注意了,我的博客开启了 MathJax 数学公式支持,MathJax 使用$标记数学公式的开始和结束.如果某条评论中出现了两个$,MathJax 会将两个$之间的内容按照数学公式进行排版,从而导致评论区格式混乱.如果大家的评论中用到了$,但是又不是为了使用数学公式,就请使用\$转义一下,谢谢. 想从头阅读该系列吗?下面是传送门: Linux 桌面玩家指南:01. 玩转 Linux 系统的方法论 [约 1.1 万字,22 张图片] Linux 桌面玩家指南

09 js函数调用过程内存分析、js函数细节

函数的调用过程 Js函数调用过程的内存分析. 一个递归调用的例子: <html> <head> <script> //abc是一个函数它接收一个数值 function abc(num1){ if (num1>3) { abc(--num1); //递归 } document.writeln(num1); } abc(5); </script> </head> <body> </body> </html>

x86函数调用约定

以下摘自<IDA Pro>,貌似有一些细节之处没有交代清楚呢,需要进一步思考.实践. 了解栈帧的基本概念后,接下来详细介绍它们的结构.下面的例子涉及x86体系结构和与常见的x86编译器(如Microsoft Visual C/C++或GNU的gcc/g++)有关的行为.创建栈帧的最重要的步骤是,通过调用函数将函数存入栈中.调用函数必须存储被调用函数所需要的参数,否则可能导致严重的问题.各个函数会选择并遵照某一特定的调用约定,以表明他们希望以何种方式接收参数. 调用约定指定调用方放置函数所需参数

强壮你的C和C++代码30个小细节

1 初始化局部变量 使用未初始化的局部变量是引起程序崩溃的一个比较普遍的原因, 2 初始化WINAPI 结构体 许多Windows API都接受或则返回一些结构体参数,结构体如果没有正确的初始化,也很有可能引起程序崩溃.大部分Windows API结构体都必须有一个cbSIze参数,这个参数必须设置为这个结构体的大小. 注意:千万不要用ZeroMemory和memset去初始化那些包括结构体对象的结构体,这样很容易破坏其内部结构体,从而导致程序崩溃. 3 检测函数输入参数有效性 在函数设计的时候

C函数调用 栈

这篇blog试图说明这么一个问题,当一个c函数被调用时,一个栈帧(stack frame)是如何被建立,又如何被消除的.这些细节跟操作系统平台及编译器的实现有关,下面的描述是针对运行在Linux的gcc编译器而言的.c语言的标准并没有描述实现的方式.所以,不同的编译器.不同的操作系统都可能有自己的建立栈帧的方式. 下面先看一个典型的栈帧: 上面个的这个图是一个典型的栈帧,图中,栈顶在上,地址空间往下增长. 在看看这个栈对应的函数代码: int foo(int arg1, int arg2, in

JavaScript语法中分号使用的细节

关于JavaScript中可选分号的问题有几个细节要注意: 一般来说,JavaScript和其他语言一样都是使用分号,将语句隔开,但在JavaScript中,如果语句各自独立一行,有时也可以省略分号的 细节1: 如果当前语句和随后的非空格字符不能当成一整体来解析的话,JavaScript就在当前语句行结束处自动填补分号 var a a = 3 console.log(a); JavaScript将上述代码解析为: var a; a=3; console.log(a); 第一行代码 var a自动

函数调用和给对象发消息(Runtime理解)

在写代码的时候这个差距其实是不打看的出得,很多时候也就无所谓叫什么,很多人为了便于理解,干脆就叫函数调用.这个其实应该是oc的一个特色,消息发送.具体的类typedef struct objc_class *Class; typedef struct objc_object { Class isa; } *id; typedef struct objc_selector *SEL; typedef id (*IMP)(id, SEL, ...);类结构struct objc_class { **