匯編語(yǔ)言知多少(二): 指令使用

上篇文章中我們具體介紹了匯編語(yǔ)言的一些背景, 以及 8086匯編 工作原理, 在這篇文章中具體講解8086匯編指令, 看完這個(gè)有助于學(xué)習(xí)ARM匯編. 文章后面手把手教你怎么利用 MASM 編譯執(zhí)行程序.

轉(zhuǎn)移指令

8086 提供了一個(gè) mov 指令, 傳送指令, 可以用來(lái)修改大部分寄存器的值,
CPU 從何處執(zhí)行指令是由 CS, IP 中的內(nèi)容決定的, 我們可以通過(guò) Jmp 這類(lèi)轉(zhuǎn)移指令, 來(lái)修改 CS, IP 的值來(lái)控制 CPU 執(zhí)行目標(biāo)指令.

    1. jmp 2AE3: 3, 執(zhí)行后: CS=2AE3H, IP= 0003H, CPU將從 2AE33H 處讀取指令.
      jmp 段地址: 偏移地址 : 用指令中的段地址, 來(lái)修改 CS 的值, 用偏移地址來(lái)修改 IP 的值.
    1. jmp ax, 指令執(zhí)行前: ax= 1000H, CS=2000H. IP=0003H
      指令執(zhí)行后: ax= 1000H, CS=2000H. IP=0003H
    • jmp 某一合法寄存器 : 用寄存器中的值來(lái)修改IP.
    • jmp ax, 在含義上類(lèi)似, mov IP, ax.
    1. jmp 0100H, 直接改變 IP 的值.

DS和[address]

CPU 要讀寫(xiě)一個(gè)內(nèi)存單元時(shí), 必須要先指出內(nèi)存單元的地址, 在 8086 中, 內(nèi)存地址(物理地址) 由 段地址 和 偏移地址 組成.

  • 8086 中有一個(gè) DS段寄存器, 通常用來(lái)存放要訪問(wèn)的數(shù)據(jù)的段地址

對(duì) al寄存器 寫(xiě)數(shù)據(jù)

mov bx, 1000H
mov ds, bx
mov al, [0]
  1. 上面3條指令的作用將10000H(1000:0)中的內(nèi)存數(shù)據(jù)賦值到 al寄存器 中.
  2. mov al,[address] 的意思將 DS:address 中的內(nèi)存數(shù)據(jù)賦值到 al寄存器 中.
  3. 由于 al 是8位寄存器,所以是將一個(gè)字節(jié)的數(shù)據(jù)賦值給 al寄存器.
  4. 8086不支持將數(shù)據(jù)直接送入到 段寄存器, 不能直接 mov ds, 1000H

對(duì) al寄存器 讀數(shù)據(jù)

mov bx, 1000H
mov ds, bx
mov [0], al

大端模式和小端模式

  • 大端模式(Big Endian): 指數(shù)據(jù)的高字節(jié)保存在內(nèi)存的低地址中,而數(shù)據(jù)的低字節(jié)保存在內(nèi)存的高地址中 ( 高低\低高 )
  • 小端模式(Little Endian): 指數(shù)據(jù)的高字節(jié)保存在內(nèi)存的高地址中,而數(shù)據(jù)的低字節(jié)保存在內(nèi)存的低地址中 ( 高高\(yùn)低低 )

大端模式: PowerPC, IBM, Sun
小端模式: x86, DEC.
ARM 既可以工作在大端模式, 也可以工作在小端模式.

mov 指令, add 指令, sub 指令

add , sub 和 mov 一樣, 都有兩個(gè)操作對(duì)象.

mov 寄存器, 數(shù)據(jù)  比如: mov ax, 8
mov 寄存器, 寄存器  比如: mov ax, bx
mov 寄存器, 內(nèi)存單元  比如: mov ax, [0]
mov 內(nèi)存單元, 寄存器  比如: mov [0], ax

是一種具有特殊訪問(wèn)方式的空間 (后進(jìn)先出, LIFO, Last In First Out)

  • 8086 會(huì)將 CS 作為代碼段的段地址评肆,將 CS:IP 指向的指令作為下一條需要取出執(zhí)行的指令
  • 8086 會(huì)將 DS 作為數(shù)據(jù)段的段地址定嗓,mov ax,[address] 就是取出 DS:address 的內(nèi)存數(shù)據(jù)放到 ax寄存器 中.
  • 8086 會(huì)將 SS 作為棧段的段地址闷祥,任意時(shí)刻笨觅,SS:SP 指向棧頂元素.
  • 8086 提供了 PUSH (入棧) 和 POP (出棧) 指令來(lái)操作 棧段 的數(shù)據(jù).
  • 比如 push ax 是將 ax的數(shù)據(jù)入棧申窘,pop ax 是將棧頂?shù)臄?shù)據(jù)送入ax

push ax

  1. SP = SP - 2, SS: SP 指向當(dāng)前棧頂前面的單元, 以 當(dāng)前棧頂 前面的單元為新的棧頂.
  2. 將 ax 中的內(nèi)容送入到 SS: SP 指向的內(nèi)存單元處, SS:SP 此時(shí)指向新棧頂.


pop ax

  1. 將 SS: SP 指向的內(nèi)存單元處的數(shù)據(jù)送入 ax 中.
  2. SP = SP + 2, SS: SP 指向當(dāng)前棧頂下面的單元, 以 當(dāng)前棧頂 下面的單元為新的棧頂.

值得注意的是, 隨著 push 和 pop 的操作, 原來(lái)內(nèi)存單元上的數(shù)據(jù)并沒(méi)有被清楚掉, 而是隨著 SP 的變化, 稱為垃圾數(shù)據(jù), 當(dāng)有新的數(shù)據(jù) push 進(jìn)來(lái)時(shí), 原數(shù)據(jù)會(huì)被覆蓋.


對(duì)于上面這種 10000H ~ 1000FH 這段椩曳海空間, 初始狀態(tài)為空, 此時(shí) SS = 1000H, SP應(yīng)該為 0010H, 因?yàn)闂十籍?諘r(shí), SS: SP 指向棧空間最高地址單元的下一個(gè)單元.

push 與pop

push 寄存器  ; 將一個(gè)寄存器中的數(shù)據(jù)入棧
pop 寄存器   ; 出棧, 用一個(gè)寄存器接收出棧的數(shù)據(jù)
push 內(nèi)存單元 ; 將一個(gè)內(nèi)存單元處的字入棧
pop 內(nèi)存單元  ; 出棧, 用一個(gè)內(nèi)存字單元接收出棧的數(shù)據(jù)
mov ax, 1000H
mov ds, ax   ; 內(nèi)存單元的段地址放在 ds 中
push [0]     ; 將 1000: 0 處的字壓入棧.
pop [2]      ; 出棧, 出棧的數(shù)據(jù)送入 1000: 2處

將 10000H ~ 1000FH 這段空間當(dāng)做棧, 此時(shí)為空棧, 設(shè)置 AX = 001AH, BX = 001BH, 利用棧, 交換 AX 和 BX 的數(shù)據(jù).

mov ax, 1000H
mov ss, ax
mov sp, 0010H ; 棿浇福空時(shí), SP 指向棧頂(椆蠢酰空間的最高地址)單元的下一單元

mov ax, 001AH
mov bx, 001BH

push ax
push bx

pop ax
pop bx

小結(jié):

  • 對(duì)于 數(shù)據(jù)段 , 將它的段地址放在 DS 中, 用 mov, add, sub 等訪問(wèn)內(nèi)存單元的指令時(shí), CPU 就將我們定義的數(shù)據(jù)段中的內(nèi)容當(dāng)做數(shù)據(jù)來(lái)訪問(wèn).
  • 對(duì)于 代碼段 , 將它的段地址放在 CS 中, 將段中的第一條指令的偏移地址放在 IP 中, 這樣 CPU 就將執(zhí)行我們定義的代碼段中的指令.
  • 對(duì)于 棧段 , 將它的段地址放在 SS 中, 將棧頂單元的偏移地址放在 SP 中, 這樣 CPU 在需要進(jìn)行 pop / push 等操作時(shí), 就將我們定義的棧段當(dāng)做棧空間來(lái)用.

終于可以開(kāi)始我們的第一個(gè)完整的匯編程序.

MASM (Microsoft Macro Assembler) 是微軟公司微處理器家族開(kāi)發(fā)的匯編開(kāi)發(fā)環(huán)境, 因?yàn)镸ASM工具 是一個(gè)exe的執(zhí)行文件, 所以為了在 Mac OS 上能使用它, 我們需要借助DOSBox.

DOSBox 是一款模擬器軟件, 為本地的 DOS 程序提供執(zhí)行環(huán)境, (DOS指 磁盤(pán)操作系統(tǒng)), 最早期是為了運(yùn)行計(jì)算機(jī)程序設(shè)計(jì), 目前已經(jīng)支持 Windows, Mac OS 多個(gè)平臺(tái), 簡(jiǎn)單來(lái)說(shuō), 它就是一個(gè)計(jì)算機(jī)的模擬, 我們可以在官網(wǎng)下載最新的 DOSBox.

使用 DOSBox

  1. 雙擊打開(kāi)程序, 默認(rèn)在 Z 盤(pán), 可以使用 dir, 查看系統(tǒng)的情況


  2. 為了方便處理, 在 用戶目錄下 新建一個(gè) LCDOSBox 文件夾, 用來(lái)存儲(chǔ)我們編寫(xiě)的代碼文件, 以及 MASM 工具. 這些工具可以在這里下載.

  3. 在 DOSBox 界面掛載我們的文件目錄, 這里 c 指的是 虛擬c盤(pán), ~/LCDOSBox 指虛擬的文件夾位置.

Z:\> mount c ~/LCDOSBox
  1. 進(jìn)入 c 盤(pán), 直接執(zhí)行當(dāng)前目錄中的 debug.exe 程序.
Z:\> c:

C:\> debug

這里的 -r 指令, 用來(lái)顯示寄存器的內(nèi)容.

  1. 編寫(xiě)我們的asm文件.
; 數(shù)據(jù)段
data segment
    string db 'Hello World! $'
data ends


; 代碼段
code segment
    assume cs: code, ds: data  ; 聲明代碼段和數(shù)據(jù)段

start:

    mov ax, data
    mov ds, ax    ; 設(shè)置 ds 為數(shù)據(jù)段
    
    mov ah, 9h    ; 功能號(hào) 9h 代表在屏幕顯示字符串
    ;mov dx, offset string ; ds: dx 代表字符串的地址
    lea dx, string ; 同上 lea指令的功能是將存儲(chǔ)單元的有效地址(偏移地址)傳送到目的操作數(shù)

    int 21h       ; 執(zhí)行 DOS 系統(tǒng)功能調(diào)用

    mov ah, 4ch   ; 功能號(hào) 4ch 代表程序退出
    int 21h
    
code ends

end start         ; 遇到 end 停止編譯 開(kāi)始執(zhí)行 start 里的內(nèi)容

對(duì)于這個(gè)程序, 有幾點(diǎn)我需要作說(shuō)明

  • 匯編程序由 2 類(lèi)指令組成
    • 匯編指令: 如 mov, add, sub 等, 它是有對(duì)應(yīng)的機(jī)器指令, 可以被編譯器編譯成機(jī)器指令, 被 CPU 執(zhí)行.
    • 偽指令: 如 assume, segment, ends, end 等, 他們沒(méi)ban有對(duì)應(yīng)的機(jī)器指令, 由編譯器解析, 最終不被 CPU 執(zhí)行.
  • 注釋符號(hào)用 ;
  • assume: 聲明 code段 是 cs 段, data段是 ds 段.
  • segment 和 ends 的作用是定義一個(gè)段, segment 代表一個(gè)段的開(kāi)始, ends代表一個(gè)段的結(jié)束.
  • int 21h, 用于執(zhí)行 DOS 系統(tǒng)功能調(diào)用, 這是一個(gè)中斷.
  1. 編譯并鏈接生成 exe 文件.


    image.png

如果你在利用 DOSBox 執(zhí)行程序的時(shí)候碰到 Unable to open input file:xxx.asm 的錯(cuò)誤, 但是代碼文件確實(shí)存在. 可能是由于文件的名字系統(tǒng)的差別造成, 你可以這樣做

  • 命令行操作是支持 tab + Hellox, 這樣會(huì)快速補(bǔ)全文件名, 即使補(bǔ)全的名字和你實(shí)際的文件名不一致, 也沒(méi)關(guān)系, 實(shí)際上系統(tǒng)是認(rèn)可的.
  • 而且, 文件名最好是英文, 而且是小寫(xiě), 這樣 通過(guò) tap 鍵 補(bǔ)全的文件名通常不會(huì)錯(cuò).

如果你在執(zhí)行的過(guò)程中碰到你需要輸入的, 直接 enter 鍵 跳過(guò).

  1. 調(diào)試程序
C:\> debug
  • -u 將內(nèi)存中的機(jī)器指令翻譯成匯編指令.
    • -u 段地址: 偏移地址 可以將內(nèi)存中內(nèi)容翻譯成對(duì)應(yīng)的匯編指令.
  • -r 查看修改, CPU寄存器中的內(nèi)容.
    • -r 寄存器的名稱, 可以修改寄存器的值.
  • -g [value] 執(zhí)行到目標(biāo)行盏筐,如:-g f 為執(zhí)行到第16行, 注意查看此時(shí) CS: IP 的值的變化
  • -t [value] 執(zhí)行機(jī)器指令 如:-t 2 為執(zhí)行2條指令后停下來(lái). 默認(rèn)執(zhí)行一條指令. 注意查看此時(shí)CS: IP 的值的變化.
  • -d 查看內(nèi)存中的內(nèi)容
    • d 段地址: 偏移地址 , 查看特定位置的內(nèi)存數(shù)據(jù)
    • d 段地址: 起始偏移地址 結(jié)尾偏移地址 , 查看特定范圍內(nèi)的地址
  • -e 段地址: 偏移地址 數(shù)據(jù)串 修改特定位置的內(nèi)存數(shù)據(jù).
  • -a, -a 段地址: 偏移地址 可以從某位置開(kāi)始寫(xiě)入?yún)R編指令.
  • -q 退出debug

中斷

中斷是由于軟件的或硬件的信號(hào)围俘,使得CPU暫停當(dāng)前的任務(wù),轉(zhuǎn)而去執(zhí)行另一段子程序.

  • 硬中斷(外中斷), 由外部設(shè)備(比如網(wǎng)卡琢融、硬盤(pán))隨機(jī)引發(fā)的界牡,比如當(dāng)網(wǎng)卡收到數(shù)據(jù)包的時(shí)候,就會(huì)發(fā)出一個(gè)中斷.
  • 軟中斷(內(nèi)中斷), 由執(zhí)行中斷指令產(chǎn)生的漾抬,可以通過(guò)程序控制觸發(fā).
  • 從本質(zhì)上來(lái)講, 中斷 是一種電信號(hào)宿亡,當(dāng)設(shè)備有某種事件發(fā)生時(shí),它就會(huì)產(chǎn)生中斷纳令,通過(guò)總線把電信號(hào)發(fā)送給中斷控制器挽荠。如果中斷的線是激活的,中斷控制器就把電信號(hào)發(fā)送給處理器的某個(gè)特定引腳泊碑。處理器于是立即停止自己正在做的事坤按,跳到中斷處理程序的入口點(diǎn)毯欣,進(jìn)行中斷處理.
  • 在匯編程序中, 可以通過(guò) int n 產(chǎn)生中斷.
    • n 是中斷碼馒过,內(nèi)存中有一張中斷向量表,用來(lái)存放中斷碼對(duì)應(yīng)中斷處理程序的入口地址
    • CPU在接收到中斷信號(hào)后酗钞,暫停當(dāng)前正在執(zhí)行的程序腹忽,跳轉(zhuǎn)到中斷碼對(duì)應(yīng)的中斷向量表地址處,去執(zhí)行中斷處理程序.
    • 常見(jiàn)中斷包含以下: int 10h 用于執(zhí)行BIOS中斷, int 3 是“斷點(diǎn)中斷”砚作,用于調(diào)試程序, int 21h 用于執(zhí)行DOS系統(tǒng)功能調(diào)用窘奏,AH 寄存器存儲(chǔ)功能號(hào).

指令要處理的數(shù)據(jù)長(zhǎng)度

8086指令能處理2種 尺寸的數(shù)據(jù), byte , word, 還有其他指令集中的 dword , 通過(guò)這來(lái)指明需要操作內(nèi)存的數(shù)據(jù)長(zhǎng)度.

  • mov byte ptr [0], 20H , 將 20H 放入 0 位置內(nèi)存的 字節(jié) 單元, 占 1 個(gè)字節(jié).
  • mov word ptr [0] 20H, 將 20H 放入 0 位置內(nèi)存的 單元, 占 2 個(gè)字節(jié).
  • mov dword ptr [0] 20H, 將 20H 放入 0 位置內(nèi)存的內(nèi)存單元, 占 4 個(gè)字節(jié).

比如 pop [0], push [0] 操作的數(shù)據(jù)長(zhǎng)度默認(rèn)只能是 2 個(gè)字節(jié).

參考
維基百科-DOSBox
如何用MASM5.0

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市葫录,隨后出現(xiàn)的幾起案子着裹,更是在濱河造成了極大的恐慌,老刑警劉巖米同,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件骇扇,死亡現(xiàn)場(chǎng)離奇詭異摔竿,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)少孝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)继低,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人稍走,你說(shuō)我怎么就攤上這事袁翁。” “怎么了婿脸?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵粱胜,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我狐树,道長(zhǎng)年柠,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任褪迟,我火速辦了婚禮冗恨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘味赃。我一直安慰自己掀抹,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布心俗。 她就那樣靜靜地躺著傲武,像睡著了一般。 火紅的嫁衣襯著肌膚如雪城榛。 梳的紋絲不亂的頭發(fā)上揪利,一...
    開(kāi)封第一講書(shū)人閱讀 51,604評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音狠持,去河邊找鬼疟位。 笑死,一個(gè)胖子當(dāng)著我的面吹牛喘垂,可吹牛的內(nèi)容都是我干的甜刻。 我是一名探鬼主播,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼正勒,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼得院!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起章贞,我...
    開(kāi)封第一講書(shū)人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤祥绞,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蜕径,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡怪蔑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了丧荐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缆瓣。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖虹统,靈堂內(nèi)的尸體忽然破棺而出弓坞,到底是詐尸還是另有隱情,我是刑警寧澤车荔,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布渡冻,位于F島的核電站,受9級(jí)特大地震影響忧便,放射性物質(zhì)發(fā)生泄漏族吻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一珠增、第九天 我趴在偏房一處隱蔽的房頂上張望超歌。 院中可真熱鬧,春花似錦蒂教、人聲如沸巍举。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)懊悯。三九已至,卻和暖如春梦皮,著一層夾襖步出監(jiān)牢的瞬間炭分,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工剑肯, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留捧毛,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓退子,卻偏偏與公主長(zhǎng)得像岖妄,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子寂祥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容