java开发系统内核:应用程序与内核运行环境的交叉转换

更详细的讲解和代码调试演示过程,请参看视频
用java开发C语言编译器

更详细的讲解和代码调试演示过程,请参看视频
如何进入google,算法面试技能全面提升指南

如果你对机器学习感兴趣,请参看一下链接:
机器学习:神经网络导论

更详细的讲解和代码调试演示过程,请参看视频
Linux kernel Hacker, 从零构建自己的内核

内核为了避免恶意程序通过污染其内存而入侵自己,在启动应用程序前,会专门给应用程序分配一块与内核完全隔离的内存,作为应用程序运行时的专属内存,这样内核就拥有了比应用程序更高的等级,也就是内核可以访问应用程序的内存,反之则不行。

应用程序在运行时,由于需要调用内核提供的API,因此它的运行过程,是一个与内核不断交互的过程,大体流程如下:

内核启动应用程序 -[DS,ES,SS寄存器指向应用程序专有的内存段描述符]-> 应用程序运行自身代码-[DS,ES,SS寄存器切换到内核对应的内存段描述符]->应用程序调用内核API,CPU指向内核代码-[DS,ES,SS寄存器切换到应用程序专有的内存段描述符]->内核执行完API后,把结果交还给应用程序,应用程序继续运行自己的代码-[DS,ES,SS寄存器切换到内核对应的内存段描述符]->应用程序运行结束,CPU控制器交还给内核。

根据上面流程描述,在整个应用程序的生命周期内,切换DS,ES,SS这三个段寄存器,使他们在不同阶段指向不同的全局描述符,以便在发送数据读写操作时,代码读取的是合适的数据,接下来,我们根据前面理论,修改代码,让应用程序在调用内核API时,实现对应的内存切换。下面是应用程序的C代码:

void api_putchar(int c);

void main() {
    api_putchar('A');
    return;
}

应用程序调用内核API在控制台上输出一个字符A, api_putchar是在api_call.asm中实现的:

[SECTION .s32]
BITS 32
call main
retf

api_putchar:
  mov edx, 1
  mov al, [esp + 4]
  int 02Dh
  ret

%include "app.asm"

调用API时,API的输入参数都会存入八个通用寄存器,也就是eax,ebc,ecx...等这些寄存器,其中寄存器edx存储的是所需内核API的编号,这个值需要传给内核,这样内核才知道该执行哪些服务。上面的代码跟以前介绍过的代码一样,真正变化的,是执行指令int 02Dh 后,被执行的中断代码需要做较大修改。当中断指令执行后,被调用的函数代码如下(kernel.asm):

asm_cons_putchar:
AsmConsPutCharHandler equ asm_cons_putchar - $$
        push ds
        push es
        pushad
        ;以上代码还运行在应用程序的环境中
        ......

上面代码执行时,先把两个段寄存器ds,es压入堆栈,然后再通过指令pushad把八个通用寄存器的值压入堆栈,一定要注意,此时这些数据都存储在应用程序的内存里,内核是无法直接访问到的,此时内存的情景如下:

应用程序堆栈 内核堆栈
edi _
esi _
ebp _
esp _
ebx _
edx _
ecx _
eax _
es _
ds _

相关寄存器的信息都被压入到应用程序的堆栈上,内核堆栈上还是空,要想让内核获得这些数据,就必须把这些数据从应用程序的堆栈搬运到内核堆栈上,接下来的代码做的就是这些苦力活:

asm_cons_putchar:
AsmConsPutCharHandler equ asm_cons_putchar - $$
        ....
        
        ;以上代码还运行在应用程序的环境中

        ;把内存段切换到内核
        mov  ax, SelectorVram
        mov  ds, ax
        mov  es, ax 
        mov  ecx, [0xfe4];获取内核堆栈指针
        add  ecx, -40
        mov  [ecx+32], esp ;保存应用程序堆栈指针
        mov  [ecx+36], ss

        ;将pushad 压入到堆栈的值复制到系统堆栈,也就是应用程序调用API时传入的参数
        mov edx, [esp]
        mov ebx, [esp+4]
        mov [ecx], edx
        mov [ecx+4], ebx
        
        mov edx, [esp+8]
        mov ebx, [esp+12]
        mov [ecx+8], edx
        mov [ecx+12], ebx

        mov edx, [esp+16]
        mov ebx, [esp+20]
        mov [ecx+16], edx
        mov [ecx+20], ebx

        mov edx, [esp+24]
        mov ebx, [esp+28]
        mov [ecx+24], edx
        mov [ecx+28], ebx

        ;把堆栈段切换到内核
        mov  ax, SelectorStack
        mov  ss, ax
        mov  esp, ecx
        sti

        call kernel_api

        .....

代码先改变两个段寄存器ds,es的值,让他们指向内核的专用内存描述符,这样读写数据时,数据就会写入内核的专有内存。然后通过读取0xfe4处的内存数据获得内核堆栈指针的值,把该值放入ecx寄存器,于是通过ecx寄存器,代码便可以读写内核堆栈。接着的代码就是搬运数据的过程,从语句mov edx, [esp]到语句mov [ecx+28], ebx,这些语句执行完后,应用程序和内核堆栈的情况如下:

应用程序堆栈 内核堆栈
edi edi
esi esi
ebp ebp
esp esp
ebx ebx
edx edx
ecx ecx
eax eax
es _
ds _

也就是处于应用程序堆栈上前32个字节的数据被拷贝到了内核的堆栈上,最后代码把内核的堆栈段拷贝到ss寄存器,同时把内核指针复制给esp指针,到此ds,es,ss等寄存器都指向了内核专有内存块,而且数据也从应用程序的堆栈拷贝到内核的堆栈上,指向指令 call kernel_api 时,CPU的控制器交给内核代码,内核代码运行时如果要读写数据的话,读写的内容都来自于内核原来的专有内存段,因此内核运行时不必担心读取到恶意数据。

当内核执行完API后,需要把CPU控制器交还给应用程序,此时就需要把内存从内核专有内存切换到应用程序专有内存,代码如下:

 ;执行完内核代码后,把内存段和堆栈段重新切回到应用程序
        mov  ecx, [esp+32];恢复应用程序的堆栈指针esp
        mov  eax, [esp+36];恢复应用程序的堆栈段
        cli
        mov  ss, ax
        mov  esp, ecx
        popad
        pop  es
        pop  ds

        iretd

上面的代码把当前堆栈从内核堆栈切换回应用程序堆栈,同时指令pop es 和 pop ds 把内存从内核专有内存切换回应用程序的专有内存,别忘了,在这些代码运行前,我们先把es,ds压入了堆栈,这里就是把前面压入的内容重新恢复给es和ds这两个寄存器。

大家可以感觉到,这个切换过程没什么技术难度,就是繁琐,很容易出错,其实intel专门提供了指令实现这样的功能,后面我们会使用到。需要执行这种繁琐切换流程的还有一处,就是时钟中断,如果应用程序运行过程中,时钟中断发生了,应用程序的代码会停止执行,而中断代码会被执行,中断代码属于内核代码,因此需要再次进行上面所描述的内存切换,因此时钟中断需要修改的代码如下:

_timerHandler:
timerHandler equ _timerHandler - $$
    push es
    push ds
    pushad
    mov  ax, ss
    cmp  ax, SelectorStack
    jne  .from_app
    ;上面代码判断中断发生时是否处于内核环境

    push fs
    push gs

    call intHandlerForTimer
    
    pop gs
    pop fs
    popad
    pop ds
    pop es
     

    iretd
.from_app:
    ;把内存段切换到内核
    mov  ax, SelectorVram
    mov  ds, ax
    mov  es, ax 
    mov  ecx, [0xfe4];获取内核堆栈指针
    add  ecx, -8
    mov  [ecx+4], ss ;保存中断时的堆栈段
    mov  [ecx], esp  ;保存中断时堆栈指针

    mov  ax, SelectorStack ;切换到内核堆栈段
    mov  ss, ax
    mov  esp, ecx ;切换内核指针
    call intHandlerForTimer

    pop  ecx
    pop  eax
    mov  ss, ax
    mov  esp, ecx
    popad
    pop  ds
    pop  es
    iretd

代码运行时,首先判断中断发生时是内核代码在执行还是应用程序的代码在执行,如果是内核代码,那么就没有必要做内存切换了,直接执行时钟中断的代码,如果中断发送时是应用程序代码在执行,那么需要把内存从应用程序专有内存切换到内核专有内存,当中断执行完后,在把内存从内核专有内存切换回应用程序专有内存。

汇编语言编写的代码不好理解,不理解其实也没关系,后面我们会使用itenl提供的专门指令来实现这些功能,当上面的代码编译执行后,结果如下:


这里写图片描述

结果表明API调用成功,字符'A'成功显示到控制台上。本节运行的结果跟前几节所描述的结果是一样的,表明虽然一样,但底层的逻辑已经发生了重大的改变。更详细的讲解和更明了的调试流程,请参看视频。

更多技术信息,包括操作系统,编译器,面试算法,机器学习,人工智能,请关照我的公众号:


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

推荐阅读更多精彩内容