下面闡述每段**的結構。
1. 引導**:
1) 流程:進入保護模式-->從硬碟中將os**讀入記憶體-->為os將要使用的段"註冊"段描述符-->跳轉到os
2) 子程式:
i. read_hard_disk_0:
;從硬碟讀取乙個邏輯扇區
;eax=邏輯扇區號
;ds:ebx=目標緩衝區位址
;返回:ebx=ebx+512
ii. make_gdt_descriptor:
;構造描述符
; ebx=段界限
; ecx=屬性(各屬性位都在原始
; 位置,其它沒用到的位置0)
;返回:edx:eax=完整的描述符
2. os
1) 頭部
作業系統的頭部包含三部分資訊,一是核心長度,用於引導時確定讀取的扇區數量;二是段起始點偏移,用於向gdt中"註冊"段描述符前計算段基位址和段界限(具體的說,核心基位址加上這些段起始點偏移就是段基位址,而下乙個段的起始點偏移減去本段起始點偏移就能得到本段大小);三是程式入口點,供mbr**跳轉,其中選擇子用equ定義好,與start一起在編譯階段作為常量資料寫入。
#00 doubleword core_length ;核心長度
#04 doubleword sys_routine_seg ;例程段的起始點位移
#08 doubleword core_data_seg ;核心資料段的起始點位移
#0c doubleword core_code_seg ;核心**段起始點位移
#10 doubleword + word start + core_code_seg_sel ;入口點:4位元組偏移+2位元組選擇子
2) 資料段
3) **段
i. 重定位子程式
load_relocate_program:
;載入並重定位使用者程式
;輸入:esi=起始邏輯扇區號
;返回:ax=指向使用者程式頭部的選擇子
重定位子程式要做兩項工作,一是從硬碟將使用者程式讀入記憶體,二是為使用者程式的執行準備環境,包括gdt的更新和os例程入口的對映。該程式的工作流程簡述如下。
首先,讀取使用者程式的頭部到核心資料段的預定區域。程式的頭部包含兩部分資訊,一是入口點。二是和段相關的資訊,包括各段相對於整個程式的偏移、各段的大小、使用者程式希望得到的棧的大小,有了這些資訊,os就可以為程式重新整理gdt,申請棧空間,將cpu控制權交給使用者程式。三是程式要使用的系統例程。這些例程由核心提供,常駐於核心的例程**段,可以由os和使用者程式呼叫(遠call)。為了讓os和使用者程式更好的隔離,即允許使用者程式方便的利用過程名而不是過程入口位址呼叫過程,os進行查表對映操作,將使用者程式頭部的過程名對映為入口位址,回寫入使用者程式頭部。所謂「核心資料段的預定區域」指核心資料段的一塊2kb的緩衝區,用以快取使用者程式頭部資訊。
第二,os從使用者程式頭部讀取使用者程式大小,並且向上擴充為512的倍數。
第三,os申請足夠大的記憶體用以承載使用者程式,讓bs指向申請到的記憶體起始點。
第四,os根據使用者程式大小,計算需要讀取的扇區數。
第五,os迴圈讀取完整的使用者程式到記憶體裡,存在之前申請到的記憶體裡。
第六,os根據頭部資訊為使用者程式安裝段描述符,並將段選擇子回寫到頭部資訊中。
第七,os根據頭部資訊申請棧空間,為棧段註冊段描述符,並回寫到頭部。
第八,os重定位使用者程式要使用的os例程。使用者程式將使用到的系統例程名字登記在頭部,os依據這些資訊查詢核心資料段中的對映表,將系統例程的名字對映到系統例程的入口位址,並且回寫到使用者程式的頭部,覆蓋其內的例程名稱。在核心中提供的例程中有乙個"terminateprogram",這個例程的入口指向os**中所謂的"返回點",也就是jmp跳轉使用者程式之後的位置。使用者程式可以呼叫(jmp)terminateprogram將cpu控制權交還給os。
經過上述複雜而繁瑣的操作之後,重定位子程式load_relocate_program為使用者程式的執行準備好了環境,並且讓ax填充入乙個選擇子,指向使用者程式頭部段(使用者程式頭部資訊自成一段)。
ii. 流程
3) 系統公共例程
i. put_string:
;顯示0終止的字串並移動游標
ii. put_char:
;在當前游標處顯示乙個字元,並推進
;游標。僅用於段內呼叫
;輸入:cl=字元ascii碼
iii. read_hard_disk_0:
;從硬碟讀取乙個邏輯扇區
;eax=邏輯扇區號
;ds:ebx=目標緩衝區位址
;返回:ebx=ebx+512
iv. put_hex_dword:
;在當前游標處以十六進製制形式顯示
;乙個雙字並推進游標
;輸入:edx=要轉換並顯示的數字
;輸出:無
v. allocate_memory:
;分配記憶體
;輸入:ecx=希望分配的位元組數
vi. set_up_gdt_descriptor:
;在gdt內安裝乙個新的描述符
;輸入:edx:eax=描述符
;輸出:cx=描述符的選擇子
vii. make_seg_descriptor:
;構造儲存器和系統的段描述符
; ebx=段界限
; ecx=屬性。各屬性位都在原始
; 位置,無關的位清零
;返回:edx:eax=描述符
1) 頭部段
i.#0x00 doubleword program_length 程式總長度
#0x04 doubleword head_len 頭部長度
#0x08 doubleword stack_seg 棧段選擇子
#0x0c doubleword stack_len 程式建議的堆疊大小
#0x10 doubleword prgentry 程式入口
#0x14 doubleword code_seg **段位置
#0x18 doubleword code_len **段長度
#0x1c doubleword data_seg 資料段位置
#0x20 doubleword data_len 資料段長度
ii. 符號位址檢索表
2) 資料段
1024位元組的緩衝區 + message。其中1024位元組緩衝區用於快取從硬碟中讀取的資料。
3) **段
流程:更新ds,ss,sp --> 顯示一些資訊 --> 呼叫terminateprogram返回os
從Rails到erlyweb 筆記
寫了幾個月的rails,終於開始把專案移植到erlyweb,這個筆記將記錄移植過程中的一些常見問題,主要是rails和erlyweb的同與不同。1.怎樣處理params rails ruby p params.fetch p,1 s params.fetch s,records per page p...
gptgen 無損轉換MBR到GPT
今天豆子發現乙個小工具叫做gptgen,很不錯,可以無損的轉換mbr到gpt分割槽。先做個小實驗,找了個vm,新增了10g的硬碟,然後分割槽格式化成mbr格式,然後隨便寫了點資料上去。gptgen的用法很簡單,稍微注意一下指向的磁碟路徑就是了,比如我的虛擬機器有2個硬碟,第乙個是 physicald...
從資料到資訊到決策
俗話說,忘記歷史就是背叛自己,今天這篇用此做開場再合適不過。這一篇將根據乙個虛擬的故事,來介紹如何通過歷史資料來幫助乙個銷售人員發現規律資訊從而輔助他來做一些決策資訊。本文的主角是tim,tim在乙個銷售部門,部門最近決定做新一輪銷售計畫,然後根據計畫結束時,各個銷售人員的銷售業績來進行kpi考核。...