- 工作環境
- Lubuntu 20.04
- VMware Workstation 16.1.1
20210518 - Day_4
- 進度摘要
- 撰寫 Makefile
- 控制畫面顏色 (白色、條紋色)
- 矩形的繪製與處理
- 螢幕顯示出狀態列圖樣
- 完整專案
- 參考文章
- Mtools 4.0.27
- undefined reference to GLOBAL_OFFSET_TABLE (only when generating binaries)
- Linux 檔案系統掛載(mount)使用教學與範例
- How would I extract a .img file
- Makefile 雙冒號規則 - zxiaocheng
- How to Use the mkfs Command on Linux
- How do I write a bin file (512 bytes) to the first sector (sector 0) of a floppy disk?
- Linker Script初探 - GNU Linker Ld手冊略讀
- gcc與Obj檔,動態連結與ELF檔
- 10分鐘讀懂 linker scripts
- oslite.ldsを開いて、以下のとおり記述します。 (參考 oslite.lds 的環節來撰寫)
撰寫 Makefile
從撰寫原始檔、組/編譯程式,到了最後還要跑虛擬機。
如果每次都要一行行打指令會很辛苦。
所以要把這些指令寫成 Makefile,在往後的測試會相對容易和簡便。
-
Makefile 主要要做的事情有:
- STEP 1 - 製作相關檔案
- 處理開機磁區 -
ipl10.asm
- 包含作業系統本體 -
asmhead.asm
、nasmfunc.asm
、bootpack.c
、os.lds
- 處理開機磁區 -
- STEP 2 - 製作映像檔
- 製作開機磁區映像檔
- 將作業系統本體寫入映像檔
STEP 1 - 製作相關檔案
主要的指令有這些
nasm ipl10.asm -o ipl10.bin -l ipl10.lst
nasm asmhead.asm -o asmhead.bin -l asmhead.lst
nasm -g -f elf nasmfunc.asm -o nasmfunc.o
gcc -march=i486 -m32 -nostdlib -g -O0 -T os.lds bootpack.c nasmfunc.o -o bootpack.hrb -fno-pie
cat asmhead.bin bootpack.hrb > haribote.sys
STEP 2 - 製作映像檔
有兩種產生映像檔的寫法,這兩種都會用到 mcopy
。
- 寫法 1 (主要指令 -
mformat
、mcopy
):mformat -f 1440 -C -B ipl10.bin -i haribote.img ::
mcopy -i haribote.img haribote.sys ::
- 寫法 2 (主要指令 -
dd
、mcopy
):dd if=/dev/zero of=haribote.img bs=512 count=2880
dd if=ipl10.bin of=haribote.img conv=notrunc
mcopy -i haribote.img haribote.sys ::
完整 Makefile 程式碼
將以上 STEP 1、STEP 2 裡的指令寫成 Makefile。 (以下為完整程式碼)
OSNAME := haribote
.DEFAULT_GOAL : all
.PHONY : all
all : img
DEBUG_DIR := ./debug
OBJDUMP_FLAGS := --full-contents --all-headers --target=binary --architecture=i386:intel --disassemble-all
#===============================================================================
ipl10.bin : ipl10.asm
asmhead.bin : asmhead.asm
nasmfunc.o : nasmfunc.asm
%.bin : %.asm
@make make-debug-dir
nasm $^ -o $@ -l ${DEBUG_DIR}/$*.lst
%.o : %.asm
@make make-debug-dir
nasm -f elf $^ -o $@ -l ${DEBUG_DIR}/$*.lst
BOOTPACK_FILES := bootpack.c nasmfunc.o
bootpack.hrb : ${BOOTPACK_FILES} os.lds
@make make-debug-dir
gcc -march=i486 -m32 -nostdlib -g -O0 \
-T os.lds \
-o $@ \
-fno-pie\
${BOOTPACK_FILES}
objdump ${OBJDUMP_FLAGS} $@ > ${DEBUG_DIR}/$@.dasm
${OSNAME}.sys : asmhead.bin bootpack.hrb
%.sys :
@make make-debug-dir
cat $^ > $@
objdump ${OBJDUMP_FLAGS} $@ > ${DEBUG_DIR}/$@.dasm
${OSNAME}.img : ipl10.bin ${OSNAME}.sys
# ======方法 1======
mformat -f 1440 -C -B ipl10.bin -i $@ ::
mcopy -i $@ ${OSNAME}.sys ::
# ================
# ======方法 2======
# dd if=/dev/zero of=${OSNAME}.img bs=512 count=2880
# dd if=ipl10.bin of=${OSNAME}.img conv=notrunc
# mcopy -i $@ ${OSNAME}.sys ::
# =================
#===============================================================================
.PHONY : asm
asm :
make ipl10.bin
.PHONY : img
img :
make ${OSNAME}.img
.PHONY : run
run :
make img
qemu-system-i386 -fda ${OSNAME}.img
.PHONY : make-debug-dir
make-debug-dir :
@if [ ! -d ${DEBUG_DIR} ]; then mkdir ${DEBUG_DIR}; fi
#===============================================================================
.PHONY : clean
clean :
@rm *.img *.bin *.sys *.hrb *.o
.PHONY : debug
debug:
make img
qemu-system-i386 -fda haribote.img -gdb tcp::10000 -S
記得將 Makefile 與其他原始檔放在同一目錄下,未來如果要編譯直接載入 Makefile 指令即可。
以下為常用的指令 (在 Makefile 和其他原始檔皆存在的狀況下):
- 編譯原始檔
make
- 編譯並執行 (以 QEMU 模擬)
make run
- 清除原始檔以外的檔案
make clean
一、讓螢幕顯示白色
1. 在 VRAM (Video RAM, 顯示畫面用的記憶體) 寫入指令,相關程式碼如下:
- bootpack.c (../01_source1_white/bootpack.c)
/* 告知C語言編譯器,有使用其他檔案所製作的函數 */
void io_hlt(void);
void write_mem8(int addr, int data);
/* 雖然是函數的宣告,卻沒有 {},而且馬上就以; 字元結束。
這是表示它存在於其他的檔案裡,請到該處去進行讀取。 */
void HariMain(void)
{
int i; /* 宣告變數。稱為 i 的變數是 32 位元的整數型別 */
for (i = 0xa0000; i <= 0xaffff; i++) {
write_mem8(i, 15); // 螢幕會顯示白色
// write_mem8(i, i & 0x0f); // 螢幕會顯示條紋色
}
for (;;) {
io_hlt(); /* 這樣在 nasmfunc.asm 的 io_hlt 將會執行 */
}
}
- nasmfunc.asm (../01_source1_white/nasmfunc.asm)
; nasmfunc
; TAB=4
; ===========================================
section .text
GLOBAL io_hlt
GLOBAL write_mem8
; ===========================================
; ===========================================
io_hlt: ; void io_hlt(void);
HLT
RET
; ===========================================
write_mem8: ; void write_mem8(int addr, int data);
MOV ECX, [ESP+4] ; 因為在 [ESP+4] 裡有 addr,所以將該值讀入到 ECX
MOV AL, [ESP+8] ; 因為在 [ESP+8] 裡有 data,所以將該值讀入 AL
MOV [ECX], AL
RET
2. 進行編譯並執行
make run
【執行結果】 螢幕顯示白色
二、讓螢幕顯示條紋
1. 在 VRAM (Video RAM, 顯示畫面用的記憶體) 寫入指令,相關程式碼如下:
- bootpack.c (../01_source2_stripes/bootpack.c)
/* 告知C語言編譯器,有使用其他檔案所製作的函數 */
void io_hlt(void);
void write_mem8(int addr, int data);
/* 雖然是函數的宣告,卻沒有 {},而且馬上就以; 字元結束。
這是表示它存在於其他的檔案裡,請到該處去進行讀取。 */
void HariMain(void)
{
int i; /* 宣告變數。稱為 i 的變數是 32 位元的整數型別 */
for (i = 0xa0000; i <= 0xaffff; i++) {
write_mem8(i, 15); // 螢幕會顯示白色
// write_mem8(i, i & 0x0f); // 螢幕會顯示條紋色
}
for (;;) {
io_hlt(); /* 這樣在 nasmfunc.asm 的 io_hlt 將會執行 */
}
}
2. 進行編譯並執行
make run
【執行結果】 螢幕顯示條紋色
三、矩形的繪製與處理
- 專案原始檔:https://github.com/shouzo/My-30OS/tree/master/20210518/01_source3_rectangle
- 參考資料
- Linker Script初探 - GNU Linker Ld手冊略讀
- 10分鐘讀懂 linker scripts
- oslite.ldsを開いて、以下のとおり記述します。 (參考 oslite.lds 的環節來撰寫)
1. 修改主要程式碼
- bootpack.c (../01_source3_rectangle/bootpack.c)
- nasmfunc.asm (../01_source3_rectangle/nasmfunc.asm)
2. 要修改 Linker Script - os.lds
,程式碼如下:
- os.lds (…/01_source3_rectangle/os.lds)
OUTPUT_FORMAT(binary)
OUTPUT_ARCH(i386)
SECTIONS {
.head 0x0 :
{
LONG((ADDR(.bss) + SIZEOF(.bss) + 0xfff) & ~ 0xfff)
BYTE(0x4f) BYTE(0x53) BYTE(0x4c) BYTE(0x69)
LONG(0x0)
LONG(ADDR(.data))
LONG(SIZEOF(.data))
LONG(LOADADDR(.data))
LONG(0xe9000000)
LONG(HariMain - 0x20)
LONG((ADDR(.bss) + SIZEOF(.bss) + 0xf) & ~ 0xf)
}
.text ADDR(.head) + SIZEOF(.head) :
SUBALIGN (1)
{
*(.text)
}
.data 0x00000400 :
AT ( LOADADDR(.text) + SIZEOF(.text) ) SUBALIGN (4)
{
*(.data)
*(.rodata*)
}
.bss :
AT ( LOADADDR(.data) + SIZEOF(.data) ) SUBALIGN (4)
{
*(.bss)
}
/DISCARD/ : { *(*) }
}
3. 進行編譯並執行
make run
【執行結果】 螢幕顯示矩形
四、螢幕顯示出狀態列圖樣
1. 修改主要程式碼
- bootpack.c (../01_source4_status/bootpack.c)
2. 進行編譯並執行
make run
【執行結果】 螢幕顯示出狀態列圖樣