MacOS环境-手写操作系统-46,47-C语言开发应用程序

简介: MacOS环境-手写操作系统-46,47-C语言开发应用程序

系统与应用内存交叉

1.简介

内核为了避免恶意程序通过污染其内存而入侵自己


在启动应用程序前 会专门给应用程序分配一块与内核完全隔离的内存 作为应用程序运行时的专属内存


这样内核就拥有了比应用程序更高的等级 也就是内核可以访问应用程序的内存 反之则不行


内核启动应用程序 -[DS,ES,SS寄存器指向应用程序专有的内存段描述符]


-> 应用程序运行自身代码-[DS,ES,SS寄存器切换到内核对应的内存段描述符]


->应用程序调用内核API CPU指向内核代码-[DS,ES,SS寄存器切换到应用程序专有的内存段描述符]


->内核执行完API后 把结果交还给应用程序


应用程序继续运行自己的代码-[DS,ES,SS寄存器切换到内核对应的内存段描述符]


->应用程序运行结束 CPU控制器交还给内核


2.代码

根据上面流程描述


在整个应用程序的生命周期内


切换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把八个通用寄存器的值压入堆栈


一定要注意 此时这些数据都存储在应用程序的内存里 内核是无法直接访问到的


此时内存的情景如下


image.png

相关寄存器的信息都被压入到应用程序的堆栈上


内核堆栈上还是空 要想让内核获得这些数据


就必须把这些数据从应用程序的堆栈搬运到内核堆栈上


接下来的代码做的就是这些苦力活

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


这些语句执行完后 应用程序和内核堆栈的情况如下

image.png

也就是处于应用程序堆栈上前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

代码运行时


首先判断中断发生时是内核代码在执行还是应用程序的代码在执行


如果是内核代码 那么就没有必要做内存切换了 直接执行时钟中断的代码


如果中断发送时是应用程序代码在执行 那么需要把内存从应用程序专有内存切换到内核专有内存


当中断执行完后 在把内存从内核专有内存切换回应用程序专有内存


3.运行

汇编语言编写的代码不好理解 不理解其实也没关系 后面我们会使用itenl提供的专门指令来实现这些功能


当上面的代码编译执行后 结果如下


目录
相关文章
|
6天前
|
人工智能 Android开发 数据安全/隐私保护
移动应用与系统:探索开发趋势与操作系统的协同进化####
当今时代,移动应用不再仅仅是简单的软件工具,它们已成为扩展智能手机及平板等设备功能的关键。本文旨在深入分析当前移动应用的开发趋势,探讨移动操作系统的最新进展及其对应用开发的影响,并阐述两者如何相互促进、协同进化,共同推动移动互联网技术向前发展。 ####
|
11天前
|
人工智能 物联网 Android开发
移动应用与系统:探索开发趋势与操作系统的协同进化####
本文深入探讨了移动应用开发的当前趋势,以及这些趋势如何与移动操作系统的发展相互影响、协同进化。通过分析最新的技术动态、市场数据及用户行为变化,本文旨在为开发者提供关于未来移动应用开发方向的洞察,并讨论操作系统层面的创新如何促进或制约应用的发展。 ####
|
14天前
|
安全 物联网 Android开发
移动应用与系统:探索开发趋势与操作系统的演进####
【10月更文挑战第29天】 本文深入探讨了移动应用开发的最新趋势与挑战,并分析了主流移动操作系统(如Android、iOS)的发展动态。通过对比不同系统的技术特点和市场表现,揭示了移动应用生态系统的复杂性及其对开发者的影响。此外,还讨论了跨平台开发工具的兴起如何改变应用开发流程,以及这些变化对未来移动计算领域的潜在影响。 ####
30 4
|
22天前
|
前端开发 测试技术 调度
移动应用与系统:探索开发与操作系统的奥秘####
【10月更文挑战第22天】 本文深入剖析了移动应用的开发流程与移动操作系统的核心原理,揭示了两者如何相互依存、共同推动移动互联网的发展。从应用架构设计到操作系统性能优化,全方位解读移动生态的技术细节,为开发者和用户提供有价值的参考。 ####
29 5
|
20天前
|
搜索推荐 前端开发 测试技术
移动应用与系统:探索开发之道与操作系统的演进#### 一、
【10月更文挑战第24天】 本文将带你深入探索移动应用开发的全过程,从构思到上架的每一个细节。同时,我们还将回顾移动操作系统的发展历程,分析当前主流系统的技术特点和未来趋势。无论你是开发者还是普通用户,都能在这里找到感兴趣的内容。 #### 二、
24 1
|
25天前
|
安全 Android开发 数据安全/隐私保护
移动应用与系统:探索开发趋势与操作系统革新#### 一、
【10月更文挑战第20天】 本文旨在剖析当前移动应用开发的热门趋势,并探讨移动操作系统的最新进展与未来展望。通过梳理从原生应用到跨平台开发的转变,以及主流操作系统如iOS和Android的技术创新,本文为开发者提供了一份详尽的行业指南,助力他们在快速迭代的移动科技领域保持领先。 #### 二、
36 2
|
29天前
|
监控 Linux 云计算
Linux操作系统在云计算环境中的实践与优化###
【10月更文挑战第16天】 本文探讨了Linux操作系统在云计算环境中的应用实践,重点分析了其在稳定性、安全性和高效性方面的优势。通过具体案例,阐述了Linux如何支持虚拟化技术、实现资源高效分配以及与其他开源技术的无缝集成。文章还提供了针对Linux系统在云计算中的优化建议,包括内核参数调整、文件系统选择和性能监控工具的应用,旨在帮助读者更好地理解和应用Linux于云计算场景。 ###
37 3
|
12天前
|
开发工具 Android开发 数据安全/隐私保护
探索移动应用的世界:从开发到操作系统的全面解析
【10月更文挑战第33天】在数字化时代,移动应用已成为我们日常生活中不可或缺的一部分。本文将深入探讨移动应用的开发过程,包括编程语言、开发工具和框架的选择,以及如何构建用户友好的界面。同时,我们还将分析移动操作系统的核心功能和安全性,以帮助读者更好地理解这些应用程序是如何在各种设备上运行的。无论你是开发者还是普通用户,这篇文章都将为你揭示移动应用背后的奥秘。
|
18天前
|
人工智能 前端开发 物联网
移动应用与系统:探索开发与操作系统的协同进化####
【10月更文挑战第26天】 本文探讨了移动应用开发和移动操作系统之间的紧密关系,揭示了它们是如何相互影响和促进彼此发展的。从早期的功能手机到现今的智能手机,移动操作系统经历了巨大的变革,而移动应用作为其生态系统中的重要组成部分,也随着技术的演进不断创新。文章将深入分析这一过程中的关键节点和技术突破,以及未来的发展趋势。 ####
23 0
|
1月前
|
存储 C语言 iOS开发
MacOS环境-手写操作系统-48-让内核从错误中恢复
MacOS环境-手写操作系统-48-让内核从错误中恢复
35 0