本篇记录《汇编语言:基于X86处理器》第10章 复习题和练习的学习笔记.
10.7复习题和练习
10.7.1 简答题
1.STRUCT伪指令的用途是什么?
答:STRUCT伪指令用来定义结构体,与ENDS成对使用,例如:
;10.7.1_1.asm 10.7.1 简答题
;1.STRUCT伪指令的用途是什么?
INCLUDE Irvine32.inc
COORD STRUCT
X WORD ?
Y WORD ?
COORD ENDS
.data
position COORD <8,9>
.code
main PROC
mov ax, position.X
mov bx, position.Y
INVOKE ExitProcess, 0
main ENDP
END main
运行调试:
2.假设定义了如下结构;
RentalInvoice STRUCT
invoiceNum BYTE 5 DUP(' ')
dailyPrice WORD ?
daysRented WORD ?
RentalInvoice ENDS
则下列声明是否有效:
a. rentals RentalInvoice <>
b. RentalInvoice rentals <> ;无效
c. march RentalInvoice <'12345', 10, 0>
d. RentalInvoice <, 10, 3333h>
e. current RentalInvoice <, 15, 0, 0> ;无效
答:a.有效, b.无效, c.有效, d.有效, e.无效
完整代码测试笔记
;10.7.1_2.asm 10.7.1 简答题
INCLUDE Irvine32.inc
RentalInvoice STRUCT
invoiceNum BYTE 5 DUP(' ')
dailyPrice WORD ?
daysRented WORD ?
RentalInvoice ENDS
.data
str1 BYTE "Please enter your name: ", 0
rentals RentalInvoice <>
;RentalInvoice rentals <> ;无效
march RentalInvoice <'12345', 10, 0>
RentalInvoice <, 10, 3333h>
;current RentalInvoice <, 15, 0, 0> ;无效
.code
main PROC
mov ebx, OFFSET str1
mov rentals.dailyPrice, 16
mov rentals.daysRented, 32
mov ax, march.dailyPrice ;ax = 10
mov esi, OFFSET march
mov bx,(RentalInvoice PTR[esi+9]).dailyPrice ;bx = 10
mov bx,(RentalInvoice PTR[esi+9]).daysRented ;bx = 3333h
call Crlf
INVOKE ExitProcess, 0
main ENDP
END main
运行调试:
3.(真/假):宏不能包含数据定义。
答:假,宏可以包含数据定义,例如
; 定义一个包含数据声明的宏
MyDataMacro MACRO
message BYTE 'Hello, World!', 0
ENDM
4.LOCAL伪指令的用途是什么?
答:LABEL伪指令可以插入一个标号,并定义它的大小属性,但是不为这个标号分配存储空间,在宏扩展时找偏移地址很有用。示例如下:
;10.7.1_4.asm 10.7.1 简答题
;4.LOCAL伪指令的用途是什么?
;答:LABEL伪指令可以插入一个标号,并定义它的大小属性,但是不为这个标号分配存储空间
;在宏扩展时找偏移地址很有用。
INCLUDE Irvine32.inc
.data
val16 LABEL WORD
val32 DWORD 12345678h
;定义一个标签以便引用这个数组
FibonacciArray LABEL DWORD
val1 = 1
val2 = 1
DWORD val1 ;前两个值
DWORD val2
val3 = val1 + val2
WHILE val3 LT 0F0000000h
DWORD val3
val1 = val2
val2 = val3
val3 = val1+val2
ENDM
;获取数组长度:
FibonacciCount = ($ - FibonacciArray) / 4
.code
main PROC
mov ax, val16 ;ax = 5678h
mov bx, [val16+2] ;bx = 1234h
mov esi, OFFSET FibonacciArray
;获取第一个斐波那契数
mov eax, [esi] ;eax = 1 ;eax = 1
mov ebx, [FibonacciArray] ;ebx = 1
INVOKE ExitProcess, 0
main ENDP
END main
运行调试:
5.哪条伪指令能在控制台上显示汇编时消息?
答:ECHO
指令
6.哪条伪指令标志条件语句块的结束?
答:ENDIF
7.列出所有能在常量布尔表达式中使用的关系运算符。
答:汇编器允许在包含IF和其他条件伪指令的常量布尔表达式中使用下列关系运算符:
LT 小于
GT 大于
EQ 等于
NE 不等
LE 小于等于
GE 大于等于
8.宏定义中的&运算符有什么作用?
答:&是替换运算符,作用是解析对宏参数名的有歧义的引用。
9.宏定义中的!运算符有什么作用?
答:!是构造文字字符(literal-character)运算符。作用与文字文本运算符的几乎完全一样:强制预处理程序把预先定义的运算符当作普通的字符。
10.宏定义中的%运算符有什么作用?
答:%是展开运算符,作用是展开文本宏并将常表达式转换为文本形式。
10.7.2 算法基础
1.创建包含两个字段的结构 SampleStruct: field1为一个16位WORD,field2为含有20个32位DWORD 的数组。不需定义字段初始值。
;10.7.2_1.asm 10.7.2 算法基础
INCLUDE Irvine32.inc
;创建包含两个字段的结构
SampleStruct STRUCT
field1 WORD ?
field2 DWORD 20 DUP(?)
SampleStruct ENDS
.data
temp SampleStruct <>
.code
main PROC
mov esi, OFFSET temp
mov ecx, LENGTHOF temp
mov (SampleStruct PTR[esi]).field1, 1122h
INVOKE ExitProcess, 0
main ENDP
END main
运行调试:
2.编写一条语句检索结构 SYSTEMTIME 的 wHour 字段。
;10.7.2_2.asm 10.7.2 算法基础
INCLUDE Irvine32.inc
SYSTEMTIME STRUCT
wYear WORD ?
wMonth WORD ?
wDayOfWeek WORD ?
wDay WORD ?
wHour WORD ?
wMinute WORD ?
wSecond WORD ?
wMilliseconds WORD ?
SYSTEMTIME ENDS
.data
sysTime SYSTEMTIME <>
.code
main PROC
INVOKE GetLocalTime, ADDR sysTime
;检索结构 SYSTEMTIME 的 wHour 字段
movzx eax, sysTime.wHour
call WriteDec
INVOKE ExitProcess, 0
main ENDP
END main
运行调试:
3.使用如下 Triangle 结构,声明一个结构变量并将其三个顶点分别初始化为(0, 0)、(5, 0)和(7, 6 ):
;10.7.2_3.asm 10.7.2 算法基础
INCLUDE Irvine32.inc
COORD STRUCT
X WORD ?
Y WORD ?
COORD ENDS
Triangle STRUCT
Vertex1 COORD <>
Vertex2 COORD <>
Vertex3 COORD <>
Triangle ENDS
.data
;声明一个结构变量并将其三个顶点分别初始化为(0, 0)、(5, 0)和(7, 6 ):
valTriangle Triangle <<0,0>, <5,0>, <7,6>>
.code
main PROC
;使用变量
mov esi, OFFSET valTriangle
movzx eax, (Triangle PTR[esi]).Vertex1.X
movzx ebx, (Triangle PTR[esi]).Vertex1.Y
movzx eax, (Triangle PTR[esi]).Vertex2.X
movzx ebx, (Triangle PTR[esi]).Vertex2.Y
movzx eax, (Triangle PTR[esi]).Vertex3.X
movzx ebx, (Triangle PTR[esi]).Vertex3.Y
INVOKE ExitProcess, 0
main ENDP
END main
运行调试:
4.声明一个 Triangle 结构的数组,并编写一个循环,用随机坐标对每个三角形的 Vertex1进行初始化,坐标范围为(0…10,0…10)。
;10.7.2_4.asm 10.7.2 算法基础
INCLUDE Irvine32.inc
COORD STRUCT
X WORD ?
Y WORD ?
COORD ENDS
Triangle STRUCT
Vertex1 COORD <>
Vertex2 COORD <>
Vertex3 COORD <>
Triangle ENDS
.data
;声明一个结构变量并将其三个顶点分别初始化为(0, 0)、(5, 0)和(7, 6 ):
valTriangle Triangle <<0,0>, <5,0>, <7,6>>
ARRAY_SIZE = 5
triangles Triangle ARRAY_SIZE DUP(<>)
.code
main PROC
;使用变量
mov esi, OFFSET valTriangle
movzx eax, (Triangle PTR[esi]).Vertex1.X
movzx ebx, (Triangle PTR[esi]).Vertex1.Y
mov (COORD PTR[esi]).X, 1122h ;Vertex1
mov (COORD PTR[esi]).Y, 3344h
mov (COORD PTR[esi+4]).X, 5566h ;Vertex2
mov (COORD PTR[esi+4]).Y, 7788h
;用随机坐标对每个三角形的 Vertex1进行初始化
mov ecx, ARRAY_SIZE
mov esi, 0
L1:
mov eax, 11 ;设置随机数范围0~10
call RandomRange ;产生随机数
mov triangles[esi].Vertex1.X, ax
mov eax, 11
call RandomRange
mov triangles[esi].Vertex1.Y, ax
add esi, TYPE Triangle
loop L1
INVOKE ExitProcess, 0
main ENDP
END main
运行调试:
5.编写宏 mPrintChar,在屏幕上显示一个字符。宏应有两个参数:第一个指定显示的字符,第二个指定字符重复的次数。示例调用如下:
mPrintChar ‘X', 20
;10.7.2_5.asm 10.7.2 算法基础
INCLUDE Irvine32.inc
.data
;定义mPrintChar宏,两个参数
mPrintChar MACRO char, count
mov ecx, count
L1:
mov al, char
call WriteChar
loop L1
ENDM
;方法2:
mPrintChar2 MACRO char, count
LOCAL temp
.data
temp BYTE count DUP(&char), 0
.code
push edx
mov edx, OFFSET temp
call WriteString
pop edx
ENDM
.code
main PROC
mPrintChar 'A', 20
call Crlf
mPrintChar2 'A', 20
INVOKE ExitProcess, 0
main ENDP
END main
运行调试:
6.编写宏mGenRandom,在0到n-1之间随机生成一个整数,n为宏的唯一参数。
;10.7.2_6.asm 10.7.2 算法基础
INCLUDE Irvine32.inc
.data
mGenRandom MACRO n
mov eax, n
call RandomRange
ENDM
.code
main PROC
mGenRandom 25
call WriteDec
call Crlf
INVOKE ExitProcess, 0
main ENDP
END main
运行调试:
7.编写宏mPromptInteger,显示提示并接收用户输人的一个整数。向该宏传递一个字符串文本和一个双字变量名。示例调用如下:
.data
minVal DWORD ?
.code
mPromptInteger "Enter the minimum value", minVal
完整的实现如下:
;10.7.2_7.asm 10.7.2 算法基础
INCLUDE Irvine32.inc
.data
minVal DWORD ?
; 定义mWriteprompt宏 LOCAL对标号的自引用——324页
mWriteprompt MACRO prompt
LOCAL string
.data
string BYTE prompt, 0 ; 定义以null结尾的字符串
.code
push edx ; 保存edx寄存器
mov edx, OFFSET string
call WriteString ; 调用Irvine32库的WriteString过程
pop edx ; 恢复edx寄存器
ENDM
mPromptInteger MACRO prompt, value
mWriteprompt prompt
call ReadInt ;输入整型数据
mov value, eax
ENDM
.code
main PROC
mov esi, OFFSET minVal
mPromptInteger "Enter the minimum value", minVal
call Crlf
INVOKE ExitProcess, 0
main ENDP
END main
运行调试:
8.编写宏mWriteAt,定位光标并在控制台窗口显示一个字符串文本。建议:调用本书宏库中的mGotoxy和mWrite。
;10.7.2_8.asm 10.7.2 算法基础
INCLUDE Irvine32.inc
INCLUDE Macros.inc
.data
;宏实现
mWriteAt MACRO x, y, string
mGotoxy x, y
mWrite string
ENDM
.code
main PROC
mWriteAt 10, 2, "定位光标显示字符串"
call Crlf
INVOKE ExitProcess, 0
main ENDP
END main
运行调试:
9.用如下语句调用10.2.5 节的宏mWriteString,请写出其生成的展开代码;
mWriteStr namePrompt
;10.7.2_9.asm 10.7.2 算法基础
INCLUDE Irvine32.inc
INCLUDE Macros.inc
.data
namePrompt BYTE "Please enter your name: ", 0
.code
main PROC
mov ebx, OFFSET namePrompt
mWriteString namePrompt
call Crlf
INVOKE ExitProcess, 0
main ENDP
END main
;mWriteStr namePrompt ;扩展为以下:
;1 push edx
;1 mov edx, OFFSET namePrompt
;1 call WriteString
;1 pop edx
运行调试:
10.用如下语句调用10.2.5节的宏mReadString,请写出其生成的展开代码:
mReadstr customerName
;10.7.2_10.asm 10.7.2 算法基础
INCLUDE Irvine32.inc
INCLUDE Macros.inc
.data
customerName BYTE 30 DUP(?)
.code
main PROC
mov esi, OFFSET customerName
mReadString customerName
call Crlf
INVOKE ExitProcess, 0
main ENDP
END main
;mReadstr customerName ;扩展为以下:
;1 push ecx
;1 push edx
;1 mov edx, OFFSET customerName
;1 mov edx, (SIZEOF customerName) - 1
;1 call ReadString
;1 pop edx
;1 pop ecx
运行调试:
11.编写宏mDumpMemx,接收一个参数和一个变量名。该宏必须调用本书链接库的宏mDumpMem,并向其传递变量的偏移量,存储对象的数量和对象的大小。演示对宏mDumpMemx的调用。
;10.7.2_11.asm 10.7.2 算法基础
INCLUDE Irvine32.inc
;以十六进制显示变量,使用变量的属性确定单位数和单位大小。
mDumpMemx MACRO varName
push ebx
push ecx
push esi
mov esi, OFFSET varName
mov ecx, LENGTHOF varName
mov ebx, TYPE varName
call DumpMem
pop esi
pop ecx
pop ebx
ENDM
.data
array1 BYTE 10h, 20h, 30h, 40h, 50h
array2 WORD 1011h, 2022h, 3033h, 4044h, 5055h
array3 DWORD 11111111h, 22222222h, 33333333h, 44444444h, 55555555h
.code
main PROC
mov esi, OFFSET array1
mDumpMemx array1
mDumpMemx array2
mDumpMemx array3
call Crlf
INVOKE ExitProcess, 0
main ENDP
END main
运行结果:
12.举例说明有默认实参初始值的宏形参。
;10.7.2_12.asm 10.7.2 算法基础
INCLUDE Irvine32.inc
INCLUDE Macros.inc
;使用默认参数作初始值
mWriteInA MACRO text:=<" ">
mWrite text
call Crlf
ENDM
.data
.code
main PROC
mWriteInA "hello"
mWriteInA " "
mWriteInA
mWriteInA "world"
INVOKE ExitProcess, 0
main ENDP
END main
运行调试:
13.编写一个简短的例子来使用IF、ELSE 和ENDIF 伪指令。
;10.7.2_13.asm 10.7.2 算法基础
INCLUDE Irvine32.inc
.data
mCopyWord MACRO intVal
IF (TYPE intVal) EQ 2
mov ax, intVal
ELSE
ECHO Error: Invalid operand size
ENDIF
ENDM
.code
main PROC
mov bx, 1111h
mCopyWord bx
mCopyWord ebx ;调用这句会出现错误提示 "Invalid operand size"
call Crlf
INVOKE ExitProcess, 0
main ENDP
END main
运行调试:
14.编写一条语句,用IF 伪指令检查常量宏参数Z的值;如果Z小于 0,则在汇编时显示一条消息说明Z是无效的。
;10.7.2_14.asm 10.7.2 算法基础
INCLUDE Irvine32.inc
.data
mCheck MACRO Z
IF Z LT 0
ECHO Error: Operand Z is invalid
ENDIF
ENDM
.code
main PROC
mov bx, 1111h
mCheck 1234
mCheck -1 ;调用这句会出现错误提示 "Operand -1 is invalid"
call Crlf
INVOKE ExitProcess, 0
main ENDP
END main
编译运行:
15.编写一个简短的宏,在宏形参嵌入文本字符串时,演示运算符 &的用法。
;10.7.2_15.asm 10.7.2 算法基础
INCLUDE Irvine32.inc
.data
mCreateString MACRO strVal
.data
temp BYTE "Var &strVal", 0
temp2 BYTE "Var strVal", 0
.code
push edx
mov edx, OFFSET temp
call WriteString
call Crlf
mov edx, OFFSET temp2
call WriteString
pop edx
ENDM
.code
main PROC
mov ebx, 1111h
mCreateString ebx
call Crlf
INVOKE ExitProcess, 0
main ENDP
END main
运行调试:
16.假设宏mLocate的定义如下:
mLocate MACRO xVal, yVal
IF xVal LT 0 ;;xval < 0 ?
EXITM ;;若是,则退出
ENDIF
IF yVal LT 0 ;;yval < 0 ?
EXITM ;;若是,则退出
ENDIF
mov bx, 0 ;;视频页面0
mov ah, 2 ;;定位光标
mov dh, yVal
mov dl, xVal
int 10h ;;调用BIOS
ENDM
若用下述语句调用该宏,请写出预处理程序在进行宏展开时生成的源代码:
.data
row BYTE 15
col BYTE 60
.code
mLocate -1, 20
mLocate 10, 20
mLocate col, row
完整代码测试笔记
;10.7.2_16.asm 10.7.2 算法基础
;16.假设宏mLocate的定义如下:
INCLUDE Irvine32.inc
mLocate MACRO xVal, yVal
IF xVal LT 0 ;;xval < 0 ?
EXITM ;;若是,则退出
ENDIF
IF yVal LT 0 ;;yval < 0 ?
EXITM ;;若是,则退出
ENDIF
mov bx, 0 ;;视频页面0
mov ah, 2 ;;定位光标
mov dh, yVal
mov dl, xVal
int 10h ;;调用BIOS
ENDM
.data
row BYTE 15
col BYTE 60
.code
main PROC
mLocate -1, 20
mLocate 10, 20
mLocate col, row
call Crlf
INVOKE ExitProcess, 0
main ENDP
END main
编译:
mLocate -1, 20
mLocate 10, 20
1 mov bx, 0
1 mov ah, 2
1 mov dh, 20
1 mov dl, 10
1 int 10h
mLocate col, row
1 IF col LT 0
chapter10\10.7.2_16.asm(29) : error A2094:operand must be relocatable
mLocate(1): Macro Called From
chapter10\10.7.2_16.asm(29): Main Line Code
1 ENDIF
chapter10\10.7.2_16.asm(29) : error A2094:operand must be relocatable
mLocate(4): Macro Called From
chapter10\10.7.2_16.asm(29): Main Line Code
1 mov bx, 0
1 mov ah, 2
1 mov dh, row
1 mov dl, col
1 int 10h