組合語言 王爽第6章

2021-10-22 17:35:17 字數 4307 閱讀 4991

在作業系統的環境中,合法通過作業系統取得的空間都是安全的。程式取得所需要空間的方法有兩種,一是在引導程式的時候為程式分配,二是程式在執行的過程中向系統申請。我們可以用 dw ***xxh來申請記憶體空間,dw的含義是定義字型資料。dw即"define word"的意思。需要注意的是如果我們直接用dw來申請記憶體空間可能會導致直接執行匯程式設計序時出錯,因為資料和指令本質上都是二進位制資料罷了。所以我們需要在源程式中指明程式的入口所在,具體做法就是在指令開始的語句前加個start標記,然後再程式結尾用 end start告訴程式入口到底在哪。

start:

end start

那麼程式時如何知道程式入口在哪的呢 end start偽指令通過把標記轉為偏移位址的方法 將ip改變為程式入口的偏移位址。

所以我們應該考慮設定多個段存放不同的內容。

如果段中的資料佔n個位元組,則程式載入後,該段實際占有的空間為(n/16 +1)*16,因為8086cpu規定乙個段的起始位址為16的倍數,

考慮這樣乙個問題,程式設計計算以下8個資料的和,結果存在ax暫存器中:

0123h、0456h、0789h、0abch、0defg、0fedh、0cbah、0987h

之前我們不關心資料本身,但是現在指定了資料給我們累加所以需要關心資料本身,那麼我們需要給這些資料安排一些儲存空間,我們不能隨意指定儲存空間,最安全的方式是隨著程式的載入讓cpu給我們自動安排儲存空間。當可執行檔案中的程式被加載入記憶體時,這些資料也同時被加載入記憶體中。

具體做法可以看下面的程式:

assume cs:code

code segment

dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h

mov bx,0

mov ax,0

mov cx,8

s:add ax,cs:[bx]

add bx,2

loop s

mov ax,4c00h

int 21h

code ends

end

但是這樣寫的程式會有些問題,第一便是程式結構太混亂,**和資料都放在乙個段中,第二便是如果我們之間執行程式,那麼便會出現問題,因為程式前面是資料而不是指令。

我們有解決方法在源程式中直接指明程式的入口所在,具體做法如下:

assume cs:code

code segment

dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h

start: mov bx,0

mov ax,0

mov cx,8

s:add ax,cs:[bx]

add bx,2

loop s

mov ax,4c00h

int 21h

code ends

end start

我們可以**下end的作用,end除了通知編譯器程式結束外,還可以通知編譯器程式的入口在什麼地方,在上面的程式中我們用end 指令指明了程式的入口在標號start處。

那麼程式時如何知道程式入口在哪的呢 end start偽指令通過把標記轉為偏移位址的方法 將ip改變為程式入口的偏移位址既標記所在**的偏移位址。歸根結底,我們若要cpu從何處開始執行程式,只要在源程式中用「end 標號」指明就可以了。

如果我們要將一些資料按逆序存放,那麼可能我們需要使用到棧。如何在**段中使用棧呢,請看下面的程式:

assume cs:codesg

code segment

dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h

dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

start: mov ax,cs

mov ss,ax

mov sp,30h

mov bx,0

mov cx,8

s: push cs:[bx]

add bx,2

loop s

mov bx,0

mov cx,8

s0: pop cs:[bx]

add bx,2

loop s0

mov ax,4c00h

int 21h

codesg ends

end start

我們在程式中用dw定義了16個為0的字型資料,我們把這16個字型資料所佔的儲存空間當作棧來使用,只要我們讓ss指向字型資料所在段,sp指向棧底便可以了。

assume cs:codesg

codesg segment

dw 0123h,0456h,0789h,0abch,0defh,0cbah,0987h

start:: mov ax,0

mov ds,ax

mov bx,0

mov cx,8

s: mov ax,[bx]

mov cs:[bx],ax

add bx,2

loop s

mov ax,4c00h

int 21h

codesg ends

end start

(2)下面的程式實現依次用記憶體0:0~0:15單元中的內容改寫程式中的資料,資料的傳送用棧來進行。棧空間設定在程式內。完成程式:

assume cs:codesg

codesg segment

dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h

dw 0,0,0,0,0, 0,0,0,0,0,0

start: mov ax,cs

mov ss,ax

mov sp,24h

mov ax,0

mov ds,ax

mov bx,0

mov cx,8

s: push [bx]

pop cs:[bx]

add bx,2

loop s

mov ax,4c00h

int 21h

codesg ends

end start

我們之前在程式中用到了資料和棧,將資料、棧和**都放到乙個段裡面,我們可以把棧空間和資料和指令都放在乙個**塊中,但是這樣使用會帶來一些問題,比如乙個**塊的大小最都為64kb,把所有東西多放到乙個段中會使得程式顯得混亂,而且使用時必須自己小心哪些段是資料段哪些是**段不好分辨。

所以我們應該考慮用多個段來存放資料、**和棧。

我們可以像定義**段一樣來定義資料段和棧。

下面的程式我們將資料、棧和**放到了不同的段中。

assume cs:code,ds:data,ss:stack

data segment

dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h

data ends

stack segment

dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

stack ends

code segment

start: mov ax,stack

mov ss,ax

mov sp,20h

mov sp,20h

mov ax,data

mov ds,ax

mov bx,0

mov cx,8

s:push [bx]

add bx,2

loop s

mov bx,0

mov cx,8

s0:pop [bx]

add bx,2

loop s0

mov ax,4c00h

int 21h

code ends

end start

**段、資料段、棧段完全是我們的安排,如何讓cpu按照我們的這種安排來執行這個程式呢,我們在源程式中使用偽指令assume cs:code,ds:data,ss:stack將cs、ds和ss分別相連但是這樣做並沒有真的讓cpu按照我們的意圖來執行程式。所以我們需要在**段中利用彙編指令設定ds和ss裡的內容將它正確指向相應的段。

下面我們解讀下程式:

程式中有多個段了,如何訪問段中的資料呢,我們可以通過位址來訪問段中的資料,而位址是分為兩部分的既段位址和偏移位址,如何指明要訪問的資料的段位址呢,在程式中,段名就相當於乙個標號,它代表了段位址,所以指令「mov ax,data」的含義就是將data段的段位址送入ax中,偏移位址就是在data段中的偏移位址。

組合語言 王爽

cpu有三條匯流排 位址 資料 控制線 位址匯流排確定儲存單元 控制匯流排傳送指令 資料匯流排 傳輸資料 cpu n個位址線 位址匯流排寬度為n 可以尋找2 n個記憶體單元 儲存單元 0開始編號,乙個儲存單元可以儲存乙個byte 8086cpu有16根位址線 1bit就是一根位址線 注意 儲存器以b...

王爽《組合語言》17章 亂記

上面是有理解,是有點技巧。檢測點17.1 在int 16h中斷例程中,一定有設定if 1的指令。這說話對嗎?試著去找一下16中斷例程彙編 沒有設定if 1的指令吧 這邊仔細考慮一下,程式執行到int 16h的時候,會呼叫16h號中斷例程,在呼叫這個中斷例程的時候,如果是沒有設定if 1,這邊在執行到...

組合語言 王爽 筆記

關於pop的知識 1.出棧後,ss sp指向新的棧頂,pop操作前的棧頂元素中的資料仍然存在,但是,它已不再棧中 2.ss和sp只記錄了棧頂的位址,依靠ss和sp可以保證在入棧和出棧時找到棧頂 3.當棧滿的時候再次使用push指令入棧,棧空的時候再次使用pop指令出棧,都將發生棧頂越界問題,它是非常...