《汇编语言 基于x86处理器》前五章的小程序

时间:2023-03-09 02:15:54
《汇编语言 基于x86处理器》前五章的小程序

▶ 书中前五章的几个小程序,基本的运算操作,使用了作者的库 Irvine32 和 Irvine64(一开始以为作者网站过期了,各网站上找到的文件大小都不一样,最后发现是要搭* Orz,顺利下载)。注意编译前将相关的库文件放到 “项目属性 → 链接器 → 输入 → 附加依赖项” 中。

● 代码,整数数组求和

 .
.model flat,stdcall
.stack ExitProcess PROTO, dwExitCode: dword .data
array DWORD 10000h, 20000h, 30000h, 40000h, .code
main PROC
mov edi, OFFSET array ; 变址寄存器获得 array 首元素地址
mov ecx, LENGTH array ; 循环计数器获得 array 元素个数
mov eax, L1:
add eax, [edi] ; 将 array 每个元素加到 eax 中
add edi, TYPE array ; 递增变址寄存器
loop L1 ; 循环直到 ecx 减为 0 INVOKE ExitProcess,
main ENDP END main

● 代码,整数数组求和,64位版本

 ExitProcess PROTO

 .data
array QWORD 1000000000000h, 2000000000000h, 3000000000000h, 4000000000000h, .code
main PROC
mov rdi, OFFSET array ; 用到的寄存器都改成 64 位的版本
mov rcx, LENGTH array
mov rax, L1:
add rax, [rdi]
add rdi, TYPE array
loop L1 mov ecx, ; 还是使用 ecx 作为返回值
call ExitProcess
main ENDP END

● 代码,复制字符串

 .
.model flat,stdcall
.stack ExitProcess PROTO, dwExitCode: dword .data
source BYTE "Something to be copied 2333.",
target BYTE SIZEOF source DUP() .code
main PROC
mov esi, OFFSET source
mov ecx, LENGTH source L1:
mov al, source[esi]
mov target[esi], al
inc esi
loop L1 INVOKE ExitProcess,
main ENDP END main

● 涨姿势,代码中间有一个块段注释没有封口(直到代码结尾都是注释),报错信息是 END directive required at end of file。

● 代码,翻转字符串

 .
.model flat,stdcall
.stack ExitProcess PROTO, dwExitCode: dword .data
source BYTE "Something to be copied 2333.",
nameSize = ($ - source) - ; 使用常量来存储字符串的长度 .code
main PROC
mov esi,
mov ecx, LENGTH source L1:
movzx eax, source[esi] ; 获取字符,压栈,递增指针,循环
push eax
inc esi
loop L1 mov esi, ; 相同的赋值
mov ecx, LENGTH source
L2:
pop eax ; 吐栈,放入字符,递增指针,循环
mov source[esi], eax
inc esi
loop L2 INVOKE ExitProcess,
main ENDP END main

● 代码,使用子过程计算数组的和

 .
.model flat,stdcall
.stack
ExitProcess proto,dwExitCode:dword .data
array dword 10000h,20000h,30000h,40000h,50000h
sum dword ? .code
sumArray proc uses esi ecx ; 定义子过程,uses 在栈中备份 esi 和 ecx,并在 ret 前还原
;push esi ; 用栈备份用到的寄存器,与 uses 作用等效
;push ecx
mov eax, L1: ; 使用循环将和放入 eax 中
add eax, [esi]
add esi, type dword
loop L1 ;pop ecx ; 从栈中还原寄存器的状态
;pop esi
ret ; 从子过程中返回
sumArray endp main proc
mov esi, offset array
mov ecx, length array call sumArray
mov sum, eax invoke ExitProcess,
main endp end main

● 代码,库 Irvine32 测试 1,简单的输入输出。记得在 “属性,配置属性,链接器,输入” 中加上 Irvine32.lib,并在工作目录下添加 Irvine32.inc,Irvine32.lib,SmallWin.inc,VirtualKeys.inc。

 INCLUDE Irvine32.inc                    ; 包含库
.data
array DWORD 1000h,2000h,3000h
message BYTE "Enter a 32-bit signed integer: ",
dwordVal DWORD ? .code
main PROC
mov eax, yellow + (blue * )
call SetTextColor
call Clrscr ; 清屏为背景色
call DumpRegs ; 显示当亲寄存器状态 mov esi, OFFSET array ; 三个寄存器分别存储数组的信息
mov ecx, LENGTHOF array
mov ebx, TYPE array
call DumpMem ; 调用库函数,输出数组所有元素
call Crlf ; 换行 mov edx, OFFSET message
call WriteString ; 输出字符串
call ReadInt ; 输入整数
mov dwordVal, eax ; 输入的整数存储到 eax 中
call Crlf
call WriteInt ; 用十进制、十六进制、二进制输出 eax
call Crlf
call WriteHex
call Crlf
call WriteBin
call Crlf
call WaitMsg ; 显示 "Press any key to cintinue" 并等待 mov eax, lightGray + (black * ) ; 恢复终端颜色
call SetTextColor
call Clrscr
call WaitMsg exit
main ENDP
END main

● 输出结果

; 清屏为蓝色

  EAX=0000001E  EBX=  ECX=  EDX=
ESI= EDI= EBP=0075FE18 ESP=0075FE08
EIP= EFL= CF= SF= ZF= OF= AF= PF= Dump of offset
------------------------------- Enter a -bit signed integer: ; 输入 + Press any key to continue... ; 清屏恢复黑色 Press any key to continue...

● 代码,库 Irvine32 测试 2,随机数

 INCLUDE Irvine32.inc

 TAB =         ; ASCII code for Tab

 .code
main PROC
call Randomize ; 随机数种子
call Rand1 ; 无符号随机数
call Rand2 ; 有符号随机数
call WaitMsg
exit
main ENDP Rand1 PROC
mov ecx,
L1:
call Random32 ; 生成随机整数用于输出
call WriteDec
mov al, TAB ; 给一个水平制表符用于输出
call WriteChar
loop L1 call Crlf
ret
Rand1 ENDP Rand2 PROC
mov ecx, L1:
mov eax,
call RandomRange ; 生成给定范围内的随机数
sub eax,
call WriteInt
mov al,TAB
call WriteChar
loop L1 call Crlf
ret
Rand2 ENDP END main

● 代码,库 Irvine32 测试 3,计时器

 INCLUDE Irvine32.inc

 .data
OUTER_LOOP_COUNT =
startTime DWORD ?
msg1 BYTE "Start", 0dh, 0ah, ; 等价于 "Start\r\n\0"
msg2 BYTE "End", 0dh, 0ah, "Time(ms): ", .code
main PROC
mov edx, OFFSET msg1
call WriteString call GetMSeconds ; 计时器1
mov startTime, eax mov ecx, OUTER_LOOP_COUNT ; 外层循环
L1:
call innerLoop
loop L1 call GetMSeconds ; 计时器2
sub eax, startTime ; 直接在 eax 中计算耗时 mov edx, OFFSET msg2 ; 显示
call WriteString
call WriteDec
call Crlf call WaitMsg
exit
main ENDP innerLoop PROC uses ecx
mov ecx, 0FFFFFFFh ; 内层循环
L1:
mul eax ; 无符号乘法
mul eax
mul eax
loop L1 ret
innerLoop ENDP END main

● 代码,库 Irvine32 测试 4,对话框

 INCLUDE Irvine32.inc

 .data
caption db "Title",
HelloMsg BYTE "This is a pop-up message box.", 0dh, 0ah, .code
main PROC
mov ebx, OFFSET caption ; 标题,可以为 0
mov edx, OFFSET HelloMsg ; 对话框内容
call MsgBox mov ebx, OFFSET caption
mov edx, OFFSET HelloMsg
call MsgBoxAsk ; 返回值在 eax 中,6(yes) 或 7(no) call WaitMsg
exit
main ENDP END main

● 代码,库 Irvine32 测试 5,用不同编码输出编号为 1~255 的字符

 INCLUDE Irvine32.inc

 SetConsoleOutputCP PROTO, pageNum:DWORD

 .data
divider BYTE " - ",
codepage DWORD
; 1250 - Central Europe
; 1251 - Cyrillic
; 1252 - Latin I
; 1253 - Greek
; 1254 - Turkish
; 1255 - Hebrew
; 1256 - Arabic
; 1247 - Baltic
; 1258 - Vietnam
; 874 - Thai
; 437 - OEM United States
; 858 - OEM Multilingual Latin and European .code
main PROC
invoke SetConsoleOutputCP, codePage mov ecx,
mov eax,
mov edx, OFFSET divider
L1:
call WriteDec ; eax 作为计数器
call WriteString ; edx 指向字符串
call WriteChar ; al 为得到的字符
call Crlf
inc aL
Loop L1 call WaitMsg
exit
main ENDP END main

● 代码,库 Irvine64 测试 1,显示 20 个 64 位随机数

 ExitProcess PROTO           ; 手动声明需要用到的函数
WriteInt64 PROTO
Crlf PROTO
Random64 PROTO
RandomRange PROTO
Randomize PROTO .code
main proc
sub rsp, ; 栈指针对其到 16 Byte
sub rsp, 20h ; 影子空间 32 Byte call Randomize
mov rcx,
L1:
mov rax,
call RandomRange ; 返回的 64 位随机数在 eax 中
call WriteInt64
call Crlf
loop L1 add rsp, 28h ; 恢复 rsp 指针位置,main 中可以不用,子过程中需要
mov ecx,
call ExitProcess
main endp end

● 涨姿势,链接时把 irvine64.obj 加入项目中(添加现有项),然后报错 LNK2017 没有 /LARGEADDRESSAWARE:NO,“ADDR32”到“bufferLHB”的重定位无效 。改正:“属性,配置属性,连接器,系统,启用大地址” 选否(/LARGEADDRESSAWARE:NO),即可正确运行。

● 代码,库 Irvine64 测试 2,简单的输入输出

 ExitProcess     proto
ReadInt64 proto
ReadString proto
WriteString proto
WriteInt64 proto
WriteHex32 proto
WriteHex64 proto
Crlf proto .data
message BYTE "Test irvine64.lib",
maxval qword
minval qword -
inbuf BYTE dup(),
inbuf_size = $ - inbuf .code
main proc mov rdx,offset message
call WriteString
call Crlf call ReadInt64 ; 从键盘读取一个 64 位整数
call Crlf
call WriteInt64
call Crlf mov rdx,offset inbuf
call WriteString
call Crlf mov rax, minVal
call WriteInt64
call Crlf mov rax, maxVal
call WriteInt64
call Crlf mov ecx,
call ExitProcess
main endp end