檢測點:9.1
(1)
assume cs:code
data segment
???????
data ends
code segment
start: mov ax,data
mov ds,ax
mov bx,0
jmp word ptr [bx+1]
mov ax,4c00H
int 21H
code ends
end start
若要使程序中jmp指令執行后,cs:ip指向程序的第一條指令,在data段中應定義哪些數據?
程序分析:
1) 這個指令jmp word ptr [bx+1]是一個段內近轉移,它只是修改了ip的值。它的轉移地址在內存中。明確:[bx+1]在此例子中是只的data段的第二個字節。
2)我們發現ds:bx指向了data段,word ptr [bx+1]指向的是data段中的第二個字節開始的字單元,也就是說它所指向的該字單元的內容。這個內容就是jmp跳轉的偏移地址。
3)word ptr [bx+1]指的是一個字單元,也就是說是2個字節,也就是說在data段中是第2和第3個字節,如果jmp轉移到程序第一條指令,也就是說ip的值應為:00 00即可;我們要保證這二個字節的值是00 00就行。
4)要想jmp跳轉到start標號處,它的ip值是offset start即可(在匯編語言層面我們也不必關心它們代表的具體ip值是多少);也就是說:(ds:[bx+1])==offset start,那么在data段中定義的第二個字必須是offset start。至於offset start具體代表的二進制碼是什么,那是編譯器的事情。
5)第一個字節,你隨意定義成什么都行。
這個結果是多個:
dw 00xxH, offset start ;xx代表任意數值(一個字節的)
講解:此時借用的是00xxH的高位字節值,00
db x,0,0 ;x代表任意數值(一個字節的)
dd 0 ;2個字的內存單元,00 00 00 00
db 3 dup (0)
dw 2 dup (0)
dd 0
簡單來說就是,只要ds:[bx+1]起始地址的兩個字節為0就可以了
(2)程序如下:
assume cs:code
data segment
dd 12345678H
data ends
code segment
start: mov ax,data
mov ds,ax
mov bx,0
mov [bx], offset start
mov [bx+2], code
jmp dword ptr ds:[0]
mov ax,4c00H
int 21H
code ends
end start
補全程序,使cs:ip指向程序的第一條指令。
程序分析:
1)在data段中定義了一個雙字的值,占用4個字節,內存中是12 34 56 78
2)jmp dword ptr ds:[0]代表的含義是,此指令是段間轉移的指令,cs和ip是存儲在一個雙字的單元中,其中高16位存儲的是cs值,低16位存儲的是ip值。
3) [bx]代表了低16位的值==ip。[bx+2]代表了高16位的值==cs。
4)也就是說保證data段中前2個字節是ip的值,第3,4字節是cs的值就可以。
5)答案也就多了。
[bx]==ip
offset start
ptr word 0
0000H
bx
[bx+2] ==cs
cs
code
(3)用Debug查看內存,結果如下:
2000:1000 BE 00 06 00 00 00 ......
則此時,CPU執行指令:
mov ax,2000h
mov es,ax
jmp dword ptr es:[1000h]
程序分析:
1)通過上面二條指令,es指向了段地址是2000H的內存段。
2)jmp dword ptr es:[1000h]指令的含義:是一個段間轉移指令,指令的轉移地址在內存中,該內存單元是一個雙字單元(32位的單元),也就是說在1000H地址開始,低16位存儲的是ip的值,高16位存儲的是cs的值。
3)我們在debug內存存儲顯示中,不難發現,低16位是BE 00,也就是它的值是00BE。高16位是0600,也就是它的值是0006H,得出結論:(cs)= 0006H ,(ip)= 00BEH
檢測點9.2
補全編程,利用jcxz指令,實現在內存2000H段中查找第一個值為0的字節,找到后,將它的偏移地址存儲在dx中。
assume cs:code
code segment
start: mov ax,2000h
mov ds,ax
mov bx,0
s:
jmp short s
ok: mov dx,bx
mov ax ,4c00h
int 21h
code ends
end start
程序分析:
標號s前面是將ds:bx指向了段地址為2000H的內存段。s標號到jmp short s是一個循環(死循環,除非有跳出語句)。
這里我們需要jcxz有條件轉移語句來實現循環的跳出,jcxz的邏輯表達式只有一個就是(cx)=0,想法將cx的內容賦值為ds:bx,也就是說從ds:[0]開始,逐個字節的將單元內容賦值給cx,然后執行jcxz語句。
由於是逐個字節的比較,bx的偏移量應該是以字節為單元。我們使用的cx寄存器是16位的,我們只需要低8位的cl寄存器就可以了。為了保證ch為0,首先必須置零。它們組合在一起就是cx的整體值(dh+dl)
需填充的第一行:mov cl,[bx] ;將2000段內存逐個字節賦值給cl
第二行:mov ch, 0 ;保證高8位為0
第三行:jcxz ok ;判斷cx值,如果cx=0,跳轉到ok標號
第四行:inc bx ;cx!=0,繼續執行jcxz后面的語句。遞增bx,
完整的程序是:
assume cs:code
code segment
start: mov ax,2000h
mov ds,ax
mov bx,0
s: mov cl,[bx]
mov ch, 0
jcxz ok
inc bx
jmp short s
ok: mov dx,bx
mov ax ,4c00h
int 21h
code ends
end start
檢測點9.3
補全編程,利用loop指令,實現在內存2000H段中查找第一個值為0的字節,找到后,將它的偏移地址存儲在dx中。
assume cs:code
code segment
start: mov ax,2000h
mov ds,ax
mov bx,0
s:mov cl,[bx]
mov ch,0
inc cx
inc bx
loop s
ok:dec bx
mov dx,bx
mov ax,4c00h
int 21h
code ends
end start
程序分析:
1)保證這個loop循環的動力是:cx!=0,首先搞清這點。
2) 如果ds:[0]=0情況下。如果我們使用jcxz指令,只有這種情況滿足條件,第一個字節為0.故不能使用jcxz指令。
3)理解loop指令的動作,首先是(cx)=(cx)-1.然后才是跳轉到標號執行。
4)添加inc cx指令
如果第一個字節是0情況,inc cx導致(cx)=1,執行到loop指令時,首先(cx)=(cx)-1,導致(cx)=0,loop順序執行下面的指令(也就是標號ok的指令)。
如果第一個字節非0情況,inc cx導致(cx)>1,執行到loop指令是,首先(cx)=(cx)-1,導致(cx)> 0(不為0),loop跳轉到s標號處執行代碼。
5)答案:inc cx
