1. 程式人生 > >匯編語言第三章總結

匯編語言第三章總結

cti http 錯誤 style 語言 指定 sub tro 字節

在csapp中的新理解:

(1)棧向下增長,棧頂元素的地址是所有棧中元素地址中最低的

(2)因為棧和程序代碼以及其他形式的程序數據都是放在同一內存中,所以程序可以用標準內存尋址方法訪問棧內的任意位置

(3)加載有效地址(load effective address)指令leap實際上是movq指令的變形,它的指令形式是從內存讀數據到寄存器,但實際上它根本就沒有引用內存。

例:leap (%rdx),%rax

它的第一個操作數看上去是一個內存引用,但該指令並不是從指定位置讀入數據,而是將有效地址寫入到目的操作數。這條指令可以為後面的內存引用產生指針。目的操作數必須是一個寄存器。

書上內容的總結:

3.1 內存中字的存儲

  • 字單元:即存放一個字型數據(16位)的內存單元,由兩個地址連續的內存單元組成。
  • 小端法:高地址內存單元中存放字型數據的高位字節,低地址內存單元中存放字型數據的地位字節
  • 低地址的內存單元作為字數據地址
  • N地址字單元:起始地址為N的字單元
  • 任何兩個地址連續的內存單元,N號單元和N+1號單元,可以將他看成兩個內存單元,也可看成一個地址為N的字單元的高位字節單元和地位字節單元

3.2 DS和[address]

  • DS段寄存器:用來存放要訪問數據的段地址
  • ds的賦值:(8086不支持將數據直接送入段寄存器的操作,只好用一個寄存器來進行中轉)
mov bx,1000H
mov ds,bx
  • [...]表示一個內存單元,[...]中的數字表示內存單元的偏移地址
  • 8086CPU自動取ds中的數據為內存單元的段地址

3.3 字的傳送

  • 8086是16位結構,有16根數據線,可以一次性傳送16位的數據,即可以一次性傳送一個字
  • 傳送字型數據的實例:
mov ax,1000h
mov ds,ax        ;改變ds的值
mov ax,[0]       ;將地址為10000的字數據送入ax
mov bx,[2]       ;將地址為10002的字數據送入bx
mov cx,[4]       ;將地址為10004的字數據送入cx

3.4 mov、add、sub指令

  • mov、add、sub指令的總結:

技術分享圖片 技術分享圖片 技術分享圖片

  • 註意事項:

1)指令中兩個操作數的長度要一樣(mov ax,cl mov al,300 這都是錯誤的)

(2)關於立即數:不能作為第一個操作數(目的操作數);在完整的匯編程序中,作第二個操作數(源操作數)時,若最高位是十六進制的a~f,前面要加零

(3)兩個內存單元之間不能直接傳送數據

(4)不能使用mov指令直接改變cs和ip的值

(5)關於段寄存器:兩個段寄存器之間不能直接傳送;不能把常數送入段寄存器

3.5 數據段

  • 可以將一組長度為N(N<=64KB)、地址連續,起始地址為16的倍數的內存單元當作專門存儲數據的內存空間——定義數據段
  • 用ds存放數據段的段地址

3.6 棧

  • 後進先出(LIFO):最後進入這個空間的數據,最先出去
  • 兩個基本操作:入棧(PUSH)和出棧(POP)
push ax  ;表示將寄存器ax中的數據送入棧中
pop ax   ;表示從棧頂取出數據送ax

技術分享圖片

(push 內存單元和pop 內存單元 實際上實現了從內存單元到內存單元的傳送)

  • 註意事項:

(1)操作對象不能是常數

(2)pop 段寄存器 中,段寄存器不能是CS和SS

(3)出棧和入棧以字為單位

3.7 CPU提供的棧機制

  • 段寄存器SS:棧段段寄存器 寄存器SP:棧指針寄存器
  • 棧頂的段地址存放在SS中,偏移地址存放在SP中
  • 任意時刻,SS:SP指向棧頂元素
  • 棧頂的物理地址:SS*16+SP
  • push的執行:(入棧時,棧頂從高地址向低地址方向增長

(1)先SP=SP-2 (2)再將ax中的內容送入SS:SP指向的內存單元處

  • pop的執行:

(1)先將SS:SP指向的內存單元處的數據送入ax中 (2)再SP=SP+2

  • 棧為空時,就相當於棧中唯一的元素出棧,此時棧頂指向的單元的偏移地址為棧最底部的字單元的偏移地址+2
  • pop操作前的棧頂元素,在pop以後,依然存在,但是它已不在棧中,當再次執行push時,它將被覆蓋

3.8 棧頂超界問題

  • 當棧空時,再使用pop出棧
  • 當棧滿時,再使用push入棧
  • 有可能取到棧以外未知的值,若棧段的大小為64KB,會使棧指針重新指向最後進棧的元素的地址,重新又執行指令
  • 棧空間的大小我們要自己管理

3.9 棧段

  • 一個棧段最大可以設為64KB

(push,pop等棧操作,修改的只是SP,也就是說,棧頂的變化範圍最大為:0~FFFFH)

  • 初始化棧段:
;將10000h~1000fh這段空間當作棧
mov ax,1000h
mov ss,ax          ;設置棧的段地址,ss=1000h
mov sp,0010h    ;設置棧頂的偏移地址,因棧為空,所以sp=0010h

3.10 利用棧保護現場和實現數據交換

  • 保護現場:
mov ax,1000h
mov ss,ax
mov sp,0010h   ;初始化棧頂
mov ax,001Ah
mov bx,001Bh
push ax
push bx

pop bx   ;從棧中恢復ax,bx原來的值
pop ax
  • 實現數據交換:
;初始化的棧段和ax,bx的值的代碼同上
push ax
push bx

pop ax   ;當前棧頂是bx中原來的數據:001Bh,此時使ax=001Bh
pop bx   ;此時棧頂使ax中原來的數據:001Ah,此時使bx=001Ah

課後思考:

思考了一下,如何使用棧操作實現字節數據的交換?

我認為首先要把字節數據擴展成字數據,再進行棧操作實現字節數據的交換。

在csapp中介紹了一系列零擴展和符號擴展的指令(AT&T匯編),其中,movzbw則是將做了零擴展的字節傳送到字,也許可以如下進行交換:

movzbw %al,%eax  ;將al中的字節數據做零擴展送到ax中
movzbw %bl,%ebx
pushl %eax
pushl %ebx

popl %eax
popl %ebx

匯編語言第三章總結