2025年4月22日 星期二

hello pc9801

從來沒想過在 pc9801 上寫程式, 不過有了 dosbox-x 模擬器之後, 可以測試看看。

toolchain 用的一樣是 gcc, AI 建議使用 TASM + Turbo C 或是 DJGPP, 這些我不熟, 要打造環境也要另外花時間, 之前有使用 gcc 寫 dos 程式的經驗, 就拿來硬上, 需要注意大概是 bios call 要轉成 dos int call, 因為 pc9801 用的 bios 和 IBM/PC 不同。

這表示也可以用 c++, 以下範例以 c++ 和組合語言完成。

本來打算用 inline assembly 完成 dos int call, 透過 ai 很容易問到語法 (gcc inline assmelby 實在太可怕, 老是記不住), 不過 edx 這邊一直編譯不過, 只好改用組合語言完成。

pc9801.cpp
 1 __asm__(".code16gcc\n");
 2 #include "io.h"
 3 #include "obj.h"
 4 
 5 typedef signed char s8;
 6 typedef signed short s16;
 7 typedef signed int s32;
 8 
 9 typedef unsigned char u8;
10 typedef unsigned short u16;
11 typedef unsigned int u32;
12 
13 extern "C" void print_string(const char* str);
14 
15 extern "C" int cpp_main(void)
16 {
17   //BOCHS_MB
18   //u32 esp = get_sp();
19 
20 #if 0
21   while (val == 3)
22   {
23   }
24 #endif
25   print_string("hello pc9801/c++\r\n$");
26 
27   __asm__ volatile ("mov  $0x4c00, %ax\t\n");
28   __asm__ volatile ("int  $0x21\t\n");   // 回到 DOS
29 
30   return 0;
31 }

本來想用 inline assembly 建立 c function, 但是一直有問題, 只好出動組合語言, 有了 AI 的幫助, 很容易就搞定組合語言版本。

dio.S dos 中斷, 顯示字串, 字串須以 $ 結尾
 1 # print_string.s - AT&T syntax for real-mode DOS
 2 # void print_string(const char* str);
 3 
 4     .code16                         # 16-bit code
 5     .globl print_string            # C 函數名 (DJGPP 會加底線)
 6 
 7 print_string:
 8     push %ebp
 9     mov  %esp, %ebp
10 
11     mov  8(%ebp), %dx                # 將參數 str 傳給 DX
12     mov  $0x09, %ah                 # AH = 09h 顯示字串
13     int  $0x21                      # 呼叫 DOS 服務
14 
15     pop  %ebp
16     ret
list 1 編譯指令
1 g++ -DRELOC -static -O0 -m32  -g -Wall -Wextra -nostdlib -fno-builtin -nostartfiles -nodefaultlibs -fno-exceptions -fno-rtti -fno-stack-protector -std=c++17  -c cpp_init.S -o cpp_init.reloc.o
2 g++ -static -O0 -m32  -g -Wall -Wextra -nostdlib -fno-builtin -nostartfiles -nodefaultlibs -fno-exceptions -fno-rtti -fno-stack-protector -std=c++17  -c pc9801.cpp
3 as --32 dio.S -o dio.o
4 ld -pie -m elf_i386 -static -Treloc.ld -nostdlib -o pc9801.elf cpp_init.reloc.o pc9801.o dio.o
5 objcopy -R .pdr -R .comment -R.note -S -O binary pc9801.elf pc9801.bin
reloc.ld
 1 /* for cb.c */
 2 ENTRY(_start);
 3 SECTIONS
 4 {
 5 
 6     . = 0x100;
 7     __image_copy_start = .;
 8     .text :
 9     {
10         *(.text)
11         *(.gnu.linkonce.t*)
12     }
13     .rodata :
14     {
15         *(.rodata*)
16         *(.gnu.linkonce.r*)
17     }
18 
19     .data :
20     {
21         *(.data.*)
22         *(.gnu.linkonce.d*)
23     }
24     __image_copy_end = .;
25 
26  . = ALIGN(4);
27 
28 __rel_dyn_start = .;
29  .rel.dyn : {
30   *(.rel.dyn*)
31  }
32 __rel_dyn_end = .;
33 
34     /* for g++ 4.7 */
35     .init_array :
36     {
37       __start_global_ctor__ = .;
38     }
39     __end_global_ctor__ = .;
40     .ctors :
41     {
42       start_ctors = .; _start_ctors = .; __start_ctors = .;
43       *(.ctor*)
44       end_ctors = .; _end_ctors = .; __end_ctors = .;
45 /*      . = ALIGN(0x1000); */
46      }
47      /*
48     .dtors :
49     {
50       start_dtors = .; _start_dtors = .; __start_dtors = .;
51       *(.dtor*)
52       end_dtors = .; _end_dtors = .; __end_dtors = .;
53       . = ALIGN(0x1000);
54      }
55      */
56 
57 
58     .bss :
59     {
60         sbss = .; __bss_start__ = .;
61         *(.bss)
62         ebss = .; __bss_end__ = .;
63         *(COMMON)
64         *(.gnu.linkonce.b*)
65     }
66 
67     /DISCARD/ :
68     {
69         *(.comment)
70         *(.eh_frame) /* discard this, unless you are implementing runtime support for C++ exceptions. */
71     }
72 }


source code:
https://github.com/descent/simple_os
branch cpp_runtime
simple_os/cpp_runtime/global_object/dos_cpp
fig 1. hello pc9801

這個程式很大可能無法在真實 pc9801 機器執行, 因為 pc9801 使用 8086 相容 cpu, 無法執行 eax 這種暫存器, 只能用 ax 才是。

沒有留言:

張貼留言

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

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