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

写时复制,读时加载

实现写时复制,读时加载,原理为,申请内存时,只给一段线性地址空间,并不分配物理内存,当cpu读、写该内存时,发生缺页中,或者写错误,中断处理程序根据前面设置的内容,决写分配物理内存,或者是共享内存,如果需要读取文件时,则根据需要读取相应的文件数据。

主要代码如下:

LPPE_FILE_ELEM load_pe_dll(char * lpFileName) {
	LPPE_FILE_ELEM lpSysFE, lpUserFE; //文件列表中的元素,保存文件信息
	//文件加载内存的默认地址
	//PIMAGE_DOS_HEADER pdh; //dos头
	PIMAGE_NT_HEADERS pnh; 	//pe文件头
	LPVOID pfile, pKrFile;
	PMEMORY_BASIC_INFORMATION pmbi;
	BYTE buf[512]; 		//临时块
	//补全文件目录路径
	add_patch((char *) buf, lpFileName);

	//1、从系统进程中查找是否已经加载
	lpSysFE = pe_find_file((char*) buf, get_sys_files_list());
	if (lpSysFE) {
		//系统中已经加载,进入下一步
		pKrFile = (LPVOID) lpSysFE->hModule;
		DbgPrint("dll已读入内存 : %s ,%x\n", lpSysFE->strFilePath,
				lpSysFE->dwNumberOfShares);
		//return lpFE->hModule;
	} else {
		//将文件加入系统文件列表中

		lpSysFE = kr_malloc(sizeof(PE_FILE_ELEM) + strlen((char*) buf) + 1);
		strcpy(lpSysFE->strFilePath, (char*) buf);
		if (load_file(lpSysFE->strFilePath, 0, 512, buf)) {

			//新exe头部的文件地址 指向PE
			pnh = (PIMAGE_NT_HEADERS) ((DWORD) buf
					+ ((PIMAGE_DOS_HEADER) buf)->e_lfanew);
			//系统进程中仅申请空间,读时加载
			pmbi = mem_virtual_alloc(&stMbiSys, 0,
					pnh->OptionalHeader.SizeOfImage, MEM_COMMIT,
					PAGE_READWRITE,
					MEM_IMAGE);
			pKrFile = (PBYTE) pmbi->BaseAddress;
			lpSysFE->hModule = (DWORD) pKrFile;
			lpSysFE->dwImgsize = pnh->OptionalHeader.SizeOfImage;
			lpSysFE->dwNumberOfShares = 0;
			list_push(get_sys_files_list(), (PLIST_ELEM) lpSysFE);
			load_pe_text((PIMAGE_DOS_HEADER) buf, (DWORD) lpSysFE->hModule,
					lpSysFE->strFilePath);

			if (!pKrFile) {
				//失败
				//DbgPrint("dll已读入内存 : %s ,%x\n");
			} else {
				//初始化时设置文件共享的次数为0,加入系统加载文件队列。

			}
		}
	}		//	if (lpFE)
	//2、检查用户空间 当前文件是否已经加载
	lpUserFE = pe_find_file(lpSysFE->strFilePath, get_current_file_list());
	if (lpUserFE) {
		//2、已经加载 直接返回
		return lpUserFE;
	} else {
		//第一次加入进程,将pKrfile的物理地址映射到 pfile

		pnh = (PIMAGE_NT_HEADERS) ((((PIMAGE_DOS_HEADER) pKrFile)->e_lfanew)
				+ (DWORD) pKrFile);

		pmbi = mem_virtual_alloc(
		MBI_USER_BASE, (LPVOID) pnh->OptionalHeader.ImageBase,
				pnh->OptionalHeader.SizeOfImage,
				MEM_COMMIT, PAGE_READWRITE, MEM_IMAGE);
		pfile = (PBYTE) pmbi->BaseAddress;
		DbgPrint("共享 dll: %s,%x,%x,%x,%x\n", lpSysFE->strFilePath, pfile,
				pKrFile, pnh->OptionalHeader.ImageBase);
		lpUserFE = kr_malloc(
				strlen((char*) lpSysFE->strFilePath) + sizeof(PE_FILE_ELEM)
						+ 1);
		strcpy(lpUserFE->strFilePath, lpSysFE->strFilePath);
		lpUserFE->hModule = (DWORD) pfile;
		lpUserFE->dwImgsize = lpSysFE->dwImgsize;
		lpUserFE->hSysModule = pKrFile;
		list_push(get_current_file_list(), (PLIST_ELEM) lpUserFE);
		lpSysFE->dwNumberOfShares++;
		DoRelocationTable(pfile);
		link_import(pfile);
		//文件头映射

		//	mem_map_demand(pKrFile, pfile,
		//		_ALIGN(	pdh->e_lfanew + sizeof(IMAGE_NT_HEADERS32)
		//					+ pnh->FileHeader.NumberOfSections
		//								* sizeof(IMAGE_SECTION_HEADER), 4096),
		//		PG_USER_R_P);

	}

	return lpUserFE;
}
BOOL mem_fail_sys(DWORD code, DWORD addr) {
	DWORD temp;
	LPPE_FILE_ELEM fe;
	PMEMORY_BASIC_INFORMATION pmbi =mem_find_mbi(&stMbiSys,
			addr);
	//DbgPrint("内核%s错误  0x%x,0x%x,0x%x,0x%x,0x%x,0x%x\n",(code&2?"写":"读"), addr, code,
	//		pmbi->BaseAddress, pmbi->RegionSize, pmbi->State, pmbi->Type);
	if (!pmbi) {
		return FALSE;
	}

//如果是映射
	if (pmbi->State == MEM_COMMIT) {

		//分配物理内存,以4K为单位,

		if (pmbi->Type == MEM_IMAGE) {
			mem_physics(addr, 4096, PGE_SYS_RW_P);
			fe = (LPPE_FILE_ELEM) pe_find_from_addr(get_sys_files_list(), addr);
			if (fe->dwNumberOfShares != 0) {
				//直接分配内存,再读取文件
				//200对齐
				load_file_4k(fe, addr);
			} else {
				//正在读文件头
			}
		} else if (pmbi->Type == MEM_4MB_PAGES) {
			// MEM_4MB_PAGES:
			//二级目录
			//	DbgPrint("二级页表%x,%x\n", addr, (DWORD *) MiGetPteAddress(addr));
			mem_physics(addr, 4096, PG_USER_RW_P);
			//*(DWORD *) MiGetPteAddress(addr) =
			//		get_freed_physics() + PG_USER_RW_P;
		} else {
			mem_physics(addr, 4096, PGE_SYS_RW_P);
		}
		//直接分配内存

	}	//if (pmbi->State == MEM_COMMIT)
	else {
		return FALSE;
	}
	return TRUE;
}
BOOL mem_fail_user(DWORD code, DWORD addr) {
	DWORD temp;
	LPPE_FILE_ELEM fe;

	PMEMORY_BASIC_INFORMATION pmbi =mem_find_mbi(MBI_USER_BASE, addr);
	//DbgPrint("用户%s错误  0x%x,0x%x,0x%x,0x%x,0x%x,0x%x\n", (code&2?"写":"读"),addr, code,
	//		pmbi->BaseAddress, pmbi->RegionSize, pmbi->State, pmbi->Type);
	if (!pmbi) {
//找不分配的段。
		return FALSE;
	}
//状态是不是已经提交
//只读,读写,还共享的读写
//如果是map类,分配内存,如果Image类,则读时加载,写时复制
	if (pmbi->State == MEM_COMMIT) {
		if (pmbi->Type == MEM_IMAGE) {
			fe = (LPPE_FILE_ELEM) pe_find_from_addr(get_current_file_list(),
					addr);
			if (fe->hSysModule == 0) {
				//说明是不是共享文件
				//DbgPrint("用户内存错误  0x%x , 0x%x , 0x%x , 0x%x \n", addr, code,
				//			pmbi->BaseAddress, pmbi->State);
				mem_physics(addr, 4096, PG_USER_RW_P);
				load_file_4k(fe, addr);
				//break;
			} else {
				//DbgPrint("用户内存错误 %x,%x\n",addr,fe);
				//先读取系统内存,如果出错则会中断到mem_fail_sys,加载文件
				//如果是读取,则映射,如果是写则分配内存再复制
				if (code & 2) {
					//重新申请物理内,再复制
					//DbgPrint("用户写错误%x\n", addr);
					mem_physics(addr, 4096, PG_USER_RW_P);
					memcpy((PVOID) (addr & 0xFFFFF000),
							(PVOID) ((fe->hSysModule + (addr - fe->hModule))
									& 0xFFFFF000), 4096);
				} else {
					//DbgPrint("用户读错误%x\n", addr);
					//说明可能内核没有读取文件,也可能没有映射
					//先试读下,没有读取文件会中断后读取,再映射
					//mem_fail_sys(0,fe->hSysModule+addr-fe->hModule);
					temp = *(PDWORD) (fe->hSysModule + addr - fe->hModule);
					//函数自己内部齐,size=1~4096效果应是一样
					mem_map_demand(fe->hSysModule + addr - fe->hModule, addr,
							4096, PG_USER_R_P);
				}

				//直接分配内存,再读取文件
				//addr-pmbi->BaseAddressg
			}
		} else if ((pmbi->Type == MEM_PRIVATE)) {//if (pmbi->Type == MEM_IMAGE)
			mem_physics(addr, 4096, PG_USER_RW_P);
		}
	}		//	if (pmbi->State == MEM_COMMIT)
	else {
		return FALSE;
	}
	return TRUE;
}


http://www.kler.cn/a/408206.html

相关文章:

  • 小柴冲刺软考中级嵌入式系统设计师系列二、嵌入式系统硬件基础知识(7)嵌入式Soc
  • 产业用机器人中的旋转花键若损伤有何影响?
  • vulhub靶场与pikachu靶场
  • 【LeetCode热题100】队列+宽搜
  • python语言基础
  • 订单日记为“惠采科技”提供全方位的进销存管理支持
  • 从零开始学习数据库 day0(基础)
  • JavaEE-线程安全专题
  • Tessy学习笔记—一些零散知识点
  • 昇腾CANN环境下Whisper.cpp安装指南
  • Windows 软件之 FFmpeg
  • Pytorch使用手册-Save and Load the Model(专题八)
  • 亚太杯数学建模竞赛介绍
  • 11.21作业
  • 【jvm】AOT编译器
  • git仓库推送到远端
  • window系统下使用open-webui+ollama部署大模型
  • LCR-003比特位计数
  • 电子电气架构 -- ASIL D安全实现策略
  • STM32ADC独立模式单通道采集实验
  • Creo 6.0 软件安装教程下载
  • 非线性控制器设计原理
  • c++应用网络编程之十五Nagle算法
  • flowable流程图详细绘制教程
  • 基于YOLOv8深度学习的智慧农业果园果树苹果类果实目标检测系统(PyQt5界面+数据集+训练代码)
  • shell脚本(6)