汇编语言学习笔记 下

举报
御麟 发表于 2023/03/13 14:29:48 2023/03/13
【摘要】 ​本文承接汇编语言学习笔记 上上篇文章记录了汇编语言寄存器,汇编语言基本组成部分,数据传送指令,寻址指令,加减法指令,堆栈,过程,条件处理,整数运算的内容​编辑高级过程大多数现代编程语言在调用子程序的时候会把参数压入对战子程序也常常把局部变量压入堆栈子程序在C和C++中被称为函数在Java中被称为方法在宏汇编程序(MASM)中被称为过程​编辑堆栈帧堆栈参数堆栈帧是一块堆栈保留区域存放被传递的...

本文承接汇编语言学习笔记 上

上篇文章记录了汇编语言寄存器,汇编语言基本组成部分,数据传送指令,寻址指令,加减法指令,堆栈,过程,条件处理,整数运算的内容

编辑


高级过程

大多数现代编程语言在调用子程序的时候会把参数压入对战

子程序也常常把局部变量压入堆栈

  • 子程序在C和C++中被称为函数
  • 在Java中被称为方法
  • 在宏汇编程序(MASM)中被称为过程

编辑

堆栈帧

堆栈参数

堆栈帧是一块堆栈保留区域

存放

  • 被传递的实际参数
  • 子程序的返回值
  • 局部变量
  • 被保存的寄存器

创建步骤

  1. 将被传递的实际参数压入堆栈
  2. 当子程序被调用时,该子程序的返回值压入堆栈
  3. 子程序开始执行的时候,EBP被压入堆栈
  4. 设置EBP等于ESP,EBP成为子程序所有参数的引用基址
  5. 如果有局部变量,修改ESP在堆栈中为其预留空间
  6. 需要保留的寄存器,将它们压入堆栈

Fastcall调用方式

顾名思义,是一种希望快速的调用方式

我们来分析一下这个调用方式: 

调用自过程的时候,需要首先将参数传入EAX,EBX,ECX,EDX,少数情况还会传入ESI,EDI

我们知道寄存器是CPU内部的原件,堆栈在内存上,寄存器调用明显更快

但是我们知道通用寄存器很少,很多都有特定的功能,乘法需要用到EAX,还有许多寄存器用来循环数值和参与计算的操作数

因此寄存器不可能一直存放传递给过程的参数

在过程调用之前, 存放参数的寄存器需要首先入栈,然后向其分配过程参数

但是这些额外的入栈操作会让代码变得混乱,还有可能消除性能优势

值传递

一个参数通过数值传递时,该值的副本会被压入堆栈

.data
val1 DWORD 3
val2 DWORD 6
.code
push val2
push val1
call AddTwo

引用传递

通过引用来传递的参数包含的是对象的地址

push OFFSET val2
push OFFSET val1

传递数组

将数组的地址压入堆栈 

不愿意采用将每个数组元素压入堆栈的原因是这样很慢而且浪费堆栈空间

访问堆栈的参数

1.将传递的参数压入堆栈,调用子过程

2.EBP寄存器存放的是原来栈帧的基址,我们需要现将EBP压入栈保存

3.然后将当前的ESP作为新的栈帧的基址

示例

int AddTwo(int x,int y)
{
    return x+y;
}

将EBP入栈,设置ebp位esp的值

AddTwo PROC
    push ebp
    mov ebp,esp


ADD(5,6)

6

[EBP+12]
5 [EBP+8]
返回地址 [EBP+4]
EBP mov ebp,esp

这样通过当前EBP和偏移量就能访问传入的参数和原来的ebp(返回地址)

显式的堆栈参数

堆栈参数的引用表达式形如[esp+8],称它们为显式的堆栈参数

清除堆栈

子程序返回时,必须将参数从堆栈中删除

否则会导致内存泄露,堆栈会被破坏

C调用方式-cdecl

用于C和C++语言

子程序的参数按逆序入栈

解决了运行时堆栈的问题

在调用子过程后,紧跟一条语句让堆栈指针ESP加上一个数,该数的值即为子程序参数所占的堆栈空间

main PROC
    push 6
    push 5
    call AddTwo
    add esp,8
    ret
main ENDP

能将参数从堆栈中删除

STDCALL调用规范

给RET指令添加了一个参数,使程序在返回调用过程的时候,ESP会加上这个参数

这个添加的整数和过程参数占用的堆栈空间字节数相等

AddTwo PROC
    push ebp
    mov ebp,esp
    mov eax,[ebp+12]
    add eax,[ebp+8]
    pop ebp
    ret 8
AddTwo ENDP

局部变量

在子过程中创建的变量

局部变量在ebp下

void Mysub()
{
    int X=10;
    int Y=20;
}

每个变量的存储大小都要向上取整保存为4的倍数

两个局部变量一共保留8个字节

MySub PROC
    push ebp
    mov ebp,esp
    sub esp,8
    mov DWORD PTR [ebp-4],10
    mov DWORD PTR [ebp-8],20
    mov esp,ebp
    pop ebp
    ret
MySub ENDP

从堆栈中删除局部变量,只需要执行:

mov esp,ebp

esp向上移动=内存释放

可以给局部变量的偏移量定义一个符号,在代码中使用这些符号

X_local EQU DWORD PTR [ebp-4]
Y_local EQU DWORD PTR [ebp-8]

MySub PROC
    push ebp
    mov ebp,esp
    sub esp,8
    mov X_local,10
    mov Y_local ,20
    mov esp,ebp
    pop ebp
    ret
MySub ENDP

保存和恢复寄存器

子程序在修改寄存器之前将它们的当前值保存到堆栈

通常在ebp入栈,设置ebp等于esp之后,相关寄存器入栈

栈帧
解释说明
传递的参数 [EBP+8]

返回地址

[EBP+4](原来栈帧的EBP)
EBP

当前栈帧的EBP

ECX
EDX 当前ESP指向的位置

EBP被初始化之后,整个过程中它的值将保持不变

ECX,EDX入栈并不影响EBP按照原来的偏移量访问传递的参数

引用参数

引用参数通常是基址-偏移量寻址方式进行访问

每个引用参数都是一个指针

.data
count=100
array WORD count DUP(?)

.code
push OFFSET array
push count
call ArrayFill
ArrayFill PROC
    push ebp
    mov ebp,esp
数组偏移量
数组长度

返回地址

EBP

LEA指令

返回间接操作数的地址

C代码:

void makeArray()
{
    char myString[30];
    for(int i=0;i<30;i++)
        myString[i]='*';
}

等效的汇编代码:

makeArray PROC
    push ebp
    mov ebp,esp
    sub esp,32                ;mystring位于EBP-30的位置
    lea esi,[ebp-30]          ;加载mystring的地址
    mov ecx,30                ;设置循环计数器
L1: mov BYTE PTR [esi],'*'    ;填充一个位置为'*'
    inc esi                   ;指向下一个元素
    loop L1                   ;循环30次,直到ecx是0
    add esp,32                ;恢复esp
    pop ebp
    ret
makeArray ENDP

ENTER指令

为被调用过程自动创建堆栈帧

包含三个操作

  • 把EBP入栈        push ebp
  • 把ebp设置为堆栈帧的基址        mov ebp,esp
  • 为局部变量保留空间          sub esp,numbytes

ENTER有两个操作数,一个是常数,是局部变量保存的堆栈空间(字节),第二个参数定义了过程的词法嵌套级

ENTER numbytes,nestinglevel

MySub PROC
    enter 0,0

等效于:

MySub PROC
    push ebp
    mov ebp,esp
MySub PROC
    enter 8,0

等效于:

MySub PROC
    push ebp
    mov ebp,esp
    sub esp,8

LEAVE指令

结束一个过程的堆栈帧,与ENTER是相对应的操作

直接上代码理解

MySub PROC
    enter 8,0
    .
    .
    leave
MySub ENDP

等效于:

MySub PROC
    push ebp
    mov ebp,esp
    sub esp,8
    .
    .
    mov esp,ebp
    pop ebp
    ret
MySub ENDP

前一篇文章汇编语言学习笔记 上

已将基本的汇编语言语法总结了一遍

暂时不更新

编辑


未完待续

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。