2012年5月16日 星期三

不能執行的 code 竟然可以在 qemu 執行 - bootloader c 語言篇 (糗了, 我錯了)

cb.c
 1 __asm__(".code16gcc\n");
 2 
 3 void print(const char   *s);
 4 
 5 void main(void)
 6 {
 7 #if 1
 8   unsigned char *vb = (unsigned char *)0xb8000;
 9   *vb = 'A';
10   *(unsigned char *)0xb8001 = 0xc;
11   *(unsigned char *)0xb8002 = 'B';
12   *(unsigned char *)0xb8003 = 0xc;
13 #else
14   print("hello world");
15 #endif
16   while(1);
17 }
18 
19 #if 0
20 void print(const char   *s)
21 {
22   while(*s)
23   {
24     __asm__ __volatile__ ("int  $0x10" : : "a"(0x0E00 | *s), "b"(7));
25     s++;
26   }
27 }
28 #endif

gcc -fno-stack-protector -std=c99 -march=i686 -ffreestanding -Wall -c cb.c
ld -static -Tl.ld -nostdlib -M -o cb.elf cb.o > cb.elf.map
objcopy -R .pdr -R .comment -R.note -S -O binary cb.elf cb.bin



疑, 看起來成功了, 印出 AB, 不過 ... 使用 bochs 再試一次,

bochs 發出了錯誤訊息 ...
以下是單步執行的過程:

 (0) [0x0000000000007c02] 0000:7c02 (unk. ctxt): movl %esp, %ebp           ; 6689e5
00153230105i[XGUI ] Mouse capture off
n
Next at t=153230106
(0) [0x0000000000007c05] 0000:7c05 (unk. ctxt): subl $0x00000010, %esp    ; 6683ec10
00153230106i[XGUI ] Mouse capture off
n
Next at t=153230107
(0) [0x0000000000007c09] 0000:7c09 (unk. ctxt): movl $0x000b8000, %ss:-4(%ebp) ; 6766c745fc00800b00
00153230107i[XGUI ] Mouse capture off
n
Next at t=153230108
(0) [0x0000000000007c12] 0000:7c12 (unk. ctxt): movl %ss:-4(%ebp), %eax   ; 67668b45fc
00153230108i[XGUI ] Mouse capture off
n
Next at t=153230109
(0) [0x0000000000007c17] 0000:7c17 (unk. ctxt): movb $0x41, %ds:(%eax)    ;




執行到紅色部份時出現了以下的錯誤:

bochs.msg

81 00153250222e[CPU0 ] write_virtual_checks(): write beyond limit, r/w
82 00153250224e[CPU0 ] write_virtual_checks(): write beyond limit, r/w
83 00153250226e[CPU0 ] write_virtual_checks(): write beyond limit, r/w
84 00153250228e[CPU0 ] write_virtual_checks(): write beyond limit, r/w
85 00153250230e[CPU0 ] write_virtual_checks(): write beyond limit, r/w
86 00153250232e[CPU0 ] write_virtual_checks(): write beyond limit, r/w
87 00153250234e[CPU0 ] write_virtual_checks(): write beyond limit, r/w
88 00153250236e[CPU0 ] write_virtual_checks(): write beyond limit, r/w
89 00153250238e[CPU0 ] write_virtual_checks(): write beyond limit, r/w
90 00153250240e[CPU0 ] write_virtual_checks(): write beyond limit, r/w
91 00153250242e[CPU0 ] write_virtual_checks(): write beyond limit, r/w
92 00153250244^Ce00153250244i[     ] Ctrl-C detected in signal handler.
93 
94 [CPU0 ] write_virtual_checks(): write beyond limit, r/w

而實際上我認為 bochs 才是正確的結果, 這不是應該可以正常跑的程式。

movb $0x41, %ds:(%eax) 
我認為應該是 %ds:(%eas) 這樣的定址能力在真實模式 16bit 下是無法執行的, 應該是要像這樣:
movb $0x41, %ds:(%ax)
雖然可以用 32 bit 暫存器, 但是並不能使用 32bit 定址能力。


20120611 補充:
糗大了, 在真正的機器上, 至少在我的 eeepc 904 上, 是可以正常執行的。原來 qemu 才是對的。有圖有真像。

以下 cb.c 為我測試時的程式碼。程式寫入軟碟, 使用 usb floppy 開機。

cb.c
 1 __asm__(".code16gcc\n");
 2 /*
 3  * c bootloader
 4  */
 5 
 6 //#define POINTER_TEST
 7 
 8 void main(const char   *s);
 9 
10 int bbb=0; // test bss section
11 
12 void WinMain(void)
13 {
14   __asm__ ("mov  %cs, %ax\n");
15   __asm__ ("mov  %ax, %ds\n");
16   __asm__ ("mov  %ax, %ss\n");
17   __asm__ ("mov  $0xff00, %sp\n");
18 #ifdef POINTER_TEST
19   unsigned char *vb = (unsigned char *)0xb8000;
20   *vb = 'A';
21   *(unsigned char *)0xb8001 = 0xc;
22   *(unsigned char *)0xb8002 = 'B';
23   *(unsigned char *)0xb8003 = 0xc;
24 #else
25   main("hello cc");
26   unsigned char *vb = (unsigned char *)0xb8000;
27   *vb = 'A';
28   *(unsigned char *)0xb8001 = 0xc;
29   *(unsigned char *)0xb8002 = 'B';
30   *(unsigned char *)0xb8003 = 0x9;
31   *(unsigned char *)0xb8004 = '@';
32   *(unsigned char *)0xb8005 = 0xc;
33 #endif
34   while(1);
35 }
36 
37 #ifndef POINTER_TEST
38 void main(const char   *s)
39 {
40   while(*s)
41   {
42     __asm__ __volatile__ ("int  $0x10" : : "a"(0x0E00 | *s), "b"(7));
43     s++;
44   }
45 }
46 #endif



到底是怎麼回事呢?有空來去 http://www.juluos.org/ 聊聊這問題。

沒有留言:

張貼留言

使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。

我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。