引用“http://blog.sina.com.cn/luckdonkey ”
全局变量保存在数据段中,即伪代码中声明的DATA SEGMENT,任何时刻都能调用:而局部变量则保存在栈段中,是伪代码中声明的STACK SEGMENT,平时不调用,调用中断时把局部变量从栈里取出来
局部变量: 不过局部变量是在你用到的时候进行初始化,占用内存空间
局部变量的作用域是单个子程序,在进入子程序的时候,通过修改栈指针esp来预留出需要的空间,在用ret指令返回主程序之前,同样通过恢复esp丢弃这些空间,这些变量就随之无效了.它的缺点是因为空间是临时分配的,所以无法定义含有初始化值的变量,对局部变量的初始化一般在子程序中同指令完成
定义格式:
local 变量名1[[重复次数]] [:类型], 变量名2[[重复次数]] [:类型]…
local伪指令必须紧接在子程序定义的伪指令proc后,其他指令开始前.
1: 可以有多个local语句.
2: 不能用类型缩写.
3: 定义结构体,可以用结构体的名称当做类型.
4: 定义dword类型的局部变量,类型可以省略
5: 定义数组时可以用[]括起来.
6: 不能使用定义全局变量的dup伪指令.
7: 不能和已经定义的全局变量重名.
8: 局部变量的起始值是随机的,所以局部变量的值一定要初始化
X64提供了两类新的寄存器:
- 8个通用寄存器:r8 – r15
- 8个128位的XMM寄存器:xmm8 – xmm15
另外,在x86架构下的寄存器则从32位扩展到了64位:rax, rbx, rcx, rdx, rsi, rdi, rbp, rsp 和 rip。它们的64位形式的名称前都一个“r”前缀。老的寄存器还可以使用,可存取位数小一些的数据,比如
Bits |
64 |
32 |
16 |
8 |
8 |
名称 |
rax |
eax |
ax |
ah |
Al |
新的寄存器可以这样使用:
Bits |
64 |
32 |
16 |
8 low |
名称 |
r8 |
r8d |
r8w |
r8b |
程序仍然可以用段寄存器来进行基本的地址处理,但在64位模式下只认3个寄存器,cs,fs和gs,只有fs和gs可以用来做基本的地址计算。
32位下的ex64调用约定
x64的调用约定也被称为x64 ABI(应用程序二进制接口),它描述调用者和函数间的接口:
- 分配参数的顺序
- 参数放置的位置(置于栈上还是置于寄存器中)
- 函数可使用哪些寄存器
- 返回时如何恢复堆栈
X64的调用约定跟x86的fastcall调用约定很相像,传参数给函数时,把寄存器和堆栈联合起来使用。
1.1 整数,指针和引用参数
- 所有寄存器中的参数都是右对齐的,这样被调用者就能按需要忽略寄存器的高位,按照需要存取寄存器的一部分。
- 所有栈上的参数都是8字节对齐。
- 所有的不是1,2,4和8字节的参数(包括结构)都通过引用传递。
- 8,16,32和64比特的结构和联合如果跟整数一样长时也可以传递。
前4个整数参数按照从左到右的顺序用rcx,rdx,r8,r9传递
剩下的参数用栈传递,压栈的顺序是从右到左(右边的参数在更低的位置)。
虽然这里不能详述,但是类的成员函数用汇编函数写出来,这时this指针让在rcx中传递。
1.2 浮点数(FP)参数
- 前4个浮点参数按照从左到右的顺序通过xmm0到xmm3传递
- 剩下的浮点参数按照从右到左的顺序压栈进行传递(越靠左的参数在栈上的地址越低)。
- x87的register stack.不能使用
1.3 返回值
- 整数,指针和引用类型通过rax传回。
- 浮点数用xmm0返回。
1.4 易变性和非易变性
- 函数中必须保留的:rbx, rbp, rdi, rsi, r12, r13, r14, r15, xmm6 - xmm15和 x87的 register stack.
- 函数中可以破坏使用的:rax, rcx, rdx, r8, r9, r10, and r11 和xmm0 - xmm5
3.5 栈
调用者必须至少保留32字节(4个64比特的值)的栈,这些空间可以让传进函数的寄存器很容易拷贝(泄露)到知名的栈位置去。函数不是必须要泄漏寄存器参数到栈上去,但是堆栈空间保留机制保障在需要的时候可以做到。
1.6 堆栈清理
调用者负责清理堆栈,一般情况是,函数需要足够多的栈空间,调用者保留足够的栈空间给函数,并调整栈空间的位置以满足它调用的所有函数。
ip寄存器在64位下变成了rip寄存器。