如何在 MS VC++ 开发的 C++ 程序的特定部分分配代码
Posted
技术标签:
【中文标题】如何在 MS VC++ 开发的 C++ 程序的特定部分分配代码【英文标题】:how to allocate code in specific section for C++ program developed in MS VC++ 【发布时间】:2012-01-11 04:03:45 【问题描述】:我正在尝试使用此代码将一段代码分配给一个独立的部分:
#ifdef _MSC_VER
#pragma section(".evil",execute)
#pragma code_seg(".evil")
#endif
#ifdef __GNUC__
static __attribute__((section (".evil")))
#elif defined _MSC_VER
static __declspec(allocate(".evil"))
#endif
void __invoke__start()
//...
但这不起作用,编译器说
__declspec(allocate()) 语法只能用于静态数据。
我这样做是因为我必须将一些代码写入一个新文件,而该文件是一个可执行文件。
实际上,如果程序是用 MS VC++ 调试模式编译的,我无法在程序运行时找到函数在内存中的确切地址 有关完整示例,请参阅此代码:full example
现在,上面的问题已经解决了,但是我还是想明确一点,如果可以把一些代码放到一个独立的部分。毕竟,当我的工作可能时,还有其他好处。
当我链接两个目标文件(COFF 格式)时,如何确保来自不同 obj 文件的不同代码位于不同部分? 还是有其他方法可以做到这一点?
我很抱歉我的英语不好。
【问题讨论】:
【参考方案1】:你可以用内联汇编找到一个函数开头的内存地址,然后调用一个函数来使用这个内存地址,比如:
void foo()
__asm
CALL 0h \\Put current address on top of stack
CALL myFunction \\Actually make a funciton call
...
int myFunction( int addrFromASM)
\\do something with addrFromASM+4, which will be where the rest of foo starts.
【讨论】:
哇,这是一个很好的方法。所以 myFunction 可以获取 foo 的地址...并做任何事情..感谢您的帮助! 返回地址由CALL myFunction
存储,可以从堆栈中拉出,但不能从参数中拉出。 CALL 0h
只会是麻烦。调用需要参数的函数也会很麻烦,并且不清楚正确的调用顺序是什么,因为调用约定是未指定的。实际上,根本不需要内联汇编。不过,将函数标记为__declspec(naked)
可能是一个好主意,否则编译器可能会调整堆栈指针并使其更难定位返回地址。
总而言之,这个想法是合理的,但是示例代码很臭。
"当CALL指令使用位移为零时,被识别并特殊处理;即使没有对应的RET指令,RAS也保持一致。" -CALL 0h
不麻烦. cdecl 是默认调用约定。
这个想法很好,我现在知道该怎么做了。再次感谢 Motes。我会将其标记为已接受的答案。【参考方案2】:
除了您的代码中有一些不错的 UB(您假设编译器将始终按照您的顺序放置函数)之外,您想要对这些部分执行的操作可以通过分配一个新的您编写的 PE 标头中的部分并将您的代码放在那里(参见 The Section Table
上的段落,找到 here),您还需要将 BaseOfCode
设置为该部分并相应地调整 NumberOfSections
。
关于函数的有趣地址,这是因为在调试模式下编译时打开了Edit & Continue,只需在项目选项中将其关闭,您的地址就会正确。
【讨论】:
真的。我测试了一整天,发现问题在某种程度上与链接器有关。也许符号解决或那种工作人员。无论如何,令我震惊的是,我只需要将 /RELEASE 选项传递给链接器,一切都解决了。这根本没有意义……另一种方法是为链接器设置 /LTCG 或 /ltcg 选项。两种方式都有效。所以我现在不必关闭调试功能。你的回答也很有启发性。感谢您的帮助。以上是关于如何在 MS VC++ 开发的 C++ 程序的特定部分分配代码的主要内容,如果未能解决你的问题,请参考以下文章
vc++ 开发windows程序怎么设置生成exe执行文件不需依赖api-ms-win...dll
在 MS VC 2013 Express 中将 C++ dll 从 32 位转换为 64 位