问题描述
我正在具有NAND(256MB或1GB)的DLL中运行固件仿真。我想避免在堆上为此分配内存,而是使用虚拟内存分配。
最初需要将内存清除为0xFF(与NAND类似)。但是,我不想为该初始化付费(也不提交未访问的页面)。因此,理想情况下,仅应在访问时进行分配。而且我不需要在模拟退出后保留数据。
最初的想法是
-
VirtualAlloc。不确定,但可能会使用保护页,然后在首次访问时捕获异常。不确定DLL处理此类SEH异常是否理想?还是有更好的方法?
想一想1)前进的道路,但想知道这是否真的是最好的选择。
编辑: 3)我想出了另一个方法,可以避免异常处理程序,也可以避免创建大文件: 创建一个与dwAllocationGranularity大小相同的文件(通常为64KiB)。填充0xFF。然后,使用MapViewOfFileEx + FILE_MAP_copY在连续的内存中创建该副本的多个写时复制视图(在初始VirtualAlloc / VirtualFree之后获得合适的基地址,我们希望可以分配并置的视图)。需要对此进行更全面的测试-对潜在的线程竞赛稍有担心。.我实际上只使用一个线程,但是CRT确实也可以启动几个线程。 这意味着任何只读取虚拟NAND的代码也不会导致所有页面都被提交。
解决方法
是的,基本上1是最佳解决方案。只有我做下一个更改-使用VEH代替 SEH - SEH 处理程序仅在您访问其中的内存时才会调用,以防万一 VEH -访问可以是任何上下文和线程。而不是使用保护页,我最初是仅保留内存的区域,而没有实际分配。因此,任何对内存区域的访问都会导致异常,您可以在 VEH 中进行处理-提交内存并填充0xFF
模式。演示代码
PVOID g_NandBegin;
SIZE_T g_NandSize = 0x1000000;
LONG NTAPI Vex(::PEXCEPTION_POINTERS ExceptionInfo)
{
::PEXCEPTION_RECORD ExceptionRecord = ExceptionInfo->ExceptionRecord;
if (ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION &&
ExceptionRecord->NumberParameters > 1)
{
PVOID pv = (PVOID)ExceptionRecord->ExceptionInformation[1];
if ((ULONG_PTR)pv - (ULONG_PTR)g_NandBegin < g_NandSize)
{
SIZE_T RegionSize = 1;
if (0 <= NtAllocateVirtualMemory(NtCurrentProcess(),&pv,&RegionSize,MEM_COMMIT,PAGE_READWRITE))
{
RtlFillMemoryUlong(pv,RegionSize,MAXULONG);
return EXCEPTION_CONTINUE_EXECUTION;
}
}
}
return EXCEPTION_CONTINUE_SEARCH;
}
void dc()
{
if (PVOID pv = AddVectoredExceptionHandler(TRUE,Vex))
{
if (g_NandBegin = VirtualAlloc(0,g_NandSize,MEM_RESERVE,PAGE_READWRITE))
{
ULONG seed = ~GetTickCount();
int n = 0x100;
do
{
if (*(UCHAR*)((PBYTE)g_NandBegin + (((ULONG64)RtlRandomEx(&seed) * g_NandSize) >> 32)) != 0xFF)
{
__debugbreak();
}
} while (--n);
VirtualFree(g_NandBegin,MEM_RELEASE);
}
RemoveVectoredExceptionHandler(pv);
}
}