[os]main-2

本文深入探讨了在自定义系统中使用printf函数打印内存大小时遇到的问题,发现是由于内存映射关系未正确设置导致堆栈段与数据段地址不同。通过分析堆栈情况和汇编代码,解释了为何即使memory_end不为0,打印结果仍显示为0。最终揭示了解决方案,确保内存映射关系的正确性。

刚刚进入内核后,开始在main中进行代码实现。

想试一下在main中实现一个printf打印功能,代码类似如下:

//main.c
int printf(char *fmt,...)
{
	va_list args;
	int i;
	va_start(args,fmt);
//	write(1,printbuf,i=vsprintf(printbuf,fmt,args));
	write(printbuf,i=vsprintf(printbuf,fmt,args));
	va_end(args);	
	return i;
}

void main(void)
{
	printf("total memory = %x",memory_end);《------------原来想打印出机器的内存大小,但是发现即使memory_end!=0,打印结果也为0

	return;
// vsprintf.c
int vsprintf(char *buf,char *fmt,va_list args)
{
   ......
	case 'x':
		case 'X':
			tmpn=va_arg(args,int);
			i=0;
			if(tmpn==0){
				*buf++='0';
				ret++;
			}
...
}


结果发现,在VS和linux下,都能正常输出字符串,但是在自己引导的系统中,却只能输出以下内容

total memory = 0

※已知memory_end不为0

经过调查,发现原来原因是刚刚进入main后,内存的映射关系还没设置,由于堆栈段的实际段地址和数据段的段地址不同导致

[原因详细]

①之前head.s里的设置里面,堆栈段描述符如下

.quad 0x00c0920900000fff /* 16Mb */ #堆栈段最大长度16M。

数据段

.quad 0x00c0920000000fff /* 16Mb */ # 数据段最大长度16M。

②在调用vsprintf后,执行到

tmpn=va_arg(args,int);

汇编代码为:

(0) [0x000000000000a4e0] 0008:000000000000a4e0 (unk. ctxt): lea eax, dword ptr s
s:[esp+36] ; 8d442424


这句话时候的堆栈情况

| STACK 0x0009fec0 [0x00000407]
| STACK 0x0009fec4 [0xfee0c000]
| STACK 0x0009fec8 [0x00314d54]
| STACK 0x0009fecc [0x900044b0]
| STACK 0x0009fed0 [0x9000feee]
| STACK 0x0009fed4 [0xfee00000]
| STACK 0x0009fed8 [0x00000000]
| STACK 0x0009fedc [0x0000a550]<---------printf函数返回地址
| STACK 0x0009fee0 [0x0000a784]<---------字符串total memory = %x
| STACK 0x0009fee4 [0x00003039]<---------memory_end的值
| STACK 0x0009fee8 [0x0000ff00]
| STACK 0x0009feec [0x00000000]
| STACK 0x0009fef0 [0x0c000607]
| STACK 0x0009fef4 [0x90009000]
| STACK 0x0009fef8 [0x0000a515]
| STACK 0x0009fefc [0x0000940c]



### 3.1 批处理脚本实现 为了实现删除 `001` 到 `050` 文件夹中的所有 `.exe` 文件,并将 `main-os.exe` 复制到这些文件夹中,可以使用 Windows 批处理脚本结合 `for /L` 循环结构来完成任务。 以下是一个完整的批处理脚本示例: ```batch @echo off setlocal :: 设置源文件路径 set "sourceFile=main-os.exe" :: 设置起始和结束编号 set start=1 set end=50 :: 遍历从1到50的数字 for /L %%i in (%start%,1,%end%) do ( :: 格式化数字为三位数,例如 1 -> 001 set "folderNum=000%%i" set "folderNum=%%folderNum:~-3%%" :: 构建目标文件夹路径 set "targetFolder=%%folderNum%%" :: 检查目标文件夹是否存在 if exist "%%targetFolder%%" ( :: 删除目标文件夹中的所有.exe文件 del /Q "%%targetFolder%%\*.exe" :: 复制文件到目标文件夹 copy /Y "%%sourceFile%%" "%%targetFolder%%" ) else ( echo 目标文件夹 %%targetFolder%% 不存在,跳过操作。 ) ) echo 操作完成。 pause ``` ### 3.2 脚本说明 - `for /L %%i in (%start%,1,%end%)`:使用 `for /L` 遍历从 `start` 到 `end` 的数字序列。 - `set "folderNum=000%%i"` 和 `set "folderNum=%%folderNum:~-3%%"`:将数字格式化为三位数,例如 `1` 转换为 `001`,`10` 转换为 `010`,`50` 转换为 `050`。 - `if exist "%%targetFolder%%"`:检查目标文件夹是否存在,避免操作不存在的目录。 - `del /Q "%%targetFolder%%\*.exe"`:使用 `/Q` 参数静默删除所有 `.exe` 文件。 - `copy /Y "%%sourceFile%%" "%%targetFolder%%"`:使用 `/Y` 参数跳过覆盖提示,直接复制 `main-os.exe` 到目标文件夹。 ### 3.3 注意事项 - 确保 `main-os.exe` 文件与批处理脚本位于同一目录,或者在 `sourceFile` 中指定完整路径。 - 如果目标文件夹不存在,脚本会跳过该步骤并提示用户。 - 该脚本不会自动创建目标文件夹,如果需要自动创建,可以添加 `md "%%targetFolder%%"` 命令。 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值