当前位置: 首页 > news >正文

30天自制操作系统(第21天)

21.1 攻克难题——字符串显示API

显示单个字符时,用 [CS:ECX] 的方式特意指定了 CS(代码段寄存器),因此可以成功读取 msg的内容。但在显示字符串时,由于无法指定段地址,程序误以为是 DS而从完全错误的内存地址中读取了内容。hrb_api并不知道代码段的起始位置位于内存的哪个地址,但cmd_app应该知道,因为当初设置这个代码段的正是cmd_app。
int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline){(中略)if (finfo != 0) {/* 找到了与字符串相同的文件 */p = (char *) memman_alloc_4k(memman, finfo->size);
/*这里*/ *((int *) 0xfe8) = (int) p;file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER);farcall(0, 1003 * 8);memman_free_4k(memman, (int) p, finfo->size);cons_newline(cons);return 1;}return 0;
}//根据输入参数打印数据 eax为当前字符 ebx为字符串 ecx长度
void hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax){
/*这里*/int cs_base = *((int *) 0xfe8);struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec);if(edx == 1)cons_putchar(cons, eax&0xff, 1);else if(edx == 2)
/*这里*/cons_putstr0(cons, (char*)ebx+cs_base);else if(edx == 3)
/*这里*/cons_putstr1(cons, (char*)ebx+cs_base, ecx);return;
}

21.2 用C语言编写应用程序

按照之前章节的理解,都是从汇编程序中输入了提前设定的字符才能进行打印,若将其整合成一个函数,当调用该函数时,便可打印岂不是更方便?函数api_putchar就是将输入参数c写入寄存器,并调用INT 0x40,该中断执行文件console.c中的hrb_api函数进行字符打印(详情看20.6节)。
按照文件分工,hello3.c文件调用了a_nask.nas文件中的函数,需要在Makefile文件中添加如下代码(文件格式请参考30天自制操作系统(第1-3天)中的2.6节):

hello3.bim : hello3.obj a_nask.obj Makefile
    $(OBJ2BIM) @$(RULEFILE) out:hello3.bim map:hello3.map hello3.obj a_nask.obj

hello3.hrb : hello3.bim Makefile
    $(BIM2HRB) hello3.bim hello3.hrb 0

/*                hello3.c                */
void api_putchar(int c);void HariMain(void)
{api_putchar('h');api_putchar('e');api_putchar('l');api_putchar('l');api_putchar('o');return;
}/*                a_nask.nas                */
_api_putchar: ; void api_putchar(int c);MOV 	EDX,1MOV 	AL,[ESP+4] ; cINT 	0x40RET

21.3 保护操作系统(1

需要为应用程序提供专用的内存空间,并且告诉它们 别的地方不许碰哦 ”。要做到这一点,可以创建应用程序专用的数据段,并在应用程序运行期间,将 DS SS 指向该段地址。
  操作系统用代码段 ……2 * 8
  操作系统用数据段 ……1 * 8
  应用程序用代码段 ……1003 * 8
  应用程序用数据段 ……1004 * 8
int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline){(中略)char name[18], *p, *q;(中略)if (finfo != 0) {/* 找到了与字符串相同的文件 */p = (char *) memman_alloc_4k(memman, finfo->size);
/*这里*/q = (char *) memman_alloc_4k(memman, 64*1024);*((int *) 0xfe8) = (int) p;file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER);
/*这里*/set_segmdesc(gdt + 1004, 64*1024 - 1, (int) q, AR_DATA32_RW);(中略)
/*这里*/start_app(0, 1003 * 8, 64 * 1024, 1004 * 8);memman_free_4k(memman, (int) p, finfo->size);
/*这里*/memman_free_4k(memman, (int) q, 64*1024);cons_newline(cons);return 1;}return 0;
}
;void start_app(int eip, int cs, int esp, int ds);
;操作系统栈的ESP保存在0xfe4这个地址,以便从应用程序返回操作系统时使用
_start_app:PUSHAD					;将8个32位寄存器压入栈,即8*(32/8)=32字节MOV		EAX,[ESP+36]	; 应用程序用EIPMOV		ECX,[ESP+40]	; 应用程序用CSMOV		EDX,[ESP+44]	; 应用程序用ESPMOV		EBX,[ESP+48]	; 应用程序用DS/SSMOV 	[0xfe4],ESP 	; 操作系统用ESPCLI 					; 在切换过程中禁止中断请求MOV 	ES,BXMOV 	SS,BXMOV 	DS,BXMOV 	FS,BXMOV 	GS,BXMOV 	ESP,EDX			; ESP为应用程序STI 					; 切换完成后恢复中断请求PUSH 	ECX 			; 用于far-CALL的PUSH(cs=1003*8)PUSH 	EAX 			; 用于far-CALL的PUSH(eip=0)CALL 	FAR [ESP] 		; 调用应用程序
; 应用程序结束后返回此处MOV 	EAX,1*8 		; 操作系统用DS/SSCLI 					; 再次进行切换,禁止中断请求MOV 	ES,AXMOV 	SS,AXMOV 	DS,AXMOV 	FS,AXMOV 	GS,AXMOV 	ESP,[0xfe4]		; 切换成操作系统ESPSTI 					; 切换完成后恢复中断请求POPAD 					; 恢复之前保存的寄存器值RET

21.4 对异常的支持

要想强制结束程序,只要在中断号 0x0d 中注册一个函数即可,这是因为在x86架构规范中,当应用程序试图破坏操作系统,或者试图违背操作系统的设置时,就会自动产生 0x0d 中断,因此该中断也被称为 异常”。写一个与 _asm_inthandler20函数大同小异的_asm_inthandler0d函数,与_asm_inthandler20的主要区别在于增加了STI/CLI这样控制中断请求禁止、恢复的指令和根据inthandler0d的结果来执行强制结束应用程序的操作
_asm_inthandler0d:STIPUSH 	ESPUSH 	DSPUSHADMOV 	AX,SSCMP 	AX,1*8JNE 	.from_app; 当操作系统活动时产生中断的情况和之前差不多MOV 	EAX,ESPPUSH 	SS 				; 保存中断时的SSPUSH 	EAX 			; 保存中断时的ESPMOV 	AX,SSMOV 	DS,AXMOV 	ES,AXCALL 	_inthandler0dADD 	ESP,8POPADPOP 	DSPOP 	ESADD 	ESP,4 			; 在INT 0x0d中需要这句IRETD
.from_app:; 当应用程序活动时产生中断CLIMOV 	EAX,1*8MOV 	DS,AX 			; 先仅将DS设定为操作系统用MOV 	ECX,[0xfe4] 	; 操作系统的ESPADD 	ECX,-8MOV 	[ECX+4],SS 		; 保存产生中断时的SSMOV 	[ECX ],ESP 		; 保存产生中断时的ESPMOV 	SS,AXMOV 	ES,AXMOV 	ESP,ECXSTICALL	_inthandler0dCLICMP 	EAX,0JNE 	.killPOP 	ECXPOP 	EAXMOV 	SS,AX 			; 将SS恢复为应用程序用MOV 	ESP,ECX 		; 将ESP恢复为应用程序用POPADPOP 	DSPOP 	ESADD 	ESP,4 			; INT 0x0d需要这句IRETD
.kill:; 将应用程序强制结束MOV 	EAX,1*8 		; 操作系统用的DS/SSMOV 	ES,AXMOV 	SS,AXMOV 	DS,AXMOV 	FS,AXMOV 	GS,AXMOV 	ESP,[0xfe4] 	; 强制返回到start_app时的ESPSTI 					; 切换完成后恢复中断请求POPAD 					; 恢复事先保存的寄存器值RET

相关文章:

  • vue-router4 (六) 命名视图
  • 在SAP HANA中使用OData(二)
  • 矩阵的范数 matrix norm Frobenius norm 弗罗贝尼乌斯 范数
  • vscode与vue/react环境配置
  • Langchain 加载网络信息实现RAG以及UnstructuredURLLoader的使用
  • MCU最小系统电路设计(以STM32F103C8T6为例)
  • Unity接入SQLite (三):C#封装SQL命令
  • 蓝桥杯倒计时47天!DFS基础——图的遍历
  • 如何将域名解析成IP地址?
  • EfficientSAM | 借助MIM机制,MetaAI让SAM更高效!
  • 编程笔记 html5cssjs 092 JavaScript 表单控件
  • 防火墙的内容安全
  • 顶顶通呼叫中心中间件-如何使处于机器人话术中的通话手动转接到坐席分机上讲解(mod_cti基于FreeSWITCH)
  • Qt篇——QTableWidget保存表格数据到Excel文件中,读Excel内容到QTableWidget
  • 人工智能之Tensorflow程序结构
  • [nginx文档翻译系列] 控制nginx
  • [分享]iOS开发 - 实现UITableView Plain SectionView和table不停留一起滑动
  • Android开源项目规范总结
  • Angular数据绑定机制
  • DOM的那些事
  • express如何解决request entity too large问题
  • JAVA并发编程--1.基础概念
  • java中具有继承关系的类及其对象初始化顺序
  • LeetCode刷题——29. Divide Two Integers(Part 1靠自己)
  • October CMS - 快速入门 9 Images And Galleries
  • uva 10370 Above Average
  • 海量大数据大屏分析展示一步到位:DataWorks数据服务+MaxCompute Lightning对接DataV最佳实践...
  • 开发了一款写作软件(OSX,Windows),附带Electron开发指南
  • 扑朔迷离的属性和特性【彻底弄清】
  • 一起来学SpringBoot | 第十篇:使用Spring Cache集成Redis
  • Java性能优化之JVM GC(垃圾回收机制)
  • 分布式关系型数据库服务 DRDS 支持显示的 Prepare 及逻辑库锁功能等多项能力 ...
  • 国内唯一,阿里云入选全球区块链云服务报告,领先AWS、Google ...
  • 没有任何编程基础可以直接学习python语言吗?学会后能够做什么? ...
  • ​ ​Redis(五)主从复制:主从模式介绍、配置、拓扑(一主一从结构、一主多从结构、树形主从结构)、原理(复制过程、​​​​​​​数据同步psync)、总结
  • ​linux启动进程的方式
  • #pragma预处理命令
  • $L^p$ 调和函数恒为零
  • (2021|NIPS,扩散,无条件分数估计,条件分数估计)无分类器引导扩散
  • (4)事件处理——(6)给.ready()回调函数传递一个参数(Passing an argument to the .ready() callback)...
  • (C语言)输入自定义个数的整数,打印出最大值和最小值
  • (day6) 319. 灯泡开关
  • (分享)自己整理的一些简单awk实用语句
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (切换多语言)vantUI+vue-i18n进行国际化配置及新增没有的语言包
  • (十三)Maven插件解析运行机制
  • (原創) 如何使用ISO C++讀寫BMP圖檔? (C/C++) (Image Processing)
  • (总结)Linux下的暴力密码在线破解工具Hydra详解
  • .net core 源码_ASP.NET Core之Identity源码学习
  • .NET Framework 服务实现监控可观测性最佳实践
  • .net 调用php,php 调用.net com组件 --
  • @Documented注解的作用
  • @EnableAsync和@Async开始异步任务支持
  • @FeignClient 调用另一个服务的test环境,实际上却调用了另一个环境testone的接口,这其中牵扯到k8s容器外容器内的问题,注册到eureka上的是容器外的旧版本...
  • @在php中起什么作用?