《汇编语言:基于X86处理器》第11章 复习题和练习
本篇记录了《汇编语言:基于X86处理器》第11章 复习题和练习的笔记。
11.7复习题和练习
11.7.1 简答题
1.写出与下面标准MS-Windows类型匹配的MASM 数据类型:
a.BOOL b.COLORREF c.HANDLE
d.LRPSTR e. WPARAM
答:a.BOOL =>DWORD b.COLORREF =>DWORD c.HANDLE =>DWORD
d.LRPSTR =>DWORD e. WPARAM =>DWORD
2.哪个 Win32 函数返回标准输入的句柄?
答:GetStdHandle函数。原型如下:
GetStdHandle PROTO,nStdHandle:HANDLE ;句柄类型
3.哪个Win32 函数从键盘读取一个字符串,并将其放入缓冲区?
答:ReadConsole函数,原型如下:
ReadConsole PROTO,hConsoleInput:HANDLE, ;输入句柄lpBuffer:PTR BYTE, ;缓冲区指针nNumberOfCharsToRead:DWROD ;读取的字符数lpNumberOfCharsRead:PTR DWORD ;指向读取字节数的指针lpReserved:DWORD ;未使用
4.请描述 COORD 结构。
答:
COORD STRUCT X WORD ?Y WROD ?
COORD ENDS
5.哪个 Win32函数能以文件开始为基址,将文件指针移动到指定偏移量的位置?
答:SetFilePointer函数。原型如下:
SetFilePointer PROTO, hFile:HANDLE, ;文件句柄lDistanceToMove:SDWORD, ;指针移动字节数lpDistanceToMoveHigh:PTR SDWORD, ;指针移动字节数,高双字dwMoveMethod:DWORD ;移动方式,可取值为 FILE_BEGIN, FILE_CURRENT 或 FILE_END
6.哪个 Win32 函数能修改控制台窗口标题?
答:SetConsoleTitle函数。原型如下:
SetConsoleTitle PROTO, ; 设置控制台标题lpConsoleTitle:PTR BYTE ; 指针字符串
7.哪个Win32 函数能修改屏幕缓冲区的外形尺寸?
答:SetConsoleWindowInfo函数。原型如下:
SetConsoleWindowInfo PROTO,hConsoleOutput:HANDLE, ;屏幕缓冲区句柄bAbsolute:DWORD, ;坐标类型lpConsoleWindow:PTR SMALL_RECT ;矩形窗口指针
8.哪个Win32 函数能修改光标大小?
答:SetConsoleCursorInfo函数。原型如下:
CONSOLE_CURSOR_INFO STRUCTdwSize DWORD ?bVisible DWORD ?
CONSOLE_CURSOR_INFO ENDSSetConsoleCursorInfo PROTO,hConsoleOutput:HANDLE,lpConsoleCursorInfo:PTR CONSOLE_CURSOR_INFO
9.哪个Win32函数能修改后续输出文本的颜色?
答:SetConsoleTextAttribute函数。函数原型如下:
SetConsoleTextAttribute RPOTO,hConsoleOutput:HANDLE, ;控制台输出句柄wAttributes:WORD ;颜色属性
10.哪个Win32函数能将一组属性值复制到控制台屏幕缓冲区的连续单元格?
答:WriteConsoleOutputAttribute函数。函数原型如下:
WriteConsoleOutputAttribute PROTO,hConsoleOutput:DWORD, ;输出句柄lpAttribute:PTR WORD, ;写属性nLength:DWORD, ;单元格数dwWriteCoord:COORD, ;第一个单元格坐标lpNumberOfAttrsWritten:PTR DWORD ;输出计数
11.哪个 Win32 函数能按指定毫秒数暂停程序?
答:Sleep函数。函数原型如下:
Sleep PROTO, dwMilliseconds:DWORD
12.调用CreateWindowEx时,如何将窗口外观信息传递给该函数?
答:根据CreateWindowEx声明属性,传递相关字段即可。原型如下:
CreateWindowExA PROTO, ; create and register a window classexWinStyle:DWORD,className:PTR BYTE,winName:PTR BYTE,winStyle:DWORD,X:DWORD,Y:DWORD,rWidth:DWORD,rHeight:DWORD,hWndParent:DWORD,hMenu:DWORD,hInstance:DWORD,lpParam:DWORD
13.请说出两个在调用 MessageBox 函数时会用到的按钮常量。
答:MB_OK按钮, MB_OKCANCEL函数
14.请说出两个在调用MessageBox 函数时会用到的图标常量。
答:问号(?):MB_ICONQUESTION,信息符(i):MB_ICONINFORMATION.
15.请说出至少 3 个由 WinMain(启动)过程执行的任务。
答:每个Windows应用程序都需要一个启动过程,通常将其命名为WinMain,该过程负责下述任务:
得到当前程序的句柄。
加载程序的图标和光标。
注册程序的主窗口类,并标识处理该窗口事件消息的过程。
创建主窗口。
显示并更新主窗口。
开始接收和发送消息的循环,直到用户关闭应用程序窗口。
16.请说明WinProc过程在示例程序中的作用。
答:WinProc过程用来处理所有与窗口有关的事件消息,例如鼠标点击,拖动,按键等事件操作。
17.示例程序中的WinProc过程处理哪些消息?
答:WM_CREATE创建主窗口的消息,WM_LBUTTONDOWN鼠标左键按下产生的消息,WM_CLOSE关闭应用程序主窗口产生的消息。
18.请说明 ErrorHandler 过程在示例程序中的作用。
答:在示例程序中的作用是若CreateWindowEx失败,则显示消息并退出。
19.CreateWindow调用后立刻激活的消息框出现在应用程序主窗口之前还是之后?
答:CreateWindow调用后立刻激活的消息框出现在应用程序主窗口之前
20.由WM_CLOSE 激活的消息框出现在关闭主窗口之前还是之后?
答:由WM_CLOSE 激活的消息框出现在关闭主窗口之前。
21.请对线性地址进行说明。
答:线性地址由段选择符(16位的段地址)加逻辑地址(32位的偏移量)组成。线性地址是一个32位整数,其范围为0FFFFFFFFh,它表达一个内存位置。如果禁止分页功能,那么线性地址也就是目标数据的物理地址。
22.线性内存与分页之间存在怎样的关系?
答:如果禁止分页功能,那么线性内存也就是目标数据的物理地址。若请允许分页,则处理器必须将32位线性地址转换为32位物理地址。这个过程会用到3种结构:页目录:(10位),页表(10)位,页(12位)这3个字段分别表示:页目录表项指针、页表项指针和页内偏移量。
23.如果禁用分页,处理器如何将线性地址转换为物理地址?
答:如果禁用分页,处理器直接将线性地址作为物理地址。
24.分页有哪些好处?
答:分页有以下以个好处:
a. 简化内存管理
非连续分配:允许进程的物理内存分散在不相邻的区域,避免连续内存分配(如分段)导致的碎片问题。
固定大小单元:以固定大小的“页”为单位管理内存,操作系统只需维护页表,无需处理复杂的内存块匹配。
b. 提高内存利用率
减少外部碎片:通过小页划分,减少因内存分配/释放产生的碎片(外部碎片几乎被消除)。
共享内存:不同进程可以共享相同的代码页(如库文件),节省物理内存空间。
c. 支持虚拟内存
按需加载:只有当前需要的页才加载到物理内存,其余保留在磁盘(如交换空间),突破物理内存容量限制。
懒加载(Lazy Loading):程序启动时无需加载全部代码和数据,加快启动速度。
d. 提升多任务性能
快速上下文切换:进程切换时只需切换页表(如CR3寄存器),无需移动物理内存内容。
并行执行:多个进程可以高效共享物理内存,系统能同时运行更多程序。
e. 内存保护与安全
权限控制:每页可单独设置读写执行权限(如代码页只读),防止非法访问。
隔离性:进程的地址空间通过页表隔离,增强系统稳定性。
f. 优化磁盘I/O
页面置换算法:当内存不足时,通过算法(如LRU)将不活跃的页换出到磁盘,优先保留高频访问页。
预取(Prefetching):根据局部性原理预加载可能需要的页,减少缺页中断。
g. 灵活性与可扩展性
支持大地址空间:32位系统可通过分页访问超过4GB的虚拟地址空间(如PAE扩展)。
多级页表:平衡内存占用与查找效率(如x86-64的四级页表)。
25.哪个寄存器包含了局部描述符表的基地址?
答:局部描述符表寄存器(LDTR)包含了局部描述符表的在基地址。 LDTR 是一个 48 位的寄存器,其结构与 GDTR 类似,其中高 32 位用于存储 LDT 的基地址,低 16 位则表示表的大小限制(值为表长度减 1)
26.哪个寄存器包含了全局描述符表的基地址?
答:全局描述符表寄存器(GDTR)包含了全局描述符表的基地址。 GDTR 是一个 48 位的寄存器,其中低 16 位用于存储 GDT 的界限(即表的大小减一),而高 32 位则用于存储 GDT 的起始地址。
27.允许存在多少全局描述符表?
答:系统全局仅需一个GDT(但可动态替换):虽然理论上可以存在多个GDT(通过LGDT
指令加载不同的基址和界限),但同一时刻只有一个GDT是活动的。操作系统通常会在任务切换或模式切换时修改GDT内容或重新加载新的GDT
28.允许存在多少局部描述符表?
答: 每个LDT本质上是一个内存段,其大小受限于内存可用空间。LDT的大小最多可包含8192个描述符条目,因此每个LDT的存储需求决定了系统中能容纳的LDT总数。
29.请说出至少 4个段描述符内的字段。
答:段描述符(segment descriptor)是一个64位的值,用于标识和描述一个内存段。它包含的信息有段基址、访问权限、段限长、类型和用法。
30.分页处理涉及哪些结构?
答:分页处理涉及3种结构:
页目录:一个数组,最多可包含1024个32位页目录项。
页表:一个数组,最多可包含1024个32位页表项。
页:4KB或4MB的地址空间。
31.哪种结构包含了页表的基地址?
答:页表项结构包含了页表的基地址。
32.哪种结构包含了页面的基地址?
答:页项结构包含了页面的基地址。
11.7.2算法基础
1.编写代码段调用函数ReadConsole。
;11.7.2_ReadConsole.asm 11.7.2 算法基础
;1.编写代码段调用函数ReadConsole。;本程序调用如下win32控制台函数:
;GetstdHandle,ExitProcess、ReadConsole
INCLUDE Irvine32.inc
BufSize = 80.data
buffer BYTE BufSize DUP(?),0,0
stdInHandle HANDLE ?
bytesRead DWORD ? .code
main PROC;获得标准输入句柄:INVOKE GetStdHandle, STD_INPUT_HANDLEmov stdInHandle, eax;等待用户输入INVOKE ReadConsole, stdInHandle, ;控制台输入句柄ADDR buffer, ;缓冲区地址BufSize, ;缓冲区大小ADDR bytesRead, ;读取的实际数大小0 ;未使用;显示缓冲区mov esi, OFFSET buffermov ecx, bytesReadmov ebx, TYPE buffercall DumpMemINVOKE ExitProcess, 0
main ENDP
END main
运行调试:
2.编写代码段调用函数WriteConsole。
;11.7.2_WriteConsole.asm 11.7.2 算法基础
;2.编写代码段调用函数WriteConsole。;本程序调用如下win32控制台函数:
;GetstdHandle,ExitProcess、WriteConsole
INCLUDE Irvine32.inc.data
endl EQU <0dh, 0ah> ;行结尾
message LABEL BYTEBYTE "Electronic versions of these documents allow you to quickly "BYTE "get the information you need and print only the pages you want. ", endl
messageSize DWORD ($ - message)
stdOutHandle HANDLE 0 ;标准输出设备句柄
bytesWritten DWORD ? ;输出字节数.code
main PROC;获得标准输出句柄:INVOKE GetStdHandle, STD_OUTPUT_HANDLEmov stdOutHandle, eax;等待用户输入INVOKE WriteConsole, stdOutHandle, ;控制台输出句柄ADDR message, ;字符串指针 messageSize, ;字符长度ADDR bytesWritten, ;返回输出字节数0 ;未使用mov esi, OFFSET messagemov ebx, bytesWrittenINVOKE ExitProcess, 0
main ENDP
END main
运行调试:
3.编写代码段调用函数 CreateFile 打开已有文档以便读出。
;11.7.2_CreateFile_ReadFile.asm 11.7.2 算法基础
;3.编写代码段调用函数 CreateFile 打开已有文档以便读出。;本程序调用如下win32控制台函数:
;CreateFile,ExitProcess、ReadFile
INCLUDE Irvine32.inc.data
flName BYTE "aaa.txt" ;文件名
fileHandle HANDLE 0 ;文件句柄
str1 BYTE "CreateFile OPEN ERROR.", 0
readBuffer BYTE 80 DUP(?), 0
readSize = 64
realSize DWORD ?.code
main PROC;打开并读取已存在文件INVOKE CreateFile,ADDR flName, ;文件名指针GENERIC_READ, ;读文件DO_NOT_SHARE, ;共享模式NULL, ;安全属性指针OPEN_EXISTING, ;打开已存在文件FILE_ATTRIBUTE_NORMAL, ;普通文件属性0 ;未使用mov fileHandle, eax;错误检查cmp eax, INVALID_HANDLE_VALUE ;发现错误?jne file_ok ;否:跳过mov edx, OFFSET str1 ;显示错误call WriteStringjmp quitfile_ok:;读取文件内容INVOKE ReadFile,fileHandle, ;文件句柄ADDR readBuffer, ;缓冲区指针readSize, ;读取的字节数ADDR realSize, ;实际读取的字节数0 ;异步信息指针mov edx, OFFSET readBuffer call WriteString ;显示读取文件的内容quit:call CrlfINVOKE ExitProcess, 0
main ENDP
END main
运行调试,打开已存在的文件:
读取文件内容
4.编写代码段调用函数 CreateFile 用标准属性新建一个文档,并删除其他已存在的同名文件。
;11.7.2_CreateFile_DeleteExist.asm 11.7.2 算法基础
;4.编写代码段调用函数 CreateFile 用标准属性新建一个文档,并删除其他已存在的同名文件。;本程序调用如下win32控制台函数:
;CreateFile,ExitProcess、WriteString
INCLUDE Irvine32.inc.data
flName BYTE "aaa.txt" ;文件名(已存在的文件)
fileHandle HANDLE 0 ;文件句柄
str1 BYTE "CreateFile OPEN ERROR.", 0
str2 BYTE "File creation successful, overwrite existing files", 0.code
main PROC;打开并删除已存在文件INVOKE CreateFile,ADDR flName, ;文件名指针GENERIC_WRITE, ;写文件DO_NOT_SHARE, ;共享模式NULL, ;安全属性指针CREATE_ALWAYS, ;覆盖已存在的文件FILE_ATTRIBUTE_NORMAL, ;普通文件属性0 ;未使用mov fileHandle, eax;错误检查cmp eax, INVALID_HANDLE_VALUE ;发现错误?jne file_ok ;否:跳过mov edx, OFFSET str1 ;显示错误call WriteStringjmp quitfile_ok:mov edx, OFFSET str2 ;覆盖已存在的文件 call WriteString ;显示文件创建成功quit:call CrlfINVOKE ExitProcess, 0
main ENDP
END main
运行调试:
5.编写代码段调用函数 ReadFile。
;11.7.2_ReadFile.asm 11.7.2 算法基础
;5.编写代码段调用函数 ReadFile。;本程序调用如下win32控制台函数:
;CreateFile,ExitProcess、ReadFile
INCLUDE Irvine32.inc.data
flName BYTE "aaa.txt" ;文件名
fileHandle HANDLE 0 ;文件句柄
str1 BYTE "CreateFile OPEN ERROR.", 0
readBuffer BYTE 80 DUP(?), 0
readSize = 70
realSize DWORD ?.code
main PROC ;打开并读取已存在文件INVOKE CreateFile,ADDR flName, ;文件名指针GENERIC_READ, ;读文件DO_NOT_SHARE, ;共享模式NULL, ;安全属性指针OPEN_EXISTING, ;打开已存在文件FILE_ATTRIBUTE_NORMAL, ;普通文件属性0 ;未使用mov fileHandle, eax;错误检查cmp eax, INVALID_HANDLE_VALUE ;发现错误?jne file_ok ;否:跳过mov edx, OFFSET str1 ;显示错误call WriteStringjmp quitfile_ok:;读取文件内容INVOKE ReadFile,fileHandle, ;文件句柄ADDR readBuffer, ;缓冲区指针readSize, ;读取的字节数ADDR realSize, ;实际读取的字节数0 ;异步信息指针mov edx, OFFSET readBuffer call WriteString ;显示读取文件的内容call Crlf;读取的字节数mov eax, readSizecall WriteDeccall Crlf;实际读取的字节数mov eax, realSizecall WriteDecquit:call CrlfINVOKE ExitProcess, 0
main ENDP
END main
运行调试:
6.编写代码段调用函数 WriteFile。
;11.7.2_WriteFile.asm 11.7.2 算法基础
;6.编写代码段调用函数 WriteFile。;本程序调用如下win32控制台函数:
;CreateFile,ExitProcess、WriteFile
INCLUDE Irvine32.inc.data
flName BYTE "aaa.txt" ;文件名
fileHandle HANDLE 0 ;文件句柄
str1 BYTE "CreateFile OPEN ERROR.", 0
writeBuffer BYTE "can be customized using style sheets", 0
bufferSize = 38
realSize DWORD ?.code
main PROC;打开并读取已存在文件INVOKE CreateFile,ADDR flName, ;文件名指针GENERIC_WRITE, ;写文件DO_NOT_SHARE, ;共享模式NULL, ;安全属性指针CREATE_ALWAYS, ;若文件存在,覆盖文件FILE_ATTRIBUTE_NORMAL, ;普通文件属性0 ;未使用mov fileHandle, eax;错误检查cmp eax, INVALID_HANDLE_VALUE ;发现错误?jne file_ok ;否:跳过mov edx, OFFSET str1 ;显示错误call WriteStringjmp quitfile_ok:;写入文件内容INVOKE WriteFile,fileHandle, ;文件句柄ADDR writeBuffer, ;缓冲区指针bufferSize, ;缓冲区大小ADDR realSize, ;写入字节数0 ;异步信息指针mov eax, realSize call WriteDec ;显示写入的字节数quit:call CrlfINVOKE ExitProcess, 0
main ENDP
END main
运行调试:
7.编写代码段调用函数 MessageBox。
;11.7.2_WriteFile.asm 11.7.2 算法基础
;7.编写代码段调用函数 MessageBox。INCLUDE Irvine32.inc.data
captionW BYTE "Warning", 0
warningMsg BYTE "The current operation may take years "BYTE "to complete.", 0
captionQ BYTE "Question", 0
questionMsg BYTE "A matching user account was not found."BYTE 0dh, 0ah, "Do you wish to continue?", 0
captionC BYTE "Information", 0
infoMsg BYTE "Select Yes to save a backup file "BYTE "before continuing,", 0dh, 0ahBYTE "or click Cancel to stop the operation", 0
captionH BYTE "Cannot View User List", 0
haltMsg BYTE "This operation not supported by your "BYTE "user account.", 0.code
main PROC;显示感叹号图标和OK按钮INVOKE MessageBox, NULL, ADDR warningMsg,ADDR captionW,MB_OK + MB_ICONEXCLAMATION;显示问号图标和Yes/No按钮INVOKE MessageBox, NULL, ADDR questionMsg,ADDR captionQ, MB_YESNO + MB_ICONQUESTION;解释用户点击的按钮cmp eax, IDYES ;点击的是Yes按钮吗?;显示信息图标和Yes/No/Cancel按钮INVOKE MessageBox, NULL, ADDR infoMsg,ADDR captionC, MB_YESNOCANCEL + MB_ICONINFORMATION + MB_DEFBUTTON2;显示停止图标和OK按钮INVOKE MessageBox, NULL, ADDR haltMsg,ADDR captionH, MB_OK + MB_ICONSTOPINVOKE ExitProcess, 0
main ENDP
END main
运行调试:
显示问号图标和Yes/No按钮
显示信息图标和Yes/No/Cancel按钮
显示停止图标和OK按钮