匯編語言-基礎知識


匯編語言-基礎知識

匯編語言的產生

計算機作為一個只能讀懂和執行二進制的東西,在其剛被發明出時,都是用機器語言(01二進制形式表示)來寫入程序,隨着程序越來越復雜,需要更長的組合,不光一個微小的0->1將會導致錯誤,以及過於難記憶與分辨。

隨后找到了一種解決方法,將這些最基礎二進制的指令,用一串字符表示,再由電腦的匯編器(Assembler)將這串字符轉化成二進制機器語言,程序員只需要負責寫匯編指令的源代碼即可。

匯編語言由三部分組成:

  1. 匯編指令(有與其專門對應的機器碼)
  2. 偽指令(由匯編器執行,沒有與其專門對應的機器碼)
  3. 其他符號(如+,-,*,/由匯編器執行,沒有與其專門對應的機器碼)

程序放在哪里

CPU是電腦能夠運算的核心部件,但是想要指揮CPU,需要有指令和數據,儲存運行中程序的指令和數據的就是常說的內存。對於磁盤中的數據, CPU無法直接直行,需要加載到內存中才可以被CPU所使用。

指令和數據一樣,都是一串二進制碼, CPU在工作的時候,會根據需要把它們解釋成指令或者數據,例如1000101111000011這一串二進制碼,它既可以表示數據8BC3_H,又可以表示指令mov ax, bx (8086CPU中)。

對於內存,目前的方式均為以8個bit即1byte為最小的存儲單元(1byte可以保存8位二進制數), CPU想從內存中讀取或者存儲數據,首先需要找到要存在內存的地址,傳達控制信息是讀入還是寫入,以及讀或寫的數據。

在一台計算機中, CPU通過總線,與內存等外部設備進行連接,總線可分為三種,分別是地址總線,數據總線以及控制總線,字如其意,地址總線負責找到要讀取或者儲存的那個位置,數據總線負責數據的傳輸,控制總線負責傳輸要執行的行為是讀入還是寫入。對於8086CPU,他的地址總線有20根,數據總線有16根,也就是說他的尋址空間為2^20Byte,也就是最多可以尋址1MB內存,最多每次只能傳輸16bit(2Byte)的數據。控制總線與上面所說的地址總線和數據總線不同,他只是一個總稱,是計算機不同控制線的集合,控制線分別連接於不同的 外部設備,控制線越多,能控制的外部設備就越多。

內存的地址空間

以典型的8086CPU為例子,他含有20條地址總線,尋址空間最大可達到2^20(00000 -> FFFFF )yte。CPU有20條地址針腳,這些針腳被接在主板上的CPU槽位,通過主板上的地址線連接到各種bios(Base input/output system),和拓展接口。

這些內存地址被分配給不同的功能器件,不同的計算機系統分配內存地址空間 的方式也不同,以8086CPU為例,00000到9FFFF為主存(RAM)空間,A0000到BFFFF為顯存的地址空間,C0000到FFFFF為各類ROM(內容無法更改)地址空間。

拆開CPU

一個典型的CPU內部,由運算器,寄存器和控制器等組成,這些器件之間靠內部總線連接,在上面部分說到的均為外部總線,他們被埋在主板中。簡單來說:運算器負責執行運算操作,寄存器負責儲存運算器要使用的數據,控制器負責控制各種器件協同工作。

對CPU來說,最能直接控制的是它的寄存器,我們通過控制寄存器,來實現對CPU的操作,不同的CPU寄存器的數量與結構不同。8086CPU包含14個寄存器,均為16bit,分別是:

  1. AX,BX,CX,DX,4個通用寄存器,可分為高低8位獨立使用
  2. CS,DS,ES,SS,4個段寄存器
  3. BP,SP,SI,DI,4個指針寄存器
  4. FR,標志寄存器
  5. IP,程序計寄存數器

8086的尋址方式

對於8086CPU它包含20條地址總線,和16條數據總線,如何用16位達到20位的尋址呢?8086CPU采用的是:物理地址=段地址*16+段內偏移地址 的方式。比如說段地址是2000H,段內偏移地址是0016H,它所指向的物理地址就是20000H+0016H=20016H。在8086CPU中執行將斷地址和段內偏移地址轉化成物理地址的器件是地址加法器。

CS段寄存器和IP寄存器

CS和IP可以說是CPU中最重要的兩個寄存器,他們指示出CPU當前要讀取的指令地址, CPU將CS16+IP所指向的內存地址之后的若干個內存單元壓入指令緩存區,通過對指令的解碼來拆分出指令,和指令長度N,IP變為IP+N。(8086CPU作為初代X86架構,是CISC指令集,每個指令及長度不等)*。

如果計算機只能按照IP不僅自增順序執行的話那肯定是不行的,因為很顯然,如果計算機不能循環,那么只能把重復的指令不停的寫,這是非常不聰明的做法。想要實現循環就需要修改CS和IP寄存器中的內容,在之前有過例子,如果我們想將0045H放到寄存器ax,可以用mov ax, 0045H,但是這對CS和IP寄存器是不可以,系統沒有提供直接對他們賦值的操作(mov ip, 0045H ;這樣的是非法操作),改變他們內容的有一套專門的指令,被稱為跳轉指令。

;跳轉指令的用法
jmp 6000H:0984H ;同時修改CS段地址和IP地址 jmp CS段地址:IP地址
jmp 0984H       ;只修改IP地址,直接常數賦值
jmp AX          ;只修改IP地址,把ax的內容賦值給IP 

數據在內存中的存儲

以8086CPU為例,在16位的寄存器,高8位儲存高位字節,低8位儲存低位字節。在內存里,16位的數據,高八位儲存在高地址,低八位儲存在低地址。

mov ax,2000H ;將2000h放入ax
mov ds,ax    ;令ds為2000h
mov [0],8967H;把8967h放入2000:0000的位置
mov [2],3457H;把8967h放入2000:0002的位置

假想內存
|67|    20000
|89|    20001
|57|    20002
|34|    20003

CPU要讀寫一個內存單元的時候, 必須先給出這個內存單元的地址, 在8086PC 中,內存地址由段地址和偏移地址組成。8086CPU中有一個DS寄存器,通常用來存放耍訪問數據的段地址。比如我們要讀取20000H單元的字內容(取一個字,16bit), 可以用如下的程序段進行。

mov ax,2000H ;將2000h放入ax
mov ds,ax    ;令ds為2000h
mov ax,[0]   ;把8967h放入ax的位置

計算機中的棧

棧是一種很常用的數據結構,在計算機系統中通常用於函數嵌套時,保存調用函數的臨時變量,8086 CPU同樣也提供了棧功能,用指令push入棧,pop出棧。

mov ax,2000H ;將2000h放入ax
push ax      ;將ax寄存器中的值壓入棧中
pop bx       ;從棧中取出一個字放入bx中

和上面談到數據如何儲存在內存中,以及指令如何儲存在內存中一樣,棧是通過段寄存器 SS 和寄存器 SP,棧頂的段地址存放在 SS 中,偏移地址存放在 SP 中。任意時刻,SS:SP 指向棧頂元素。push 指令和 pop 指令執行時,CPU 從 SS 和 SP 中得到棧頂的地址。與指令與數據存儲不同,計算機中的棧空間是從地址高位儲存向低位,每次push壓入元素,SP都會自減2,每次POP出棧,SP都會自增2。

mov ax,1000H ;將2000h放入ax
mov ss,ax
mov ax,000FH
mov sp,ax
mov ax,7892H
push ax
pop bx

---------------PUSH前----------------
|  |10007
|  |10008
|  |10009
|  |1000A			SS=1000
|  |1000B			SP=000F
|  |1000C
|  |1000D
|  |1000E
|  |1000F
---------------PUSH后----------------
|  |10007
|  |10008
|  |10009
|  |1000A			SS=1000
|  |1000B			SP=000D
|  |1000C
|92|1000D
|78|1000E
|  |1000F
----------------POP后----------------
|  |10007
|  |10008
|  |10009
|  |1000A			SS=1000
|  |1000B			SP=000F
|  |1000C
|92|1000D
|78|1000E
|  |1000F
------------------------------------

可以注意到在執行PUSH操作時,SP是先自減2,然后再將SS:SP所指的內存地址中放入ax寄存器中的值,依舊遵照高位放在高地址,低位放在低地址。而執行POP操作時,並不改變內存中的值,只是將將SS:SP所指的內存地址中的值放入bx寄存器,隨后SP自增2。

使用棧還有可能出現超出棧空間的問題,比如我們將10000-1000F設為棧地址,當連續10幾次PUSH或POP的時候,SS:SP所指向的位置已經偏移出了棧地址,在8086CPU中並未對棧越界提供保護,只能靠自己小心不要超出。

除了上面用到的對通用寄存器PUSH和POP,還支持對段寄存器的操作,如PUSH DS,以以及對內存數據的操作 PUSH [0].

如何設置棧段:假如說我們希望將10000-1FFFF這塊兒內存設為棧,初始的SS和SP應該設備多少呢?SS毋庸置疑為1000,上面說過SS:SP指所指向的地址是棧頂元素,當有一個16位的數據在棧中時,SP為FFFE,出棧后,SP=SP+2,SP=0,初始的SP應該是0。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM