本篇記錄《匯編語言:基于X86處理器》第3章 復習題和練習,編程練習的學習。
3.9復習題和練習
3.9.1 簡答題
1.舉例說明三種不同的指令助記符。
答:MOV,ADD和MUL。
2.什么是調用規范?如何在匯編語言聲明中使用它?
答: 在匯編語言中,?調用規范(Calling Convention)? 是定義函數調用過程中參數傳遞、堆棧管理、寄存器使用和返回值傳遞等細節的底層規則集。 例如
; 聲明內存模型和調用規范(如 stdcall)
.model flat, stdcall ; 32 位平坦內存模型 + stdcall 規范:ml-citation{ref="1" data="citationList"}
3.如何在程序中為堆棧預留空間?
答:.stack 4096
4.說明為什么術語匯編器語言不太正確。
答: 術語“匯編器語言”(assembler language)不太正確,因為它混淆了“匯編語言”(assembly language)與“匯編器”(assembler)工具的區別。
5.說明大端序和小端序之間的區別,并在網絡上查找這些術語的起源。
答:大端序和小端序之間的區別是,大小端低位放在高地址,而小端序低位放低地址。
6.為什么在代碼中使用符號常量而不是整數常量?
答:使用符號常量會讓程序更加容易閱讀和維護。設想,如果COUNT在整個程序中出現多次,那么在之后的時間里,程序員就能方便地重新定義它的值。
7.源文件與列表文件的區別是什么?
答:列表文件包含了程序源代碼的副本,再加上行號、偏移地址、翻譯的機器代碼和符號表,適合打印。
8.數據標號與代碼標號的區別是什么?
答:數據標號標記數據位置,代碼標號標記代碼的位置,并且以(:)號結束。
9.(真/假):標識符不能以數字開頭。
答:真。第一個字符必須為字母(A...Z, a...z),下劃線(_)、@ 、?或$。其后的字符也可以是數字。
10.(真/假);十六進制常量可以寫為0x3A。
答:假。匯編代碼里不能寫成0x開頭的十六進制數,這應該寫成3Ah.
11.(真/假):匯編語言偽指令在運行時執行。
答:假。匯編的偽指令在匯編時處理。
12.(真/假):匯編語言偽指令可以寫為大寫字母和小寫字母的任意組合。
答:真
13.說出匯編語言指令的四個基本組成部分。
答:1.標號(可選),2.指令助記符(必需),3.操作數(通常是必需的),4.注釋(可選)
14.(真/假):MOV是指令助記符的例子。
答:真
15.(真/假):代碼標號后面要跟冒號(:),而數據標號則沒有。
答:真
16.給出塊注釋的例子。
答:COMMENT !
....這里是多行注釋
CoMMENT !
17.使用數字地址編寫指令來訪問變量,為什么不是一個好主意?
答:使用數字地址編寫指令來訪問變量有這幾個問題:可維護性差,可讀性低,平臺依賴性強,安全性風險高,調試困難。
18.必須向ExitProcess過程傳遞什么類型的參數?
答:DWORD
19.什么偽指令用來結束子程序?
答:ENDP偽指令用來結束子程序。
20.32位模式下,END偽指令中的標識符有什么用?
答:END偽指令標記一個程序的結束。
21.PROTO偽指令的作用是什么?
答:PROTO
偽指令主要用于?聲明函數原型?,為后續的函數調用提供參數和返回值類型規范
22(真/假):目標文件由鏈接器生成。
答:假,目標文件由匯編器讀取源文件生成。
23.(真/假):列表文件由匯編器生成。
答:真。
24.(真/假):鏈接庫只有在生成可執行文件之前才加到程序中。
答:假。
- 靜態鏈接庫?:在生成可執行文件之前(編譯的鏈接階段)被嵌入到程序中,成為可執行文件的一部分,程序可獨立運行。
- ?動態鏈接庫?:在程序運行時(如加載或調用時)才被鏈接和加載到內存中,而非在生成可執行文件之前添加。動態鏈接庫允許內存共享和按需加載,避免了靜態鏈接的冗余拷貝問題
25.哪個數據偽指令定義32位有符號整數變量?
答:SDWORD,例如:val SDWORD ?
26.哪個數據偽指令定義16位有符號整數變量?
答:WORD,例如:val WORD ?
27.哪個數據偽指令定義64位無符號整數變量?
答:SQWORD,例如:val SQWORD ?
28.哪個數據偽指令定義8位有符號整數變量?
答:QWORD,例如:val QWORD ?
29.哪個數據偽指令定義10字節壓縮BCD變量?
答:TBYTE, 例如:val TBYTE ?
3.9.2 算法基礎
答:val1 EQU 25
val2 EQU 0001 1001b
val3 EQU 31o
val4 EQU 19h
2.通過實驗和錯誤,找出一個程序是否能有多個代碼段和數據段。
答:通過實現,一個程序可以有多個代碼段和數據段,例如:
;3.9.2_2.asm 第3章 3.9.2算法基礎 第2題 驗證.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.data
sum DWORD 0.data
res SDWORD 0.code
start PROCmov bx, 7add bx, 8
start ENDP.code
main PROCmov eax, 5add eax, 6mov sum, eax INVOKE ExitProcess, 0
main ENDP
END main
3.編寫數據定義,把一個雙字按大端序存放在內存中。
;3.9.2_3.asm 第3章 3.9.2算法基礎 第3題 編寫數據定義,把一個雙字按大端序存放在內存中。.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.data
;big_endian_value db 0xA1, 0xB2, 0xC3, 0xD4
LittleEndianDWORD DWORD 12345678h.code
main PROCmov eax, dword ptr [LittleEndianDWORD] ; 加載原始值mov ebx, 0 ; 初始化目標值mov edx, eax ; 提取最低有效字節shl edx, 24 ; 移動到最高有效字節位置or ebx, edx ; 合并到目標值 此時bx=78000000hmov edx, 0mov dl, byte ptr [LittleEndianDWORD+1] ;edx=00000056hshl edx,16 ;edx=005600hor ebx,edx ;ebx=78560000hmov edx, 0mov dl, byte ptr [littleEndianDWORD+2] ;edx=00000034hshl edx, 8 ;edx=00003400hor ebx, edx ;ebx=78563400hmov edx, 0mov dl, byte ptr [littleEndianDWORD+3] ;edx=00000012hor ebx, edx ;ebx=78563412hmov dword ptr [littleEndianDWORD], ebx ; 將結果存儲到內存地址 littleEndianDWORDmov eax, dword ptr [LittleEndianDWORD] ; 查看修改后的值 INVOKE ExitProcess, 0
main ENDP
END main
運行調試:調試前:
調試后:
內存中的數據由12345678h轉換成78563412h
4.試發現用 DWORD 類型定義一個變量時,是否能向其賦予負數值。這說明了匯編器類型檢查的什么問題?
;3.9.2_4.asm 第3章 3.9.2 算法基礎 第4題 試發現用 DWORD 類型定義一個變量時,是否能向其賦予負數值。這說明了匯編器類型檢查的什么問題?.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.data
sum DWORD -3 ;初始化為一個負數.code
main PROCmov eax, 5add eax, 6mov sum, eax INVOKE ExitProcess, 0
main ENDP
END main
運行調試:
說明匯編器檢查數據是,如果是負數會轉成補碼。
5.編寫一個程序,包含兩條指令:(1)EAX寄存器加5;(2)EDX寄存器加5。生成列表文件并檢查由匯編器生成的機器代碼。發現這兩條指令的不同之處了嗎?如果有,是什么?
;3.9.2_5.asm 第3章 3.9.2 算法基礎 第5題 編寫一個程序,包含兩條指令:(1)EAX寄存器加5;(2)EDX寄存器加5。
;生成列表文件并檢查由匯編器生成的機器代碼。發現這兩條指令的不同之處了嗎?如果有,是什么?.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.data
sum DWORD 0
sum2 DWORD 0.code
main PROCmov eax, 0add eax, 5mov sum, eax mov edx, 0add edx, 5mov sum2, edxINVOKE ExitProcess, 0
main ENDP
END main
列表文件
Microsoft (R) Macro Assembler Version 14.41.34120.0 06/20/25 16:23:54
3.9.2_5.asm Page 1 - 1;3.9.2_5.asm 第3章 3.9.2 算法基礎 第5題 編寫一個程序,包含兩條指令:(1)EAX寄存器加5;(2)EDX寄存器加5。;生成列表文件并檢查由匯編器生成的機器代碼。發現這兩條指令的不同之處了嗎?如果有,是什么?.386.model flat, stdcall.stack 4096ExitProcess PROTO, dwExitCode:DWORD00000000 .data00000000 00000000 sum DWORD 000000004 00000000 sum2 DWORD 000000000 .code 00000000 main PROC00000000 B8 00000000 mov eax, 000000005 83 C0 05 add eax, 500000008 A3 00000000 R mov sum, eax 0000000D BA 00000000 mov edx, 000000012 83 C2 05 add edx, 500000015 89 15 00000004 R mov sum2, edxINVOKE ExitProcess, 00000001B 6A 00 * push +000000000h0000001D E8 00000000 E * call ExitProcess00000022 main ENDPEND mainMicrosoft (R) Macro Assembler Version 14.41.34120.0 06/20/25 16:23:54
3.9.2_5.asm Symbols 2 - 1Segments and Groups:N a m e Size Length Align Combine ClassFLAT . . . . . . . . . . . . . . GROUP
STACK . . . . . . . . . . . . . 32 Bit 00001000 DWord Stack 'STACK'
_DATA . . . . . . . . . . . . . 32 Bit 00000008 DWord Public 'DATA'
_TEXT . . . . . . . . . . . . . 32 Bit 00000022 DWord Public 'CODE' Procedures, parameters, and locals:N a m e Type Value AttrExitProcess . . . . . . . . . . P Near 00000000 FLAT Length= 00000000 External STDCALL
main . . . . . . . . . . . . . . P Near 00000000 _TEXT Length= 00000022 Public STDCALLSymbols:N a m e Type Value Attr@CodeSize . . . . . . . . . . . Number 00000000h
@DataSize . . . . . . . . . . . Number 00000000h
@Interface . . . . . . . . . . . Number 00000003h
@Model . . . . . . . . . . . . . Number 00000007h
@code . . . . . . . . . . . . . Text _TEXT
@data . . . . . . . . . . . . . Text FLAT
@fardata? . . . . . . . . . . . Text FLAT
@fardata . . . . . . . . . . . . Text FLAT
@stack . . . . . . . . . . . . . Text FLAT
sum2 . . . . . . . . . . . . . . DWord 00000004 _DATA
sum . . . . . . . . . . . . . . DWord 00000000 _DATA 0 Warnings0 Errors
同樣是加法操作,生成的機器碼不一樣
6.假設有數值456789ABh,按小端序列出其字節內容。
答:小端序是低位存放在低地址,因此列出字節的內容為:0A8h, 89h, 67h, 45h.
7.聲明一個數組,其中包含 120個未初始化無符號雙字數值。
答:val sdword 120 dup(?)
8.聲明一個字節數組,并將其初始化為字母表的前5個字母。
答:myArray byte 'a', 'b', 'c', 'd', 'e'
9.聲明一個 32 位有符號整數變量,并初始化為盡可能小的十進制負數。(提示:參閱第1 章的整數范圍。
答:minNegative32 DWORD -2147483648 ; 聲明并初始化為最小的 32 位有符號整數
10.聲明一個 16 位無符號整數變量 wArray,使其具有 3 個初始值。
答:wArray SWORD 10, 20, 30
11.聲明一個字符串變量,包含你最喜歡顏色的名字,并將其初始化為空字節結束的字符串。
答:myColor BYTE "blue", 0
12.聲明一個未初始化數組dArray,包含50個有符號雙字。
答:myArray DWORD 50 dup(?)
13.聲明一個字符串變量,包含單詞“TEST”并重復500次。
答:myString BYTE 500 dup("TEST")
14.聲明一個數組 bArray,包含 20個無符號字節,并將其所有元素都初始化為 0。
答:bArray SBYTE 20 dup(0)
15.寫出下述雙字變量在內存中的字節序列(從最低字節到最高字節);
val1 DWORD 87654321h
答:x86處理器在內存中按小端序存放數據,因此從最低字節到最高字節的序列為:21h, 43h, 65h, 87h。
3.10 編程練習
*1.整數表達式的計算
參考 3.2 節的程序 AddTwo,編寫程序,利用寄存器計算表達式:A-(A+B)-(C-D)。整數值分配給寄存器 EAX、EBX、ECX 和EDX。
;3.10_1.asm 第3章 編程練習 *1.整數表達式的計算
;參考 3.2 節的程序 AddTwo,編寫程序,利用寄存器計算表達式:A-(A+B)-(C-D)。
;整數值分配給寄存器 EAX、EBX、ECX 和EDX。.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.data
sum DWORD 0.code
main PROCmov eax, 10mov ebx, 5mov ecx, 6mov edx, 15add ebx, eax ;ebx = (A + B)sub eax, ebx ;eax = A - (A + B)sub ecx, edx ;ecx = C - D sub eax, ecx ;eax = A - (A + B) - (C - D)mov sum, eaxINVOKE ExitProcess, 0
main ENDP
END main
結果:10-(10+5)-(6-15)= 4
運行結果:
*2.符號整數常量
編寫程序,為一周七天定義符號常量。創建一個數組變量,用這些符號常量作為其初始值。
;3.10_2.asm 第3章 編程練習 *2.符號整數常量
;編寫程序,為一周七天定義符號常量。創建一個數組變量,用這些符號常量作為其初始值。 .386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.data
Monday EQU 1 ;星期一
Tuesday EQU 2 ;星期二
Wednesday EQU 3 ;星期三
Thursday EQU 4 ;星期四
Friday EQU 5 ;星期五
Saturday EQU 6 ;星期六
Sumday EQU 7 ;星期日WorkdayArray DWORD Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sumday.code
main PROCmov eax, [WorkdayArray] mov ebx, [WorkdayArray+4] ;一個數占32位,4個字節,如果WorkdayArray定義的是BYTE,這里都是加1mov ecx, [WorkdayArray+8]mov edx, [WorkdayArray+12]INVOKE ExitProcess, 0
main ENDP
END main
運行測試:
**3.數據定義
編寫程序,對 3.4 節表 3-2 中列出的每一個數據類型進行定義,并將每個變量都初始化為與其類型一致的數值。
;3.10_3.asm 第3章 數據定義
;編寫程序,對 3.4 節表 3-2 中列出的每一個數據類型進行定義,
;并將每個變量都初始化為與其類型一致的數值。.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode:DWORD.data
val1 BYTE 0 ;最小的無符號數,8位無符號整數,B代表字節
val2 SBYTE -128 ;最小的有符號數,8位有符號整數,S代表有符號
val3 WORD 0 ;最小的無符號數,16位無符號整數
val4 SWORD -32768 ;最小的有符號數,16位有符號整數
val5 DWORD 0 ;最小的無符號數,32位無符號整數,D代表雙(字)
val6 SDWORD -2147483648 ;最小的有符號數,32位有符號整數,SD代表有符號雙(字)
val7 FWORD 1234567890h ;48位整數(保護模式中的遠指針)
val8 QWORD 1234567812345678h ;64位整數,Q代表四(字)
val9 TBYTE 11223344556677889900h;80位(10字節)整數,T代表10字節
val10 REAL4 5.6 ;32位(4字節)IEEE短實數
val11 REAL8 3.2E-260 ;64位(8字節)IEEE長實數
val12 REAL10 4.6E+4096 ;80位(10字節)IEEE擴展實數.code
main PROCmov eax, val5mov ebx, val6INVOKE ExitProcess, 0
main ENDP
END main
運行調試:
*4.符號文本常量
編寫程序,定義幾個字符串文本(引號之間的字符)的符號名稱,并將每個符號名稱都用于變量定義。
;3.10_4.asm 第3章 *4.符號文本常量
;編寫程序,定義幾個字符串文本(引號之間的字符)的符號名稱,并將每個符號名稱都用于變量定義。.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
constStr1 TEXTEQU <"this is a string",0>
myString1 BYTE constStr1
constStr2 TEXTEQU <"aaaa is a string",0>
myString2 BYTE constStr2.code
main PROCmov eax, 5mov ebx, DWORD PTR [myString2]INVOKE ExitProcess, 0
main ENDP
END main
運行調試:
*****5.AddTwoSum 的列表文件
生成 AddTwoSum 程序的列表文件,為每條指令的機器代碼字節編寫說明。某些字節值的含義可能需要猜測。
;3.10_5.asm 第3章 *****5.AddTwoSum 的列表文件
;生成 AddTwoSum 程序的列表文件,為每條指令的機器代碼字節編寫說明。
;某些字節值的含義可能需要猜測。.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD.data
sum DWORD 0.code
main PROC mov eax, 5add eax, 6mov sum, eaxINVOKE ExitProcess,0
main ENDP
END main
列表文件:
Microsoft (R) Macro Assembler Version 14.41.34120.0 06/20/25 23:38:06
3.10_5.asm Page 1 - 1;3.10_5.asm 第3章 *****5.AddTwoSum 的列表文件;生成 AddTwoSum 程序的列表文件,為每條指令的機器代碼字節編寫說明。;某些字節值的含義可能需要猜測。.386 ; 32位指令集標識符(機器碼無直接對應).model flat,stdcall ; 內存模式聲明(偽指令無機器碼).stack 4096 ; 棧空間聲明(偽指令無機器碼)ExitProcess PROTO,dwExitCode:DWORD ; 函數原型聲明(偽指令)00000000 .data00000000 00000000 sum DWORD 0 ; 變量定義(機器碼: 00 00 00 00)00000000 .code00000000 main PROC 00000000 B8 00000005 mov eax, 5 ; B8: MOV指令 opcode, 05 00 00 00: 立即數5(小端序)00000005 83 C0 06 add eax, 6 ; 83 C0: ADD指令 opcode+modrm, 06: 立即數600000008 A3 00000000 R mov sum, eax ; A3: MOV指令 opcode, 00 00 00 00: sum地址(需鏈接時確定)INVOKE ExitProcess,00000000D 6A 00 * push +000000000h ; 6A: PUSH立即數 opcode0000000F E8 00000000 E * call ExitProcess ; E8: CALL相對地址(需重定位)00000014 main ENDPEND mainMicrosoft (R) Macro Assembler Version 14.41.34120.0 06/20/25 23:38:06
3.10_5.asm Symbols 2 - 1Segments and Groups:N a m e Size Length Align Combine ClassFLAT . . . . . . . . . . . . . . GROUP
STACK . . . . . . . . . . . . . 32 Bit 00001000 DWord Stack 'STACK'
_DATA . . . . . . . . . . . . . 32 Bit 00000004 DWord Public 'DATA'
_TEXT . . . . . . . . . . . . . 32 Bit 00000014 DWord Public 'CODE' Procedures, parameters, and locals:N a m e Type Value AttrExitProcess . . . . . . . . . . P Near 00000000 FLAT Length= 00000000 External STDCALL
main . . . . . . . . . . . . . . P Near 00000000 _TEXT Length= 00000014 Public STDCALLSymbols:N a m e Type Value Attr@CodeSize . . . . . . . . . . . Number 00000000h
@DataSize . . . . . . . . . . . Number 00000000h
@Interface . . . . . . . . . . . Number 00000003h
@Model . . . . . . . . . . . . . Number 00000007h
@code . . . . . . . . . . . . . Text _TEXT
@data . . . . . . . . . . . . . Text FLAT
@fardata? . . . . . . . . . . . Text FLAT
@fardata . . . . . . . . . . . . Text FLAT
@stack . . . . . . . . . . . . . Text FLAT
sum . . . . . . . . . . . . . . DWord 00000000 _DATA 0 Warnings0 Errors
調試對比猜想:
***6.AddVariables 程序
修改 AddVariables 程序使其使用 64 位變量。描述匯編器產生的語法錯誤,并說明為解決這些錯誤采取的措施。
答:修改相應變量后,編譯報錯:
根據錯誤提示,修改相關代碼:
去掉這3行
.386
.model flat, stdcall
.stack 4096
把 ExitProcess PROTO, dwExitCode:DWORD 改成 ExitProcess PROTO
把 INVOKE ExitProcess, 0 改成 call ExitProcess
把 END main 改成 END
修改后,完整的代碼如下
;3.10_6_AddVariables.asm ***6.AddVariables 程序
;修改 AddVariables 程序使其使用 64 位變量。描述匯編器產生的語法錯誤,并說明為解決這些錯誤采取的措施。ExitProcess PROTO.data
firstval QWORD 20002000h
secondval QWORD 11111111h
thirdval QWORD 22222222h
sum QWORD 0.code
main PROCmov rax, firstvaladd rax, secondvaladd rax, thirdvalmov sum, raxcall ExitProcess
main ENDP
END
運行調試: