1. 程式人生 > >組合語言——1-6章

組合語言——1-6章

彙編指令和機器指令一一對應,有編譯器翻譯識別,計算機無法直接識別

一個儲存單元等於1位元組 1位元組等於8位

1KB=1024Byte(位元組)

1Byte=8bit(位)

CPU中,指令和資料都是二進位制形式存在

磁碟的資料,CPU無法直接使用,只能讀到記憶體中,才能被CPU使用

CPU可以使用的資料,是在儲存器中儲存器被劃分為很多儲存單元,以0開始編號,

一個單元儲存一位元組,即8位

暫存器是一種比記憶體和二級快取更低一層,更接近CPU的儲存器

CPU進行資料讀寫時,必須和外部晶片進行3類資訊交換:

1.地址資訊 即地址匯流排

2.控制資訊 即控制匯流排

3.資料資訊 即資料匯流排

CPU多少根地址匯流排,就代表這個CPU地址匯流排的寬度為多少

就是說cpu定址範圍是2的N次方個儲存單元

資料匯流排N根,即一次可傳送N位二進位制數即N位,例:

16位資料匯流排,可傳輸16位二進位制,即2個位元組

控制匯流排決定CPU對外部器件的控制能力

儲存器分為:隨即儲存器RAM和只讀儲存器ROM

隨即儲存器,斷電後資料丟失,如記憶體,視訊記憶體

只讀儲存器,關機後記憶體不消失,如主機板,網絡卡的BIOS

CPU對各類儲存器只看做一個邏輯的儲存器,每個物理上的儲存器在邏輯上佔有一段地址段,

CPU對其段進行操作,就是對物理儲存進行操作

8086 CPU的記憶體地址分配:

00000—9FFFF為主儲存器

A0000—BFFFF為視訊記憶體地址空間

C0000—FFFFF為各類ROM地址空間

第一章檢測點:

1.

定址能力為8kb,即為8,反向推論,8kb=8192位元組,CPU定址公式:

N=地址匯流排寬度

M=定址大小(單位位元組)

M=2的N次方

這裡M=8192,所以開平方,N就是13,2的13次方為8192位元組

2.

1kb=1024b,因為1個儲存單元大小為1B,所以1kb儲存器可以為1024個儲存單元

編號從零開始,即編號為0——1023

3.

1kb的儲存器為1024個儲存單元,每個儲存單元1Byte,1Byte=8bit,即10248=8192bit位 即1024byte位元組

4.

1GB=1024MB

1MB=1024KB

1KB=1024Byte

5.

地址匯流排寬度為16,那麼定址能力就是2的16次方,65536個儲存單元,即65536Byte,即64kb

6.

1Byte=8bit 8根資料匯流排,一次傳輸8bit,即1Byte

7.

8086為16根資料匯流排,每次讀取16bit,即2位元組,1024位元組,需讀取512次

8.

儲存器中,資料和指令都是二進位制形式存在



第二章:

CPU主要有有運算器,控制器,暫存器,三部分組成

8086 CPU有14個暫存器,如AX,BX,CX,DX,SI。。。。

8086所有暫存器都是16位的,可以存放2個Byte即位元組,16位二進位制數

通用暫存器為4個,是:AX,BX,CX,DX

為了相容8088 CPU,所有通用暫存器,可以單獨分為兩個暫存器使用,即高地址和低地址,如AX可分,AH,AL

一個位元組,即8bit,可以存在8位暫存器中

一個字 word 等於2個位元組,即16bit

在寫一條彙編指令或暫存器時不區分大小寫

mov ax,10和MOV,AX,10 一樣

mov ax,18 意思是把18送入暫存器ax

mov ah,18 意思是把18送入暫存器ah

mov ax,bx 意思是把bx的值輸入暫存器ax中

add ax,5  意思是將暫存器ax的值加上5

add ax,bx 意思是吧bx和ax相加,值存入ax中

H為16進位制的意思

ax=0000H

bx=0000H



8086 16位 一個暫存器能儲存16個2進位制數

例如:al和ah沒有關係,當ah的值超出8位時,CPU就會丟棄資料,當al的值超出8位時,CPU不會丟棄資料

但不會進位到ah暫存器中

彙編指令進行操作時,要注意雙方位數和資料大小溢位問題

檢測點2.1詳解:

mov ax,62627           ax=F4A3H

記住,這裡的62627是十進位制,轉換為十六進位制後,就是F4A3

mov ah,31h             ax=31A3H

意思,是把31值送入ah中,並覆蓋,即31A3H

mov al,23h             ax=3123h

意思,是把23值送入al中,並覆蓋,即3123H

add,ax,ax             ax=6246H

意思就是把AX加上AX在送入AX中,和C語言的a+=a;一個意思

mox bx,826ch           bx=826ch

意思就是把826ch的值送入bx中

mov cx,ax              cx=6246h

意思就是把ax的值覆蓋cx中

mov ax,bx              ax=826ch

意思就是把bx的值覆蓋ax中

add ax,bx              ax=04d8h

意思是把bx和ax的值相加,並送入ax中,結果為104d8,

超過8086 CPU的十六位儲存大小,所以拋棄1,即得04d8h

mov al,bh              ax=0482h

意思是把bh的值覆蓋al中,bh為82,ax為04d8,覆蓋得0482h

mov ah,bl              ax=6c82H

意思是把bl的值覆蓋ah中,bl為6c,ax為0482,覆蓋得6c82h

add ah,ah              ax=d882h

意思是把ah加上ah,值放入ah中,即6c+6c=d8,即得d882h

add al,6               ax=d888h

意思把6加入al中,al值為82,82+6即得88,當然是十六進位制演算法,最後得d888h

add al,al              ax=d810h

意思是把al加上al的值放入al中,值為110,超出al8位暫存器的大小,故只留10

結果為d810h

mov ax,cx              ax=6246h

此題作者怎麼想得,最後問個最簡單的,呵呵

對CPU而言,所有記憶體單元構成的儲存空間是一個一維線性空間

CPU實體地址送入暫存器的只能是一個實體地址,如:0010

8086為16位CPU,16為CPU有以下特性

運算器一次最多處理16位資料

暫存器的寬度為16位

暫存器和運算器的通路為16位

8086有20位地址匯流排,即可傳送20位資料,定址能力為:2的20次方位元組,即1MB

但8086為16位結構,每次處理,儲存,傳送都為16位,即定址能力為2的16次方個位元組,即64kb

為了不浪費使用吧,8086採用內部2個16位暫存器合成一個20位實體地址就行傳輸

具體為:

實體地址=段地址

16+偏移地址,注意,這裡16是16進位制,和10進位制10的意義一樣

例如:

段地址為1230,偏移地址為00c8 那經過運算就是123c8的20位實體地址

具體:123016=12300

然後:12300+00c8=123c8

十進位制理解就是:

例如:12812這個數由

1000和2812組成

1000
10=10000

任何10000+2812=12812

自己慢慢理解理解就可以了!

段地址的概念,是來自CPU,來分段管理記憶體!

10000H——100FFH組成一個段

基礎地址為10000H

段地址為1000H

大小為:

100H

這裡的段地址大小,很多人都暈,確實難理解,想通就好

100H的來源:

100FFH—10000H=FFH

這個FFH,轉換為10進位制就255,而計算機是從零開始,那麼就有0—255,256個數

再把256轉換為16進位制,那就是100,即大小為100H,這是最笨的方法,但初學者好理解些,呵呵

一個段地址必然是16的倍數

偏移地址為16位,16位定址能力為64kb,一個段的最大為64kb

監測點2.2:

1.

00010H—1000FH

0010H-1000FH 有答案是這個,不知道0010H行不行,大家研究!

2.

20000H

sa16+0000=20000

sa
16+ffff=20000

最大2000

最小1001 1000不行,最後只能1001,大家測試

8086 CPU通過段地址和偏移合成物理地址來定址,所以段地址肯定有暫存器,

那就是:CS DS,SS,ES 4個,和前面我們說的4個通用暫存器:AX,BX,CX,DX一樣

CS和IP這兩個暫存器,CS為程式碼段暫存器,IP為指令指標暫存器,8086會從

CS16+IP單元開始讀取指令

關鍵要理解8086CPU的工作過程:

1.從CS:IP指向德記憶體單元讀取指令,指令進入緩衝器

2.IP=IP+所讀指令的長度,從而指向下一條指令

3.執行指令,轉到步驟一,重複這個過程

記住:8086CPU加電覆位後,CS和IP的設定為CS=FFFFH,IP=0000H

即CPU從記憶體FFFF0H單元中讀取執行,也是8086CPU的第一條執行指令



debug進入方式:開始—執行——debug XP系統下



r檢視當前暫存器值,修改

d檢視記憶體地址段的內容

e修改記憶體地址中的內容

u將記憶體地址段的內容翻譯為指令

t執行開始CS:IP處的指令

a輸入彙編指令

實驗任務,根據各自電腦不同,初始值可能不同!大家自己測試,很簡單!





第三章:

CPU用16位暫存器儲存一個字

1字=2位元組

一個記憶體單元為1位元組,所以一個字要用兩個連續的記憶體單元

存放,高地址存放高位元組,低地址存放低位元組

DS暫存器用來儲存訪問資料的段地址

8086CPU位16位結構,即一次傳送16位資料,也就是1個字

在程式設計時,我們可以將一組記憶體單元定義為一個段,這個完全取決於我們

但段的長度必須<=64kb的連續地址,且起始地址為16的倍數

如:123B0H—123B9H

這個段記憶體的段地址就是1230H,長度就是10個位元組了,5個字

棧的定義,入棧PUSH 出棧POP

入棧就是將一個新的資料放入棧頂,出棧就是從棧頂取出一個數據

規律是:後進先出

如: POP ax 就是將棧頂部的資料讀取到AX中

相反,PUSH AX 就是將AX的資料讀取到棧頂

CPU是通過段暫存器SS和暫存器SP來確定棧的位置和棧頂得位置

SP裡面就是棧頂的地址,CPU執行就是從SS:IP處執行

棧的溢位問題,我們要根據位元組的需求,進了用到最大的棧空間以

防止入棧超界,和出棧超界

我們可以將一段記憶體定義為一個段,這個段可以我們位元組安排

如:

定義一個段存放資料,那就是資料段  就是通過DS暫存器控制段地址

如果存放程式碼,那就是程式碼段   就是通過CS暫存器控制段地址,IP暫存器

控制偏移地址

同樣如果當做棧,那就是棧段  就是通過SS暫存器控制段地址,用SP暫存器

控制棧頂的單元地址



      第三章概念性東西很少,很多都是上級實驗的所有課後題我就不寫了,大家按照

課後要求,一步一步來,肯定都能做出來!

第四章:

呵呵,本章還是比較簡單的,主要介紹下程式的執行步驟

一個組合語言寫的程式要經過以下的步驟

第一步:編寫彙編源程式

我喜歡用記事本,方便些,新手可以用支援高亮顯示的編輯器,會更好

第二步:是對生成的源程度,.ASM的檔案進行編譯,產生目標檔案

第三步:就是連線,對目標檔案進行連線,生成可執行程式,如:.EXE的

這個過程主要完成對源程式的彙編指令到機器碼的轉變,以後相關描述等

彙編指令分為:偽指令和彙編指令,和標號,其實標號和偽指令和劃分一起

例如:

assume cs:qq

qq segment

MOV,AX,1111H

MOV BX,2222H

ADD AX,BX

MOV AX,4C00H

INT 21H

qq ends

end

這裡面的偽指令如: qq segment… qq ends 如同C語言的{}一樣 ,代表一段組合語言的

開始和結束,偽指令對CPU來說是不認識的,他只是由編譯器認識和執行的

qq segment 代表定義一個段qq,這個段開始

而qq ends 就是結束這個段

如:上面的assume 和end 拿end來說,就是說明這個程式的結束,如果不加,

那麼程式將找不到結束點,後果自己試驗

標號的話,如上面的qq,他代表一個地址,做為一個段的名稱

如果寫一個1+1的程式,那就是

assume cs:qq

qq segment

MOV,AX,1

ADD AX,ax

MOV AX,4C00H

INT 21H

qq ends

end

注意H代表十六進位制,大小寫不區分,程式最後的

mov ax,4c00H

int 21H

他就是固定的意思,就是實現程式執行完成後,返回,注意,他是彙編指令

一個組合語言的編寫,編譯,連線,執行,這個的話,大家建議先勇masm這個完成

前期很簡單,不要開始就用整合環境,這樣能更深入瞭解程式的整個過程,具體過程,

大家看書,有圖,一步一步來

說下組合語言從寫道執行的過程

1.首先先寫一段彙編指令,工具不限,確保正確

2.生成.asm檔案

3.然後拿masm進行編譯,得到目標檔案.obj

4.然後用link進行連線,得到.exe可執行檔案

5.然後載入,載入到記憶體以後,CPU進行讀寫執行,然後返回到相應的裝置上

有時為了解決問題,可以使用debug來跟蹤程式的執行,看到每一步執行後,CPU的結果

好了,重點就是這麼多,具體對某一點仔細理解,都是日後的重點

第五章:

首先大家一定要分清,debug命令和編譯指令,具體看第四章debug命令,進行對比

開始:

mov [0],ax

意思是把 ax的內容送入段地址為ds,偏移地址為0的地址中

送入單元長度,由物件暫存器確定,如ax就是16位,2位元組

al就是8位,1位元組

[bx] 和上面基本一樣,不同點就是他得地址的偏移地址在bx暫存器中

loop指令,迴圈命令,大致步驟

首先進行loop迴圈標記

然後根據cx的值判斷迴圈次數,每次-1,cx為0時,則向下執行

如:計算2的10次方:

assume cs:qq

qq segment

   mov ax,2

   mov cx,9

q:add ax,ax

   loop q

   mov ax,4c00h

   int 21h

qq ends

end

上面例子中,標號就是q,cx=9,就是迴圈10次執行 add,AX,AX

彙編原程式中,資料不能以字母開頭,如FFFFH,要寫為:0FFFFH

段字首的意思:

例如:

mov ax,ds:[bx]

就是把一個單元地址的內容送人ax中,長度為2位元組

地址的段地址在ds中,偏移地址在bx中

這個ds可以換成其他暫存器,如ss,cs

mov ax,ds:[0]

和上面一樣,唯一不同的就是偏移地址是0

上述的ds,就段的字首,簡稱段字首

一段安全的空間:意思就是在一個一維性的記憶體空間中,有一些地址是系統或其他

重要程式使用的,這些地方我們如果不小心修改將會引起很多錯誤,所以我們要使用一段安全的地址空間

在dos方式下,一般:0:200——0:2ff這個256個地址是安全的地址空間。

其實從第五章開始,以後的課程就很少概念性的東西了,大部分需要大家親自反覆的操作實驗,熟練掌握

第六章:

一般來說,在作業系統環境下,程式所獲得的空間都是安全的

包含多段的程度中,

dw 即定義8個字型資料,即8
2=16個位元組

db 就是定義位元組嘍

程式中在結尾處,end 後門的標號,對應在程式中的標號位置,就是

程式的入口,也就是第一條執行的命令

將多資料,程式碼,棧,放入不同的段,是為了為了理清思路,便於理解

其次為了解決8086一個段最大64kb的問題

定義一個段:

如:assume cs:ps,ds:pp,ss:oo



其實第六章的內容,就是包含了前面幾章的內容,也就是一個混合應用,

具體的細節不多說,拿一個例項來說,我將對例項進行剖析:

assume cs:qq, ds:ww,ss,ee  (把qq與cs扯上關係,其他兩個一樣,不多說)

ww segment

      dw 1111h,2222h,3333h,4444h,5555h

ww ends   (上面一段聲明瞭資料內容,參照dw的意思,大家都明白了吧)

ee segment

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

ee ends(上面就是定義出多個棧地址空間)

qq segment

link:mov ax,ee

      mov ss,ax

      mov sp,20h(上面是把ee段當做棧空間,設定ss:sp為:ee:20)      

      mov ax,ww

      mov ds,ax(希望用ds:bx訪問ww中的資料,ds指向ww段)

mov bx,0(設定第一個ds:bx的訪問ww段單元)

mov cx,5(設定迴圈次數)

s:push[bx]

   add bx,2

   loop s(將ww段資料依次入棧)

   mov bx,0

   mov cx,5

   s1:pop[]

   add bx,2

   loop s1(和上面相反,依次出棧)

   mov ax,4c00H

   int 21h

qq ends

end link (設定程式的入口)

(注意:

1.8086 CPU不允許直接將資料直接送入一個段暫存器

2.上述的,qq,ww,ee,s,s1,link,都是自己定義的

3.上面註釋方式不對,是為了說明問題而寫,大家注意

4.所以的程式碼段,棧,資料段,都是我們人為定義的)