Kip Irvine 汇编语言 基于x86处理器 Chapter08 代码(含习题)

本文通过一系列示例展示了汇编语言在函数调用、数组操作和递归计算方面的应用。包括使用寄存器传参、局部变量处理、数组填充、数组求和、递归计算整数和等。同时,还探讨了不同调用规范如stdcall和fastcall的使用,以及如何在汇编程序中实现递归和栈空间管理。

案例代码

01.使用寄存器传参调用DumpMem函数实例

include irvine32.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data

	array	DWORD	1,2,3,4,5,6,7,8,9	

.code
	main PROC

		push	ebx					;保存寄存器的值
		push	ecx
		push	esi
		mov		esi,offset array	;初始offset
		mov		ecx,lengthof array	;大小,按元素个数计
		mov		ebx,TYPE array		;双字格式
		call	DumpMem				;显示内存
		pop		esi					;恢复寄存器的值
		pop		ecx
		pop		ebx

		invoke ExitProcess,0
	main ENDP
END main

02.使用寄存器参数的缺点

include irvine32.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data

	array		DWORD	1,2,3,4,5,6,7,8,9	
	error_msg	BYTE	"Sometthing wrong happened!",0

.code
	main PROC

		push	ebx					;保存寄存器的值
		push	ecx
		push	esi

		mov		esi,offset array	;初始offset
		mov		ecx,lengthof array	;大小,按元素个数计
		mov		ebx,TYPE array		;双字格式
		call	DumpMem				;显示内存

		cmp		eax,1				;设置错误标志?
		je		error_exit			;设置标志后退出

		pop		esi					;恢复寄存器的值
		pop		ecx
		pop		ebx

		ret
	error_exit:
		mov		edx,offset error_msg
		call	WriteString			;显示错误消息
		ret

		invoke ExitProcess,0
	main ENDP
END main

03.两数之和

include irvine32.inc
.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data


.code
	main PROC
		
		call	Example1
		call	WriteInt
		call	WaitMsg
		invoke ExitProcess,0
	main ENDP

	Example1 PROC
		push 5
		push 6
		call AddTwo
		pop ebx			;这里单纯的只是想要将栈中的两个数值弹出
		pop	ebx			;暴露出返回地址
		ret
	Example1 ENDP

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

END main

04.两数之和 C调用规范

include irvine32.inc
.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data


.code
	main PROC
		
		call	Example1
		call	WriteInt
		call	WaitMsg
		invoke ExitProcess,0
	main ENDP

	Example1 PROC
		push 5
		push 6
		call AddTwo
		add	 esp,8			;这里使用了C调用规范,后面的数值是子程序参数所占用堆栈空间字节数的总和
		ret					;这里必须要跟上ret指令,否则会导致访问到其他位置的代码导致错误
	Example1 ENDP

	AddTwo PROC
		enter	0,0
		mov		eax,[ebp+12]
		add		eax,[ebp+8]	;[ebp+4]这块内存存储的是主调函数调用子函数的栈帧
		pop		ebp
		ret
	AddTwo ENDP

END main

05.两数之和 STDCALL调用规范

include irvine32.inc
.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data


.code
	main PROC
		
		mov		eax,10
		push	eax
		mov		eax,20
		push	eax
		call	AddTwo
		call	WriteInt
		call	WaitMsg
		invoke ExitProcess,0
	main ENDP


	AddTwo PROC
		push	ebp
		mov		ebp,esp
		mov		eax,[ebp+12]
		add		eax,[ebp+8]	;[ebp+4]这块内存存储的是主调函数调用子函数的栈帧
		pop		ebp
		ret		8			;使用STDCALL调用规范清除堆栈参数
							;这里的8指的是两个32位参数所占用的字节数一共8byte
	AddTwo ENDP

END main

06.局部变量的反汇编

#include<iostream>

using namespace std;

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

int main()
{
   
   
	//Do nothing!
	system("pause");
	return 0;
}

反汇编结果片段为(仅仅截取代码块内部的部分)

void MySub()
{
   
   
	00007FF65C091760  push        rbp  
	00007FF65C091762  push        rdi  
	00007FF65C091763  sub         rsp,128h  
	00007FF65C09176A  lea         rbp,[rsp+20h]  
	00007FF65C09176F  lea         rcx,[__3BCE52E7_06@局部变量的反汇编\源@cpp (07FF65C0A1029h)]  
	00007FF65C091776  call        __CheckForDebuggerJustMyCode (07FF65C091352h)  
		int X = 20;
	00007FF65C09177B  mov         dword ptr [X],14h  
		int Y = 10;
	00007FF65C091782  mov         dword ptr [Y],0Ah  
}

int main()
{
   
   
	00007FF65C091830  push        rbp  
	00007FF65C091832  push        rdi  
	00007FF65C091833  sub         rsp,0E8h  
	00007FF65C09183A  lea         rbp,[rsp+20h]  
	00007FF65C09183F  lea         rcx,[__3BCE52E7_06@局部变量的反汇编\源@cpp (07FF65C0A1029h)]  
	00007FF65C091846  call        __CheckForDebuggerJustMyCode (07FF65C091352h)  
		//Do nothing!
		system("pause");
	00007FF65C09184B  lea         rcx,[string "pause" (07FF65C099BB0h)]  
	00007FF65C091852  call        qword ptr [__imp_system (07FF65C0A02F8h)]  
		return 0;
	00007FF65C091858  xor         eax,eax  
}

07.局部变量符号的使用

include irvine32.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


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

.code
	main PROC
		mov		eax,10
		push	eax
		mov		eax,20
		push	eax

		call	MySub

		invoke ExitProcess,0
	main ENDP

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

END main

08.ArrayFill

include irvine32.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data

	count	=		100
	array	WORD	count DUP(0)

.code
	main PROC
		
		push	offset array
		push	COUNT
		call	ArrayFill

		mov		esi,offset array	
		mov		ecx,count
		mov		ebx,2
		call	DumpMem

		call	WaitMsg
		exit

		invoke ExitProcess,0
	main ENDP

	ArrayFill PROC
		push	ebp
		mov		ebp,esp
		pushad

		mov		esi,[ebp+12]	;数组的偏移量
		mov		ecx,[ebp+8]		;数组的长度
		cmp		ecx,0			;如果循环未结束
		jle		L2				;如果循环结束跳出
	L1:
		mov		eax,10000h
		call	RandomRange		;生成一个随机数存入eax
		mov		[esi],eax		;将随机数存入数组
		add		esi,TYPE word	;数组指针指向下一个元素位置
		loop	L1
	L2:
		popad					;程序结束 善后处理
		pop		ebp
		ret		8				;弹出栈中的两个参数,暴露出栈帧
		
	ArrayFill ENDP

END main

09.无限递归

include irvine32.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data

	endlessStr		BYTE	"This recursion never stop",0

.code
	main PROC

		call	Endless
		invoke ExitProcess,0
	main ENDP
	
	Endless PROC
		mov		edx,offset endlessStr
		call	WriteString
		call	Endless
		ret									;从不执行
	Endless ENDP

END main

10.递归求和

include irvine32.inc

.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data


.code
	main PROC
		
		mov		ecx,5	;计数值ecx=5
		mov		eax,0	;存放和数
		call	CalcSum	;计算和数
	L1:
		call	WriteDec;显示EAX
		call	Crlf	;换行
		call	WaitMsg
		
		invoke ExitProcess,0
	main ENDP

	;-----------------------
	CalcSum	PROC
	;计算整数列表的和数
	;接收:ECX=计数值
	;返回:EAX=和数
	;-----------------------
		cmp		ecx,0
		jz		L2
		add		eax,ecx
		dec		ecx
		call	CalcSum	
	L2:
		ret
	CalcSum	ENDP

END main

11.LEA

include irvine32.inc
.686p


.model flat,stdcall


.stack 4096


	ExitProcess PROTO,dwExitCode:DWORD


.data

.code
	main PROC
        
        call    makeArray   ;函数将所有的#号都存入栈中(重复30)

		invoke ExitProcess,0
	main ENDP

	makeArray PROC
        push    ebp
        mov     ebp,esp
        sub     esp,32
        lea     esi,[ebp-32];lea实现从间接操作数向寄存器的赋值以及间接寻址符号内地址计算操作,整体功能上相当于高级版本的mov
        mov     ecx,30
    L1: 
        mov     BYTE PTR [esi],'#'
        inc     esi
        loop    L1
        add     esp,32
        pop     ebp
        ret
    makeArray ENDP

END main

12.计算阶乘

include irvine32.inc
.686p
.model flat,stdcall
.stack 4096
	ExitProcess PROTO,dwExitCode:DWORD
.data
.code
	main PROC

		push	3			;计算5!
		call	Factorial	;计算阶乘(EAX)
		call	WriteDec	;显示结果
		call	Crlf
		exit

		invoke ExitProcess,0
	main ENDP

	;----------------------------
	Factorial	PROC
	;计算阶乘
	;接收:[ebp+8]=n,需计算的数
	;返回:eax=n的阶乘
	;----------------------------
		enter	0,0
		mov		eax,[ebp+8]	;获取n
		cmp		eax,0		;n>0?
		ja		L1			;是 继续
		mov		eax,1		;否 返回0!=1
		jmp		L2			;并且返回主调程序
	L1:
		dec		eax
		push	eax			;Factorial(n-1)
		call	Factorial
	;每次递归调用返回时
	;都需要执行下面的指令
	ReturnFact:
		mov		ebx,
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值