32位x86处理器编程导入——《x86汇编语言:从实模式到保护模式》读书笔记08
在說正題之前,我們先看2個(gè)概念。
1.指令集架構(gòu)(ISA)
ISA 的全稱是 instruction set architecture,中文就是指令集架構(gòu),是指對(duì)程序員實(shí)際“可見”的指令集,包含了程序員編寫一個(gè)能正確運(yùn)行的二進(jìn)制機(jī)器語言程序的所有信息,涉及到指令、 I/O 設(shè)備等。例如 Intel 的 IA-32、Intel 64、ARM 的 ARMv7、ARMv8 等等。
2.微架構(gòu)
微架構(gòu)(Microarchitecture)又稱為微體系結(jié)構(gòu)/微處理器體系結(jié)構(gòu)。是將一種給定的指令集架構(gòu)在處理器中執(zhí)行的方法。一種給定的指令集可以在不同的微架構(gòu)中執(zhí)行。 [1]
?
需要說明的是:
微架構(gòu)與指令集是兩個(gè)概念:指令集是CPU選擇的語言,而微架構(gòu)是具體的實(shí)現(xiàn).[2]
ARM公司將自己研發(fā)的指令集叫做ARM指令集,同時(shí)它還研發(fā)具體的微架構(gòu)(如Cortex系列)并對(duì)外授權(quán)。但是,一款CPU使用了ARM指令集不等于它就使用了ARM研發(fā)的微架構(gòu)。Intel、高通、蘋果、Nvidia等廠商都自行開發(fā)了兼容ARM指令集的微架構(gòu),同時(shí)還有許多廠商使用ARM開發(fā)的微架構(gòu)來制造CPU。通常,業(yè)界認(rèn)為只有具備獨(dú)立的微架構(gòu)研發(fā)能力的企業(yè)才算具備了CPU研發(fā)能力,而是否使用自行研發(fā)的指令集則無關(guān)緊要。廠商研發(fā)CPU時(shí)并不需要獲得指令集授權(quán)就可以獲得指令集的相關(guān)資料與規(guī)范,指令集本身的技術(shù)含量并不是很高。獲得授權(quán)主要是為了避免法律問題。然而微架構(gòu)的設(shè)計(jì)細(xì)節(jié)是各家廠商絕對(duì)保密的,而且由于其技術(shù)復(fù)雜,即便獲得相應(yīng)文檔也難以山寨。 [2]
如前所述,僅僅從ARM購(gòu)買微架構(gòu)來組裝芯片的廠商是不能被稱作CPU研發(fā)企業(yè)的,這些芯片也不能被稱為“xx廠商研發(fā)的CPU”.典型如華為的海思920、三星Exynos 5430,只能說是“使用ARM Cortex-A15核心的芯片”。但是如果一款兼容ARM指令集的芯片使用了廠商自主研發(fā)的微架構(gòu),情況就不同了。高通驍龍800、蘋果A7就是這樣的例子——它們分別使用了高通、蘋果自主研發(fā)的CPU. [2]
3. 32位寄存器
(1)通用寄存器
在16位處理器內(nèi),有8個(gè)通用寄存器,分別是AX,BX,CX,DX,SI,DI,BP,SP. 其中,前4個(gè)還可以拆分成2個(gè)獨(dú)立的寄存器來用。32處理器在16位處理器的基礎(chǔ)上,擴(kuò)展了這8個(gè)通用寄存器的長(zhǎng)度,使之達(dá)到32位。它們的名字分別是EAX,EBX,ECX,EDX,ESI,EDI,ESP,EBP.
注意:
- 在使用這些寄存器的時(shí)候,指令的源操作數(shù)和目的操作數(shù)必須具有相同的長(zhǎng)度(個(gè)別特殊用途的指令除外)。如果目的操作數(shù)是32位寄存器,源操作數(shù)是立即數(shù),那么立即數(shù)被視為是32位的。
- 32位通用寄存器的高16位是不能獨(dú)立使用的,但是低16位保持同16位處理器的兼容性(可以拆成8位的來用)。
- 可以在32位的處理器上運(yùn)行16位處理器上的軟件。
(2)指令指針寄存器
在32位模式下,為了生成32位物理地址,處理器需要使用32位的指令指針寄存器,也就是說之前的16位的IP擴(kuò)展成為32位的EIP。當(dāng)處理器工作在16位模式下時(shí),依然使用16位的IP;工作在32位模式下時(shí),使用32位的EIP。
注意:和之前一樣,EIP也只能由處理器自己使用,程序員無法直接訪問。 對(duì)IP和EIP的修改通常是通過某些隱式的指令進(jìn)行的,比如JMP,CALL,RET,IRET等等。
(3)標(biāo)志寄存器
在32位處理器中,標(biāo)志寄存器由之前16位的FLAGS擴(kuò)展為32位的EFLAGS,低16位的每個(gè)字段和原先保持一致。
下圖摘自《 The Intel Architecture Software Developer’s Manual——Volume 3 》
(4)段寄存器
在32位模式下,對(duì)內(nèi)存的訪問從理論上來說不需要分段,因?yàn)橛?2根地址線,可以直接尋址4G的內(nèi)存。但是,IA-32結(jié)構(gòu)的處理器是基于分段模型的,因此,32位處理器依然需要以段為單位訪問內(nèi)存,即使它工作在32位模式下。
不過,可以采取一個(gè)變通的方案,即只分一個(gè)段。也就是說段的基地址是0x0000_0000,段的長(zhǎng)度是4GB。在這種情況下,相當(dāng)于不分段,即平坦模型(Flat Mode)。
在32位模式下,處理器要求在加載程序時(shí),先定義該程序擁有的段,然后才可以使用這些段。定義段時(shí),除了起始地址外,還附加了段界限、特權(quán)級(jí)別、類型等屬性。當(dāng)程序訪問一個(gè)段時(shí),處理器將通過固件進(jìn)行各種檢查工作,以防止對(duì)內(nèi)存的違規(guī)訪問。
在32位模式下,傳統(tǒng)的段寄存器,如CS,SS,DS,ES保存的不再是16位的段基地址,而是段選擇子(到底什么是段選擇子,我們以后再說)。另外,32位處理器還增加了兩個(gè)額外的段寄存器,分別是FS和GS。
4.實(shí)模式與保護(hù)模式
8086是16位的處理器,可以通過分段來訪問1M的內(nèi)存,段的最大長(zhǎng)度是64KB。8086只有一種工作模式,就是我們現(xiàn)在所說的“實(shí)模式”。1985年,Intel公司推出了80386,獲得了極大的成功。80386以及后續(xù)的處理器,都向前兼容,可以運(yùn)行實(shí)模式下的8086程序。而且,在加電時(shí),這些處理器都自動(dòng)處于實(shí)模式下。只有在一番設(shè)置之后,才能運(yùn)行在保護(hù)模式下。
5.邏輯地址和線性地址
在8086,我們把“段地址:段內(nèi)偏移地址”稱為邏輯地址。8086CPU內(nèi)部有一個(gè)地址加法器,用來把邏輯地址轉(zhuǎn)換成物理地址。轉(zhuǎn)換規(guī)則是:物理地址=段地址×10H+段內(nèi)偏移量
但是在80386中,情況就不同了。80386的邏輯地址(也叫虛擬地址)構(gòu)成是“段選擇子:段內(nèi)偏移量”。邏輯地址經(jīng)過80386CPU內(nèi)部的分段部件轉(zhuǎn)換后成為線性地址。線性地址再經(jīng)過分頁部件轉(zhuǎn)換就成為物理地址。如果禁用分頁機(jī)制,那么線性地址就是物理地址。
6.處理器的尋址方式
在16位處理器上,內(nèi)存尋址方式為:
?
在32位處理器上,內(nèi)存尋址方式為:
也是就是說,在指定有效地址的時(shí)候,可以使用所有的32位通用寄存器作為基址寄存器。同時(shí),還可以再加上一個(gè)除ESP之外的32位通用寄存器作為變址寄存器。另外,變址寄存器還允許乘以一個(gè)比例因子(1或2或4或8)。最后,還可以加上一個(gè)8位或者32位的偏移量。
舉例:
add eax,[0x2008]
sub eax,[eax+0x04]
mov ecx,[edx+esi*8+0x02]
7.匯編器指令 BITS
相同的機(jī)器指令,在16位模式和32位模式下的解釋和執(zhí)行效果是不同的。舉例來說:
8B5022,這條機(jī)器碼,在16位模式下,對(duì)應(yīng)的匯編指令是:mov dx,[bx+si+0x02]; 但是,在32位模式下,對(duì)應(yīng)的匯編指令卻是 mov edx,[eax+0x02];
NASM匯編器中有一個(gè)偽指令——BITS.
'BITS'指令指定 NASM 產(chǎn)生的代碼是被設(shè)計(jì)運(yùn)行在 16 位模式的處理器上還是運(yùn)行在32位模式的處理器上。語法是'BITS 16'或'BITS 32'. NASM以.bin格式輸出時(shí),默認(rèn)是16位模式。如果我們需要編譯成32位的,則需要加上[bits 32](方括號(hào)可以有,也可以沒有。)
8.一般指令的擴(kuò)展
(1)loop指令
在16位處理器上,loop指令的循環(huán)次數(shù)在寄存器CX中。在32位處理器上,如果當(dāng)前模式是16位的,那么loop指令執(zhí)行時(shí),仍然使用CX寄存器;如果運(yùn)行在32位模式下,則使用ECX;
(2)mul指令
在16位處理器上,無符號(hào)數(shù)乘法指令mul的格式為
mul r/m8???? ; AX <- AL * r/m8
mul r/m16? ; DX:AX <- AX * r/m16
說明:這里的r/m8表示8位的通用寄存器或內(nèi)存單元, r/m16表示16位的通用寄存器或內(nèi)存單元,下面的r/m32表示32位的通用寄存器或內(nèi)存單元
在32位處理器上,除了依然支持上面的的操作,另外還支持以下擴(kuò)展格式:
mul r/m32? ;EDX:EAX <- EAX * r/m32
有符號(hào)數(shù)乘法指令imul與此相同。
(3)div指令
在16位處理器上,無符號(hào)除法指令div的格式為:
div r/m8? ; AX? ÷? r/m8?? = AL …… AH
div r/m16 ; DX:AX ÷ r/m16? = AX ……DX
在32位處理器上,除了依然支持上面的操作,還支持以下擴(kuò)展格式:
div r/m32 ; EDX:EAX ÷ r/m32 = EAX……EDX
有符號(hào)數(shù)除法指令idiv于此相同;
(4)push和pop指令
操作數(shù)是立即數(shù)的情況
32處理器的棧操作指令push和pop也有所擴(kuò)展,允許壓入雙字操作數(shù)。特別是,它支持立即數(shù)的壓棧操作。指令格式為(imm8/16/32表示8位或16位或32位立即數(shù)):
push imm8? ;操作碼為6A
push imm16 ; 操作碼為68
push imm32; 操作碼也為68
還是舉書上的例子吧:
- 例1:壓入一個(gè)字節(jié)
push byte 0x55;?
這里的關(guān)鍵字byte是給編譯器看的,告訴它壓入的是字節(jié)(畢竟0x55可以解釋為字0x0055或者雙字0x0000_0055).這條指令的16位形式(用bits 16 編譯)和32位形式(用bits 32 編譯)是一樣的,機(jī)器碼都是
6A 55
但是,執(zhí)行的時(shí)候就不同了。注意,無論什么時(shí)候,處理器都不會(huì)壓入一個(gè)字節(jié)。它要么壓入字,要么壓入雙字。
在16位模式下,默認(rèn)的操作數(shù)是16位。于是處理器將0x55作符號(hào)擴(kuò)展,擴(kuò)展成16位的0x0055,然后壓入棧。(壓棧時(shí)用sp寄存器,且先將sp減去2);
在32位模式下,處理器將0x55擴(kuò)展成32位的0x0000_0055,然后壓入。(壓棧時(shí)用esp寄存器,且先將esp減去4)
- 例2:壓入一個(gè)字
壓入一個(gè)字,必須用word關(guān)鍵字來修飾,如
push word 0xfffb
在16位模式下,默認(rèn)的操作數(shù)是16位的。處理器直接壓入該字(壓棧時(shí)用sp寄存器,且先將sp減去2);
在32位模式下,處理器將0xfffb擴(kuò)展成32位的0xffff_fffb,然后壓入。(壓棧時(shí)用esp寄存器,且先將esp減去4)
- 例3:壓入一個(gè)雙字
如果壓入雙字,則必須用關(guān)鍵字dword來修飾。如
push dword 0xfb
在16位模式下,壓入的是0x0000_00fb(壓棧時(shí)用sp寄存器,且先將sp減去4);
在32位模式下,壓入的也是0x0000_00fb(壓棧時(shí)用esp寄存器,且先將esp減去4).
操作數(shù)位于通用寄存器或者內(nèi)存單元的情況
對(duì)于操作數(shù)位于通用寄存器或者內(nèi)存單元的情況,只能壓入字或者雙字。指令格式為:
push r/m16
push r/m32
比如:
push ax
push edx
如果操作數(shù)位于內(nèi)存單元中,則必須用關(guān)鍵字word或者dword修飾,如:
push word [0x2000]
push dword [ecx+esi*2+0x02]
無論操作數(shù)位于寄存器還是內(nèi)存單元,
在16位模式下,壓入字的時(shí)候,將sp的內(nèi)容減去2;壓入雙字的時(shí)候,將sp的內(nèi)容減去4;
在32位模式下,壓入字的時(shí)候,將esp的內(nèi)容減去2;壓入雙字的時(shí)候,將esp的內(nèi)容減去4.
操作數(shù)是段寄存器的情況
指令格式為:
push cs/ds/es/fs/gs/ss
在16位模式下,將sp的內(nèi)容減去2,然后直接壓入段寄存器的內(nèi)容;
在32位模式下,先將段寄存器的內(nèi)容擴(kuò)展為32位(高16位全為0),然后將esp的內(nèi)容減去4,再壓入擴(kuò)展后的32位的值。
?
今天就說到這里,下次我們開啟保護(hù)模式之旅
?
?
參考資料:
[1]百度百科:http://baike.baidu.com/link?url=I1wsXUAGa541Pn8h1XVgSnR6GmUsfWK8VOjpALlzmE7vOccJVOpxkQfKjYYHODUe2BxqOw2q5KAB6pS4ZQjD9K
[2]知乎:王強(qiáng),http://zhuanlan.zhihu.com/xpenrynidea/19893066
與50位技術(shù)專家面對(duì)面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的32位x86处理器编程导入——《x86汇编语言:从实模式到保护模式》读书笔记08的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 8086键盘输入实验——《x86汇编语言
- 下一篇: 全局描述符表(GDT)——《x86汇编语