ASM 板


LINE

看板 ASM  RSS
first edit: 20120506 這是在傳統的 BIOS 的環境, UEFI 就不是這樣了。 相關文章: 作業系統之前的程式 (1) - c++ 篇 ( http://goo.gl/HJy4jn ) 作業系統之前的程式 (2) - c++ global object ctor/dtor can not be invoked ( http://goo.gl/S248QM ) 這是我在 mosut ( http://goo.gl/YEfGEz ) 分享的主題。介紹一下在作業系統之前的程 式 (僅僅印出個字串)。寫一個作業系統之前的程式就和在作業系統下很類似, 不過有幾 點要注意。 bootloader hello world 被載入的位址是 0x7c00, 也就是從這裡開始執行。 510, 511 byte 必須是 0xaa, 0x55 結尾。 不能大於 512 byte, 其實扣掉 0x11, 0x55 2 byte, 只能有 510 byte。 沒有 printf 可以用, 得使用 bios call 或是寫入 video ram 來完成螢幕的輸出。 可以使用組合語言, 還有大家很熟悉的 c/c++ 語言來寫這樣的練習程式, 其他可用的語 言我就不知道了, 我只實作過這幾種語言。不過使用的 toolchain 和在作業系統下有點 不同。也就是說, 程式的寫法是一樣的, 但是使用 compiler 產生執行檔的方式是不一樣 的。而使用 C 語言只是展示用, 實際上一個 bootloader 要完成的事情可能無法使用C 語言來完成, 因為很容易就超過 512 byte。 bh.asm 1 ( http://goo.gl/l2TEyL ) org 07c00h ; 告訴編譯器程序加載到 7c00 處 2 ( http://goo.gl/l2TEyL ) mov ax, cs 3 ( http://goo.gl/l2TEyL ) mov ds, ax 4 ( http://goo.gl/l2TEyL ) mov es, ax 5 ( http://goo.gl/l2TEyL ) call DispStr ; 使用顯示字元串例程 6 ( http://goo.gl/l2TEyL ) jmp $ ; 無限循環 7 ( http://goo.gl/l2TEyL ) DispStr: 8 ( http://goo.gl/l2TEyL ) mov ax, BootMessage 9 ( http://goo.gl/l2TEyL ) mov bp, ax ; ES:BP = 串位址 10 ( http://goo.gl/l2TEyL ) mov cx, 16 ; CX = 串長度 11 ( http://goo.gl/l2TEyL ) mov ax, 01301h ; AH = 13, AL = 01h 12 ( http://goo.gl/l2TEyL ) mov bx, 000ch ; 頁號為 0(BH = 0) 黑底紅字 (BL = 0Ch, 高亮) 13 ( http://goo.gl/l2TEyL ) mov dl, 0 14 ( http://goo.gl/l2TEyL ) int 10h ; 10h 號中斷 15 ( http://goo.gl/l2TEyL ) ret 16 ( http://goo.gl/l2TEyL ) BootMessage: db "Hello, NASM!" 17 ( http://goo.gl/l2TEyL ) times 510-($-$$) db 0 ; 填充剩下的空間,使生成的 二進制程式碼恰好為 512 字節 18 ( http://goo.gl/l2TEyL ) dw 0xaa55 ; 結束標誌 bh.asm 是使用 nasm 來完成的 bootloader 程式 (from Orange's 一個作業系統的實現 ( http://goo.gl/fFD7QT ) p 1-3), 範例的組合語言的是 intel 語法。使用 nasm 產生 bootloader 的可執行檔很簡單。 nasm bh.asm -o bh.asm.bin bh.asm.bin 為 512 byte 的執行檔, 寫入軟碟第 1 個磁區即可。把軟碟放入開機後即可 看到 Hello, NASM! ( http://goo.gl/W1OxZx ) bh.s 1 ( http://goo.gl/l2TEyL ) .code16 2 ( http://goo.gl/l2TEyL ) .text 3 ( http://goo.gl/l2TEyL ) .global begin 4 ( http://goo.gl/l2TEyL ) begin: 5 ( http://goo.gl/l2TEyL ) mov %cs,%ax 6 ( http://goo.gl/l2TEyL ) mov %ax,%ds 7 ( http://goo.gl/l2TEyL ) mov %ax,%es 8 ( http://goo.gl/l2TEyL ) movw $0xb800, %ax 9 ( http://goo.gl/l2TEyL ) movw %ax, %gs 10 ( http://goo.gl/l2TEyL ) 11 ( http://goo.gl/l2TEyL ) 12 ( http://goo.gl/l2TEyL ) mov $0, %edi /* Destination */ 13 ( http://goo.gl/l2TEyL ) mov $msg, %esi /* Source */ 14 ( http://goo.gl/l2TEyL ) 15 ( http://goo.gl/l2TEyL ) 1: 16 ( http://goo.gl/l2TEyL ) #cmp $0, %ecx 17 ( http://goo.gl/l2TEyL ) cmpb $0, (%esi) 18 ( http://goo.gl/l2TEyL ) jz 2f 19 ( http://goo.gl/l2TEyL ) movb %ds:(%esi), %al 20 ( http://goo.gl/l2TEyL ) inc %esi 21 ( http://goo.gl/l2TEyL ) movb %al, %gs:(%edi) 22 ( http://goo.gl/l2TEyL ) inc %edi 23 ( http://goo.gl/l2TEyL ) movb $0xc, %gs:(%edi) 24 ( http://goo.gl/l2TEyL ) inc %edi 25 ( http://goo.gl/l2TEyL ) dec %ecx 26 ( http://goo.gl/l2TEyL ) jmp 1b 27 ( http://goo.gl/l2TEyL ) 2: 28 ( http://goo.gl/l2TEyL ) movb $'E', %gs:(160) 29 ( http://goo.gl/l2TEyL ) jmp . 30 ( http://goo.gl/l2TEyL ) #msg:.ascii "Hello GAS" 31 ( http://goo.gl/l2TEyL ) msg: 32 ( http://goo.gl/l2TEyL ) .asciz "Hello GAS" 33 ( http://goo.gl/l2TEyL ) #.asciz "Hello World" 34 ( http://goo.gl/l2TEyL ) .org 510 35 ( http://goo.gl/l2TEyL ) .word 0xaa55 36 ( http://goo.gl/l2TEyL ) bh.s 是使用 gas 來完成的 bootloader 程式,範例的組合語言是at & t 語法, 使用 gas 產生 bootloader 的可執行檔有點複雜, 除了程式碼本身, 還要一個 linker script, 在連結的時候使用。 as.ld 1 ( http://goo.gl/l2TEyL ) ENTRY(begin); 2 ( http://goo.gl/l2TEyL ) SECTIONS 3 ( http://goo.gl/l2TEyL ) { 4 ( http://goo.gl/l2TEyL ) . = 0x7C00; 5 ( http://goo.gl/l2TEyL ) .text : AT(0x7C00) 6 ( http://goo.gl/l2TEyL ) { 7 ( http://goo.gl/l2TEyL ) _text = .; 8 ( http://goo.gl/l2TEyL ) *(.text); 9 ( http://goo.gl/l2TEyL ) _text_end = .; 10 ( http://goo.gl/l2TEyL ) } 11 ( http://goo.gl/l2TEyL ) .data : 12 ( http://goo.gl/l2TEyL ) { 13 ( http://goo.gl/l2TEyL ) _data = .; 14 ( http://goo.gl/l2TEyL ) *(.bss); 15 ( http://goo.gl/l2TEyL ) *(.bss*); 16 ( http://goo.gl/l2TEyL ) *(.data); 17 ( http://goo.gl/l2TEyL ) *(.rodata*); 18 ( http://goo.gl/l2TEyL ) *(COMMON) 19 ( http://goo.gl/l2TEyL ) _data_end = .; 20 ( http://goo.gl/l2TEyL ) } 21 ( http://goo.gl/l2TEyL ) /* 22 ( http://goo.gl/l2TEyL ) .sig : AT(0x7DFE) 23 ( http://goo.gl/l2TEyL ) { 24 ( http://goo.gl/l2TEyL ) SHORT(0xaa55); 25 ( http://goo.gl/l2TEyL ) } 26 ( http://goo.gl/l2TEyL ) */ 27 ( http://goo.gl/l2TEyL ) /DISCARD/ : 28 ( http://goo.gl/l2TEyL ) { 29 ( http://goo.gl/l2TEyL ) *(.note*); 30 ( http://goo.gl/l2TEyL ) *(.iplt*); 31 ( http://goo.gl/l2TEyL ) *(.igot*); 32 ( http://goo.gl/l2TEyL ) *(.rel*); 33 ( http://goo.gl/l2TEyL ) *(.comment); 34 ( http://goo.gl/l2TEyL ) /* add any unwanted sections spewed out by your version of gcc and flags here */ 35 ( http://goo.gl/l2TEyL ) } 36 ( http://goo.gl/l2TEyL ) } 產生 bootloader 執行檔的步驟為: as -o bh.s.o bh.s ld -Tas.ld -o bh.s.elf bh.s.o objcopy -O binary bh.s.elf bh.s.bin ( http://goo.gl/T9QT13 ) bh.s.bin 就是 bootloader 執行檔, 不像 nasm 那麼乾脆是吧! 你一定不喜歡, 不過這 樣的學習負擔是有額外的收穫的。下面的 C 語言版本就需要這樣的作法。 cb.c 1 ( http://goo.gl/l2TEyL ) __asm__(".code16gcc\n"); 2 ( http://goo.gl/l2TEyL ) /* 3 ( http://goo.gl/l2TEyL ) * c bootloader 4 ( http://goo.gl/l2TEyL ) */ 5 ( http://goo.gl/l2TEyL ) 6 ( http://goo.gl/l2TEyL ) 7 ( http://goo.gl/l2TEyL ) 8 ( http://goo.gl/l2TEyL ) void main(const char *s); 9 ( http://goo.gl/l2TEyL ) 10 ( http://goo.gl/l2TEyL ) int bbb=0; // test bss section 11 ( http://goo.gl/l2TEyL ) 12 ( http://goo.gl/l2TEyL ) void WinMain(void) 13 ( http://goo.gl/l2TEyL ) { 14 ( http://goo.gl/l2TEyL ) main("hello world"); 15 ( http://goo.gl/l2TEyL ) while(1); 16 ( http://goo.gl/l2TEyL ) } 17 ( http://goo.gl/l2TEyL ) 18 ( http://goo.gl/l2TEyL ) void main(const char *s) 19 ( http://goo.gl/l2TEyL ) { 20 ( http://goo.gl/l2TEyL ) while(*s) 21 ( http://goo.gl/l2TEyL ) { 22 ( http://goo.gl/l2TEyL ) __asm__ __volatile__ ("int $0x10" : : "a"(0x0E00 | *s), "b"(7)); 23 ( http://goo.gl/l2TEyL ) s++; 24 ( http://goo.gl/l2TEyL ) } 25 ( http://goo.gl/l2TEyL ) } 很像一般的 C 程式吧!不過我們有著 windows 才有的 WinMain 和一般 C 的 main, 哪 個才是程式開始的地方呢?仍然需要搭配的 linker script, 從以下的 linker script 可以看出, 我們的程式由 WinMain 開始。 l.ld 1 ( http://goo.gl/l2TEyL ) /* for cb.c */ 2 ( http://goo.gl/l2TEyL ) ENTRY(WinMain); 3 ( http://goo.gl/l2TEyL ) SECTIONS 4 ( http://goo.gl/l2TEyL ) { 5 ( http://goo.gl/l2TEyL ) . = 0x7C00; 6 ( http://goo.gl/l2TEyL ) .text : AT(0x7C00) 7 ( http://goo.gl/l2TEyL ) { 8 ( http://goo.gl/l2TEyL ) _text = .; 9 ( http://goo.gl/l2TEyL ) *(.text); 10 ( http://goo.gl/l2TEyL ) _text_end = .; 11 ( http://goo.gl/l2TEyL ) } 12 ( http://goo.gl/l2TEyL ) .data : 13 ( http://goo.gl/l2TEyL ) { 14 ( http://goo.gl/l2TEyL ) _data = .; 15 ( http://goo.gl/l2TEyL ) *(.bss); 16 ( http://goo.gl/l2TEyL ) *(.bss*); 17 ( http://goo.gl/l2TEyL ) *(.data); 18 ( http://goo.gl/l2TEyL ) *(.rodata*); 19 ( http://goo.gl/l2TEyL ) *(COMMON) 20 ( http://goo.gl/l2TEyL ) _data_end = .; 21 ( http://goo.gl/l2TEyL ) } 22 ( http://goo.gl/l2TEyL ) .sig : AT(0x7DFE) 23 ( http://goo.gl/l2TEyL ) { 24 ( http://goo.gl/l2TEyL ) SHORT(0xaa55); 25 ( http://goo.gl/l2TEyL ) } 26 ( http://goo.gl/l2TEyL ) /DISCARD/ : 27 ( http://goo.gl/l2TEyL ) { 28 ( http://goo.gl/l2TEyL ) *(.note*); 29 ( http://goo.gl/l2TEyL ) *(.iplt*); 30 ( http://goo.gl/l2TEyL ) *(.igot*); 31 ( http://goo.gl/l2TEyL ) *(.rel*); 32 ( http://goo.gl/l2TEyL ) *(.comment); 33 ( http://goo.gl/l2TEyL ) /* add any unwanted sections spewed out by your version of gcc and flags here */ 34 ( http://goo.gl/l2TEyL ) } 35 ( http://goo.gl/l2TEyL ) } 使用以下的步驟來產生 bootloader 執行檔: gcc -fno-stack-protector -std=c99 -march=i686 -ffreestanding -Wall -c cb.c ld -Tl.ld -nostdlib -o cb.elf cb.o objcopy -R .pdr -R .comment -R.note -S -O binary cb.elf cb.bin 最前面提到的第一點: 載入的位址是 0x7c00, 這表示, 在程式裡變數的位址要從 0x7c00 來當作計算標準。nasm 使用 org 07c00h 來達成目的。而 gas 使用 linker script 來完成。C 版本也是一樣。 as.ld L4 . = 0x7C00; 就是告訴 ld 用 0x7c00 來計算位址, 而不是從 0 開始算起。 至於第二點: nasm 使用 bh.asm L17, 18 的方式來產生 0xaa55; gas 使用 bh.s L34, 35 的方法來產生 0xaa55; C 版本則使用 linker script 來產生 0xaa55, l.ld L21 ~ 24 20120611 補充 C 語言篇: 模擬器畢竟是模擬器, 在真實的機器上測試果然就有問題了, 需要加入 L14 - L17, 將 %ds, %ss, %sp 設定好才行。 cb.c 1 ( http://goo.gl/3d1tcH ) __asm__(".code16gcc\n"); 2 ( http://goo.gl/3d1tcH ) /* 3 ( http://goo.gl/3d1tcH ) * c bootloader 4 ( http://goo.gl/3d1tcH ) */ 5 ( http://goo.gl/3d1tcH ) 6 ( http://goo.gl/3d1tcH ) //#define POINTER_TEST 7 ( http://goo.gl/3d1tcH ) 8 ( http://goo.gl/3d1tcH ) void main(const char *s); 9 ( http://goo.gl/3d1tcH ) 10 ( http://goo.gl/3d1tcH ) int bbb=0; // test bss section 11 ( http://goo.gl/3d1tcH ) 12 ( http://goo.gl/3d1tcH ) void WinMain(void) 13 ( http://goo.gl/3d1tcH ) { 14 ( http://goo.gl/3d1tcH ) __asm__ ("mov %cs, %ax\n"); 15 ( http://goo.gl/3d1tcH ) __asm__ ("mov %ax, %ds\n"); 16 ( http://goo.gl/3d1tcH ) __asm__ ("mov %ax, %ss\n"); 17 ( http://goo.gl/3d1tcH ) __asm__ ("mov $0xff00, %sp\n"); ... 35 ( http://goo.gl/3d1tcH ) } 36 ( http://goo.gl/3d1tcH ) 37 ( http://goo.gl/3d1tcH ) #ifndef POINTER_TEST 38 ( http://goo.gl/3d1tcH ) void main(const char *s) 39 ( http://goo.gl/3d1tcH ) { 40 ( http://goo.gl/3d1tcH ) while(*s) 41 ( http://goo.gl/3d1tcH ) { 42 ( http://goo.gl/3d1tcH ) __asm__ __volatile__ ("int $0x10" : : "a"(0x0E00 | *s), "b"(7)); 43 ( http://goo.gl/3d1tcH ) s++; 44 ( http://goo.gl/3d1tcH ) } 45 ( http://goo.gl/3d1tcH ) } 46 ( http://goo.gl/3d1tcH ) #endif 執行畫面像這樣: ( http://goo.gl/8BtA2Q ) 20120726 補充: 身為 c++ 愛好者, 怎麼可以沒有 c++ 版本, 要不是因為 c++ runtime 實在太過複雜, 只好先屈就 c runtime, 我實際上很想用 c++ 來寫 os。 先來看看 c++ 版本, 不知道為什麼 g++ 一定會檢查 main() 的 prototype (加上 -ffreestanding 即可, 這樣 g++ 就不會檢查 main() prototype), 所以無法任意宣告 ( 一定要 int main(int argc, char** argv)), 我只好將 main 改成 print, 我不知道有 無 option 可以關掉這種檢查。其他和 c 版本差不多。 12 ( http://goo.gl/3d1tcH ) extern "C" void WinMain(void) c++ Mangling ( http://goo.gl/blDB4P ) 的特性會把 function 重新改名, 使用 L:12 來避免這樣的情形, 因為 linker script 指定 WinMain 當進入點, 要不然自己改 linker script。 用了一個 c++ 的特性, function 的參數可以有預設值, 要不然就和 c 版本沒什麼差別 了。 8 ( http://goo.gl/3d1tcH ) void print(const char *s, const char *msg="\r\ng++ test"); cppb.cpp 1 ( http://goo.gl/3d1tcH ) __asm__(".code16gcc\n"); 5 ( http://goo.gl/3d1tcH ) 7 ( http://goo.gl/3d1tcH ) 8 ( http://goo.gl/3d1tcH ) void print(const char *s, const char *msg="\r\ng++ test"); 9 ( http://goo.gl/3d1tcH ) 11 ( http://goo.gl/3d1tcH ) 12 ( http://goo.gl/3d1tcH ) extern "C" void WinMain(void) 13 ( http://goo.gl/3d1tcH ) { 14 ( http://goo.gl/3d1tcH ) __asm__ ("mov %cs, %ax\n"); 15 ( http://goo.gl/3d1tcH ) __asm__ ("mov %ax, %ds\n"); 16 ( http://goo.gl/3d1tcH ) __asm__ ("mov %ax, %ss\n"); 17 ( http://goo.gl/3d1tcH ) __asm__ ("mov $0xfff0, %sp\n"); 25 ( http://goo.gl/3d1tcH ) print("hello cpp"); 36 ( http://goo.gl/3d1tcH ) while(1); 37 ( http://goo.gl/3d1tcH ) } 38 ( http://goo.gl/3d1tcH ) 40 ( http://goo.gl/3d1tcH ) void print(const char *s, const char *msg) 41 ( http://goo.gl/3d1tcH ) { 42 ( http://goo.gl/3d1tcH ) #if 1 43 ( http://goo.gl/3d1tcH ) while(*s) 44 ( http://goo.gl/3d1tcH ) { 45 ( http://goo.gl/3d1tcH ) __asm__ __volatile__ ("int $0x10" : : "a"(0x0E00 | *s), "b"(7)); 46 ( http://goo.gl/3d1tcH ) s++; 47 ( http://goo.gl/3d1tcH ) } 48 ( http://goo.gl/3d1tcH ) #endif 49 ( http://goo.gl/3d1tcH ) #if 1 50 ( http://goo.gl/3d1tcH ) while(*msg) 51 ( http://goo.gl/3d1tcH ) { 52 ( http://goo.gl/3d1tcH ) __asm__ __volatile__ ("int $0x10" : : "a"(0x0E00 | *msg), "b"(7)); 53 ( http://goo.gl/3d1tcH ) msg++; 54 ( http://goo.gl/3d1tcH ) } 55 ( http://goo.gl/3d1tcH ) #endif 56 ( http://goo.gl/3d1tcH ) } 使用以下的步驟來產生 bootloader 執行檔 (linker script 同 c 版本那個): g++ -m32 -g -Wall -Wextra -Werror -nostdlib -fno-builtin -nostartfiles -nodefaultlibs -fno-exceptions -fno-rtti -fno-stack-protector -c cppb.cpp ld -m elf_i386 -static -Tl.ld -nostdlib -M -o cppb.elf cppb.o > cb.elf.map objcopy -R .pdr -R .comment -R.note -S -O binary cppb.elf cppb.bin ref: http://wiki.osdev.org/C%2b%2b_Bare_Bones ( http://goo.gl/EeqHT ) 真實機器的執行畫面。 ( http://goo.gl/DqyqjX ) 以下方式可以取得本文的程式碼: git clone [email protected]:descent/simple_os.git cd simple_os git checkout origin/cpp_bootloader -b cpp_bootloader // 本文使用 Blog2BBS 自動將Blog文章轉成縮址的BBS純文字 http://goo.gl/TZ4E17 // blog 原文: http://descent-incoming.blogspot.tw/2012/05/0-hello-xyz.html --



※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 58.114.140.89
※ 文章網址: http://webptt.com/m.aspx?n=bbs/ASM/M.1402114724.A.51E.html
1F:推 aelin:push 06/07 13:50
2F:推 alibuda174:推專業 06/08 08:41
3F:推 mikeqoo1:推 06/29 22:49







like.gif 您可能會有興趣的文章
icon.png[問題/行為] 貓晚上進房間會不會有憋尿問題
icon.pngRe: [閒聊] 選了錯誤的女孩成為魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一張
icon.png[心得] EMS高領長版毛衣.墨小樓MC1002
icon.png[分享] 丹龍隔熱紙GE55+33+22
icon.png[問題] 清洗洗衣機
icon.png[尋物] 窗台下的空間
icon.png[閒聊] 双極の女神1 木魔爵
icon.png[售車] 新竹 1997 march 1297cc 白色 四門
icon.png[討論] 能從照片感受到攝影者心情嗎
icon.png[狂賀] 賀賀賀賀 賀!島村卯月!總選舉NO.1
icon.png[難過] 羨慕白皮膚的女生
icon.png閱讀文章
icon.png[黑特]
icon.png[問題] SBK S1安裝於安全帽位置
icon.png[分享] 舊woo100絕版開箱!!
icon.pngRe: [無言] 關於小包衛生紙
icon.png[開箱] E5-2683V3 RX480Strix 快睿C1 簡單測試
icon.png[心得] 蒼の海賊龍 地獄 執行者16PT
icon.png[售車] 1999年Virage iO 1.8EXi
icon.png[心得] 挑戰33 LV10 獅子座pt solo
icon.png[閒聊] 手把手教你不被桶之新手主購教學
icon.png[分享] Civic Type R 量產版官方照無預警流出
icon.png[售車] Golf 4 2.0 銀色 自排
icon.png[出售] Graco提籃汽座(有底座)2000元誠可議
icon.png[問題] 請問補牙材質掉了還能再補嗎?(台中半年內
icon.png[問題] 44th 單曲 生寫竟然都給重複的啊啊!
icon.png[心得] 華南紅卡/icash 核卡
icon.png[問題] 拔牙矯正這樣正常嗎
icon.png[贈送] 老莫高業 初業 102年版
icon.png[情報] 三大行動支付 本季掀戰火
icon.png[寶寶] 博客來Amos水蠟筆5/1特價五折
icon.pngRe: [心得] 新鮮人一些面試分享
icon.png[心得] 蒼の海賊龍 地獄 麒麟25PT
icon.pngRe: [閒聊] (君の名は。雷慎入) 君名二創漫畫翻譯
icon.pngRe: [閒聊] OGN中場影片:失蹤人口局 (英文字幕)
icon.png[問題] 台灣大哥大4G訊號差
icon.png[出售] [全國]全新千尋侘草LED燈, 水草

請輸入看板名稱,例如:e-shopping站內搜尋

TOP