Day3:函数与栈帧、数组与串指令、宏与结构体、x64汇编框架、内联汇编与混合编程
函数与栈帧、数组与串指令、宏与结构体、x64汇编框架、内联汇编与混合编程
函数与栈帧
“栈“是内存中的一部分,可以理解为连续的一块内存,它为程序运行提供了一个暂时的存放数据的地方,地址、数据等可以通过push指令从寄存器中被复制到栈中,进而寄存器可以进行其他操作,等到这些数据再次被需要时再从栈中被pop出来。栈遵循先进后出的规则,先push的在高地址,后push的在低地址
在程序运行时,每个函数都会拥有独立的栈帧,即独立的栈上的一部分空间。有两个寄存器,esp,ebp(x86即32位环境下)负责维护函数的栈空间。ebp存放的是函数栈空间的栈基址,esp存放的是函数栈空间的栈顶。可以理解为ebp是指向函数栈空间最高位的一个指针(因为栈空间从高地址开始分配,因此指向的是最高位,但是是栈空间的起始地址),而esp是指向函数栈空间最低位的一个指针(指向的是最低位,但是会随着后续栈空间的扩充而变化)。
CALL指令:
1
2
3;call一个函数的时候,会发生以下内容
push 返回地址(call所在指令的下一条)
jmp 目标函数地址RET指令:
1
2;函数结束时,RET指令会发生以下内容
pop eip ;从栈上弹出返回地址到eip(保存下一步指令地址的寄存器)栈帧:
1
2
3
4
5
6
7;跳转到每一个函数,会发生以下内容以开辟栈帧
push ebp ;把上一个函数的ebp值放到栈上
mov ebp,esp ;把esp值给ebp,开辟新函数的栈帧
;函数执行完毕后,会发生以下内容清理栈帧
mov esp,ebp ;把ebp值给esp,清理函数栈帧
pop ebp ;恢复ebp原来的值,即上一个函数的ebp
ret
数组与串指令
声明数组:
1
2
3.data ;在数据段声明
szHello db 'HelloWorld',0 ;声明一个字符串
nNumber dd 20 dup(0) ;声明一个DWORD数组,20位,使用dup()初始化数组内容为0使用数组基址的几种方式:
1
2lea eax,szHello
mov ebx,offset Nnumber访问数组成员:
1
2
3
4
5
6
7
8
9
10
11;[数组起始地址+索引寄存器*比例因子+偏移量](索引寄存器用来存放索引值,比例因子对应类型的字节大小,偏移量可用于结构体数组等场景)
;如:
mov ebx,offset Array ;把数组基址给ebx
mov esi,0 ;esi用来当索引寄存器
mov ecx,10 ;ecx用来放索引上限(ecx常用作计数器)
loop_start: ;创建一个循环
mov eax,[ebx+esi*4] ;取出数组内容放到eax中
add esi,1 ;索引递增
cmp esi,ecx ;与索引上限比较,判断是否遍历完数组
jl loop_start ;还没遍历完数组就循环操作,jump到loop_start再走一遍串指令:
1
2
3
4;stos系列:stosb,stosw,stosd,stosq(分别对应byte,word,dword,qword,功能是把al/ax/eax/rax中的内容存到edi/rdi)
;lods系列:lodsb,lodsw,lodsd,lodsq(同样分别对应四个类型,功能是把esi/rsi的内容加载到al/ax/eax/rax中)
;movs系列:movsb,movsw,movsd,movsq(同样分别对应四个类型,功能是把esi的内容复制到edi中)
;cmps系列:cmpsb,cmpsw,cmpsd,cmpsq(同样分别对应四个类型,功能是比较esi和edi的内容并设置标志位)
宏与结构体
宏:
1
2
3
4
5
6
7
8;无参宏使用关键字EQU,如
PI EQU 3 ;定义PI=3
;含参宏使用关键字MACRO,用endm结尾,如
Myadd MACRO Number
add eax,Number
endm ;定义Myadd函数实现eax加上参数
;含参宏的调用:
Myadd<参数>结构体:
1
2
3
4
5
6
7
8
9
10
11;使用关键字struct和ends,如
Point struct
x word ?
y word ?
Point ends
;实例化结构体
MyPoint Point<?> ;实例化出MyPoint
;访问结构体成员
mov MyPoint.x,123
x64汇编框架(MASM)
1 | |
内联汇编与混合编程
x86下,在Microsoft Visual C++ (MSVC)程序中使用汇编,可以通过_asm{}直接写在C++代码中:
1
2
3
4
5
6
7
8
9#include<iostream>
int main(){
_asm{
xor eax,eax
mov eax,1
add eax,1
}
return 0;
}x64下,在Microsoft Visual C++ (MSVC)程序中使用汇编,需要独立的asm文件,通过extern声明使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include<iostream>
extern "C" long long Add(long long number1,long long number2);
int main(){
long long res=Add(1,2);
std::cout<<res<<std::endl;
return 0;
}
//asm文件
.code
Add proc
push rbp
mov rbp,rsp
xor rax,rax
add rax,rcx
add rax,rdx
pop rbp
ret
Add endp
end
Day3:函数与栈帧、数组与串指令、宏与结构体、x64汇编框架、内联汇编与混合编程