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

Kip Irvine 汇编语言 基于x86处理器 Chapter08 代码(含习题)案例代码 01 使用寄存器传参调用 DumpMem 函数实例 include irvine32 inc 686 p model flat stdcall stack 4096 ExitProcess PROTO dwExitCode DWORD data array DWORD 1 2 3 4

大家好,我是讯享网,很高兴认识大家。

案例代码

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,[ebp+8] ;获取n mul ebx ;EDX:EAX=EAX*EBX L2: pop ebp ;返回EAX ret 4 ;清除堆栈 Factorial ENDP END main 

13.使用PROC伪指令的AddTwo

讯享网include irvine32.inc .386p .model flat,stdcall .stack 4096 ExitProcess PROTO,dwExitCode:DWORD AddTwo PROTO,val1:DWORD,val2:DWORD,val3:DWORD ;在调用之前要书写函数原型 .data val1 DWORD 1 val2 DWORD 2 val3 DWORD 3 .code main PROC invoke AddTwo, val1, val2, val3 call WriteInt call WaitMsg invoke ExitProcess,0 main ENDP ;------------------------------------------------------ ;功能:求解三个整数之和 ;参数:自定义32bit双字整数 ;返回:eax中包含三个整数之和 ;------------------------------------------------------ AddTwo PROC, ;函数头 PROC 的编译结果就已经包含了enter 00 value1:DWORD, ;形参列表 value2:DWORD, ;函数的形参列表的形参名称不可以和实际定义的变量名称重复 value3:DWORD ;函数体 mov eax,value1 add eax,value2 add eax,value3 ret ;这里不涉及stack的使用ret后面不加参数 AddTwo ENDP ;------------------------------------------------------ END main 

14.使用PROC伪指令的数组求和程序

include irvine32.inc .686p .stack 4096 ExitProcess PROTO,dwExitCode:DWORD ArraySum PROTO,ptrArray:PTR DWORD,szArray:DWORD .data array DWORD 10000h,20000h,30000h,40000h,50000h .code main PROC invoke ArraySum, ADDR array, ;传递数组地址 LENGTHOF array ;传递数组元素个数 call WriteInt ;输出结果是相当于十六进制下的A0000h invoke ExitProcess,0 main ENDP ;------------------------- ;ArraySum ;计算32位整数数组之和 ;------------------------- ArraySum PROC USES esi ecx, ;声明函数会使用esi ecx两个寄存器 ptrArray:ptr DWORD, ;声明接收指向数组的指针的参数 szArray : DWORD ;声明所要处理的数组的长度 mov esi,ptrArray ;数组地址 mov ecx,szArray ;数组大小 mov eax,0 ;和数清零 cmp ecx,0 ;数组长度=0? je L2 ;是 退出 L1: add eax,[esi] ;将每个整数累加到和数中 add esi,4 ;指向下一个整数 loop L1 ;按数组大小重复 L2: ret ;由于本程序不涉及栈所以不在ret后面加上参数 ArraySum ENDP END main 

15.两个整数的交换

讯享网;Swap过程实例 (Swap.asm) include irvine32.inc .686p .model flat,stdcall .stack 4096 ExitProcess PROTO,dwExitCode:DWORD Swap PROTO,pValX:PTR DWORD, pValY:PTR DWORD .data Array DWORD 10000h,20000h .code main PROC ;显示交换前的数组 mov esi,offset Array mov ecx,2 mov ebx,TYPE Array call DumpMem invoke Swap,ADDR Array,ADDR [Array+4];传递数组中前两个数字的地址 call DumpMem exit invoke ExitProcess,0 main ENDP ;------------------------------------- Swap PROC USES eax esi edi, pValX:PTR DWORD, ;第一个整数的指针 pValY:PTR DWORD ;第二个整数的指针 ;交换两个32位整数的值 ;返回值 无 ;------------------------------------- mov esi,pValX ;获得指针 mov edi,pValY mov eax,[esi] ;交换两个元素的值 xchg eax,[edi] mov [esi],eax ret Swap ENDP ;PROC在这里生成ret 8 END main 

16.使用含有EXTERNDEF的INCLUDE文件

vars.inc

;vars.inc EXTERNDEF count:DWORD ,SYM1:ABS ;ABS用于定义宏 

sub1.asm

讯享网;sub1.asm .386 .model flat,stdcall include vars.inc SYM1 = 10 .data count DWORD 0 END 

source.asm

include irvine32.inc include vars.inc .386p .model flat,stdcall .stack 4096 ExitProcess PROTO,dwExitCode:DWORD .data .code main PROC mov count,2000h mov eax,SYM1 invoke ExitProcess,0 main ENDP END main 

17.ArraySum程序

_prompt.asm

讯享网;提示整数输入请求 include irvine32.inc .code ;------------------------- PromptForIntegers PROC ;提示用户为数组输入整数,并用 ;用户输入填充该数组。 ;接收: ; ptrPrompt : PTR BYTE ;提示信息字符串指针 ; ptrArray : PTR DWORD ;数组指针 ; arraySize : DWORD ;数组大小 ;返回:无 ;------------------------- ;使用栈空间传递参数 arraySize EQU [ebp+16] ptrArray EQU [ebp+12] ptrPrompt EQU [ebp+8] enter 0,0 pushad ;保存全部寄存器 mov ecx,arraySize cmp ecx,0 ;数据大小<=0? jle L2 ;是:退出 mov edx,ptrPrompt ;提示信息的地址 mov esi,ptrArray L1: call WriteString ;显示字符串 call ReadInt ;将整数读入EAX call Crlf ;换行 mov [esi],eax ;保存入数组 add esi,4 ;下一个整数 loop L1 L2: popad ;恢复全部寄存器 leave ret 12 ;恢复堆栈 PromptForIntegers ENDP END 

_arraysum.asm


讯享网

;Array过程 (_arraysum) include irvine32.inc .code ;------------------------------------ ArraySum PROC ; ;计算32bit整数数组之和 ;接收: ; ptrArray ;数组指针 ; arraySize ;数组大小(DWORD) ;返回:EAX=和数 ;------------------------------------ ptrArray EQU [ebp+8] arraySize EQU [ebp+12] enter 0,0 push ecx ;EAX不入栈 push esi ;和数清零 mov eax,0 mov esi,ptrArray mov ecx,arraySize cmp ecx,0 ;数组大小<=0? jle L2 ;是:退出 L1: add eax,[esi] ;将每一个整数加到和数值中 add esi,4 ;指向数组中下一个整数 loop L1 ;按数组大小重复 L2: pop esi pop ecx ;使用寄存器返回和数 leave ret 8 ;恢复堆栈 ArraySum ENDP END 

_display.asm

讯享网;DisplaySum过程 (_display.asm) include irvine32.inc .code ;------------------------ DisplaySum PROC ;在控制台显示和数 ;接收: ; ptrPrompt ;提示字符串的偏移量 ; theSum :数组和数(DWORD) ;返回:无 ;------------------------ theSum EQU [ebp+12] ;这里使用加号是因为栈的增长方向是从高地址到底地址 ptrPrompt EQU [ebp+8] ;由于参数在调用函数之前就已经压入栈中,所以函数的 enter 0,0 ;栈帧位于参数的前面也就是地址相对低的地方,由于一 push eax ;个参数占用了四个字节,栈帧也占用四个字节,所以,第 push edx ;一个参数的位置在栈帧的相对高地址处,也就是使用ebp ;加上12 第二个参数位于相对地的地址处,也就是使用ebp ;加上8 mov edx,ptrPrompt ;提示字符串的指针 call WriteString mov eax,theSum call WriteInt ;显示EAX call Crlf pop edx pop eax leave ret 8 ;清除堆栈 DisplaySum ENDP END 

Sum_main.asm

;整数求和过程(Sum_main.asm) ;多模块实例 ;本程序由用户输入多个整数 ;将他们存入数组,计算数组之和 ;并显示和数。 include irvine32.inc ;引用外部函数 extern PromptForIntegers@0:PROC extern DisplaySum@0:PROC extern ArraySum@0:PROC ;为方便起见,重新定义外部符号 ArraySum EQU ArraySum@0 PromptForIntegers EQU PromptForIntegers@0 DisplaySum EQU DisplaySum@0 ;修改count来改变数组大小 Count = 3 .data prompt1 BYTE "Enter a signed integer:",0 prompt2 BYTE "The sum of the integer is:",0 array DWORD Count DUP(0) sum DWORD 0 .code main PROC call Clrscr ;PromptForIntegers(addr prompt1,addr array,Count) push Count push offset array push offset prompt1 call PromptForIntegers ;sum = ArraySum( addr array,Count ) push Count push offset array call ArraySum mov sum,eax ;DisplaySum(addr prompt2,sum) push sum push offset prompt2 call DisplaySum call Crlf exit main ENDP END main 

18.ArraySum程序,使用invoke与proto新建模块

_prompt.asm

讯享网;提示整数输入请求 (_prompt.asm) include sum.inc .code ;------------------------ PromptForIntegers PROC, ptrPrompt:PTR BYTE, ;提示字符串 ptrArray:PTR DWORD, ;数组指针 arraySize: DWORD ;数组大小 ; ;提示用户输入数组的元素值,并使用用户输入 ;填充数组 ;返回:无 ;------------------------ pushad ;保存所有的寄存器 mov ecx,arraySize cmp ecx,0 ;数组大小≤0? jle L2 ;:退出 mov edx,ptrPrompt ;提示信息的地址 mov esi,ptrArray L1: call WriteString ;显示字符串 call ReadInt ;把整数读入EAX call Crlf ;换行 mov [esi],eax ;将刚刚读入的整数保存到数组 add esi,4 ;在指向数组中下一个整数位置 loop L1 L2: popad ;恢复所有寄存器 ret PromptForIntegers ENDP END 

_arraysum.asm

;ArraySum过程 (_arraysum.asm) include sum.inc .code ;------------------------------- ArraySum PROC USES ecx esi, ptrArray:PTR DWORD, ;数组指针 arraySize: DWORD ;数组大小 ; ;计算32bit数组之和 ;返回EAX=和数 ;------------------------------- ;push ecx ;EAX不入栈 ;push esi mov eax,0 ;和数清零 mov esi,ptrArray mov ecx,arraySize cmp ecx,0 ;数组大小≤0? jle L2 ;是:退出 L1: add eax,[esi] ;把每一个整数加到和数中 add esi,4 ;指向下一个整数 loop L1 ;按数组大小重复 L2: ;pop esi ;用EAX返回和数 ;pop ecx ret ArraySum ENDP END 

_display.asm

讯享网;Display过程 (_display.asm) include sum.inc .code ;------------------------------------ DisplaySum PROC USES eax edx, ptrPrompt: PTR BYTE, ;提示字符串 theSum: DWORD ;数组之和 ; ;在控制台显示和数 ;返回:无 ;------------------------------------ ;push eax ;push edx mov edx,ptrPrompt ;提示信息的指针 call WriteString mov eax,theSum call WriteInt ;显示EAX call Crlf ;pop edx ;pop eax ret DisplaySum ENDP END 

Sum_main.asm

;正整数求和程序(Sum_main.asm) include sum.inc Count = 3 .data prompt1 BYTE "Enter a signed integer:",0 prompt2 BYTE "The sum of the integers is:",0 array DWORD Count DUP(0) sum DWORD 0 .code main PROC call Clrscr invoke PromptForIntegers,ADDR prompt1,ADDR array,Count invoke ArraySum,ADDR array,Count mov sum,eax invoke DisplaySum,ADDR prompt2,sum call Crlf exit main ENDP END main 

习题

8.10.02.01

讯享网include irvine32.inc .686p .model flat,stdcall .stack 4096 ExitProcess PROTO,dwExitCode:DWORD .data .code main PROC push 10 push 20 push 30 call AddThree call WriteInt call WaitMsg invoke ExitProcess,0 main ENDP AddThree PROC push ebp mov ebp,esp mov eax,0 add eax,[ebp+8] add eax,[ebp+12] add eax,[ebp+16] pop ebp ret 12 AddThree ENDP END main 

8.10.02.02

include irvine32.inc .386p .model flat,stdcall .stack 4096 ExitProcess PROTO,dwExitCode:DWORD AddTwo PROTO,val1:DWORD,val2:DWORD,val3:DWORD ;在调用之前要书写函数原型 .data val1 DWORD 1 val2 DWORD 2 val3 DWORD 3 .code main PROC invoke AddTwo, val1, val2, val3 call WriteInt call WaitMsg invoke ExitProcess,0 main ENDP ;------------------------------------------------------ ;功能:求解三个整数之和 ;参数:自定义32bit双字整数 ;返回:eax中包含三个整数之和 ;------------------------------------------------------ AddTwo PROC, ;函数头 PROC 的编译结果就已经包含了enter 00 value1:DWORD, ;形参列表 value2:DWORD, ;函数的形参列表的形参名称不可以和实际定义的变量名称重复 value3:DWORD ;函数体 mov eax,value1 add eax,value2 add eax,value3 ret ;这里不涉及stack的使用ret后面不加参数 AddTwo ENDP ;------------------------------------------------------ END main 

8.10.02.08

讯享网include irvine32.inc .686p .model flat,stdcall .stack 4096 ExitProcess PROTO,dwExitCode:DWORD SetColor PROTO,frontcolor:byte,backcolor:byte .data .code main PROC invoke SetColor,2,3 call WaitMsg call Clrscr invoke SetColor,1,0 call WaitMsg call Clrscr invoke SetColor,0,15 call WaitMsg call Clrscr invoke ExitProcess,0 main ENDP SetColor PROC uses eax, frontcolor:byte, backcolor:byte movzx eax,backcolor shl eax,4 add al,frontcolor call SetTextColor ret SetColor ENDP END main 

8.10.02.09

include irvine32.inc .686p .model flat,stdcall .stack 4096 ExitProcess PROTO,dwExitCode:DWORD SetColor PROTO,frontcolor:byte,backcolor:byte WriteColorChar PROTO,frontcolor:byte,backcolor:byte,singlechar:byte .data .code main PROC invoke WriteColorChar,2,14,'a' invoke ExitProcess,0 main ENDP SetColor PROC uses eax, frontcolor:byte, backcolor:byte movzx eax,backcolor shl eax,4 add al,frontcolor call SetTextColor ret SetColor ENDP WriteColorChar PROC, frontcolor:byte, backcolor:byte, singlechar:byte invoke SetColor,frontcolor,backcolor mov al,singlechar call WriteChar ret WriteColorChar ENDP END main 

8.10.02.10

讯享网 include irvine32.inc .686p .model flat,stdcall .stack 4096 ExitProcess PROTO,dwExitCode:DWORD DumpMemory PROTO,offsetOfArray:dword,lengthOfArray:dword,typeOfArray:dword .data arrayD DWORD 1,2,3,4,5,6,7,8,9,10,11,12 .code main PROC invoke DumpMemory,addr arrayD,lengthof arrayD,type arrayD invoke ExitProcess,0 main ENDP DumpMemory PROC uses esi ecx ebx, offsetOfArray:dword, lengthOfArray:dword, typeOfArray :dword mov esi,offsetOfArray mov ecx,lengthOfArray mov ebx,typeOfArray call DumpMem ret DumpMemory ENDP END main 

8.11.01

include irvine32.inc .686p .model flat,stdcall .stack 4096 ExitProcess PROTO,dwExitCode:DWORD FindLargest PROTO,aPtr:PTR SDWORD,arraySize:DWORD .data Ex1Array1 sdword 10,20,30,50,40,2 ; 50 Ex1Array2 sdword 10 ; 10 Ex1Array3 sdword 10,-20,30,50,40,-2,85 ; 85 .code main PROC invoke FindLargest,ADDR Ex1Array3,lengthof Ex1Array3 invoke ExitProcess,0 main ENDP FindLargest PROC USES esi ecx, aPtr:PTR SDWORD, arraySize:DWORD mov eax,h ;eax暂存最小值,用于后续的比较 mov ecx,arraySize mov esi,aPtr L1: cmp eax,[esi] jg L2 mov eax,[esi] L2: add esi,4 loop L1 call WriteInt ret FindLargest ENDP END main 

8.11.02

讯享网; Chapter 8, Exercise 2: Chess Board Comment ! Write a program that draws an 8 X 8 chess board, with alternating gray and white squares. You can use the SetTextColor and Gotoxy procedures from the Irvine32 library. Avoid the use of global variables, and use declared parameters in all procedures. Use short procedures that are focused on a single task. ! INCLUDE Irvine32.inc SetColor PROTO forecolor:BYTE, backcolor:BYTE WriteColorChar PROTO char:BYTE,forecolor:BYTE, backcolor:BYTE PrintRowOdd PROTO color:BYTE PrintRowEven PROTO color:BYTE .data rows = 8 columns = 8 horizCharsPerSquare = 2 .code main PROC call Crlf ; Display the board mov ecx,rows / horizCharsPerSquare L1: INVOKE PrintRowOdd, gray call Crlf INVOKE PrintRowEven, gray call Crlf loop L1 INVOKE SetColor, lightGray, black call Crlf exit main ENDP ; Print a single row PrintRowOdd PROC uses ecx, color:BYTE mov ecx,columns / 2 L1: INVOKE WriteColorChar, ' ', color,color INVOKE WriteColorChar, ' ', color,color INVOKE WriteColorChar, ' ', white, white INVOKE WriteColorChar, ' ', white, white loop L1 ret PrintRowOdd ENDP ; Print a single row PrintRowEven PROC uses ecx, color:BYTE mov ecx,columns / horizCharsPerSquare L1: INVOKE WriteColorChar, ' ', white, white INVOKE WriteColorChar, ' ', white, white INVOKE WriteColorChar, ' ', color, color INVOKE WriteColorChar, ' ', color, color loop L1 ret PrintRowEven ENDP SetColor PROC, forecolor:BYTE, backcolor:BYTE movzx eax,backcolor shl eax,4 add al,forecolor call SetTextColor ret SetColor ENDP WriteColorChar PROC USES eax, char:BYTE,forecolor:BYTE, backcolor:BYTE, INVOKE SetColor, forecolor, backcolor mov al,char call WriteChar ret WriteColorChar ENDP END main 

8.11.03

; Chapter 8, Exercise 3: Chess Board with Alternating Colors Comment ! *** YOU MAY HAVE TO TURN OFF REAL-TIME VIRUS SCANNING TO RUN THIS PROGRAM *** Write a program that draws an 8 X 8 chess board, with alternating colored and white squares. Each square is 2 characters wide and 1 character high. You can use the SetTextColor and Gotoxy procedures from the Irvine32 library. Optionally, you can use the WriteColorChar procedure created in the solution to Exercise 1. Added for Exercise 8-B: Every 500 milliseconds, change the color of the colored squares and redisplay the board. Continue until you have shown the board 16 times, using all possible 4-bit background colors. (The white squares remain white throughout.) ! INCLUDE Irvine32.inc Print_Board PROTO, color:BYTE SetColor PROTO forecolor:BYTE, backcolor:BYTE WriteColorBlock PROTO char:BYTE,forecolor:BYTE, backcolor:BYTE PrintRow PROTO color1:BYTE, color2:BYTE .data rows = 8 columns = 8 boardColor BYTE 0 .code main PROC mov ecx,16 ; loop through 16 colors L1: INVOKE Print_Board, boardColor mov eax,500 call Delay inc boardColor loop L1 ; return to the console's default color INVOKE SetColor, lightGray, black call Crlf exit main ENDP ; Display the complete board in the specified color. Print_Board PROC USES ecx edx,color:BYTE mov dh,0 mov dl,0 call Gotoxy mov ecx,rows / 2 L1: INVOKE PrintRow, color, white call Crlf INVOKE PrintRow, white, color call Crlf loop L1 ret Print_Board ENDP ; Print a single row with color1 followed by color2 in ; each pair of consecutive squares. PrintRow PROC uses ecx, color1:BYTE, color2:BYTE mov ecx,columns / 2 L1: INVOKE WriteColorBlock, ' ', color1,color1 INVOKE WriteColorBlock, ' ', color2,color2 loop L1 ret PrintRow ENDP ; Set the foreground and background colors SetColor PROC, forecolor:BYTE, backcolor:BYTE movzx eax,backcolor shl eax,4 add al,forecolor call SetTextColor ret SetColor ENDP ; Write a block of 2 side-by-side characters WriteColorBlock PROC USES eax, char:BYTE,forecolor:BYTE, backcolor:BYTE, INVOKE SetColor, forecolor, backcolor mov al,char call WriteChar call WriteChar ret WriteColorBlock ENDP END main 

8.11.04

讯享网; Chapter 8 Exercise 4: ThreeThrees Procedure COMMENT ! Create a procedure named FindThrees that returns 1 if an array has three consecutive values of 3 somewhere in the array. Otherwise, return 0. The procedure's input parameter list contains a pointer to the array and the array's size. Use the PROC directive with a parameter list when declaring the procedure. Preserve all registers (except EAX) that are modified by the procedure. Write a test program that calls FindThrees several times with different arrays. ! .386 .model flat,stdcall .stack 4096 ExitProcess proto,dwExitCode:dword FindThrees proto aPtr:PTR SDWORD, arraySize:DWORD .data Ex5Array1 sdword 4, 6, 3, 3, 2, 5 ; false Ex5Array2 sdword 3,3,3,9,5 ; true Ex5Array3 sdword 1,2,3,3,4,3,3,3,9 ; true Ex5Array4 sdword 1,2,4,-4,-5,9 ; false .code main proc invoke FindThrees, ADDR Ex5Array1, LENGTHOF Ex5Array1 invoke FindThrees, ADDR Ex5Array2, LENGTHOF Ex5Array2 invoke FindThrees, ADDR Ex5Array3, LENGTHOF Ex5Array3 invoke FindThrees, ADDR Ex5Array4, LENGTHOF Ex5Array4 invoke ExitProcess,0 main endp FindThrees proc, aPtr:PTR SDWORD, arraySize:DWORD push esi push ecx mov eax,0 ; initialize repetition count mov esi,aPtr mov ecx,arraySize L1: cmp sdword ptr [esi],3 jne L2 ; larger than max inc eax ; increment the count cmp eax,3 ; has it reached 3? je success ; return with success jmp L2A ; keep counting L2: mov eax,0 ; reset the count L2A: ; point to next array element add esi,4 loop L1 jmp L3 ; failure! success: mov eax,1 ; return True L3: pop ecx pop esi ret FindThrees endp end main 

8.11.05

; Chapter 8, Exercise 5: Different Inputs COMMENT ! Write a procedure named DifferentInputs that returns EAX = 1 if the values of its three input parameters are all different; otherwise, return with EAX = 0. Use the PROC directive with a parameter list when declaring the procedure. Create a PROTO declaration for your procedure, and call it five times from a test program that passes different inputs. ! .386 .model flat,stdcall .stack 4096 ExitProcess proto,dwExitCode:dword DifferentInputs proto v1:dword, v2:dword, v3:dword .data .code main proc invoke DifferentInputs,2,2,2 invoke ExitProcess,0 main endp DifferentInputs proc, v1:dword, v2:dword, v3:dword mov eax,1 mov v1,eax cmp v2,eax ; v1 = v2? je L2 cmp v3,eax ; v1 = v3? je L2 jmp exit ; return true L2: mov eax,0 ; return false exit: ret DifferentInputs endp end main 

8.11.06

讯享网; Chapter 8, Exercise 6: Exchanging Integers Comment ! Create an array of randomly ordered integers. Using the Swap procedure from Section 8.4.6 as a tool, write a loop that exchanges each consecutive pair of integers in the array. ! INCLUDE Irvine32.inc Swap PROTO, ; procedure prototype pValX:PTR DWORD, pValY:PTR DWORD DumpMemory PROTO, address:DWORD, units:DWORD, unitType:DWORD .data array DWORD 16 DUP(?) msgBefore BYTE "Array before the swap: ",0 msgAfter BYTE "Array after the swap: ",0 .code main PROC call Randomize ; seed the random number generator mov esi, OFFSET array mov ecx, LENGTHOF array ; counter L1: call Random32 ; EAX = random number mov [esi], eax ; save random number in array add esi, TYPE array ; next entry in array loop L1 ; Display the array before the exchange: mov edx, OFFSET msgBefore ; message to display call WriteString call Crlf INVOKE DumpMemory,OFFSET array,LENGTHOF array,TYPE array mov esi, OFFSET array mov ecx, LENGTHOF array ; number of elements in the array shr ecx, 1 ; divide counter by 2. (pair of elements) L2: INVOKE Swap, esi, ADDR [esi + 4] ; swap the pair add esi, TYPE array * 2 ; next pair loop L2 ; Display the array after the exchange: mov edx, OFFSET msgAfter ; message to display call WriteString call Crlf INVOKE DumpMemory, OFFSET array, LENGTHOF array, TYPE array exit main ENDP ;------------------------------------------------------- Swap PROC USES eax esi edi, pValX:PTR DWORD, ; pointer to first integer pValY:PTR DWORD ; pointer to second integer ; ; Exchange the values of two 32-bit integers ; Receives: nothing ; Returns: nothing ;------------------------------------------------------- mov esi,pValX ; get pointers mov edi,pValY mov eax,[esi] ; get first integer xchg eax,[edi] ; exchange with second mov [esi],eax ; replace first integer ret Swap ENDP ;------------------------------------------------------- DumpMemory PROC USES esi ebx ecx, address:DWORD, ; starting address units:DWORD, ; number of units unitType:DWORD ; unit size ; ; Wrapper procedure for the link library's DumpMem procedure ; Receives: nothing ; Returns: nothing ;------------------------------------------------------- mov esi, address mov ecx, units mov ebx, unitType call DumpMem ret DumpMemory ENDP END main 

8.11.07

; Chapter 8, Exercise 7: Greatest Common Divisor Comment ! Write a recursive implementation of Euclid抯 algorithm for finding the greatest common divisor (GCD) of two integers. Descriptions of this algorithm are available in algebra books and on the Web. Write a test program that calls your GCD procedure five times, using the following pairs of integers: (5,20), (24,18), (11,7), (432,226), (26,13). After each procedure call, display the GCD. ! INCLUDE Irvine32.inc CalcGcd PROTO,int1:DWORD, int2:DWORD .data array SDWORD 5,20,24,18,11,7,438,226,26,13 str1 BYTE "Greatest common divisor is: ",0 .code main PROC mov ecx,LENGTHOF array / 2 mov esi,OFFSET array L1: INVOKE CalcGcd,[esi],[esi+4] mov edx,OFFSET str1 call WriteString call WriteDec call Crlf add esi,TYPE array * 2 loop L1 exit main ENDP ;--------------------------------------------- CalcGcd PROC, int1:DWORD, int2:DWORD ; ; Calculate the greatest common divisor, of two ; nonnegative integers, using Euclid's algrithm. ; Implemented using recursion. ; Receives: int1, int2 ; Returns: EAX = Greatest common divisor ;--------------------------------------------- mov eax,int1 mov ebx,int2 mov edx,0 ; clear high dividend div ebx ; divide int1 by int2 cmp edx,0 ; remainder = 0? je L2 ; yes: quit INVOKE CalcGcd,ebx,edx ; recursive call L2: mov eax,ebx ; EAX = GCD ret CalcGcd ENDP END main 

8.11.08

讯享网; Chapter 8, Exercise 8: Counting Matching Elements COMMENT ! Write a procedure named CountMatches that receives points to two arrays of signed doublewords, and a third parameter that indicates the length of the two arrays. For each element xi in the first array, if the corresponding yi in the second array is equal, increment a counter. At the end, return a count of the number of matching array elements in EAX. Write a test program that calls CountMatches and passes pointers to two different pairs of arrays. Use the INVOKE statement to call CountMatches and pass stack parameters and create a PROTO statement for CountMatches. Save and restore any registers (other than EAX) changed by your procedure. ! .386 .model flat,stdcall .stack 4096 ExitProcess proto, dwExitCode:dword CountMatches proto, ptr1:PTR SDWORD,ptr2:PTR SDWORD, arraySize:DWORD .data array1 sdword 10,5,4,-6,2 array2 sdword 10,5,3,-6,2 ; 4 matches array3 sdword 4,1,2,8,9 ; 0 matches count = LENGTHOF array1 .code main proc invoke CountMatches,ADDR array1, ADDR array2, count invoke CountMatches,ADDR array1, ADDR array3, count invoke ExitProcess,0 main endp CountMatches proc, ptr1:PTR SDWORD, ptr2:PTR SDWORD, arraySize:DWORD push esi push edi push ecx push edx mov esi,ptr1 mov edi,ptr2 mov ecx,arraySize mov eax,0 ; counts the matches L1: mov edx,[esi] cmp edx,[edi] jne L2 ; not equal? skip to L2 inc eax ; increment the count L2: add esi,4 add edi,4 loop L1 pop edx pop ecx pop edi pop esi ret ; return the count in EAX CountMatches endp end main 

8.11.09

; Chapter 8, Exercise 9: Counting Nearly Matching Elements COMMENT ! Write a procedure named CountNearMatches that receives points to two arrays of signed doublewords, a third parameter that indicates the length of the two arrays, and a fourth parameter that indicates the maximum difference (called diff) allowed between matching elements. For each element x[i] in the first array, if the difference between it and the corresponding y[i] in the second array is less than or equal to diff, increment a counter. At the end, return a count of the number of matching array elements in EAX. Write a test program that calls CountMatches and passes pointers to two different pairs of arrays. Use the INVOKE statement to call CountMatches and pass stack parameters and create a PROTO statement for CountMatches. Save and restore any registers (other than EAX) changed by your procedure. ! .386 .model flat,stdcall .stack 4096 ExitProcess proto, dwExitCode:dword CountMatches proto, ptr1:PTR SDWORD,ptr2:PTR SDWORD, arraySize:DWORD, diff:DWORD .data array1 sdword 10,5,4,-6,2 array2 sdword 12,3,5,-6,1 ; 5 matches when diff = 2 array3 sdword 13,2,-4,-8,20 ; 1 match (-6 to -8) when diff = 2 count = LENGTHOF array1 .code main proc invoke CountMatches,ADDR array1, ADDR array2, count, 2 ; last parameter is DIFF invoke CountMatches,ADDR array1, ADDR array3, count, 2 ; last parameter is DIFF invoke ExitProcess,0 main endp CountMatches proc, ptr1:PTR SDWORD, ptr2:PTR SDWORD, arraySize:DWORD, diff:DWORD push esi push edi push ecx push edx mov esi,ptr1 mov edi,ptr2 mov ecx,arraySize mov eax,0 ; counts the matches L1: mov edx,[esi] sub edx,[edi] jns L1A ; is the difference negative? neg edx ; if so, make it positive L1A: cmp edx,diff ja L2 ; difference too large? skip to L2 inc eax ; else increment the count L2: add esi,4 add edi,4 loop L1 pop edx pop ecx pop edi pop esi ret ; return the count in EAX CountMatches endp end main 

8.11.10

讯享网; Chapter 8, Exercise 8: Show Procedure Parameters Comment ! Write a procedure named ShowParams that displays the address and hexadecimal value of the 32-bit parameters on the runtime stack of the procedure that called it. Input to the procedure will be a single integer that indicates the number of parameters to display. ! INCLUDE Irvine32.inc .data str1 BYTE "Address ",0 str2 BYTE " = ",0 str3 BYTE "Stack Parameters:",0dh,0ah BYTE "---------------------------",0dh,0ah,0 MySample PROTO first:DWORD, second:DWORD, third:DWORD ShowParams PROTO numParams:DWORD .code main PROC INVOKE MySample,1234h,5000h,6543h exit main ENDP ;--------------------------------------------- ; MySample PROC, first:DWORD, second:DWORD, third:DWORD paramCount = 3 INVOKE ShowParams, paramCount ; the output shows how the parameters are pushed ; on the stack in reverse order. ret MySample ENDP ;---------------------------------------------------- ShowParams PROC, numParams:DWORD ; ; Displays the parameter values of the calling procedure. ; Receives: paramCount, indicating the number of parameters. ; Returns: nothing ; The stack depth is calculated from: (1) ShowParams ret address, ; (2) numParams, (3) EBP, (4) ; ;---------------------------------------------------- STACK_DEPTH = 5 * TYPE DWORD mov edx,offset str3 ; show heading call WriteString mov ecx,numParams mov esi,esp add esi,20 ; find the parameters L1: mov edx,offset str1 ; " Address " call WriteString mov eax,esi ; get the address call WriteHex mov edx,offset str2 ; " = " call WriteString mov eax,[esi] ; get the parameter value call WriteHex ; display it call Crlf add esi,4 ; next parameter loop L1 ret ShowParams ENDP END main 
小讯
上一篇 2025-02-08 19:09
下一篇 2025-03-24 12:17

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/63720.html