新知識點
定義存放字串的資料區
當傳送 文本和顯示他們的指令過多時 便會顯得臃腫
所以定義一個存放字串的資料區,
當我們要使用他們的時候再用指令顯示出來
這樣負責顯示的指令和顯示的內容就無關了.
注意:換行可以使用 續行符‘\’,
但我們通常在下一行加上一個 db 而不是使用‘\’
如下所示
mytext db 'L',0x07,'a',0x07,'b',0x07,'e',\
0x07,'l',0x07,' ',0x07,'o',0x07,
db 'f',0x07,'f',0x07,'s',0x07,'e',0x07,'t',0x07,':',0x07
設定資料段基地址
mov ax,0x7c0
mov ds,ax

資料串傳送指令movsb,movsw和標志暫存器FLAGS
注:8086以上處理器可以按雙字及更多進行操作
在8086處理器中
movsb:按位元組(byte)只能執行或傳送一次
movsw:按字(word)只能執行或傳送一次
要重復操作要加上rep前綴 如 rep movsw
rep重復的次數由暫存器cx指定
-------------------------------------------------------------
16位標志暫存器FLAGS:
按位:
|15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
| | | | | |DF| | |SF|ZF| | | | | | |
DF: 方向標志
SF: 符號位
ZF: 零標志
(判斷最近一次邏輯運算的結果是零或非零,如果是非零這一位為零反之為1)
傳送前的準備作業:
DS:SI 原始資料串的段地址:偏移地址
ES:DI 目標位置的段地址:偏移地址
正向傳送時,每進行一次movsb或movsw SI和DI的值自動加上傳送的位元組數
自動指向下一個傳送的位置
反向傳送時,每進行一次movsb或movsw SI和DI的值自動減去傳送的位元組數
自動指向下一個傳送的位置
-------------------------------------------------------------
cld: 方向標志DF清零指令,將flags暫存器DF標志清零以指示傳送為正方向
std: 與cld相反

$ 和 $$
這兩個標記為NASM編譯器特有的
$: 當前行的匯編地址
$$: 當前程式段的匯編地址
loop指令
用法:
loop 標號
如:
loop digit
loop指令編譯之后操作碼為E2 后面是8位相對偏移量
所以標號的位置不能太遠
執行程序:
將cx減一,cx不為0,轉到標號位置執行,
如為0,則順序執行后面的指令
inc和dec指令
每個暫存器的用途參見計算機暫存器分類簡介
在8086處理器中要使用暫存器提供偏移地址只能使用
BX SI DI BP 其他的都是非法的
inc:加一操作
用法:inc r/m
如:inc al 或 inc byte [0x2002]
dec:減一操作
用法:dec r/m
如:dec di 或 dec byte [0x2002]
代碼
jmp start
mytext db 'L',0x07,'a',0x07,'b',0x07,'e',0x07,'l',0x07,' ',0x07,'o',0x07,
db 'f',0x07,'f',0x07,'s',0x07,'e',0x07,'t',0x07,':',0x07
start:
mov ax,0x7c00 ;//設定資料段基地址,此處ax只是一個介質
;//(主引導扇區加載的邏輯段地址為0x7c0)
mov ds,ax
mov ax,0xb800 ;//設定附加段基地址
mov es,ax
cld
;//方向標志清零指令,將flags暫存器DF標志清零以指示傳送為正方向(與其相反的std)
mov si,mytext ;//由于設定了資料段基地址 mytext匯編地址為偏移地址
mov di,0 ;//文本的傳送是從顯存的起始位置開始的 即es附加段,di為偏移地址即為0
mov cx,(start-mytext)/2
;//設定cx,cx的值為rep的次數實際上等于13
rep movsw ;//按字操作
mov ax,number
mov bx,ax ;//得到標號所代表的匯編地址
mov cx,5 ;//loop回圈次數
mov si,10 ;//除數10傳送到暫存器si
digit:
xor dx,dx ;//dx清零
div si
mov [bx],dl ;//訪問的偏移地址來自bx暫存器
inc bx ;//[bx]指向下一個0的地址
loop digit
;//開始顯示各個數位
mov cx,5
show:
dec bx
;//在上一部分操作中最后我們把dx指向number的最后一個0處
;//所以顯示時從尾部開始顯示
mov al,[bx]
add al,0x30 ;//轉換數字為字符編碼
mov ah,04 ;//黑底紅字
mov [es:di],ax ;//前面已將顯存地址傳給es且di位置為最后一個字符屬性的位置
add di,2 ;//一個字符一個屬性共一個字
loop show
jmp $ ;//跳到本行
number db 0,0,0,0,0 ;//用于臨時存放余數
times 510-($-$$) db 0
db 0x55, 0xaa
使用bochs除錯
我們設定斷點來到指令’cld‘,指令r觀察暫存器si和di內容

多次執行單步執行命令s后發現的確是按我們的邏輯進行

注:eflags為32位標志暫存器 如圖小寫代表為0 大寫為1
基址變址尋址和條件轉移指令
在8086處理器中
只允許以下幾種基址變址組合:
bx + si
bx + di
bp + si
bp + di
標志暫存器FLAGS的第7位SF符號位
如果最近一次邏輯運算結果二進制最高位為1則將SF置為1反之置為0
(不一定是符號位處理器不管你是不是符號位只管最高位)
jns指令跳轉指令:
如果標志暫存器FLAGS的第7位SF位為0就跳轉為1就不跳轉
我們改寫loop digit后的代碼
;//開始顯示各個數位
mov bx,number
mov si,4
show:
mov al,[bx+si] ;//si的作用相當于索引
;//所以顯示時從尾部開始顯示
add al,0x30 ;//轉換數字為字符編碼
mov ah,04 ;//黑底紅字
mov [es:di],ax ;//前面已將顯存地址傳給es且di位置為最后一個字符屬性的位置
add di,2 ;//一個字符一個屬性共一個字
dec si ;//最后一次si為-1
jns show ;//基于SF位決定是否跳轉
jmp $ ;//跳到本行
number db 0,0,0,0,0
times 510-($-$$) db 0
db 0x55, 0xaa
第一次執行 dec si 后 si 為3 二進制為:0000 0000 0000 0011 SF位為0
最后一次執行 dec si 后 si 為-1 二進制為:1111 1111 1111 1111 SF為1
除錯bochs虛擬機
設定斷點到0x7c58 鍵入info eflags命令 可以看到位sf為0

多次執行c命令 可以看到最后SF為1

最后我們在vbox上直接顯示結果

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/283094.html
標籤:其他
