(爛豬腳‧‧續)_GLOBAL_OFFSET_TABLE_為基底位址的符號會
得到當前段的起始地址到global offset table的距離(offset),由於此
時已經是32bits的flat4G定址,因此引用這個符號相當等同於取得
.data segment及.bss區的啟始位址,因此我們比較一下為什麼setup.S
就不是用這種方式來計算offset值 ,因為那時還在真實模式,而現在
是在保護模式。
movl $(LOW_TEST_ADR + _GLOBAL_OFFSET_TABLE_), %esp
#LOW_TEST_ADR=0x2000=8k
所以這一行相當於,將堆疊指標暫存器設在.data區開始後的8k處。
/*********************************************************/
/* Load the GOT pointer */
call 0f #為什要這樣call目的何在,目前I do'nt know.
0: popl %ebx
addl $_GLOBAL_OFFSET_TABLE_+[.-0b], %ebx
上面這一行就是獲得標籤"0:",也就是popl %ebx這條指令的地址
,然後保存在%ebx中。
/*********************************************************/
/* Reload all of the segment registers */
leal gdt@GOTOFF(%ebx), %eax #取得gdt位址存入eax
movl %eax, 2 + gdt_descr@GOTOFF(%ebx)
#將gdtㄉ基底位址存到gdt_descr+2ㄉ位址
lgdt gdt_descr@GOTOFF(%ebx)
#看到這一行你就應該要知道上一行ㄉ目的
leal flush@GOTOFF(%ebx), %eax
pushl $KERNEL_CS
pushl %eax
lret
#上面這三行是ㄍ很特殊ㄉ寫法,lret會pop出(cs)segment:offset
#所以相當於程式會繼續網下執行,但由於不能寫成如下:
#movl $KERNEL_CS, %eax
#movw %ax, %cs
#jmp flush 因為cs不可這樣搞
flush: movl $KERNEL_DS, %eax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
/*
* Zero BSS 將_bss區清0
*/
cmpl $1, zerobss@GOTOFF(%ebx)
jnz zerobss_done
xorl %eax, %eax
leal _bss@GOTOFF(%ebx), %edi
leal _end@GOTOFF(%ebx), %ecx
subl %edi, %ecx
1: movl %eax, (%edi)
addl $4, %edi
subl $4, %ecx
jnz 1b
movl $0, zerobss@GOTOFF(%ebx)
zerobss_done:
此時你腦袋中應該要浮現出到目前為止程式在記
憶體中如何配置如上圖。
但這是沒有在dos環境下跑的流程:所以我們要找時間來看看這個mt86+_loader.asm檔,因此把它弄清楚就可以知道和正常的booting有何不同。
call 0f #為什要這樣call目的何在,目前I do'nt know.
回覆刪除0: popl %ebx
----------------------------------
call 0f #將cs:ip push入堆疊
0: popl %ebx #然後在將ip取出到ebx
不知道這樣解釋有沒有錯
謝謝您的解答.
回覆刪除