汇编宏编程与Win32函数应用解析

table {
border-collapse: collapse;
width: 100%;
margin-bottom: 1rem;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
pre {
background-color: #f8f8f8;
padding: 15px;
border-radius: 4px;
overflow-x: auto;
}

142、编写一个名为 mPrintChar 的宏,用于在屏幕上显示单个字符。它应该有两个参数:第一个参数指定要显示的字符,第二个参数指定该字符应重复显示的次数。假设存在一个函数 WriteChar 用于在控制台显示单个字符,以下是一个示例调用:mPrintChar ‘X’,20

以下是实现

mPrintChar

宏的代码:


mPrintChar MACRO char, count
    push ecx
    mov  ecx, count
L1:
    push eax
    mov  al, char
    call WriteChar
    pop  eax
    loop L1
    pop  ecx
ENDM

该宏通过循环,根据传入的重复次数,多次调用

WriteChar

函数来显示指定字符。

143、给出调用 mWriteString 宏的语句 mWriteStr namePrompt 所生成的展开代码


push edx
mov edx, OFFSET namePrompt
call WriteString
pop edx

144、在使用标签的宏中会用到 LOCAL 指令。a. 编写一个使用该指令的宏。b. 使用这个宏,说明如果不使用该指令会出现的问题。

a. 以下是一个使用

LOCAL

指令的宏示例:


makeString MACRO text
    LOCAL string
.data
string BYTE text,0
ENDM

b. 如果不使用

LOCAL

指令,当多次调用宏时,汇编器不允许两个标签有相同的名称,会导致错误。例如:


makeString "Hello"
.data
string BYTE "Hello",0

makeString "Goodbye"
.data
string BYTE "Goodbye",0

这里会出现错误,因为两次使用了相同的标签名

string

。而使用

LOCAL

指令后,预处理器会将标签名转换为唯一标识符,如第一次调用宏生成的标签可能是

??0000

,第二次是

??0001

,避免了标签重定义问题。

145、给出一个宏参数具有默认参数初始化器的示例。

例如,

mWriteln

宏可以提供一个包含单个空格的字符串作为其默认参数。其定义如下:


mWriteln MACRO text:=<" ">
    mWrite text
    call Crlf
ENDM

如果调用时没有参数,它仍会打印一个空格并换行。

146、编写一个使用IF、ELSE和ENDIF指令的简短示例。

示例代码如下:


.data
X  DWORD 0
op1 DWORD 2 ; test data
op2 DWORD 4 ; test data
op3 DWORD 5 ; test data
.code
mov eax,op1
mov ebx,op2
mov ecx,op3
.WHILE eax < ebx
  inc eax 
  .IF eax == ecx
    mov X,2 
  .ELSE
    mov X,3 
  .ENDIF
.ENDW

147、假设以下 mLocate 宏定义:mLocate MACRO xval,yval IF xval LT 0 ;; xval < 0? EXITM ;; if so, exit ENDIF IF yval LT 0 ;; yval < 0? EXITM ;; if so, exit ENDIF mov bx,0 ;; video page 0 mov ah,2 ;; locate cursor mov dh,yval mov dl,xval int 10h ;; call the BIOS ENDM 显示以下每条语句展开宏时预处理器生成的源代码:.data row BYTE 15 col BYTE 60.code mLocate -2,20 mLocate 10,20 mLocate col,row

对于

mLocate -2,20

:无代码生成,因为

xval = -2 < 0

,宏执行

EXITM

退出。

对于

mLocate 10,20



asm
mov bx,0
mov ah,2
mov dh,20
mov dl,10
int 10h

对于

mLocate col,row



asm
mov bx,0
mov ah,2
mov dh,row
mov dl,col
int 10h

148、创建一个宏,该宏等待用户按键并返回按下的键。该宏应包含用于存储 ASCII 码和键盘扫描码的参数。编写一个程序来测试你的宏。例如,以下代码等待按键;返回时,两个参数将包含 ASCII 码和扫描码:.data ascii BYTE? scan BYTE?.code mReadkey ascii, scan

下面是实现该功能的宏及测试程序代码:


; mReadkey 宏定义
mReadkey MACRO ascii, scan
    call ReadChar
    mov ascii, al
    mov scan, ah
ENDM

; 测试程序
INCLUDE Irvine32.inc
.data
ascii BYTE ?
scan  BYTE ?
.code
main PROC
    mReadkey ascii, scan ; 这里可以添加代码来验证 ascii 和 scan 的值,例如显示它们
    exit
main ENDP
END main

上述代码定义了

mReadkey

宏,它调用

ReadChar

函数获取按键信息,并将 ASCII 码和扫描码分别存储到传入的参数中。测试程序调用该宏并等待按键,之后可以添加代码来验证存储的值。

149、创建一个宏,该宏将一个以空字符结尾的字符串以给定的文本颜色写入控制台。宏参数应包括字符串名称和颜色。调用一个能设置文本颜色的函数(假设为 SetTextColor)。编写一个程序,使用不同颜色的多个字符串来测试你的宏。示例调用:.data myString db “Here is my string”,0.code mWritestring myString, white

以下是实现该功能的代码示例:


.data
myString1 db "String in red",0
myString2 db "String in blue",0
red EQU 4
blue EQU 1

.code
mWritestring MACRO str, color
    pushad
    mov eax, color
    call SetTextColor
    mov edx, OFFSET str
    call WriteString
    popad
ENDM

main PROC
    mWritestring myString1, red
    mWritestring myString2, blue
    INVOKE ExitProcess,0
main ENDP

END main

上述代码定义了一个名为

mWritestring

的宏,它接受一个字符串和颜色作为参数,通过调用

SetTextColor

设置颜色,然后使用

WriteString

输出字符串。在主程序中,调用该宏两次,分别输出不同颜色的字符串。

150、编写一个名为 mMove32 的宏,该宏接收两个 32 位内存操作数。宏应将源操作数移动到目标操作数。编写一个程序来测试你的宏。

以下是实现

mMove32

宏及测试程序的代码示例(使用 MASM 语法):


; 定义 mMove32 宏
mMove32 MACRO source, destination
    MOV EAX, source
    MOV destination, EAX
ENDM

; 测试程序
.MODEL SMALL
.STACK 100H
.DATA
    sourceOperand     DWORD 12345678h
    destinationOperand DWORD ?
.CODE
MAIN PROC
    MOV AX, @DATA
    MOV DS, AX

    ; 调用 mMove32 宏
    mMove32 sourceOperand, destinationOperand

    ; 程序结束
    MOV AH, 4CH
    INT 21H
MAIN ENDP

END MAIN

上述代码定义了

mMove32

宏,它将源操作数移动到目标操作数。测试程序中,我们定义了一个源操作数和一个目标操作数,然后调用

mMove32

宏进行数据移动。最后程序正常结束。

151、创建一个宏,该宏等待按键输入并返回按下的键。宏应包含用于存储 ASCII 码和键盘扫描码的参数。编写一个程序来测试你的宏。例如,以下代码等待按键输入;返回时,两个参数将包含 ASCII 码和扫描码:.data ascii BYTE ? scan BYTE ? .code mReadkey ascii, scan

以下是实现该功能的代码:


; mReadkey 宏定义
mReadkey MACRO ascii, scan
    call ReadChar
    mov ascii, al
    mov scan, ah
ENDM

; 测试程序
INCLUDE Irvine32.inc

.data
ascii BYTE ?
scan  BYTE ?

.code
main PROC
    mReadkey ascii, scan ; 可以在这里添加代码来验证 ascii 和 scan 的值
    exit
main ENDP
END main

上述代码定义了

mReadkey

宏,它调用

ReadChar

函数获取按键的 ASCII 码和扫描码,并将其分别存储到传入的参数中。然后编写了一个简单的测试程序来调用这个宏。

152、创建一个宏,该宏能将一个以空字符结尾的字符串以指定的文本颜色写入控制台。宏的参数应包括字符串名称和颜色。编写一个程序,用不同颜色的多个字符串来测试你的宏。示例调用:.data myString db “Here is my string”,0 .code mWritestring myString, white

以下是实现该功能的代码示例:


INCLUDE Irvine32.inc

; 定义mWritestringAttr宏
mWritestringAttr MACRO stringName, color
    push eax
    push edx
    mov eax, color
    call SetTextColor
    mov edx, OFFSET stringName
    call WriteString
    pop edx
    pop eax
ENDM

.data
myString1 db "This is a red string",0
myString2 db "This is a green string",0
myString3 db "This is a blue string",0

.code
main PROC
    ; 测试mWritestringAttr宏
    mWritestringAttr myString1, red
    call Crlf
    mWritestringAttr myString2, green
    call Crlf
    mWritestringAttr myString3, blue
    call Crlf
    INVOKE ExitProcess,0
main ENDP

END main

上述代码定义了

mWritestringAttr

宏,它接受字符串名称和颜色作为参数。在宏内部,先调用

SetTextColor

设置文本颜色,然后调用

WriteString

输出字符串。主程序中使用不同颜色的字符串对宏进行了测试。

153、编写一个名为 mMove32 的宏,该宏接收两个 32 位内存操作数。宏应将源操作数移动到目标操作数。编写一个程序来测试你的宏。

以下是 mMove32 宏的实现和测试程序示例(使用 MASM 语法):


; 定义 mMove32 宏
mMove32 MACRO dest, src
    mov eax, src
    mov dest, eax
ENDM

; 测试程序
.MODEL SMALL
.STACK 100H
.DATA
source      DWORD 12345678h
destination DWORD ?

.CODE
MAIN PROC
    MOV AX, @DATA
    MOV DS, AX

    ; 调用 mMove32 宏
    mMove32 destination, source

    ; 退出程序
    MOV AH, 4CH
    INT 21H
MAIN ENDP

END MAIN

上述代码中,定义了 mMove32 宏,它将源操作数的值移动到目标操作数。测试程序创建了一个源操作数和一个目标操作数,调用宏进行数据移动,最后退出程序。

154、模拟一个人在校园里进行随机游走的过程,要求程序在随机的某个时间点,将手机丢在这个人当时所在的位置,且每次运行程序时,手机丢失的时间点和位置都不同。

此为编程任务描述,需编写程序模拟人随机游走过程,在随机时间点让人丢失手机,每次运行程序手机丢失时间和位置不同。

155、哪个Win32函数返回标准输入的句柄?


`GetStdHandle` 函数返回标准输入、输出或错误输出的控制台流句柄。当 `nStdHandle` 参数为 `STD_INPUT_HANDLE` 时,可返回标准输入的句柄。

156、哪个Win32函数可以从键盘读取一串文本并将其放入缓冲区?

ReadConsole

157、描述COORD结构。


COORD结构定义于Windows API中,用于标识屏幕的X和Y坐标。该结构包含两个字段:X和Y,均为WORD类型。字段X相对于结构起始位置的偏移量为0,字段Y的偏移量为2。其定义如下:

```text
COORD STRUCT
    X   WORD ?   ; offset 00
    Y   WORD ?   ; offset 02
COORD ENDS

158、哪个Win32函数可以更改控制台窗口的标题?

SetConsoleTitle函数可以更改控制台窗口的标题。

159、哪个Win32函数可以让你改变屏幕缓冲区的尺寸?

SetConsoleScreenBufferSize函数可以设置屏幕缓冲区的大小为X列Y行。

160、哪个Win32函数可以让你更改后续文本输出的颜色?

SetConsoleTextAttribute

函数可以更改后续文本输出到控制台窗口的前景色和背景色。

161、哪个Win32函数可以将属性值数组复制到控制台屏幕缓冲区的连续单元格中?

WriteConsoleOutputAttribute函数

162、哪个Win32函数可以让程序暂停指定的毫秒数?

Win32的Sleep函数可以让程序暂停指定的毫秒数。

163、列举两个调用 MessageBox 函数时可以使用的按钮常量。

MB_RETRYCANCEL、MB_ABORTRETRYIGNORE

164、列举两个调用MessageBox函数时可以使用的图标常量。

MB_ICONSTOP、MB_ICONQUESTION

165、列举WinMain(启动)过程执行的至少三项任务。

显示并更新主窗口;

开始一个接收和分发消息的循环,该循环持续到用户关闭应用程序窗口;

调用

GetMessage

从程序的消息队列中检索下一个可用消息;


GetMessage

检索到

WM_QUIT

消息则停止程序,对于其他消息,将其传递给

DispatchMessage

函数。

166、描述示例程序中WinProc过程的作用。


WinProc过程接收并处理与窗口相关的所有事件消息,大多数事件由用户通过鼠标点击、拖动和按键等操作发起。该过程的任务是解码每条消息,若消息被识别,则执行与该消息相关的面向应用程序的任务。对于未处理的消息,会传递给MS-Windows的默认消息处理程序`DefWindowProc`。

167、示例程序中WinProc过程处理哪些消息?

示例程序中

WinProc

过程处理以下三种消息:

WM_LBUTTONDOWN

(用户按下鼠标左键时生成)

WM_CREATE

(主窗口刚创建时)

WM_CLOSE

(应用程序主窗口即将关闭时)

168、描述示例程序中 ErrorHandler 过程的作用。

ErrorHandler 过程是可选的,当系统在程序主窗口的注册和创建过程中报告错误时会调用它。它有几个重要任务:

调用

GetLastError

检索系统错误号;

调用

FormatMessage

检索适当的系统格式化错误消息字符串;

调用

MessageBox

显示包含错误消息字符串的弹出消息框;

调用

LocalFree

释放错误消息字符串使用的内存。

169、调用CreateWindow后立即激活的消息框是在应用程序主窗口之前还是之后出现?

在调用

CreateWindowEx

创建主窗口后,若创建成功会保存窗口句柄、显示并绘制窗口,之后才调用

MessageBox

显示消息框,所以消息框在应用程序主窗口之后出现。

170、在段的相关概念中,什么是描述符?

段描述符可存在于

全局描述符表



局部描述符表

两种表中。除了段的基地址外,段描述符还包含指定段限制和段类型的位映射字段。段描述符还可以包含保护级别,保护操作系统数据不被应用程序访问。

描述符的各个选择器字段描述如下:


基地址

:是一个32位整数,定义了段在4GB线性地址空间中的起始位置;


特权级别

:可在0到3之间分配,0最具特权,通常用于操作系统内核代码;


段类型

:指示段的类型,指定对段的访问类型和段的增长方向;


段存在标志位

:指示段当前是否存在于物理内存中;


粒度标志位

:决定段限制字段的解释方式;


段限制

:是一个20位整数,指定段的大小,根据粒度标志位以字节或4096字节为单位解释。

171、一个系统有多少个局部描述符表(LDT)和全局描述符表(GDT)?

一个系统只有一个全局描述符表(GDT);在多任务操作系统中,每个任务或程序通常被分配一个局部描述符表(LDT),因此系统中LDT的数量取决于任务或程序的数量。

172、多任务处理在Windows环境中可行,但在DOS中不可行。

这句话是正确的。Windows是多任务操作系统,支持同时运行多个程序;而DOS是单任务操作系统,一次通常只能运行一个程序。

173、给出一个调用ReadConsole函数的示例。

以下是调用

ReadConsole

函数的示例代码:


; Read From the Console (ReadConsole.asm)
INCLUDE Irvine32.inc

BufSize = 80
.data
buffer      BYTE BufSize DUP(?),0,0
stdInHandle HANDLE ?
bytesRead   DWORD ?
.code
main PROC
    ; Get handle to standard input
    INVOKE GetStdHandle, STD_INPUT_HANDLE
    mov stdInHandle,eax

    ; Wait for user input
    INVOKE ReadConsole, stdInHandle, ADDR buffer, BufSize, ADDR bytesRead, 0

    ; Display the buffer
    mov  esi,OFFSET buffer
    mov  ecx,bytesRead
    mov  ebx,TYPE buffer
    call DumpMem

    exit
main ENDP
END main

174、展示一个对WriteConsole函数的调用示例。


INVOKE WriteConsole, consoleHandle, ADDR message, messageSize, ADDR bytesWritten, 0

175、给出一个调用CreateFile函数的示例,该示例能打开同名的现有文件,若文件不存在则创建一个具有普通属性的新文件。


INVOKE CreateFile, ADDR filename, GENERIC_WRITE, DO_NOT_SHARE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0

176、展示一个如何在汇编语言程序中使用动态内存分配调用来分配堆内存的示例。

以下是一个使用动态内存分配创建并填充一个1000字节数组的示例程序(Heaptest1.asm):


; Heap Test #1 (Heaptest1.asm)
INCLUDE Irvine32.inc

; This program uses dynamic memory allocation to allocate and 
; fill an array of bytes. 

.data
ARRAY_SIZE = 1000
FILL_VAL EQU 0FFh
hHeap HANDLE ?              ; handle to the process heap
pArray DWORD ?              ; pointer to block of memory
newHeap DWORD ?             ; handle to new heap
str1 BYTE "Heap size is: ",0

.code
main PROC
    INVOKE GetProcessHeap   ; get handle prog's heap

    .IF eax == NULL         ; if failed, display message
        call WriteWindowsMsg
        jmp quit
    .ELSE
        mov hHeap,eax       ; success
    .ENDIF

    call allocate_array
    jnc arrayOk             ; failed (CF = 1)?
    call WriteWindowsMsg
    call Crlf
    jmp quit

arrayOk:                    ; ok to fill the array
    call fill_array
    call display_array
    call Crlf

    ; free the array
    INVOKE HeapFree, hHeap, 0, pArray

quit:
    exit
main ENDP

;--------------------------------------------------------
allocate_array PROC USES eax
;
; Dynamically allocates space for the array.
; Receives: EAX = handle to the program heap
; Returns: CF = 0 if the memory allocation succeeds.
;--------------------------------------------------------
    INVOKE HeapAlloc, hHeap, HEAP_ZERO_MEMORY, ARRAY_SIZE

177、给出一个调用 MessageBox 函数的示例。

以下是一个调用 MessageBox 函数的示例,完整的 MessageBox 函数原型为:


MessageBoxA PROTO, hWnd:DWORD, lpText:PTR BYTE, lpCaption:PTR BYTE, uType:DWORD

在控制台应用程序中可将

hWnd

设为

NULL


lpText

是指向要显示在消息框内的以空字符结尾的字符串的指针,

lpCaption

指向对话框标题的以空字符结尾的字符串,

uType

指定对话框的内容和行为。

代码示例如下:


INVOKE MessageBox, NULL, ADDR warningMsg,
© 版权声明

相关文章

暂无评论

none
暂无评论...