写时复制,读时加载

实现写时复制,读时加载,原理为,申请内存时,只给一段线性地址空间,并不分配物理内存,当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;
}
相关推荐
一禅(OneZen)24 分钟前
「Windows/Mac OS」AIGC图片生成视频 ,webui + stable-diffusion环境部署教程
windows·stable diffusion
AirDroid_cn1 小时前
OPPO手机怎样被其他手机远程控制?两台OPPO手机如何相互远程控制?
android·windows·ios·智能手机·iphone·远程工作·远程控制
小龙在山东3 小时前
Python 包管理工具 uv
windows·python·uv
昏睡红猹3 小时前
我在厂里搞wine的日子
windows·wine
love530love6 小时前
Docker 稳定运行与存储优化全攻略(含可视化指南)
运维·人工智能·windows·docker·容器
1024小神11 小时前
tauri项目在windows上的c盘没有权限写入文件
c语言·开发语言·windows
程序视点20 小时前
Window 10文件拷贝总是卡很久?快来试试这款小工具,榨干硬盘速度!
windows
wuk99820 小时前
基于MATLAB编制的锂离子电池伪二维模型
linux·windows·github
lzb_kkk21 小时前
【C++】C++四种类型转换操作符详解
开发语言·c++·windows·1024程序员节
Paper_Love1 天前
x86-64_windows交叉编译arm_linux程序
arm开发·windows