汇编笔记01

调用约定

调用约定 传参方式 平衡栈
cdecl(c语言调用约定) 从右向左 调用者平衡堆栈,add esp,xx方式平衡
stdcall(标准调用约定) 从右向左 被调用者平衡堆栈,ret xx方式平衡
fastcall(快速调用约定) 前两个参数使用ecx,edx传递,后续参数从右向左依次入栈 被调用者平衡,ret xx方式
thiscall(对象调用约定) 通过ecx保存this指针,参数从右向左依次入栈 被调用者平衡,ret xx方式

x64软件调用约定

三大结构

顺序结构

选择结构

  1. if … else if … else (c)
1
2
3
4
5
6
7
8
9
10
11
int nDay=0;
scanf("%d",&nDay);
if(nDay == 1){
printf("星期一");
}
else if(nDay == 2){
printf("星期二");
}
else if(nDay == 3){
printf("星期三");
}

汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
.386
.model flat,stdcall
option casemap:none

include msvcrt.inc
includelib msvcrt.lib

.const
pszD db "%d",00h

pszMon db "星期一",0dh,0ah,00h
pszTues db "星期二",0dh,0ah,00h
pszWed db "星期三",0dh,0ah,00h

.code
function proc
push ebp
mov ebp,esp

sub esp,4 ;为局部变量分配栈空间

lea eax,[ebp-4]
push eax
push offset pszD
call crt_scanf

cmp dword ptr [ebp-4],3
jg _ENDIF

cmp dword ptr [ebp-4],1
jne _IF_1

push offset pszMon
call crt_printf
add esp,4
jmp _ENDIF

_IF_1:
cmp dword ptr [ebp-4],2
jne _IF_2
push offset pszTues
call crt_printf
add esp,4
jmp _ENDIF

_IF_2:
cmp dword ptr [ebp-4],3
jne _ENDIF
push offset pszWed
call crt_printf
add esp,4
jmp _ENDIF


_ENDIF:
mov esp,ebp
pop ebp
ret
function endp

start:
call function
ret
end start
end

switch … case

1
2
3
4
5
6
7
8
int nDay=0;
scanf("%d", &nDay);

switch( nDay ){
case 1: printf("星期一");break;
case 2: printf("星期二");break;
case 3: printf("星期三");break;
}

汇编(跳转表)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
.386
.model flat,stdcall
option casemap:none

include msvcrt.inc
includelib msvcrt.lib

.const
pszD db "%d",00h

pszMon db "星期一",0dh,0ah,00h
pszTues db "星期二",0dh,0ah,00h
pszWed db "星期三",0dh,0ah,00h

.code
function proc
push ebp
mov ebp,esp

sub esp,4 ;为局部变量分配栈空间

lea eax,[ebp-4]
push eax
push offset pszD
call crt_scanf

cmp dword ptr [ebp-4],3
jg _ENDIF

mov eax,[ebp-4]
dec eax
jmp dword ptr [jmptab + eax * 4]

jmptab dd _IF_0,_IF_1,_IF_2 ;跳转表

_IF_0:
push offset pszMon
call crt_printf
add esp,4
jmp _ENDIF

_IF_1:
push offset pszTues
call crt_printf
add esp,4
jmp _ENDIF

_IF_2:
push offset pszWed
call crt_printf
add esp,4
jmp _ENDIF


_ENDIF:
mov esp,ebp
pop ebp
ret
function endp

start:
call function
ret
end start
end

img

循环结构

  1. while
1
2
3
4
5
int i=0;
while(i < 100){
printf("%d\n",i);
++i;
}

汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
.386
.model flat,stdcall
option casemap:none

include msvcrt.inc
includelib msvcrt.lib

.const
pszD db "%d",0dh,0ah,00h

.code
function proc
sub esp,4
mov [esp],dword ptr 0

_WHILE:
cmp dword ptr [esp],100
jge _ENDWHILE
push dword ptr [esp]
push offset pszD
call crt_printf
add esp,8
inc dword ptr [esp]
jmp _WHILE

_ENDWHILE:
add esp,4
ret
function endp

start:
call function
ret
end start
end
  1. do … while
1
2
3
4
5
int i=0;
do{
printf("%d\n", i);
++i;
}while(i < 100);

汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
.386
.model flat,stdcall
option casemap:none

include msvcrt.inc
includelib msvcrt.lib

.const
pszD db "%d",0dh,0ah,00h

.code
function proc
sub esp,4
mov [esp],dword ptr 0

_DOWHILE:
push dword ptr [esp]
push offset pszD
call crt_printf
add esp,8
inc dword ptr [esp]
cmp dword ptr [esp],100
jl _DOWHILE
ret
function endp

start:
call function
ret
end start
end
  1. for
1
2
3
for(int i=0 ; i<100 ; i++){
printf("%d\n", i);
}

for循环同while循环

函数栈帧

1
2
3
4
5
6
7
8
9
10
11
12
13
fun proc
push ebp
mov ebp,esp

...

mov esp,ebp
pop ebp
ret
fun endp

push ...
call fun

x64堆栈分配

img

内联汇编

32位

内联程序集不支持在 ARM 和 x64 处理器

1
2
3
4
5
6
int n=0;
__asm mov eax,100 //行内联
__asm { //块内联
mov eax, 100
mov[n], eax
}

混合编程

64位

内联 ASM 没有为 x64支持。

img

img

img

.cpp

1
2
3
4
5
6
7
8
#include <stdio.h>

extern "C" int asm_fun(int n1, int n2);
int main()
{
int n = asm_fun(1,2);
return 0;
}

.asm

1
2
3
4
5
6
7
.code
asm_fun proc
mov eax,ecx

ret
asm_fun endp
end

裸函数

对于使用 naked 特性声明的函数,编译器将生成编码,而无需 prolog 和 epilog 代码。 可以使用此功能来编写使用汇编程序代码的您自己的 prolog/epilog 代码顺序。 裸函数尤为用在编写虚拟设备驱动程序。请注意 naked 特性仅适用于 x86和ARM,并不用于 x64 。

备注

由于 naked 属性仅与函数定义相关且不是类型修饰符,因此裸函数必须使用扩展属性语法和 __declspec 关键字。

该编译器无法生成具有 naked 特性的内联函数,即使该函数也标有 __forceinline 关键字。

如果 naked 特性应用于任何非成员方法定义,该编译器会释放一个错误。

此代码用 naked 特性定义了函数:

1
__declspec( naked ) int func( formal_parameters ) {}

或者

1
2
#define Naked __declspec( naked )
Naked int func( formal_parameters ) {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void __declspec(naked) main()
{
// Naked functions must provide their own prolog...
__asm {
push ebp
mov ebp, esp
sub esp, __LOCAL_SIZE
}

// ... and epilog
__asm {
pop ebp
ret
}
}