匯編語言第三章總結
在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,1000Hmov 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
匯編語言第三章總結