操作系统系统内核开发:内核编译自动化

若想更好的理解本节内容,可参看视频:
用java开发编译器

在前面的章节中,我们内核的编译始终是手动的,例如编译内核的C语言部分时,都是手动编译各个模块,然后手链接成一个二进制文件,然后再手动反汇编。要想成为一个合格的技术人员,这种手动模式是很不专业的,一是手动处理很容易出错,假如我们更新了某个模块,却忘了重新编译链接的话,那么最后的内核就会出现一些难以排除的诡异bug;二是,自动化程度是菜鸟和大牛的区别,我们可以发现,那些技术大牛,都是依赖脚步自动化来加速开发流程的,因此,不懂得将业务逻辑进行自动化实现,就无法真正的提升自己的技术内核。

从本节开始,我们将把以前手动处理的业务流程,全面自动化。第一个要自动化的,是内核C模块部分的编译,反汇编,以及从虚拟机拷贝到实体机。现在我们C内核有以下几部分组成,write_vga_desktop.c, mem_util.c, mem_util.h, win_sheet.c, win_sheet.h。我们将通过下面的makefile文件实现这些源代码文件编译,链接,反汇编,以及拷贝等流程,makefile内容如下:

ckernel : ckernel_u.asm
 cp ckernel_u.asm win_sheet.h win_sheet.c mem_util.h mem_util.c write_vga_desktop.c makefile '/media/psf/Home/Documents/操作系统/文档/19/OS-kernel-win-sheet/'
ckernel_u.asm : ckernel.o
 ./objconv -fnasm ckernel.o ckernel_u.asm
ckernel.o : write_vga_desktop.o win_sheet.o mem_util.o
 ld -m elf_i386 -r write_vga_desktop.o mem_util.o win_sheet.o -o ckernel.o
write_vga_desktop.o : write_vga_desktop.c win_sheet.c win_sheet.h mem_util.c mem_util.h
 gcc -m32 -fno-asynchronous-unwind-tables -s -c -o write_vga_desktop.o write_vga_desktop.c
win_sheet.o : win_sheet.c win_sheet.h
 gcc -m32 -fno-asynchronous-unwind-tables -s -c -o win_sheet.o win_sheet.c
mem_util.o : mem_util.h mem_util.c
 gcc -m32 -fno-asynchronous-unwind-tables -s -c -o mem_util.o mem_util.c

makefile 由以下文法格式组成:
target : prerequest
command

target 指要实现的目标,prerequest 是指完成目标要具备的先前条件,command指的是实现目标需要运行的指令。以上面内容为例,ckernel是一个目标,一个目标可以任意命名,实现ckernel这个目标的前提是ckernel_u.asm这个文件必须存在,如果这个文件存在,则执行cp拷贝命令,把指定的文件拷贝到指定目录。如果ckernel_u.asm 这个文件不存在,那么make程序则执行下面的命令,以便生成ckernel_u.asm这个文件,这个规则以此类推。

有了上面的makefile文件后,每次我们修改相关文件,或增添新的模块,只要把makefile做一些小更改,然后只要直接运行命令make就可以了,不用再像以前一样,对每个单独模块各自编译,然后再统一链接,这么做不但容易出错,而且消耗不必要的宝贵精力。

反编译好内核的C模块后,把该模块反汇编,要想结合近内核汇编模块,我们还需要做的,就是把反汇编文件内的一些不必要的语句给删除,前面章节我们提到过,要删除那些带有 global, extern, SECTION 等指令语句,才能正常对结合后的汇编代码进行编译,例如下面是反汇编后的代码中需要删除的部分:


这里写图片描述

原来我在视频中,给大家展示的是手动删除这些语句,手动删除很容易出错,而且很累,现在,我们用java开发这种功能,以实现删除自动化,算法原理很简单,读入ckernlen_u.asm文件,然后每次获取一行,如果改行含有关键字global, extern, SECTION, 那么程序就把这一行给删除,代码如下:

public void process() {
     String lineText = null;
     try {
   while ((lineText = fileReader.readLine()) != null) {
    String line = lineText.toLowerCase();
    if (line.contains("global") || line.contains("extern") || line.contains("section")) {
     continue;
    }
    
    fileBuffer.append(lineText).append("\r\n");
   }
   
   fileReader.close();
   BufferedWriter bw = new BufferedWriter(new FileWriter("ckernel.asm"));
   bw.write(fileBuffer.toString());
   bw.close();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
    }

上面这段代码运行后,反汇编源码文件里带有global , extern, SECTION等关键字的语句就可以自动被删除了。

剩下还需要处理的是,反汇编后的代码文件,编译起来会出现下面这种错误:

ckernel.asm:192: error: short jump is out of range

此类错误主要是因为跳转指令后面的目的地所在的距离跟当前指令的距离超过了127个字节,解决这种问题的办法也很简单,只要找到出错行,在对应的跳转指令后面加上near关键字就可以了,这个过程也可以自动化,实现代码如下:

private void handleOutOfRangeError() {
     try {
   ArrayList<String> jumps = new ArrayList<String>();
   jumps.add("jz");
   jumps.add("jnz");
   jumps.add("jc");
   jumps.add("jne");
   jumps.add("jg ");
   jumps.add("jle");
   jumps.add("jge");
   
   
      fileReader = new BufferedReader(new FileReader("ckernel.asm"));
   File f = new File("ckernenl.asm");
   fileBuffer = new StringBuffer((int)f.length()); 
   String lineText = null;
   
   while ((lineText = fileReader.readLine()) != null) {
    String line = lineText.toLowerCase();
    for(int i = 0; i < jumps.size(); i++) {
     if (line.contains(jumps.get(i))) {
      int pos = line.indexOf(jumps.get(i));
      String strFirst = line.substring(0, pos + jumps.get(i).length());
      String strSecond = line.substring(pos + jumps.get(i).length(), line.length());
      lineText = strFirst + " near " + strSecond;
      break;
     }
    }
    
    fileBuffer.append(lineText).append("\r\n");
   }
   
   fileReader.close();
   BufferedWriter bw = new BufferedWriter(new FileWriter("ckernel.asm"));
   bw.write(fileBuffer.toString());
   bw.close();
   
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
    }

我们的做法是,把汇编代码文件一行一行的读入,然后判断改行是否含有跳转关键字,例如jg, jge 等,如果有的话就将该行断成两部分,前半部分包含跳转关键字,后半部分包含跳转关键字后面的内容,然后程序在这两部分中间加上 "near", 这样就能实现在跳转关键字后面添加near的功能,从而就能解决jump out of range 的错误。

最后,我们再通过java调用nasm程序来编译修改好的内核代码,做法如下:

 public void createKernelBinary() {
     handleOutOfRangeError();
     
     try {
   Process process = Runtime.getRuntime().exec("nasm -o kernel.bat kernel.asm");
   readProcessOutput(process);
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
     
    }
    
    private void readProcessOutput(Process process) {
     read(process.getInputStream(), System.out);
     read(process.getErrorStream(), System.err);
    }
    
    private void read(InputStream inputStream, PrintStream out) {
     try {
      BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
      String line;
      while ((line = reader.readLine()) != null) {
       out.println(line);
      }
     } catch(IOException e) {
      e.printStackTrace();
     } finally {
      try {
       inputStream.close();
      } catch(IOException e) {
       e.printStackTrace();
      }
     }
    }

运行上面代码后,原来需要手动编译的kernel.bat二进制内核文件,就可以通过程序生成了。

通过这一系列步骤,原来需要手动操作,繁琐无比的内核编译流程,现在,我们只需要运行两个命令就可以自动化完成了,有了这个自动化流程,不但能减轻我们的开发负担,而且能极大的避免手动所可能产生的错误,进而为我们后面开发功能更强大,逻辑更复杂的内核打下良好的基础。

为了更好的理解本节内容,可参看视频:
用java开发编译器

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,565评论 25 707
  • Android游戏开发实践(1)之NDK与JNI开发02 承接上篇Android游戏开发实践(1)之NDK与JNI...
    AlphaGL阅读 3,686评论 0 24
  • 我们说的Linux其实指的就是 内核(kernel)而已。这个内核控制你主机的所有硬件并提供系统所有的功能,所以它...
    Zhang21阅读 7,273评论 0 18
  • 丝雨细如愁,墨云遮月羞。 吴铭举杯酒,相拥忍挥手。 谁知何年月,再叙情长久。 背道回走迟,一步三回头。 雅雨知我意...
    8a5bc35c564a阅读 260评论 0 4
  • 今天很愉快。
    沃雷塔尔阅读 68评论 0 0