2009年3月20日 星期五

●memtest86+教學 Part4


(爛豬腳‧‧續)_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有何不同。

--> 閱讀更多...

●memtest86+教學 Part3

在我們進入最佳男主角(爛豬腳)ㄉ主題之前,我希望先把makefile及三ㄍlds檔 memtest.bin.lds、memtest.lds、memtest_shared.lds稍加探討探討。若你還不知道什麼是makefile那先去溫習功課再來看這裡。makefile的寫法你去比較一下1.70版,稍有不同,但達成ㄉ效果是一樣的。一般我們很少會去寫lds檔,因為寫apㄉ人搞不好根本就不知道這是什麼東東,lds檔是給linux下gcc附的linker連結器LD所參考用的,若你不指定lds檔,LD還是會叫用預設lds檔,故名思義就是連結器專用的script(描述檔),畢竟memtest86+不是OS下ㄉapplication它等於是ㄍ小型的OS,因為從Boot到run實際應用都是要去和實際硬體溝通,因此lds檔當然要符合它自己ㄉ需求。先截取部分makefile內容:
memtest.bin: memtest_shared.bin bootsect.o setup.o memtest.bin.lds
$(LD) -T memtest.bin.lds bootsect.o setup.o -b binary \
memtest_shared.bin -o memtest.bin
以上敘述: bootsect.o setup.o連結時要參考memtest.bin.lds
以下是
memtest.bin.ldsㄉ內容:
OUTPUT_FORMAT("binary")
OUTPUT_ARCH("i386")

ENTRY(_main);
SECTIONS {
. = 0;
.bootsect : { *(.bootsect) }
.setup : { *(.setup) }
.memtest : {
_start = . ;
*(.data)
_end = . ;
}
_syssize = (_end - _start + 15) >> 4;
}
若沒有全部看懂,先懂一半也行。
其他的makefile內容依此類推,應該難不倒大家。

爛豬腳:head.S
.code32
.globl startup_32
startup_32:
cld
cli
‧‧‧
看到沒,它是32位元的code,而且它沒有.section ㄉ宣告,因為它和Cㄉ部分是整合為同一區段,如下所示:
下面ㄉOBJS除了head.o是組合語言寫ㄉ,其餘都是C寫ㄉ,但這本來就無關緊要,重要ㄉ是這些物件檔被連結成
memtest_shared(依照memtest_shared.ldsㄉ敘述)
OBJS= head.o reloc.o main.o test.o init.o lib.o patn.o screen_buffer.o \
config.o linuxbios.o memsize.o pci.o controller.o random.o extra.o \
spd.o error.o dmi.o

memtest_shared: $(OBJS) memtest_shared.lds Makefile
$(LD) --warn-constructors --warn-common -static -T memtest_shared.lds \
-o $@ $(OBJS) && \
$(LD) -shared -Bsymbolic -T memtest_shared.lds -o $@ $(OBJS)

我們還是看一下
memtest_shared.ldsㄌㄌ等(台語)
OUTPUT_FORMAT("elf32-i386");
OUTPUT_ARCH(i386);

ENTRY(startup_32);
SECTIONS {
. = 0;
.text : {
_start = .;
*(.text)
*(.text.*)
*(.plt)
_etext = . ;
} = 0x9090
.rodata : {
*(.rodata)
*(.rodata.*)
}
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.hash : { *(.hash) }
.dynamic : { *(.dynamic) }

.rel.text : { *(.rel.text .rel.text.*) }
.rel.rodata : { *(.rel.rodata .rel.rodata.*) }
.rel.data : { *(.rel.data .rel.data.*) }
.rel.got : { *(.rel.got .rel.got.*) }
.rel.plt : { *(.rel.plt .rel.plt.*) }

. = ALIGN(4);
.data : {
_data = .;
*(.data)
*(.data.*)
}
.got : {
*(.got.plt)
*(.got)
_edata = . ;
}
. = ALIGN(4);
.bss : {
_bss = .;
*(.dynbss)
*(.bss)
*(.bss.*)
*(COMMON)
/* _end must be at least 256 byte aligned */
. = ALIGN(256);
_end = .;
}
/DISCARD/ : { *(*) }
}

若是看ㄌ一頭霧水,至少你也看到startup_32,它就是head.Sㄉ頭,至於_start和 _end 請看:
memtest: memtest_shared.bin memtest.lds
$(LD) -s -T memtest.lds -b binary memtest_shared.bin -o $@
以下是 memtest.lds內容 0x10000=64k
OUTPUT_FORMAT("elf32-i386");
OUTPUT_ARCH(i386);

ENTRY(_start);
SECTIONS {
. = 0x10000;
_start = . ;
.data : {
*(.data)
}
}

所以startup_32=_startyou know!
--> 閱讀更多...