四、實驗結論
1. 實驗任務1
此部分書寫內容:
- 給出程序task1.asm源碼,及,運行截圖
1 assume cs:code, ds:data 2 3 data segment 4 x db 1, 9, 3 5 len1 equ $ - x 6 7 y dw 1, 9, 3 8 len2 equ $ - y 9 data ends 10 11 code segment 12 start: 13 mov ax, data 14 mov ds, ax 15 16 mov si, offset x 17 mov cx, len1 18 mov ah, 2 19 s1:mov dl, [si] 20 or dl, 30h 21 int 21h 22 23 mov dl, ' ' 24 int 21h 25 26 inc si 27 loop s1 28 29 mov ah, 2 30 mov dl, 0ah 31 int 21h 32 33 mov si, offset y 34 mov cx, len2/2 35 mov ah, 2 36 s2:mov dx, [si] 37 or dl, 30h 38 int 21h 39 40 mov dl, ' ' 41 int 21h 42 43 add si, 2 44 loop s2 45 46 mov ah, 4ch 47 int 21h 48 code ends 49 end start
- 回答問題①
① line27, 匯編指令 loop s1 跳轉時,是根據位移量跳轉的。通過debug反匯編,查看其機器碼,分析其跳轉的位移量是多少?(位移量數值以十進制數值回答)從CPU的角度,說明是如何計算得到跳轉后標號s1其后指令的偏移地址的。
0Dh-1Bh=F2h 換算成十進制為-14,即跳轉位移量是-14
從CPU的角度,loop指令后,
跳轉地址=loop指令后第一個字節的地址+(“標號”處的地址-loop指令后的第一個字節的地址 )
簡單計算即:跳轉地址=1Bh+(0Dh-1Bh)=0Dh
在計算機內,偏移量是用八位二進制補碼表示,而補碼的減法又要轉換成加法來計算,實際計算過程如下:
1.首先算出8位偏移量——“標號”處的地址-loop指令后的第一個字節的地址
0000 1101(0D二進制補碼形式)
0001 1011(1B二進制補碼形式)
1110 0101(-1B的二進制補碼形式)
0000 1101-0001 1011=0000 1101+1110 0101=1111 0010(F2的二進制補碼形式)
計算機內,機器碼用補碼表示,可以看到機器碼E2F2,F2則是表示計算出的偏移量,換算成十進制-14。
2.算出偏移量后和loop指令后第一個字節首地址相加:
0001 1011+1111 0010=0000 1101(0D的二進制補碼形式)
- 回答問題②
② line44,匯編指令 loop s2 跳轉時,是根據位移量跳轉的。通過debug反匯編,查看其機器碼,分析其跳轉的位移量是多少?(位移量數值以十進制數值回答)從CPU的角度,說明是如何計算得到跳轉后標號s2其后指令的偏移地址的。
如問題①所示,偏移量=29h-39h=f0h 換算成十進制-16
CPU角度不再贅述。
2. 實驗任務2
此部分書寫內容:
- 給出程序task2.asm源碼
1 assume cs:code, ds:data 2 3 data segment 4 dw 200h, 0h, 230h, 0h 5 data ends 6 7 stack segment 8 db 16 dup(0) 9 stack ends 10 11 code segment 12 start: 13 mov ax, data 14 mov ds, ax 15 16 mov word ptr ds:[0], offset s1 17 mov word ptr ds:[2], offset s2 18 mov ds:[4], cs 19 20 mov ax, stack 21 mov ss, ax 22 mov sp, 16 23 24 call word ptr ds:[0] 25 s1: pop ax 26 27 call dword ptr ds:[2] 28 s2: pop bx 29 pop cx 30 31 mov ah, 4ch 32 int 21h 33 code ends 34 end start
- 給出分析、調試、驗證后,寄存器(ax) = ? (bx) = ? (cx) = ? 附上調試結果界面截圖。
(ax)=0021 (bx)=0026 (cx)=076C
① 根據call指令的跳轉原理,先從理論上分析,程序執行到退出(line31)之前,寄存器(ax) =? 寄存器(bx) = ? 寄存器(cx) = ?
line 13-14 將數據段首地址賦值到ds寄存器
line 16-18 取標號s1的IP存入ds[0]地址,
取標號s2的IP存入下一個字節首地址即ds[2]地址,
取cs段首地址存入下一個字節首地址即ds[4]
line 20-23 將棧段首地址賦值給ss寄存器並且將棧段指針指向棧頂
line 24 將下一條語句IP進棧,並且轉移到ds[0]所指向地址,由前文可知是s1標號地址進棧
line 25 將當前棧頂指針指向數據賦值給bx,由上文可知是s1標號IP地址
line 27 程序繼續向下執行,將下一條語句IP進棧,然后CS進棧,程序跳轉到ds[2]所指向地址即s2標號地址
line 28 將當前棧頂指針指向數據賦值給bx,即當前地址CS值
line 28 將當前棧頂指針指向數據賦值給cx,即當前地址IP值
② 對源程序進行匯編、鏈接,得到可執行程序task2.exe。使用debug調試,觀察、驗證調試
結果與理論分析結果是否一致。
對源程序反匯編可以看到,在line16處標號s1地址是0021,與下文s1標號出位置相符。line17同理。
程序執行前,棧內預存16個字節均為0。
單步執行到line25,棧內數據為:
可以看到0021進棧,同時也因為單步執行保護現場,將下一條命令的CS、IP值也存入棧。
繼續執行到line 27,棧內數據為:
可以看到下一條指令的IP、CS值進棧。
程序繼續執行到line29,可以看到結果如下:
與理論分析結果一致。
3. 實驗任務3
此部分書寫內容:
- 給出程序源碼task3.asm
1 assume cs:code, ds:data 2 data segment 3 x db 99, 72, 85, 63, 89, 97, 55 4 len equ $- x 5 data ends 6 7 code segment 8 start: 9 mov ax, data 10 mov ds, ax 11 mov si, offset x 12 mov cx, len 13 mov bl,10 14 15 s1:mov ah,0 16 mov al, [si] 17 div bl 18 or al,30h 19 mov dh,al;存商 20 or ah,30h 21 mov bh,ah;存余數 22 23 mov ah,2 24 ;輸出商位 25 mov dl,dh 26 int 21h 27 ;輸出余數位 28 mov dl,bh 29 int 21h 30 ;輸出空格 31 mov dl, ' ' 32 int 21h 33 34 inc si 35 loop s1 36 37 mov ah,4ch 38 int 21h 39 code ends 40 end start
- 運行測試截圖
4. 實驗任務4
此部分書寫內容:
- 給出程序源碼task4.asm
1 assume cs:code,ds:data 2 3 data segment 4 str db 'try' 5 len equ $-str 6 data ends 7 8 code segment 9 start: 10 mov ax,data 11 mov ds,ax 12 13 mov ax,0b800h 14 mov es,ax 15 mov bx,0h;第一行 16 17 mov si,offset str 18 mov cx,len 19 s1: 20 mov dl,[si];低位存放字符Ascii碼 21 mov es:[bx],dl 22 mov dl,2h;設置屬性 23 mov es:[bx+1],dl;屬性放入顯示地址 高位地址 24 25 add bx,2 26 inc si 27 loop s1 28 29 mov bx,0f00h;第25行 30 mov cx,len 31 mov si,offset str 32 s2: 33 mov dl,[si];低位存放字符Ascii碼 34 mov es:[bx],dl 35 mov dl,4h;設置屬性 36 mov es:[bx+1],dl;屬性放入顯示地址 高位地址 37 38 add bx,2 39 inc si 40 loop s2 41 42 43 mov ah,4ch 44 int 21h 45 code ends 46 end start
- 運行測試截圖
5. 實驗任務5
此部分書寫內容:
- 給出程序源碼task5.asm
1 assume cs:code,ds:data 2 3 data segment 4 stu_no db '201983290480' 5 len = $-stu_no 6 data ends 7 8 code segment 9 start: 10 mov ax,data 11 mov ds,ax 12 13 mov ax,0b800h 14 mov es,ax 15 16 mov bx,0 17 mov cx,1920 18 call s1 19 20 mov bx,0f00h 21 Tos2: mov cx,34 22 call s2 23 24 mov si,offset stu_no 25 mov cx,len 26 mov bx,0f44h 27 call s3 28 29 mov ah,4ch 30 int 21h 31 32 s1: 33 mov dl,' ' 34 mov es:[bx],dl 35 mov dl,1fh 36 mov es:[bx+1],dl 37 add bx,2 38 loop s1 39 ret 40 41 s2: 42 mov dl,'-' 43 mov es:[bx],dl 44 mov dl,1fh 45 mov es:[bx+1],dl 46 add bx,2 47 loop s2 48 ret 49 50 s3: 51 mov dl,[si] 52 mov es:[bx],dl 53 mov dl,1fh 54 mov es:[bx+1],dl 55 add bx,2 56 inc si 57 cmp cx,1;如果=1,跳轉 58 je Tos2 59 loop s3 60 ret 61 62 code ends 63 end start
- 運行測試截圖
五、實驗總結
知識點歸納:
1.EQU 偽指令把一個符號名稱與一個整數表達式或一個任意文本連接起來,它有 3 種格式:
name EQU expression
name EQU symbol
name EQU <text>
第一種格式中,expression 必須是一個有效整數表達式。第二種格式中,symbol 是一個已存在的符號名稱,已經用 = 或 EQU 定義過了。第三種格式中,任何文本都可以岀現在<...>內。當匯編器在程序后面遇到 name 時,它就用整數值或文本來代替符號。
與 = 偽指令不同,在同一源代碼文件中,用 EQU 定義的符號不能被重新定義。這個限制可以防止現有符號在無意中被賦予新值。
2.$
“$” 是匯編語言中的一個預定義符號,等價於當前正匯編到的段的當前偏移值。例如eg:指令“jmp $+3”中的“$”表示當前這條指令在代碼段中的偏移量。
eg即“jmp $+3”表示要向前跳轉到距離這條指令3個字節的地方。若是“jmp $-3”,則表示要向后跳轉到距離這條指令3個字節的地方。
在匯編中是字符串結束的標志
如:DATA SEGMENT
MES1 'HELLO',0AH,0DH,'$'