日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

16位模式/32位模式下PUSH指令探究——《x86汇编语言:从实模式到保护模式》读书笔记16

發(fā)布時(shí)間:2025/3/15 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 16位模式/32位模式下PUSH指令探究——《x86汇编语言:从实模式到保护模式》读书笔记16 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、Intel 32 位處理器的工作模式

如上圖所示,Intel 32 位處理器有3種工作模式。

(1)實(shí)模式:工作方式相當(dāng)于一個(gè)8086

(2)保護(hù)模式:提供支持多任務(wù)環(huán)境的工作方式,建立保護(hù)機(jī)制

(3)虛擬8086模式:這種方式可以使用戶(hù)在保護(hù)模式下運(yùn)行8086程序(比如cmd打開(kāi)的console窗口,就是工作在虛擬8086模式)

有幾點(diǎn)需要特別說(shuō)明:

(1)保護(hù)模式可分為16位和32位的,由段描述符中的D標(biāo)志指明。對(duì)于32位代碼段和數(shù)據(jù)段,這個(gè)標(biāo)志總是設(shè)為1;對(duì)于16位代碼和數(shù)據(jù)段,這個(gè)標(biāo)志被設(shè)置為0.

D=1:默認(rèn)使用32位地址和32位或8位的操作數(shù)。

D=0:默認(rèn)使用16位地址和16位或8位的操作數(shù)。(主要是為了能夠在32位處理器上運(yùn)行16位保護(hù)模式的程序)

指令前綴0x66用來(lái)選擇非默認(rèn)值得操作數(shù)大小,0x67用來(lái)選擇非默認(rèn)值的地址大小。

(2)在實(shí)模式下,也可以使用32位的寄存器,比如

mov eax,ecx mov ebx,0x12345678

(3)在書(shū)中,把實(shí)模式和16位的保護(hù)模式統(tǒng)稱(chēng)為“16位模式”;把32位保護(hù)模式稱(chēng)為“32位模式”。我的博文也沿用這種叫法。

(4)32位處理器可以執(zhí)行16位的程序,包括實(shí)模式和16位保護(hù)模式。

(5)當(dāng)處理器在16位模式下運(yùn)行時(shí),可以使用32位的寄存器,執(zhí)行32位運(yùn)算。

(6)在16位模式下,數(shù)據(jù)的大小是8位或者16位的;控制轉(zhuǎn)移和內(nèi)存訪問(wèn)時(shí),偏移量也是16位的。

(7)32位保護(hù)模式兼容80286的16位保護(hù)模式。

(8)在16位模式下,處理器把所有指令都看成是16位的。

結(jié)合(5)和(8),我們發(fā)現(xiàn)一個(gè)問(wèn)題:當(dāng)處理器運(yùn)行16位模式下,既然把所有指令都看成16位的,那么怎么使用32位的寄存器,執(zhí)行32位的運(yùn)算呢?答案是利用指令前綴0x66和0x67.前面已經(jīng)說(shuō)過(guò),指令前綴0x66用來(lái)選擇非默認(rèn)值的操作數(shù)大小,0x67用來(lái)選擇非默認(rèn)值的地址大小。

比如說(shuō),指令碼0x40在16位模式下對(duì)應(yīng)的指令是

inc ax

如果加上前綴0x66,也就是指令碼66 40,當(dāng)處理器在16位模式下運(yùn)行,66 40對(duì)應(yīng)的指令是

inc eax

同理,如果處理器運(yùn)行在32位模式下,處理器認(rèn)為指令是32位的,如果加了0x66,那么就表示指令的操作數(shù)是16位的。

在編寫(xiě)程序的時(shí)候,我們應(yīng)該考慮指令的運(yùn)行環(huán)境。為了指令默認(rèn)的運(yùn)行環(huán)境,NASM提供了偽指令bits,用于指明其后的指令是被編譯成16位的還是32位的。比如:

[bits 16] mov cx,dx ;89 D1 mov eax,ebx ;66 89 D8 [bits 32] mov cx,dx ;66 89 D1 mov eax,ebx ;89 D8

注意,[bits 16]和[bits 32]的方括號(hào)是可以省略的。

二、PUSH指令探究

由于32位的處理器都擁有32位的寄存器和算術(shù)邏輯部件,而且同內(nèi)存芯片之間的數(shù)據(jù)通路至少是32位的,因此,所有以寄存器或者內(nèi)存單元為操作數(shù)的指令都被擴(kuò)充,以適應(yīng)32位的算術(shù)邏輯操作。而且,這些擴(kuò)展的操作即使是在16位模式下(實(shí)模式和16位保護(hù)模式)也是可用的。

我在博文 32位x86處理器編程導(dǎo)入——《x86匯編語(yǔ)言:從實(shí)模式到保護(hù)模式》讀書(shū)筆記08 中已經(jīng)總結(jié)了一般指令的擴(kuò)展,在這里,我僅對(duì)PUSH指令進(jìn)行實(shí)驗(yàn)和總結(jié)。

實(shí)驗(yàn)?zāi)康木褪菧y(cè)試在3種模式下,PUSH指令的工作行為(比如SP或ESP到底怎么變化,壓入的數(shù)到底是多少)。所以,我列了一個(gè)單子,把所有能想到的形式都列出來(lái)了,其中有的我也不確定(或許這樣寫(xiě)編譯都會(huì)報(bào)錯(cuò))。不管那么多,先寫(xiě)出來(lái),然后讓編譯器篩選吧

1 ;測(cè)試各種push 2 3 ;操作數(shù)是立即數(shù),分為一字節(jié)、兩字節(jié)、四字節(jié) 4 push 0x80 5 push byte 0x80 6 7 push 0x8000 8 push word 0x8000 9 10 push 0x87654321 11 push dword 0x87654321 12 13 ;操作數(shù)是寄存器,分為16位寄存器和32位寄存器 14 mov eax,0x86421357 15 push ax 16 push eax 17 18 ;操作數(shù)是內(nèi)存單元,分為一字節(jié)、兩字節(jié)、四字節(jié) 19 push [data] 20 push byte [data] 21 push word [data] 22 push dword [data]

是不是有的寫(xiě)法明顯就不對(duì)呢?

首先,第20行,肯定不對(duì)。因?yàn)槿绻莾?nèi)存操作數(shù)的話,不能用byte修飾。剩下來(lái)的錯(cuò)誤,我會(huì)在后文揭曉答案。

1.在實(shí)模式下的實(shí)驗(yàn)

(1)實(shí)驗(yàn)代碼

1 ;PUSH 指令實(shí)驗(yàn) 2 3 jmp near start 4 5 data db 0x12,0x34,0x56,0x78 6 message db 'Hello,PUSH!' 7 8 start: 9 mov ax,0x7c0 ;設(shè)置數(shù)據(jù)段的段基地址 10 mov ds,ax 11 12 mov ax,0xb800 ;設(shè)置附加段基址到顯示緩沖區(qū) 13 mov es,ax 14 15 ;以下顯示字符串 16 mov si,message 17 mov di,0 18 mov cx,start-message 19 @g: 20 mov al,[si] 21 mov [es:di],al 22 inc di 23 mov byte [es:di],0x02 24 inc di 25 inc si 26 loop @g 27 28 ;測(cè)試各種push 29 push 0x80 30 push byte 0x80 31 32 push 0x8000 33 push word 0x8000 34 35 push 0x87654321 36 push dword 0x87654321 37 38 mov eax,0x86421357 39 push ax 40 push eax 41 42 ;push [data] 43 push word [data] 44 push dword [data] 45 46 push ds 47 push gs 48 49 jmp near $ 50 51 52 times 510-($-$$) db 0 53 db 0x55,0xaa

這段代碼不是用的配書(shū)代碼,是我自己寫(xiě)的。

第5行,定義了4字節(jié)的數(shù)據(jù),這是為了后面驗(yàn)證“push + 內(nèi)存操作數(shù)”這一情況。

第6行,定義了一個(gè)字符串,要把它顯示在屏幕上。這樣做是為了調(diào)試方便,讓我們知道我們的程序已經(jīng)RUN了。

第29行到47行,測(cè)試各種push,我會(huì)利用Bochs的調(diào)試功能,跟蹤每條Push的執(zhí)行情況,把結(jié)果總結(jié)出來(lái)。

好的,我們開(kāi)始編譯吧。

對(duì)于30行,有個(gè)警告:

push byte 0x80 ;warning: signed byte value exceeds bounds 既然是警告,那么30行不必去掉。相反我們更加好奇了,看看執(zhí)行時(shí)會(huì)發(fā)生什么。

對(duì)于35行,還是一個(gè)警告:

push 0x87654321 ;warning: word data exceeds bounds

對(duì)于42行,呵呵,就是一個(gè)錯(cuò)誤了。

push [data] ; error: operation size not specified

好吧,看來(lái)這樣不指定操作數(shù)的大小是不行的,所以我們把42行注釋掉。

然后再編譯,好的,可以了。

調(diào)試的過(guò)程就是不斷用n命令,反復(fù)用print-stack命令,還有reg命令等,仔細(xì)觀察棧的變化和SP的變化。(此處省略2000字)

(2)實(shí)驗(yàn)報(bào)告

小二,上實(shí)驗(yàn)報(bào)告!

通過(guò)上面的實(shí)驗(yàn),我們可以知道,如果CPU運(yùn)行在實(shí)模式,如果用NASM編譯,push指令可以這么用:

2.在16位保護(hù)模式下的實(shí)驗(yàn)

(1)關(guān)于16位保護(hù)模式

請(qǐng)參考我的博文 關(guān)于80286——《x86匯編語(yǔ)言:從實(shí)模式到保護(hù)模式》讀書(shū)筆記15

(2)實(shí)驗(yàn)代碼

實(shí)驗(yàn)代碼由配書(shū)代碼(代碼清單11-1 (文件名:c11_mbr.asm))修改而成。目的就是我們要從實(shí)模式進(jìn)入16位的保護(hù)模式,然后測(cè)試16位保護(hù)模式下PUSH指令的行為。

1 ;test push (16位保護(hù)模式下) 2 3 ;設(shè)置堆棧段和棧指針 4 mov ax,cs 5 mov ss,ax 6 mov sp,0x7c00 7 8 ;計(jì)算GDT所在的邏輯段地址 9 mov ax,[cs:gdt_base+0x7c00] ;低16位 10 mov dx,[cs:gdt_base+0x7c00+0x02] ;高16位 11 mov bx,16 12 div bx 13 mov ds,ax ;令DS指向該段以進(jìn)行操作 14 mov bx,dx ;段內(nèi)起始偏移地址 15 16 ;創(chuàng)建0#描述符,它是空描述符,這是處理器的要求 17 mov dword [bx+0x00],0x00 18 mov dword [bx+0x04],0x00 19 20 ;創(chuàng)建#1描述符,保護(hù)模式下的代碼段描述符 21 mov dword [bx+0x08],0x7c0001ff 22 mov dword [bx+0x0c],0x00009800 23 24 ;創(chuàng)建#2描述符,保護(hù)模式下的數(shù)據(jù)段描述符(文本模式下的顯示緩沖區(qū)) 25 mov dword [bx+0x10],0x8000ffff 26 mov dword [bx+0x14],0x0000920b 27 28 ;創(chuàng)建#3描述符,保護(hù)模式下的堆棧段描述符 29 mov dword [bx+0x18],0x00007a00 30 mov dword [bx+0x1c],0x00009600 31 32 ;初始化描述符表寄存器GDTR 33 mov word [cs: gdt_size+0x7c00],31 ;描述符表的界限(總字節(jié)數(shù)減一) 34 35 lgdt [cs: gdt_size+0x7c00] 36 37 in al,0x92 ;南橋芯片內(nèi)的端口 38 or al,0000_0010B 39 out 0x92,al ;打開(kāi)A20 40 41 cli ;保護(hù)模式下中斷機(jī)制尚未建立,應(yīng) 42 ;禁止中斷 43 mov eax,cr0 44 or eax,1 45 mov cr0,eax ;設(shè)置PE位 46 47 ;以下進(jìn)入保護(hù)模式... ... 48 jmp 0x0008:flush ;描述符選擇子:16位偏移 49 ;清流水線并串行化處理器 50 51 52 flush: 53 mov cx,00000000000_10_000B ;加載數(shù)據(jù)段選擇子(0x10) 54 mov ds,cx 55 56 ;以下在屏幕上顯示"ABCDEFGHIJK" 57 mov byte [0x00],'A' 58 mov byte [0x02],'B' 59 mov byte [0x04],'C' 60 mov byte [0x06],'D' 61 mov byte [0x08],'E' 62 mov byte [0x0a],'F' 63 mov byte [0x0c],'G' 64 mov byte [0x0e],'H' 65 mov byte [0x10],'I' 66 mov byte [0x12],'J' 67 mov byte [0x14],'K' 68 69 70 ;測(cè)試push 71 mov cx,00000000000_11_000B ;加載堆棧段選擇子 72 mov ss,cx 73 mov sp,0x7c00 74 75 76 push 0x80 77 push byte 0x80 ; warning: signed byte value exceeds bounds 78 79 push 0x8000 80 push word 0x8000 81 82 push 0x87654321 83 ;warning: word data exceeds bounds 84 push dword 0x87654321 85 86 87 mov eax,0x86421357 88 push ax 89 push eax 90 91 ;push [0x00]error: operation size not specified 92 push byte [0x00] 93 push word [0x00] 94 95 push dword [0x00] 96 97 push ds 98 push gs 99 push es 100 push cs 101 102 ghalt: 103 hlt ;已經(jīng)禁止中斷,將不會(huì)被喚醒 104 105;------------------------------------------------------------------------------- 106 107 gdt_size dw 0 108 gdt_base dd 0x00007e00 ;GDT的物理地址 109 110 times 510-($-$$) db 0 111 db 0x55,0xaa

對(duì)比32位保護(hù)模式的代碼,就會(huì)發(fā)現(xiàn)16位保護(hù)模式的代碼略有不同。

首先,比如說(shuō)22行,段描述符的定義是

22 mov dword [bx+0x0c],0x00009800

因?yàn)?0286中,段描述符的格式是

所以,高4字節(jié)的16~32位全部為0.

其次,

47 ;以下進(jìn)入保護(hù)模式... ... 48 jmp 0x0008:flush ;描述符選擇子:16位偏移 49 ;清流水線并串行化處理器

這里,沒(méi)有加偽指令[bits 32],而且,偏移flush沒(méi)有用dword修飾。因?yàn)椴僮鲾?shù)和偏移是16位的。

好了,代碼就說(shuō)到這里,我們看實(shí)驗(yàn)報(bào)告吧。

(3)實(shí)驗(yàn)報(bào)告

通過(guò)和實(shí)模式的對(duì)比,可以發(fā)現(xiàn),除了9、10兩行中的指令碼的偏移不一樣(這和數(shù)據(jù)存放的位置有關(guān)系,和PUSH沒(méi)有關(guān)系),PUSH指令的行為是驚人的相同。所以我們可以得出結(jié)論,16位保護(hù)模式下,PUSH的用法和實(shí)模式是一樣的。我想,這也是在原書(shū)中,作者把實(shí)模式和16位的保護(hù)模式統(tǒng)稱(chēng)為“16位模式”,把32位保護(hù)模式稱(chēng)為“32位模式”的原因吧。

3.在32位保護(hù)模式下的實(shí)驗(yàn)

(1)實(shí)驗(yàn)代碼

實(shí)驗(yàn)代碼由配書(shū)代碼(代碼清單11-1 (文件名:c11_mbr.asm))修改而成。

1 ;test push (32位保護(hù)模式) 2 3 ;設(shè)置堆棧段和棧指針 4 mov ax,cs 5 mov ss,ax 6 mov sp,0x7c00 7 8 ;計(jì)算GDT所在的邏輯段地址 9 mov ax,[cs:gdt_base+0x7c00] ;低16位 10 mov dx,[cs:gdt_base+0x7c00+0x02] ;高16位 11 mov bx,16 12 div bx 13 mov ds,ax ;令DS指向該段以進(jìn)行操作 14 mov bx,dx ;段內(nèi)起始偏移地址 15 16 ;創(chuàng)建0#描述符,它是空描述符,這是處理器的要求 17 mov dword [bx+0x00],0x00 18 mov dword [bx+0x04],0x00 19 20 ;創(chuàng)建#1描述符,保護(hù)模式下的代碼段描述符 21 mov dword [bx+0x08],0x7c0001ff 22 mov dword [bx+0x0c],0x00409800 23 24 ;創(chuàng)建#2描述符,保護(hù)模式下的數(shù)據(jù)段描述符(文本模式下的顯示緩沖區(qū)) 25 mov dword [bx+0x10],0x8000ffff 26 mov dword [bx+0x14],0x0040920b 27 28 ;創(chuàng)建#3描述符,保護(hù)模式下的堆棧段描述符 29 mov dword [bx+0x18],0x00007a00 30 mov dword [bx+0x1c],0x00409600 31 32 ;初始化描述符表寄存器GDTR 33 mov word [cs: gdt_size+0x7c00],31 ;描述符表的界限(總字節(jié)數(shù)減一) 34 35 lgdt [cs: gdt_size+0x7c00] 36 37 in al,0x92 ;南橋芯片內(nèi)的端口 38 or al,0000_0010B 39 out 0x92,al ;打開(kāi)A20 40 41 cli ;保護(hù)模式下中斷機(jī)制尚未建立,應(yīng) 42 ;禁止中斷 43 mov eax,cr0 44 or eax,1 45 mov cr0,eax ;設(shè)置PE位 46 47 ;以下進(jìn)入保護(hù)模式... ... 48 jmp dword 0x0008:flush ;16位的描述符選擇子:32位偏移 49 ;清流水線并串行化處理器 50 [bits 32] 51 52 flush: 53 mov cx,00000000000_10_000B ;加載數(shù)據(jù)段選擇子(0x10) 54 mov ds,cx 55 56 ;以下在屏幕上顯示"ABCDEFGHIJK" 57 mov byte [0x00],'A' 58 mov byte [0x02],'B' 59 mov byte [0x04],'C' 60 mov byte [0x06],'D' 61 mov byte [0x08],'E' 62 mov byte [0x0a],'F' 63 mov byte [0x0c],'G' 64 mov byte [0x0e],'H' 65 mov byte [0x10],'I' 66 mov byte [0x12],'J' 67 mov byte [0x14],'K' 68 69 70 ;測(cè)試push 71 mov cx,00000000000_11_000B ;加載堆棧段選擇子 72 mov ss,cx 73 mov esp,0x7c00 74 75 76 push 0x80 77 push byte 0x80 ;warning: signed byte value exceeds bounds 78 79 push 0x8000 80 push word 0x8000 81 82 push 0x87654321 83 push dword 0x87654321 84 85 mov eax,0x86421357 86 push ax 87 push eax 88 89 90 push word [0x00] 91 push dword [0x00] 92 93 push ds 94 push gs 95 push es 96 push cs 97 98 ghalt: 99 hlt ;已經(jīng)禁止中斷,將不會(huì)被喚醒 100 101;------------------------------------------------------------------------------- 102 103 gdt_size dw 0 104 gdt_base dd 0x00007e00 ;GDT的物理地址 105 106 times 510-($-$$) db 0 107 db 0x55,0xaa

如果對(duì)上面的代碼不熟悉的話,可以參考我的博文 進(jìn)入保護(hù)模式(一)——《x86匯編語(yǔ)言:從實(shí)模式到保護(hù)模式》讀書(shū)筆記12 等文章。

(2)實(shí)驗(yàn)報(bào)告

根據(jù)測(cè)試報(bào)告,我們可以歸納出32位保護(hù)模式下,針對(duì)NASM編譯器的push指令用法:

?

(完)

總結(jié)

以上是生活随笔為你收集整理的16位模式/32位模式下PUSH指令探究——《x86汇编语言:从实模式到保护模式》读书笔记16的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。