第八章 高级过程

8.1 简介

本章主要讲:

堆栈框架

变量作用域和生存期

对战参数的类型

通过传递值或者传递引用来传递参数

在堆栈上创建和初始化局部变量

递归

编写多模块程序

内存模型和语言关键字

注意关键词:

子过程=函数=方法(因不同语言导致名字不统一)

8.2堆栈框架(很重要)

堆栈框架(stack frame)也称活动记录(activation record),它是为传递的参数、子例程的返回地址、局部变量和保存的寄存器保留的堆栈空间。堆栈框架是按一下步骤创建的:

1.如果有传递的参数,则压入堆栈。

2.子历程被调用,字垒成的返回地址压入堆栈。

3.子例程开始时,EBP被压入堆栈。

4.EBP设为ESP的值,从这时开始,EBP就被座位寻址所有子例程参数的基址指针使用了。

5.如果任何寄存器需要保存,则亚茹堆栈。

堆栈框架的结构手程序的内存模式及参数传递约定直接影响。

8.2.1 堆栈参数

有两种基本类型的子例程参数:寄存器参数和堆栈参数。Irvine32和Irvine16库使用寄存器参数,本节讲述如何声明和使用堆栈参数。

被调用的子例程访问调用子例程时亚茹堆栈的参数。使用寄存器参数可以优化程序的执行速度,但是遗憾的是,这样可能会造成代码的混乱,因为有些寄存器在装入参数之前必须首先保存。例如,调用DumpMem时就是这种情况:

Pushad

Mov esi,OFFSET array           ;起始偏移地址

Mov ecx,LENGTHOF array       ;大小

Mov ebx,TYPE array            ;双字格式

Call DumpMem                ;显示内存内容

Popad

另外一种更灵活的方式是堆栈参数,在调用子例程之前,参数首先压入堆栈。例如,假设DumpMem使用堆栈参数,那么可以使用下面的代码进行调用:

Push TYPE array

Push LENGTHOF array

Push PFFSET array

Call DumpMem

在进行子例程调用时在堆栈上压入了两类参数:

值参数(变量和常量的值)

引用参数(地址)

堆栈参数的访问(C/C++)

在调用函数时,C/C++程序使用标准的方法初始化和访问参数。C/C++中的函数以序言(prologue)开始,序言部分的代码保存了EBP寄存器,并使EBP指向当时堆栈的顶部,函数还有可能把一些寄存器压栈,这些寄存器的值将在函数返回的时候恢复。函数以收尾(epilogue)代码结束,在这部分代码中,EBP寄存器被恢复,RET指令从函数返回。

例子AddTwo

C:

Int AddTwo(int x ,int y){

Return x + y;

}

对应汇编:

AddTwo PROC

Push ebp

Mov ebp,esp          ;堆栈框架的基址

Mov eax,[ebp+12]     ;第二个参数

Mov eax,[ebp+8]      ;第一个参数

Pop  ebp

Ret

AddTwo ENDP

自己用vs2012看了下反汇编(DeBug模式)

调用部分:

函数部分

堆栈的清理

在子例程返回时,必须要有某种方法清除堆栈上的参数,否则就会导致内存泄漏以及堆栈的破坏。假设main中调用AddTwo的语句如下:

Push 5

Push 5

Call AddTwo

下面是从调用返回后堆栈的示意图:

如果没有清理,那么函数结束的时候就会从栈里拿出来一个地址,然后跳转过去。那么上面就直接跳转到存储5的地 址了,这样就发生问题了。

对于这个问题,一种简单的解决方法是在CALL指令后使用一条ADD指令给ESP加上一个值,以使ESP指向正确的返回地址:

Example1 PROC

Push  5

Push  6

Call  AddTwo

Add  esp,8

Ret

Example1 ENDP

这实际上也是C++使用的一种方法。

STDCALL调用约定(Calling Convention):处理堆栈清理问题的另一种方法是使用STDCALL调用约定,可以在AddTwo过程中的RET指令后提供一个整数参数以修复ESP的值,这个整数值必须等于堆栈参数小号的堆栈空间字节数。

大体是下面这样的姿势:

AddTwo PROC

Push  ebp

Mov  ebp,esp

Mov  eax,[ebp+12]

Add  eax,[ebp+8]

Pop ebp

Ret 8

AddTwo ENDP

这样一来,上面堆栈清理问题就简化了:谁应该对清理堆栈负责?是调用子例程的代码,还是子例程本身?这两种方式都有各自的优缺点:STDCALL减少了为子例程调用生成代码数量(只有一条指令)并且能够确保调用者永远不会忘记清理堆栈;另一方面,C调用约定允许子例程生命可变数目的参数,由调用者决定要传递多少参数。例子之一是printf函数,这种类型的,清理堆栈的职责职能留给调用者了。

通过堆栈传递8位和16位的参数

在保护模式下传递参数时,最好使用32位的操作数,虽然可以砸IDUI站上压入16位的操作数,但这样会似的ESP无法对其在双字地址边界上,由此可能会导致发生页故障,程序的性能也能会降低。因此在传递8位或16位对扎你参数时,应把它扩展到32位在压栈。

So需要把一些小宽度参数扩展成32位的:movzx eax,word1

那如果是大于32位的怎么办?:这个我们可以分开传递,先传32位,再传32位...

USER操作符对堆栈的影响

之前应该说过USER,它可以帮助保存和恢复一些寄存器的值。例如:

MySub1 PROC USES ecx ,edx

Ret

MySub1 ENDP

下面是汇编时产生的代码:

Push ecx

Push edx

Pop  edx

Pop  ecx

Ret

假设在MySub2中把USES和堆栈参数一起使用,我们预期第一个参数在堆栈位置EBP+8处:

MySub2 PROC USES ecx ,edx

Push ebp

Mov ebp,esp

Mov eax,[ebp+8]

Pop ebp

Ret 4

MySub2 ENDP

下面是生成的汇编代码

push ecx

Push edx

Push ebp

Mov ebp,esp

Mov eax,dword ptr[ebp+8]  ;错误的位置!

Pop ebp

Pop edx

Pop ecx

Ret 4

Intel汇编程序设计-高级过程(上)的更多相关文章

  1. Intel汇编程序设计-整数算术指令(上)

    第七章 整数算术指令 7.1 简介 每种汇编语言都有进行操作数移位的指令,移位和循环移位指令在控制硬件设备.加密数据,以及实现高速的图形操作时特别有用.本章讲述如何进行移位和循环移位操作以及如何使用移 ...

  2. Intel汇编程序设计-整数算术指令(中)

    7.3  移位和循环移位的应用 7.3.1  多双字移位 要对扩展精度整数(长整数)进行移位操作,可把它划分为字节数组.字数组或双字数组,然后再对该数组进行移位操作.在内存中存储数字时通常采用的方式是 ...

  3. Intel汇编程序设计-整数算术指令(下)

    7.5  扩展加法和减法 扩展精度的假发和减法是指任意尺寸大小数字的加法和减法.例如要求你写一个C++程序,把两个1024位的整数相加,解决方案可不是那么简单!但在汇编语言中,ADC(带进位加)指令和 ...

  4. Linux下AT&T汇编语法格式与Intel汇编语法格式异同

    由于绝大多数的国内程序员以前只接触过Intel格式的汇编语言,很少或几乎没有接触过AT&T汇编语言,虽然这些汇编代码都是Intel风格的.但在Unix和Linux系统中,更多采用的还是AT&a ...

  5. AT&T 和 Intel 汇编语法的主要区别

    转自AT&T 和 Intel 汇编语法的主要区别 作为一个爱折腾的大好青年,补番之余还要补一些 Linux 下的基础,比如 GDB 的正确使用方法.但无论是看 gdb 还是 gcc -S 里的 ...

  6. 《Intel汇编第5版》 Intel CPU小端序

    一.MASM汇编器中的数据类型 二.Intel汇编中的立即数类型 三.定义有符号和无符号整数 四.小端序 内存中数据按照字节存储,一个4个字节无符号整数,其高位存储在低地址上,低位存储在高地址上. 比 ...

  7. JVM(五):探究类加载过程-上

    JVM(五):探究类加载过程-上 本文我们来研究一个Java字节码文件(Class文件)是如何加载入内存中的,在這個过程中涉及类加载过程中的加载,验证,准备,解析(连接),初始化,使用,销毁过程,并探 ...

  8. ARM学习笔记11——GNU ARM汇编程序设计

    GNU ARM汇编程序设计中,每行的语法格式如下: [<label>:] [<instruction | directive | pseudo-instruction>] @c ...

  9. 《Intel汇编第5版》 汇编减法程序

    第一步: 安装虚拟机32位XP系统 + RadAsm软件 第二步:    下载<Intel汇编语言程序设计第5版>中相关的源代码以及库文件           http://kipirvi ...

随机推荐

  1. MyBatis(八):MyBatis插件机制详解

    MyBatis插件插件机制简介 ​ MyBatis插件其实就是为使用者提供的自行拓展拦截器,主要是为了可以更好的满足业务需要. ​ 在MyBatis中提供了四大核心组件对数据库进行处理,分别是Exec ...

  2. 微软跨平台UI框架MAUI真的要来啦

    .NET 6 preview已经上线,是时候为在BUILD 2020上宣布的新.NET Multi-platform App UI(MAUI)做准备了.对于客户端应用程序开发人员来说,这一年.NET有 ...

  3. dk.exe自动填报程序的反编译

    dk.exe自动填报程序的反编译 dk.exe用于学校每日健康报的自动填写.

  4. js 算数组平均值、最大值、最小值、偏差、标准差、中位数、数组从小打大排序、上四分位数、下四分位数

    要算的数组命名为data var sum = function(x,y){ return x+y;}; //求和函数 var square = function(x){ return x*x;}; / ...

  5. python 实现输出一个等腰三角形

    这个问题实际上是一个数学问题,我们主要找出每行的规律就可以根据规律来书写代码 """ 2 代码实现输出一个等腰三角形,实际上就是一个等差数列求各项的一个数学> 问题 ...

  6. 密码学系列之:csrf跨站点请求伪造

    目录 简介 CSRF的特点 CSRF的历史 CSRF攻击的限制 CSRF攻击的防范 STP技术 Cookie-to-header token Double Submit Cookie SameSite ...

  7. concurrentHashMap扩容相关方法详解

    上一个博客中说到了concurrentHashMap的put操作,在put操作之后如果添加了节点,我们首先会把全局的节点数+1,如果满足了扩容条件,我们则进行扩容 我们先从addCount方法说起 / ...

  8. 运维小姐姐说这篇Consul集群和ACL配置超给力(保姆级)

    前言 上一篇简单介绍了Consul,并使用开发模式(dev)进行流程演示,但在实际开发中需要考虑Consul的高可用和操作安全性,所以接着来聊聊集群和ACL的相关配置,涉及到的命令会在环境搭建过程中详 ...

  9. Shell:如何遍历包含空格的文本

    Blog:博客园 个人 翻译自Looping Through a File that Contains Spaces – Bash for Loop 处理包含空格或特殊字符的文件是每个使用Linux的 ...

  10. CSS3新增了哪些新特性

    一.是什么 css,即层叠样式表(Cascading Style Sheets)的简称,是一种标记语言,由浏览器解释执行用来使页面变得更为美观 css3是css的最新标准,是向后兼容的,CSS1/2的 ...