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/cn.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灯, 水草

请输入看板名称,例如:WOW站内搜寻

TOP