組合語言的準備知識 給初次接觸彙編者

2021-08-07 14:03:56 字數 2887 閱讀 6537

彙編指令的運算元可以是記憶體中的資料, 如何讓程式從記憶體中正確取得所需要的資料就是對記憶體的定址。

intel 的cpu 可以工作在兩種定址模式:實模式和保護模式。 前者已經過時,就不講了, windows 現在是32位保護模式的系統, pe 檔案就基本是執行在乙個32位線性位址空間, 所以這裡就只介紹32位線性空間的定址方式。

其實線性位址的概念是很直觀的, 就想象一系列位元組排成一長隊,第乙個位元組編號為0, 第二個編號位1, 。。。。 一直到4294967295(十六進製制ffffffff,這是32位二進位制數所能表達的最大值了)。 這已經有4gb的容量!

足夠容納乙個程式所有的**和資料。 當然, 這並不表示你的機器有那麼多記憶體。 物理記憶體的管理和分配是很複雜的內容, 初學者不必在意, 總之, 從程式本身的角度看, 就好象是在那麼大的記憶體中。

在intel系統中, 記憶體位址總是由"段選擇符:有效位址"的方式給出。段選擇符(selector)存放在某乙個段暫存器中, 有效位址則可由不同的方式給出。

段選擇符通過檢索段描述符確定段的起始位址, 長度(又稱段限制), 粒度, 訪問許可權, 訪問性質等。 先不用深究這些, 只要知道段選擇符可以確定段的性質就行了。 一旦由選擇符確定了段, 有效位址相對於段的基位址開始算。

比如由選擇符1a7選擇的資料段, 其基位址是400000, 把1a7 裝入ds中, 就確定使用該資料段。 ds:0 就指向線性位址400000。

ds:1f5278 就指向線性位址5e5278。 我們在一般情況下, 看不到也不需要看到段的起始位址, 只需要關心在該段中的有效位址就行了。

在32位系統中, 有效位址也是由32位數字表示, 就是說, 只要有乙個段就足以涵蓋4gb線性位址空間, 為什麼還要有不同的段選擇符呢? 正如前面所說的, 這是為了對資料進行不同性質的訪問。 非法的訪問將產生異常中斷, 而這正是保護模式的核心內容, 是構造優先順序和多工系統的基礎。

這裡有涉及到很多深層的東西, 初學者先可不必理會。

有效位址的計算方式是: 基址+間址*比例因子+偏移量。 這些量都是指段內的相對於段起始位址的量度, 和段的起始位址沒有關係。

比如, 基址=100000, 間址=400, 比例因子=4, 偏移量=20000, 則有效位址為:

100000+400*4+20000=100000+1000+20000=121000。 對應的線性位址是400000+121000=521000。 (注意, 都是十六進製制數)。

基址可以放在任何32位通用暫存器中, 間址也可以放在除esp外的任何乙個通用暫存器中。 比例因子可以是1, 2, 4 或8。 偏移量是立即數。

如: [ebp+edx*8+200]就是乙個有效的有效位址表示式。 當然, 多數情況下用不著這麼複雜, 間址,比例因子和偏移量不一定要出現。

記憶體的基本單位是位元組(byte)。 每個位元組是8個二進位制位, 所以每個位元組能表示的最大的數是11111111, 即十進位制的255。 一般來說, 用十六進製制比較方便, 因為每4個二進位制位剛好等於1個十六進製制位, 11111111b = 0xff。

記憶體中的位元組是連續存放的, 兩個位元組構成乙個字(word), 兩個字構成乙個雙字(dword)。 在intel架構中, 採用small endian格式, 即在記憶體中,高位位元組在低位位元組後面。 舉例說明:

十六進製制數803e7d0c, 每兩位是乙個位元組, 在記憶體中的形式是: 0c 7d 3e 80。 在32位暫存器中則是正常形式,如在eax就是803e7d0c。

當我們的形式位址指向這個數的時候,實際上是指向第乙個位元組,即0c。 我們可以指定訪問長度是位元組, 字或者雙字。 假設ds:

[edx]指向第乙個位元組0c:

mov al, byte ptr ds:[edx] ;把位元組0c存入al

mov ax, word ptr ds:[edx] ;把字7d0c存入ax

mov eax, dword ptr ds:[edx] ;把雙字803e7d0c存入eax

在段的屬性中,有乙個就是預設訪問寬度。如果預設訪問寬度為雙字(在32位系統中經常如此),那麼要進行位元組或字的訪問,就必須用byte/word ptr顯式地指明。

預設段選擇:如果指令中只有作為段內偏移的有效位址,而沒有指明在哪乙個段裡的時候,有如下規則:

如果用ebp和esp作為基址或間址,則認為是在ss確定的段中;

其他情況,都認為是在ds確定的段中。

如果想打破這個規則,就必須使用段超越字首。舉例如下:

mov eax, dword ptr [edx] ;預設使用ds,把ds:[edx]指向的雙字送入eax

mov ebx, dword ptr es:[edx] ;使用es:段超越字首,把es:[edx]指向的雙字送入ebx

堆疊:堆疊是一種資料結構,嚴格地應該叫做「棧」。「堆」是另一種類似但不同的結構。ss 和 esp 是intel對棧這種資料結構的硬體支援。

push/pop指令是專門針對棧結構的特定操作。ss指定乙個段為棧段,esp則指出當前的棧頂。push *** 指令作如下操作:

把esp的值減去4;

把***存入ss:[esp]指向的記憶體單元。

這樣,esp的值減小了4,並且ss:[esp]指向新壓入的***。 所以棧是「倒著長」的,從高位址向低位址方向擴充套件。

pop yyy 指令做相反的操作,把ss:[esp]指向的雙字送到yyy指定的暫存器或記憶體單元,然後把esp的值加上4。這時,認為該值已被彈出,不再在棧上了,因為它雖然還暫時存在在原來的棧頂位置,但下乙個push操作就會把它覆蓋。

因此,在棧段中位址低於esp的記憶體單元中的資料均被認為是未定義的。

最後,有乙個要注意的事實是,組合語言是面向機器的,指令和機器碼基本上是一一對應的,所以它們的實現取決於硬體。有些看似合理的指令實際上是不存在的,比如:

mov ds:[edx], ds:[ecx] ;記憶體單元之間不能直接傳送

mov ds, 1a7 ;段暫存器不能直接由立即數賦值

mov eip, 3d4e7 ;不能對指令指標直接操作。

組合語言 第3章巨集組合語言

第三章巨集組合語言 一 巨集組合語言格式 3.1.1 指令語句格式 指令語句的一般格式如下 標號 指令助記符運算元 注釋 1 標號 標號是機器指令語句存放位址的符號表示,代表該指令目標 的第乙個位元組位址,後面必須緊跟冒號 2 指令助記符 指令助記符為語句的核心成分,表示了該語句的操作型別。3 運算...

組合語言總結

一 乙個完整的源程式的結構 乙個源程式一般由若干個段組成,每個分段可以是棧段 資料段和 段。乙個源程式可以有多個棧段 資料段和 段,從語法規則上來看,棧段是有明顯標誌的 段最好的型別為 code 的標記,並用cs作為段界暫存器,只有資料段不要求標誌。完整的源程式的結構一般形式如下 程式名稱 二 源程...

組合語言總結

組合語言學習體會 大一大二期間學寫了一些高階語言,如c語言和c 在對一些實際問題的程式設計處理上使用這些高階語言顯得很是方便。於是在剛接觸這門課的時候就對其實用性產生了懷疑和一些的牴觸情緒。再學習了一段時間後,雖然對一些繁雜的指令有些討厭 但還是硬著頭皮學著下來了 但後來再經過實驗課的學習感覺組合語...