操作系统开发系列—10.内核HelloWorld ●

a.我们先来体验一下在Linux下用汇编编程的感觉,见代码

[section .data]	; 数据在此

strHello	db	"Hello, world!", 0Ah
STRLEN equ $ - strHello [section .text] ; 代码在此 global _start ; 我们必须导出 _start 这个入口,以便让链接器识别 _start:
mov edx, STRLEN
mov ecx, strHello
mov ebx, 1
mov eax, 4 ; sys_write
int 0x80 ; 系统调用
mov ebx, 0
mov eax, 1 ; sys_exit
int 0x80 ; 系统调用

编译方法:

nasm -f elf hello.asm -o hello.o

ld -m elf_i386 -s -o hello hello.o

./hello

运行结果是打印出Hello, world!

入口点默认的是_start,我们不但要定义它,而且要通过global这个关键字将它导出,这样链接程序才能找到它。两个系统调用不用深究,因为在我们自己的OS中根本用不到Linux的系统调用。

b.汇编和C同步使用

; 编译链接方法
; (ld 的‘-s’选项意为“strip all”)
;
; $ nasm -f elf foo.asm -o foo.o
; $ gcc -c bar.c -o bar.o
; $ ld -s hello.o bar.o -o foobar
; $ ./foobar
; the 2nd one
; $ extern choose ; int choose(int a, int b); [section .data] ; 数据在此 num1st dd 3
num2nd dd 4 [section .text] ; 代码在此 global _start ; 我们必须导出 _start 这个入口,以便让链接器识别
global myprint ; 导出这个函数为了让 bar.c 使用 _start:
push dword [num2nd] ; `.
push dword [num1st] ; |
call choose ; | choose(num1st, num2nd);
add esp, 8 ; / mov ebx, 0
mov eax, 1 ; sys_exit
int 0x80 ; 系统调用 ; void myprint(char* msg, int len)
myprint:
mov edx, [esp + 8] ; len
mov ecx, [esp + 4] ; msg
mov ebx, 1
mov eax, 4 ; sys_write
int 0x80 ; 系统调用
ret

1.由于在bar.c中用到函数myprint(),所以要用关键字global将其导出。

2.由于用到本文件外定义的函数choose(),所以要用关键字extern声明。

3.不管是myprint()还是choose(),遵循的都是C调用约定,后面的参数先入栈,并由调用者清理堆栈。

void myprint(char* msg, int len);

int choose(int a, int b)
{
if(a >= b){
myprint("the 1st one\n", 13);
}
else{
myprint("the 2nd one\n", 13);
} return 0;
}

编译和执行的过程:

nasm -f elf -o foo.o foo.asm

gcc -m32 -c -o bar.o bar.c

ld -m elf_i386 -s -o foobar foo.o bar.o

./foobar

运行结果:the 2nd one

操作系统开发系列—10.内核HelloWorld ●操作系统开发系列—10.内核HelloWorld ●操作系统开发系列—10.内核HelloWorld ●

操作系统开发系列—10.内核HelloWorld ●

有了关键字global和extern就可以方便地在汇编和C代码之间*来去。

操作系统开发系列—10.内核HelloWorld ●

源码

上一篇:Excel日期格式单元格写成yyyy.MM.dd格式将无法读取到DataTable


下一篇:IIS7.0 asp不能连接access数据 静态系统后台列表不显示 的问题