PE文件中的跳转存根

4
最近我拆解了一个用c/c++编写的DLL文件,并注意到在代码段中有许多"跳转存根"。这些存根除了跳转到DLL内部的函数外,没有其他作用。
例如:
jmp foo() 
jmp foo2()
...

为什么编译器(Visual Studio 2012)会在二进制文件中包含这些函数存根?
谢谢!
3个回答

6
如果在所有存根之后有一堆0xCC字节,那么你看到的就是启用了增量链接(调试版本默认启用)的代码。
在进行增量链接时,编译器为每个函数创建一个存根,并确保所有调用通过存根进行。如果需要用更新的代码替换函数,则可以将新代码添加到末尾,只需修补跳转缓冲区即可 - 所有现有调用将被重定向到新代码。多余的CC用于保留用于新函数的更多存根。
如需更多背景信息,请参见MSDN

1
是的,在这些 Thunk 之后有一堆 0xcc 字节。而且这些 Thunk 只在发布版本中出现。 - user2458855

2
这就是连接器和动态链接库的符号是如何“混合在一起”的。这样可以确保在符号表中使用正确类型的偏移量,由加载DLL的加载器解析(并因此更新DLL中函数的地址),并且编译代码仍然可以处理例如函数指针的情况:
void (*fptr)() = foo;

如果foo只是指向DLL中的一个位置的引用,那么如何解析该地址将取决于加载程序。解决这个问题要比解决“这里有一个foo()入口点,可以让你到达真正的foo”问题复杂得多。

DLL = 共享库。是的,我们谈论的是 foomydll.dll 的一部分,而不是 myprog.exe - Mats Petersson

1

DLL是可重定位的,这意味着它们可能出现在内存中的任何位置。这意味着所有对它们的调用都必须被重新编写。通过将所有这样的调用保持在一个小的跳转表中,只有一页需要在重定位时被重新编写。这很重要,因为未更改的代码页可以在进程之间共享,但每个进程都有自己的修改后的页面副本。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接