用java和汇编开发一个Hello World系统内核
生活随笔
收集整理的這篇文章主要介紹了
用java和汇编开发一个Hello World系统内核
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 1 匯編實現
- 1.1 匯編實現
- 1.2 使用nasm編譯器進行編譯
- 2 利用java生成軟盤文件
- 2.1 利用java生成軟盤文件的代碼如下
1 匯編實現
1.1 匯編實現
匯編代碼如下:
org 0x7c00;entry:mov ax, 0mov ss, axmov ds, axmov es, axmov si, msgputloop:mov al, [si]add si, 1cmp al, 0je finmov ah, 0x0emov bx, 15int 0x10jmp putloopfin:HLTjmp finmsg:DB 0x0a, 0x0adb "hello, world"db 0x0adb 0上面的匯編代碼主要是設置了一些初始化數據,然后調用bios中斷,將某個緩沖區中的字符打印到屏幕上,然后進入一個死循環。代碼段的詳細解釋如下:
/* org 的意思是origin, 中文意思是“起始,起源,” org 后面的7c00 是物理內存地址,假設物理內存是一個byte類型 的大數組,例如byte[] memory, 如果你有2 G內容,換算成字節就是2097152, 也就相當于memory數組有2097152字 節,于是當虛擬機上電,然后new一塊內存 byte[] memory = new byte[2097152]. org 0x7c00 的意思是將本匯編 編譯后的二進制數據從memory[0x7c00]處寫入memory. */ org 0x7c00;/* jmp entry 中的jmp 其實就是c語言中的語句goto, jmp entry 其實是讓cpu跳轉到entry 處,執行entry下面的代 碼,如果entry是一個函數名字的話,jmp entry 相當于調用entry函數,類比于java就是函數調用:entry(); */ jmp entry// 下面的代碼一直到RESB 18這行代碼是可以直接刪除的,我這里之所以放在這里是為了記錄一下匯編知識點 /* jmp entry 對應的機器代碼,長度是3字節,那么db 0x90 的意思就是 memory[0x7c00+3] = 0x90, 也就是說db 0x90 實際上做的是賦值操作,db 0x90 表示將給定位置處的一個字節賦予數值0x90, 賦值的內存位置就在0x7c00+3處。 */ db 0x90 /* DB 和 db 是同一個意思, 那么DB “OSKERNEL” 意思是,strcpy(memory + 0x7c00 + 3 + 1, “OSKERNEL”); 也就 是把”OSKERNEL”這個字符串拷貝到內存0x7c00 + 3 + 1 處, 3是什么意思呢,3就是jmp entry 編譯成二進制代碼后 的數據長度, 1 就是db 0x90 所所賦值的那個字節的長度。DW 跟DB是一個意思, DB 是將數據賦值給一個字節,由于 一個字節只有8位,那么賦值給這個字節的數據大小不能超過256, 512大于256,所以需要兩個字節才能存儲512這個數 據,DD 0xFFFFFFFF 就是把0xFFFFFFFF存儲到四個字節長的內存中, 語句RESB 18 表示把接下來的18個字節的內存全 部初始化為0,轉換為java代碼就類似于: byte[] block = new byte[18]; for (int i = 0; i < 18; i++) { block[i] = 0; } */ DB "OSKERNEL" DW 512 DB 1 DW 1 DB 2 DW 224 DW 2880 DB 0xf0 DW 9 DW 18 DW 2 DD 0 DD 2880 DB 0,0,0x29 DD 0xFFFFFFFF DB "MYFIRSTOS " DB "FAT12 " RESB 18entry: /* 先做的是初始化一系列寄存器,寄存器其實相當于java程序中,我們定義的變量,ax 是一個2字節長的寄存器, mov ax, 0是把數值0放入到ax寄存器中,類比于java 就是: char ax = 0; char類型的數據在java中是兩個字節長,跟寄存器ax的長度一樣,類似的,語句: mov ss, ax 相當于java的 char ss = ax; 后面的語句意思類推。 */mov ax, 0mov ss, axmov ds, axmov es, ax /* 我們要注意看語句 mov si, msg. msg 相當于一段內存, msg: DB 0x0a, 0x0a db “hello, world” db 0x0a 就類似于 C 語言中的char* msg = “\n\nhello,world\n”. 字符’\n’的ascii值就是0xa.mov si, msg 就相當于把msg內存的起始地址放入到寄存器si里。如果用C語言做類比,那么就相當于: char* si = msg; */mov si, msgputloop: /* mov al, [si] [si]表示讀取si存儲的內存地址處的一個字節長度的信息, mov al, [si] ,把該字節的數據存儲到寄存器al 中,ax是兩個字節長度的寄存器,這樣ax就可以分解成兩部分,第一 部分就對應于al, 第二部分就對應于ah, 也就是al, ah合起來就是ax, 對應于C語言就相當于 char ax[2], al 表示的是ax[0], ah 表示的就是 ax[1], mov al, [si], 轉換成C語言就是 char al = *si; */mov al, [si] /* add si, 1 表示將寄存器si中的數值加1,也就相當于C語言的 si++; */add si, 1 /* cmp al, 0 表示將al寄存器中的數據跟0比較,看al中的值是否等于0 */cmp al, 0 /* je fin 中的 je 表示 jump if equal, 也就是如果al 的值確實等于0,那么就跳轉到fin所表示的代碼處去執行,轉 換成C語言就是 : if (al == 0) { goto fin } */je fin/* mov ah, 0xe 就是把0xe賦值給寄存器 ah, mov bx ,15 同理。接下來要調用一個中斷,中斷其實就是一個函數調用, 我們在寫c語言或java程序時,往往需要調用一些系統庫函數,例如printf, 或java的System.out.print. 中斷就是 bios提供給匯編語言的庫函數,這些庫函數都放入到一個數組里,int 0x10 意思是在庫函數數組中取出第0x10個庫函 數,然后執行該庫函數的代碼。我們知道,函數調用時需要傳遞參數,那么調用bios提供的函數時,怎么傳遞參數呢,做法是,把需要傳遞的參數放入到 指定的寄存器中,例如想要在屏幕上輸出字符,那么bios提供的編號為0x10的庫函數可以實現這個功能,同時按規定, 要把寄存器ah設置為0x0e, 把要輸出的字符的ascii值放入到寄存器al, 同時要把寄存器設bh的值設置成0,字符的顏色 可以通過寄存器bl的值來設定。看起來相當麻煩,這是由于我們做的是非常底層的編程,所以麻煩也就不可避免。 */mov ah, 0x0emov bx, 15int 0x10jmp putloop /* 于是代碼片段: putloop: mov al, [si] add si, 1 cmp al, 0 je fin mov ah, 0x0e mov bx, 15 int 0x10 jmp putloop就相當于C語言: do { char al = *si; si++; if (al == 0) { goto fin }printf(“%c”, al); } while(true); *//* hlt 表示 halt, 也就是讓cpu進入休眠狀態,如果此時我們點擊一下鍵盤,或動一下鼠標,那么cpu就被喚醒,然后執行hlt后面的語句: jmp fin 也就是跳轉到fin開始處去執行,也就是進入了死循環。 */ fin:HLTjmp finmsg:DB 0x0a, 0x0adb "hello, world"db 0x0adb 01.2 使用nasm編譯器進行編譯
nasm boot.asm -o boot.bat 。
2 利用java生成軟盤文件
2.1 利用java生成軟盤文件的代碼如下
import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList;public class OperatingSystem {private ArrayList<Integer> imgByteToWrite = new ArrayList<Integer>();private void readKernelFormatFile(String fileName){File file = new File(fileName);FileInputStream in = null;try{in = new FileInputStream(file);int val = 0;while ((val = in.read()) != -1){imgByteToWrite.add(val);}in.close();}catch (IOException e){e.printStackTrace();return;}// 當前代碼之后至510字節全部寫0int len = 510;int curlen = imgByteToWrite.size();for (int i=curlen; i<len; i++){imgByteToWrite.add(0);}// 第511、512字節為磁盤主引導扇區的有效標志,必須為0x55、0xaaimgByteToWrite.add(0x55);imgByteToWrite.add(0xaa);//imgByteToWrite.add(0xf0);//imgByteToWrite.add(0xff);//imgByteToWrite.add(0xff);}public OperatingSystem(String fileName) {readKernelFormatFile(fileName);// 1.44MB大小的軟盤int len = 0x168000;int curSize = imgByteToWrite.size();for (int i=curSize; i<len; i++) {imgByteToWrite.add(0);}}public void makeFllopy() {try {DataOutputStream out = new DataOutputStream(new FileOutputStream("system.img"));for (int i = 0; i < imgByteToWrite.size(); i++) {out.writeByte(imgByteToWrite.get(i).byteValue());}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}public static void main(String[] args) {OperatingSystem op = new OperatingSystem("boot.bat");op.makeFllopy();} }參考資料:
總結
以上是生活随笔為你收集整理的用java和汇编开发一个Hello World系统内核的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深州装修公司排名前十口碑推荐有哪些?
- 下一篇: 数据库与数据库管理系统的基本概念