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

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

源码

操作系统开发系列—10.内核HelloWorld ●的更多相关文章

  1. 封装一个简单好用的打印Log的工具类And快速开发系列 10个常用工具类

    快速开发系列 10个常用工具类 http://blog.csdn.net/lmj623565791/article/details/38965311 ------------------------- ...

  2. 操作系统开发系列—12.f.在内核中添加中断处理 ●

    因为CPU只有一个,同一时刻要么是客户进程在运行,要么是操作系统在运行,如果实现进程,需要一种控制权转换机制,这种机制便是中断. 要做的工作有两项:设置8259A和建立IDT. /*========= ...

  3. 操作系统开发系列—12.d.扩充内核 ●

    现在把esp.GDT等内容放进内核中,我们现在可以用C语言了,只要能用C,我们就避免用汇编. 下面看切换堆栈和GDT的关键代码: ; 导入函数 extern cstart ; 导入全局变量 exter ...

  4. 操作系统开发系列—12.c.从Loader加载ELF内核,顺便解释下函数调用过程 ●

    实际上,我们要做的工作是根据内核的Program header table的信息进行类似下面这个C语言语句的内存复制: memcpy(p_vaddr, BaseOfLoaderPhyAddr+p_of ...

  5. 操作系统开发系列—12.a.从Loader到内核 ●

    Loader要做两项工作,我们先来做第一项,把内核加载到内存: 1.加载内核到内存. 2.跳入保护模式. 首先编译无内核时: nasm boot.asm -o boot.bin nasm loader ...

  6. 操作系统开发系列—1.HelloWorld ●

    org 07c00h ;伪指令,告诉编译器程序会被加载到7c00处 mov ax, cs mov ds, ax mov es, ax call DispStr ;调用显示字符串例程 jmp $ ;无限 ...

  7. 操作系统开发系列—12.g.在内核中设置键盘中断

    8259A虽然已经设置完成,但是我们还没有真正开始使用它呢. 所有的中断都会触发一个函数spurious_irq(),这个函数的定义如下: PUBLIC void spurious_irq(int i ...

  8. 操作系统开发系列—9.Loader

    一个操作系统从开机到开始运行,大致经历“引导—>加载内核入内存—>跳入保护模式—>开始执行内核”这样一个过程.也就是说,在内核开始执行之前不但要加载内核,而且还有准备保护模式等一系列 ...

  9. 操作系统开发系列—4.LDT

    一直以来,我们把所有的段描述符都放在GDT中,而不管它属于内核还是用户程序,为了有效地在任务之间实施隔离,处理器建议每个任务都应当具有自己的描述符表,称为局部描述符表LDT,并且把专属于自己的那些段放 ...

随机推荐

  1. Windows Azure Cloud Service (12) PaaS之Web Role, Worker Role, Azure Storage Queue(下)

    <Windows Azure Platform 系列文章目录> 本章DEMO部分源代码,请在这里下载. 在上一章中,笔者介绍了我们可以使用Azure PaaS的Web Role和Worke ...

  2. 性能调优:理解Set Statistics IO输出

    性能调优是DBA的重要工作之一.很多人会带着各种性能上的问题来问我们.我们需要通过SQL Server知识来处理这些问题.经常被问到的一个问题是:早上这个存储过程运行时间还是可以的,但到了晚上就很慢很 ...

  3. html/css/js小技巧实例

    一些学习中碰到的小技巧 让div自动撑起来: .clearfix:after{ content: "."; clear: both; display: block; visibil ...

  4. shell脚本专题之-----------全自动编译安装mysql

    mysql的编译安装,在博客 开源服务专题之--------mysql的编译安装 中已经说明了,但是还是比较麻烦,尤其是一大堆命令,来手动执行,稍有不慎,就会出错.生产上一般都是先在本地测试环境进行自 ...

  5. js限制文本框只可以输入数字

    封装了一下,要用的话直接调用下面getEvent函数即可   function getEvent() { if (document.all) { return window.event; //for ...

  6. 【转载】async & await 的前世今生(Updated)

    async 和 await 出现在C# 5.0之后,给并行编程带来了不少的方便,特别是当在MVC中的Action也变成async之后,有点开始什么都是async的味道了.但是这也给我们编程埋下了一些隐 ...

  7. 通过指定函数/方法形参类型提高PHP代码可靠性

    指定形参类型是PHP 5就支持的一项特性.形参支持array - 数组. object - 对象两种类型. class User{ public $name; public $password; fu ...

  8. 从零开始学Python04作业思路:模拟ATM电子银行

    标签(空格分隔):Python 一,程序文件说明 程序分为5个组成部分 bin:放置Python程序的启动接口文件 通过Python命令启动文件夹内文件即正常执行Python程序 例如:ATM_sta ...

  9. Android提升篇系列:Android项目代码优化实践

    Android开发中,不同的开发团队,不同的开发人员,在实际编码中会有一些不同的地方.但是,具有一定的更普适性的编码习惯,无疑还是相当重要的.本文主要罗列项目中常见的一些编码片段,并给出相关建议. 1 ...

  10. Java Selenium封装--RemoteWebElement

    package com.liuke.selenium.driver; import java.sql.SQLException; import java.util.List; import org.j ...