【汇编总结3】函数调用

这块儿的知识长时间不用老是忘掉,本文依据《0Day安全:软件漏洞分析技术》第二章部分内容做个总结。

1. 函数调用约定

TODO

2. 函数调用过程分析

2.1 函数调用大致包括以下几个步骤

>1. 参数入栈: 根据函数调用约定将参数按照一定顺序依次压入系统栈中,最常用的就是从 右 往 左 压入栈中。这里可以思考下为什么要从右往左? 因为从右往左压入栈的话,被调函数里面取参数使用的时候,就是从左往右的顺序,一般而言 [EBP + 8] 就是第一个参数,[EBP+0xC]是第二个参数,比较方便

>2. 返回地址入栈:将调用指令(CALL指令)的下一条指令的地址压入栈中。

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

>4. 栈帧调整: 第一步,保存当前栈帧状态值,以备后面恢复栈帧时使用(PUSH EBP, 这里的EBP实际上指的是其调用函数的栈帧的栈底位置)

第二步,将当前栈帧切换到新栈帧,(MOV EBP, ESP,  更新本函数栈帧的栈底位置)

第三步,给新栈帧分配空间(SUB ESP,8H, 把ESP减去所需空间(局部变量所占空间)的大小,更新栈顶)

上述步骤可用下述指令描述:

; 调用函数中指令
; 调用前的一堆指令
PUSH 参数3    ; (假设将要调用的函数有3个参数,从右往左入栈)
PUSH 参数2
PUSH 参数1
CALL  函数地址        ; CALL指令依次完成了两项工作
                        ; 第一项,将当前指令的下一条指令地址(返回地址)入栈
                        ; 第二项,跳转到所调用函数的入口处
                        ; 假设下一条指令地址是 0x4000 1234,被调用函数地址
                        ;                       为 0x40002345
                        ; 则相当于有,PUSH 0x40001234  ; JMP 0x40002345

; 被调函数中指令
PUSH EBP         ; 保存旧栈帧的底部
MOV  EBP, ESP  ; 设置新栈帧的底部  (上述两条指令顺利完成了栈帧切换)
SUB  ESP, XXX  ; 设置新栈帧的顶部  (为新栈帧开辟了空间)                                                                                   

2.2 函数返回包含以下几个步骤

>1. 保存返回值: 将函数的返回值保存在EAX寄存器中

>2. 弹出当前栈帧,恢复上一个栈帧:  第一步, 回收当前栈帧的空间(MOV ESP, EBP, 即将栈顶指针恢复到本栈帧的帧底位置)

第二步,将当前栈帧底部保存的前栈帧的EBP值弹入EBP寄存器,恢复出上一个栈帧

第三步,将函数返回地址弹给EIP寄存器

>3. 跳转: 根据上面获取到的返回地址,跳转到母函数中继续执行

ADD ESP, XXX    ; 回收当前栈帧空间,或者直接( MOV ESP, EBP )
POP  EBP           ; 将上一个栈帧底部位置恢复到EBP
RETN               ;  1. 弹出返回地址
                   ;  2. 跳转到返回地址
时间: 2024-10-22 18:59:37

【汇编总结3】函数调用的相关文章

汇编看C函数调用

http://blog.csdn.net/wishfly/article/details/5022008 简单的函数调用,通过简单的函数调用反汇编可以清楚了解如下 1.栈到底是什么,如何操纵栈的? 2.参数和临时变量是以什么形式在哪存放? 3.如何传递返回值? 测试代码如下(这是一个简单的通过调用函数计算两数之和的程序): C++ Code 12345678910111213141516171819 #include <stdio.h> int add(int a, int b) {    i

从汇编层面看函数调用的实现原理

本文是<go调度器源代码情景分析>系列 第一章 预备知识的第6小节. 前面几节我们介绍了CPU寄存器.内存.汇编指令以及栈等基础知识,为了达到融会贯通加深理解的目的,这一节我们来综合运用一下前面所学的这些知识,看看函数的执行和调用过程. 本节我们需要重点关注的问题有: CPU是如何从调用者跳转到被调用函数执行的? 参数是如何从调用者传递给被调用函数的? 函数局部变量所占内存是怎么在栈上分配的? 返回值是如何从被调用函数返回给调用者的? 函数执行完成之后又需要做哪些清理工作? 解决了这些问题,我

C编译器剖析_6.3.4 汇编代码生成_为函数调用与返回产生汇编代码

6.3.4        为函数调用与返回产生汇编代码 在这一小节中,我们来讨论一下如何为函数调用和函数返回生成汇编代码.函数调用对应的中间指令如下所示: //中间指令的四元式: < opcode, DST, SRC1, SRC2> <CALL, 用于接收返回值的变量retVal, 函数名func,  参数列表[arg1,arg2, -,argn]> 让我们先熟悉一下C函数的调用约定CallingConvention,我们需要把参数从右向左入栈(即从argn到arg1依次入栈),不

arm:c语言和汇编混合编程

仅作演示.c和汇编可相互调用,汇编子函数格式参考 汇编:普通的函数调用的汇编代码解析 http://www.cnblogs.com/mylinux/p/4139972.html ;//call_asm.s PRESERVE8 AREA |C$$code|, CODE, READONLY ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; IMPORT cfunc_called_by_asm IMPORT c_add IMPORT c_sub EXPO

[转]iOS高级调试&amp;逆向技术-汇编寄存器调用

前言 本文翻译自Assembly Register Calling Convention Tutorial 序言 通过本教程,你会可以看到CPU使用的寄存器,并探索和修改传递给函数调用的参数.还将学习常见的苹果计算机架构以及如何在函数中使用寄存器.这就是所谓架构的调用约定. 了解汇编是如何工作的,以及特定架构调用约定是如何工作是一项极其重要的技能.它可以让你在没有源码的情况下,观察和修改传递给函数的参数.此外,因为源码存在不同或未知名称的变量情况,所以有时候更适合使用汇编. 比如说,假设你总想知

delphi程序设计之底层原理

虽然用delphi也有7,8年了,但大部分时间还是用在系统的架构上,对delphi底层还是一知半解,今天在网上看到一篇文章写得很好,虽然是07年的,但仍有借鉴的价值. 现摘录如下: Delphi程序设计之--经验技巧 这些日子太忙了,今天把剩下的部分贴完,希望对大家有用.看过前一篇的都知道此文的作者和出处,我就不详细说了. { No. 16 } //对于记录类型Record的分析. 实例: type TBaseRec = record   rStr: Integer;   rStr2: Stri

Lua2.4 执行之前 opcode.c

上节说到了 lua_dofile 执行脚本文件,或者编译过的脚本二进制文件.这节看下,Lua 是如何区别这两种文件的,以及虚拟机在开始执行字节码之前,程序里面都发生了什么? lua.c 里面的调用了 lua_dofile 来执行文件,看下 lua_dofile /* ** Open file, generate opcode and execute global statement. Return 0 on ** success or 1 on error. */ int lua_dofile 

《Linux内核分析》课程第一周学习总结

姓名:何伟钦 学号:20135223 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 学习内容:通过汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的 第一部分:视频教学笔记总结 一.存储程序计算机 冯诺依曼体系结构概念:即具有存储程序计算机的体系结构,大多数拥有计算和存储功能的设备(手机.平板.计算机等)其核心构造均为冯诺依曼体系结构 冯诺依曼体系结构工作

实现操作系统TOS lab1

实验目的: 操作系统是一个软件,也需要通过某种机制加载并运行它. 在这里我们将通过另外一个更加简单的软件-bootloader来完成这些工作,为此,我们需要完成一个能够切换到x86的保护模式并显示字符的bootloader,为启动操作系统TOS来做准备. lab1提供了一个非常小的boot loader和 TOS ,真个bootloader执行代码小于512字节(一个扇区),这样才能放到硬盘的主引导扇区中. 通过分析和实现这个boot loader和TOS ,可以了解到: 计算机原理 cpu的编

inline

inline 大学在教科书上学习过inline函数,定义为inline函数之后,会省去函数调用的开销,直接嵌套汇编代码,取代函数调用,提高效率.工作后项目中也很少用到inline来定义函数,近几天在研读google的google c++ style guide,发现之前自己对inline函数的认识太过肤浅了,这里学习总结一下. 1.inline函数不要超过10行代码,且不能包含循环.switch.if语句 2.在一个c文件中定义的inline函数是不能在其它c文件中直接使用,google推荐把i