WinAPI:是否需要在可执行内存映射文件上调用 FlushInstructionCache?

WinAPI: Is it needed to call FlushInstructionCache on an executable memory-mapped file?

我写了一个小程序来读取 windows obj 文件并找到 .text 部分和 运行 其中的代码。为此,我进行了以下 Windows API 函数调用(Full code [gist.github.com],对于那些感兴趣的人):

HANDLE FileHandle = CreateFile("lib.obj",
                               GENERIC_READ | GENERIC_EXECUTE,
                               FILE_SHARE_READ, 0,
                               OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

HANDLE MappingHandle = CreateFileMapping(FileHandle, 0, PAGE_EXECUTE_READ, 0, 0, 0);

void *Address = MapViewOfFile(MappingHandle, FILE_MAP_EXECUTE | FILE_MAP_READ,
                              0, 0, 0);

然后我找到文件中的 .text 部分,并将指向代码的指针转换为 C++ 中的函数指针,然后简单地调用该函数。这实际上似乎对我有用。

我没有在映射到文件的虚拟内存范围内调用 FlushInstructonCache 是不是出错了?

我问这个是因为我最近正在阅读 VirtualAlloc 文档,它在底部注释:

When creating a region that will be executable, the calling program bears responsibility for ensuring cache coherency via an appropriate call to FlushInstructionCache once the code has been set in place. Otherwise attempts to execute code out of the newly executable region may produce unpredictable results.

我的代码是否可能导致 CPU 执行指令缓存中的旧指令?

MapViewOfFile or CreateFileMapping 页上没有这样的注释。

如果只使用 MapViewOfFile 将文件内容加载到内存中,没有它应该没问题。

如果您修改内存中的内容,您需要在执行代码之前刷新指令缓存,因为它可能以未修改的形式存在于缓存中,然后可能会在没有您修改的情况下执行。

我使用 MAY 这个词是因为两件事:

  1. 处理器是否检测到对即将执行的内存的写入取决于处理器架构[有些处理器甚至没有硬件来注册对指令缓存中数据的写入——因为它是如此罕见以至于不太可能]。

  2. 因为很难预测缓存中可能有什么 - 处理器 有各种 "clever" 方式来预取,一般来说 "fill" 缓存。

显然,VirtualAlloc 包含您想要的数据的可能性为零,因此在此处提及它是因为您总是在执行之前写入它。

修改包括 "fix up for absolute addresses" 例如(如果你想完成一个加载复杂的东西来执行它的项目,你必须做的事情),或者如果你写一个调试器,当你设置一个断点通过用 x86 上的 INT 3 指令替换指令。

"modification" 的第二种情况是,如果您卸载文件,然后加载另一个文件(例如,可能是 "same" 文件,但已重建),在这种情况下,先前执行的代码可能还在缓存中,你得到了神秘的 "why didn't my changes do what I expect"