程序的加载和执行(四)——《x86汇编语言:从实模式到保护模式》读书笔记24
程序的加載和執行(四)——《x86匯編語言:從實模式到保護模式》讀書筆記24
通過本文能學到什么?
- 怎樣跳轉到用戶程序
- 用戶程序通過調用內核過程完成自己的功能
- 怎樣從用戶程序返回到內核
接著上篇博文說。
1.跳轉到用戶程序
截取內核程序的后半部分代碼(文件名:c13_core.asm):
570 call load_relocate_program 571 572 mov ebx,do_status 573 call sys_routine_seg_sel:put_string 574 575 mov [esp_pointer],esp ;臨時保存堆棧指針 576 577 mov ds,ax 578 579 jmp far [0x10] ;控制權交給用戶程序(入口點) 580 ;堆棧可能切換 581 582 return_point: ;用戶程序返回點 583 mov eax,core_data_seg_sel ;使ds指向核心數據段 584 mov ds,eax 585 586 mov eax,core_stack_seg_sel ;切換回內核自己的堆棧 587 mov ss,eax 588 mov esp,[esp_pointer] 589 590 mov ebx,message_6 591 call sys_routine_seg_sel:put_string 592 593 ;這里可以放置清除用戶程序各種描述符的指令 594 ;也可以加載并啟動其它程序 595 596 hlt 597570:調用過程load_relocate_program,關于此過程的詳細講解,可以參考我的博文:
程序的加載和執行(二)——《x86匯編語言:從實模式到保護模式》讀書筆記22
程序的加載和執行(三)——《x86匯編語言:從實模式到保護模式》讀書筆記23
在這個過程的末尾,有
注意,這時候ES是用戶頭部段的選擇子,如下圖所示,這句話就是取出頭部偏移0x04處的頭部段選擇子,賦值給AX;
其實這么做有點繞彎子,因為ES自身的值就是頭部段選擇子,所以這句話可以修改為:
也就是說,這個過程把用戶程序頭部段的選擇子保存在AX中,作為返回參數。
再復習一下這個過程的輸入和返回參數。
572~573:調用過程put_string,在屏幕上輸出”Done.”,并且換行,表示加載和重定位工作已經完成。
369 do_status db 'Done.',0x0d,0x0a,0575:通過把當前ESP的值寫入內核數據段來保存內核的棧指針。內核數據段第378行,保留了一個雙字,專門用來保存內核棧指針。
378 esp_pointer dd 0 ;內核用來臨時保存自己的棧指針當內核把控制權交給用戶程序后,用戶程序應該切換到自己的棧。當從用戶程序返回到內核的時候,內核需要從這個內存位置還原自己的棧指針。
577:將用戶頭部段的選擇子傳送到DS,也就是說用戶程序應該明白,從內核那里接過控制權的時候,DS指向了用戶程序的頭部段。
579:如上圖所示,偏移0x10處,綠色部分就是用戶程序的入口。一個華麗的間接遠轉移,終于跳到了用戶程序。
2.用戶程序的執行
截取用戶程序的部分代碼(文件名:c13.asm)。
7 SECTION header vstart=0 8 9 program_length dd program_end ;程序總長度#0x00 10 11 head_len dd header_end ;程序頭部的長度#0x04 12 13 stack_seg dd 0 ;用于接收堆棧段選擇子#0x08 14 stack_len dd 1 ;程序建議的堆棧大小#0x0c 15 ;以4KB為單位 16 17 prgentry dd start ;程序入口#0x10 18 code_seg dd section.code.start ;代碼段位置#0x14 19 code_len dd code_end ;代碼段長度#0x18 20 21 data_seg dd section.data.start ;數據段位置#0x1c 22 data_len dd data_end ;數據段長度#0x20 40 ;=============================================================================== 41 SECTION data vstart=0 42 43 buffer times 1024 db 0 ;緩沖區 44 45 message_1 db 0x0d,0x0a,0x0d,0x0a 46 db '**********User program is runing**********' 47 db 0x0d,0x0a,0 48 message_2 db ' Disk data:',0x0d,0x0a,0 49 50 data_end: 51 52 ;=============================================================================== 53 [bits 32] 54 ;=============================================================================== 55 SECTION code vstart=0 56 start: 57 mov eax,ds 58 mov fs,eax 59 60 mov eax,[stack_seg] 61 mov ss,eax 62 mov esp,0 63 64 mov eax,[data_seg] 65 mov ds,eax 66 67 mov ebx,message_1 68 call far [fs:PrintString] 69 70 mov eax,100 ;邏輯扇區號100 71 mov ebx,buffer ;緩沖區偏移地址 72 call far [fs:ReadDiskData] ;段間調用 73 74 mov ebx,message_2 75 call far [fs:PrintString] 76 77 mov ebx,buffer 78 call far [fs:PrintString] ;too. 79 80 jmp far [fs:TerminateProgram] ;將控制權返回到系統 81 82 code_end:用戶程序從第57行開始執行。注意,此時DS指向用戶程序的頭部段。
57~58:把DS賦值給FS,令FS指向頭部段。因為后面要令DS指向用戶程序的數據段。
60~62:用戶棧段的初始化,并且令ESP=0;這樣就完成了棧的切換。
64~65:令DS指向用戶數據段。
67~68:調用內核提供的例程put_string;本質上是一個16位間接絕對遠調用。
當內核對用戶程序的符號表完成重定位后,PrintString處就擁有了內核例程put_string的入口地址(低地址處是4字節的偏移地址,高地址處是2字節的段選擇子);
80 jmp far [fs:TerminateProgram] ;將控制權返回到系統執行這條指令的時候,處理器根據[fs:TerminateProgram]進行內存尋址,得到偏移地址和段選擇子,然后壓棧CS,再壓棧EIP,再然后把剛才取得的偏移地址和段選擇子賦值給EIP和CS,于是程序的執行流就轉移到內核代碼段中的put_string過程了。說得通俗點,就是用戶程序調用了內核的代碼,完成了自己的功能。這有點像Linux中的系統調用。
如果你對call far指令不熟悉的話,可以參考我的博文:
call、ret、retf 指令詳解
70~72:調用內核過程read_hard_disk_0,從硬盤讀取一個扇區。
read_hard_disk_0: ;從硬盤讀取一個邏輯扇區;EAX=邏輯扇區號;DS:EBX=目標緩沖區地址;返回:EBX=EBX+512用戶程序傳入的邏輯扇區號是100,當然這個值也可以是別的,這里僅僅是舉個例子。目標緩沖區地址是數據段內buffer標號處,這里定義了1024字節的0。為了用戶程序可以順利運行并且能看到效果,我們需要在100扇區寫點東西。在配書代碼中,提供了一個文本文件diskdata.txt,它的大小剛好是512字節。用UltraEdit軟件打開后,如下圖所示:
可以看到,這個文本剛好是512字節,最后一個字節是字符];
77~78:顯示從剛才硬盤讀出來的內容。
有一個細節需要說明,內核過程put_string要求字符串必須以0終止,不然會無盡地顯示下去。可是我們這個文件是以]結尾的,這是否會影響顯示呢?答案是不會。因為目標緩沖區buffer標號處,定義了1024字節的0,當把目標文件讀到這里后,前512字節被覆蓋,字符]后面有512個0,所以顯示到]為止。
到這個時候,用戶程序的工作算是完成了,但是還差最后一步,把控制權交給系統。
3.返回到內核
80:一個瀟灑的jmp far,跳到內核過程return_point,以把控制權返回給內核。注意,jmp和call的區別是:前者有去無回,后者有去有回。
我們再穿越到內核的代碼:
583~584:DS重新指向內核數據段;
586~588:切換到內核的棧,并恢復之前保存的ESP的值。
對于一個內核來說,接下來應該回收前一個用戶程序所占用的內存,并啟動下一個用戶程序。不過因為是初學,我們就不搞那么復雜了,于是596行,讓處理器處于停機狀態。從此世界安靜了。
下一篇博文,我們會講本章代碼的編譯、運行和調試。敬請期待……
總結
以上是生活随笔為你收集整理的程序的加载和执行(四)——《x86汇编语言:从实模式到保护模式》读书笔记24的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 爬虫项目之豆瓣电影排行榜前10页
- 下一篇: ubuntu终端显示乱码的解决