汇编2 ----C语言函数2

上文讲到call之后,程序发生跳转。之后因为博主设错了一个断点,结果折腾了整整一周,真是欲哭无泪。

这才是正确的断点设置啊TAT。这是call之后的语句。

01281427 83 C4 08 add esp,8

执行call之后ESP的值减少4。在memory窗体中查看ESP的值。

由小端机存储可只栈顶正是函数的返回地址。

012813C0 55 push ebp

012813C1 8B EC mov ebp,esp

函数体开头两条指令是将EBP压栈,将ESP赋给EBP。

Intel几个通用寄存器的作用概括:

EAX — Accumulator for operands and results data

? EBX — Pointer to data in the DS segment

? ECX — Counter for string and loop operations

? EDX — I/O pointer

? ESI — Pointer to data in the segment pointed to by the DS register; source pointer for string operations

? EDI — Pointer to data (or destination) in the segment pointed to by the ES register; destination pointer for

string operations

? ESP — Stack pointer (in the SS segment)

? EBP — Pointer to data on the stack (in the SS segment)

因为ESP的值一直在变化,而函数参数的值和返回值又是根据栈地址的偏移量来计算的,所以需要EBP暂存ESP的值来寻址。

这两条操作后,栈的结构如下图所示:

之后我们来看函数如何取得形参的值。前文已经说过,在函数执行前参数的值已经压栈。观察接下来的指令:

mov eax,dword ptr [ebp+8]

add eax,dword ptr [ebp+0Ch]

在这两条指令之前并无对EBP的操作,所以参数的地址分别为EBP+8和EBP+c

而上述两条指令正是将两个地址处的值相加并传给EAX(正如EAX的作用)

那么函数如何返回值sum?观察下一条指令-

mov dword ptr [ebp-8],eax

EAX的值又传递给了EBP-8的地址。栈结构如图所示。

查看EBP-8的值,恰为1和2的和3

为什么要存在EBP-8而非EBP-4,原书上说是为了防止溢出攻击,我一个记笔记的当然不不明觉厉啦。先在此mark,以后学到相关内容再补充。

函数执行完毕后,当然需要返回喽。上文已经详细介绍了RET指令的过程。观察函数体部分对栈的操作。

push ebx

push esi

push edi

之后都有相对应的pop,所以最后ESP的指向恰和上图的ESP相同。之后pop EBP后,ESP恰好指在返回地址。RET指令返回,函数执行完毕。

执行完后的扫尾工作:

注意到call指令下面的那条指令:

add esp,8

RET作用之一是Pops the top-of-stack value (the return instruction pointer) into the EIP register.

所以RET之后,ESP+4处的1和ESP+8处的2仍然存在,而函数已经调用完毕。将ESP+8即标记1和2已经无用,实现栈回收。

接下来下面的操作如何获得返回值,以及RET特殊用法,release优化,将在下节讨论。

?

?

?

?

时间: 2024-12-26 19:34:11

汇编2 ----C语言函数2的相关文章

从linux0.11中起动部分代码看汇编调用c语言函数

上一篇分析了c语言的函数调用栈情况,知道了c语言的函数调用机制后,我们来看一下,linux0.11中起动部分的代码是如何从汇编跳入c语言函数的.在LINUX 0.11中的head.s文件中会看到如下一段代码(linux0.11的启动分析部分会在另一部分中再分析,由于此文仅涉及c与汇编代码的问题,). after_page_tables: pushl $0 # These are the parameters to main :-) pushl $0 pushl $0 pushl $L6 # re

C语言中递归什么时候可以省略return引发的思考:通过内联汇编解读C语言函数return的本质

事情的经过是这样的,博主在用C写一个简单的业务时使用递归,由于粗心而忘了写return.结果发现返回的结果依然是正确的.经过半小时的反汇编调试,证明了我的猜想,现在在博客里分享.也是对C语言编译原理的一次加深理解. 引子: 首先我想以一道题目引例,比较能体现出问题. 例1: #include <stdio.h> /** 函数功能:用递归实现位运算加法 */ int Add_Recursion(int a,int b) { int carry_num = 0, add_num = 0; if (

C语言中递归什么时候能够省略return引发的思考:通过内联汇编解读C语言函数return的本质

事情的经过是这种,博主在用C写一个简单的业务时使用递归,因为粗心而忘了写return.结果发现返回的结果依旧是正确的.经过半小时的反汇编调试.证明了我的猜想,如今在博客里分享.也是对C语言编译原理的一次加深理解. 引子: 首先我想以一道题目引例,比較能体现出问题. 例1: #include <stdio.h> /** 函数功能:用递归实现位运算加法 */ int Add_Recursion(int a,int b) { int carry_num = 0, add_num = 0; if (b

汇编1 ----C语言函数1

构造以下C程序并在合适位置插入breakpoints 在Visual Studio 2015 CTP6对其反汇编. 下面来分析 z = add(1, 2); 009C170E 6A 02 push 2 ????int z; ????z = add(1, 2); 009C1710 6A 01 push 1 009C1712 E8 8D FA FF FF call 009C11A4 009C1717 83 C4 08 add esp,8 009C171A 89 45 F8 mov dword ptr

Linux汇编GAS调用C语言函数实例

Blum的书上只讲了C语言调用汇编,没讲汇编调用C语言.我自己尝试了下. 最终试验成功了,在此写出与大家分享.期间历经无数错误,无数异常,我不是醉了,而是跪了...好在最后好了. 程序实现一个换值功能,在main.s里定义a=10,b=20,然后调用C语言函数把a,b换值. 新建两个文件分别为main.s的汇编文件,还有pro.c的C语言函数文件. main.s的代码如下: .section .data a: .int 10 b: .int 20 .section .text .globl ma

[汇编与C语言关系]2. main函数与启动例程

为什么汇编程序的入口是_start,而C程序的入口是main函数呢?以下就来解释这个问题 在<x86汇编程序基础(AT&T语法)>一文中我们汇编和链接的步骤是: $ as hello.s -o hello.o $ ld hello.o -o hello 我们用gcc main.c -o main开编译一个c程序,其实际分为三个步骤:编译.汇编.链接 $ gcc -S main.c 生成汇编代码 $ gcc -c main.s 生成目标文件 $ gcc main.o 生成可执行文件 我们

ARM汇编的一般形式和汇编调用C语言

.text //代码段.global _start //表明程序入口_start: //入口函数 BL main //跳转到c语言中的main,不一定要转跳到main,也可以执行其他的汇编指令 一般工程中,纯汇编复杂,而且效率比C语言并没有提高多少,所以在没有操作系统的工程中,最好的开发方式就是用汇编调用C语言,使用C语言来完成所需要的工作(只有在对效率要求极高的时候才会使用汇编编写代码块),当然裸机开发没有现成的库,就算是简单的printf函数也是没法调用的,其实就是就是汇编的高级语言版本.个

C语言函数参数压栈顺序为何是从右到左?(从左向右的话,碰到printf的会陷入死循环)

上学期学习了汇编语言,并在操作系统实验中使用了汇编+C语言混合编程,中间也了解了一些C语言与汇编语言的对应关系. 由于汇编语言是底层的编程语言,各种函数参数都要直接控制栈进行存取,在混合编程中,要用汇编来调用C函数,当然就要知道参数的压栈情况了. 当知道C函数的参数压栈顺序是从右到左时,我觉得很奇怪,因为大多数情况下,人们的习惯是从左到右的,难不成设计者学咱们中国古代写字从右到左的习惯不成? 当时只是记下了这个规则而已,并没有去探究这其中的缘由,后来在实验中自己用汇编实现了printf和scan

借助动态代码生成技术在基于Webkit引擎的HTML5网页JS内调用易语言函数

作者:庄晓立(Liigo) 日期:2015年3月3日夜 原创链接:http://blog.csdn.net/liigo/article/details/44045177 版权所有,转载请注明出处:http://blog.csdn.net/liigo 前两天我协助解决了一个技术问题,在此稍作记录和总结. 具体来说,就是在使用基于Webkit引擎的封装组件wke的过程中,需要把一个易语言函数注册给JavaScript引擎,让它可以在网页里被调用(就像在网页里调用普通JavaScript函数一样).如