我想避免在大型项目中执行一个系统功能。不可能重新定义它或添加一些 ifdef
逻辑。所以我想将代码修补为仅 ret
操作。
函数是:
void __cdecl _wassert(const wchar_t *, const wchar_t *, unsigned);
和:
void __dj_assert(const char *, const char *, int, const char *) __attribute__((__noreturn__));
所以我需要在 Visual C++
编译器上修补第一个,在 GCC
编译器上修补第二个。
对于 x86/x64,我能否直接在 _wassert
/__dj_assert
函数的地址处编写 ret
指令?
更新:
我只想像这样修改函数体:
*_wassert = `ret`;
或者像这样复制另一个函数体:
void __cdecl _wassert_emptyhar_t *, const wchar_t *, unsigned)
{
}
for (int i = 0; i < sizeof(void*); i++) {
((char*)_wassert)[i] = ((char*)_wassert_empty
}
更新 2:
我真的不明白为什么有这么多人反对沉默的asserts
。事实上,RELEASE
模式下没有断言,但没人关心。我只想能够在 DEBUG
模式下打开/关闭断言。
最佳答案
您需要了解特定处理器 calling conventions 和系统 ISA 的 ABI。有关 x86 和 x86-64 调用约定,请参见 this。
有些调用约定在结语中需要不止一条 ret
机器指令,您必须考虑到这一点。顺便说一句,某些函数的代码通常位于 只读 code segment 中,您需要一些肮脏的技巧来修补它并在其中写入。
您可以编译一个具有相同签名的无操作函数,并要求编译器显示发出的汇编代码(例如,如果使用 GCC,则使用 gcc -O -Wall -fverbose-asm -S
....)
在 Linux 上,您可以使用动态链接器 LD_PRELOAD
tricks 。如果使用最近的 GCC 您可能会考虑使用 MELT 对其进行自定义,但我认为在您的特定情况下不值得...
但是,您显然有一些 assert
故障。如果没有任何 undefined behavior,您的程序不太可能继续运行。因此,实际上,您的程序很可能会在您建议的“修复”时在其他地方崩溃,并且您会浪费更多时间。
最好花足够的时间来纠正原来的错误,并改进你的开发过程。您的方法是推迟关键错误更正,并且您极有可能花更多的时间避免错误修复,而不是像您应该的那样正确处理它(现在,而不是以后)。 避免增加您的 technical debt 并使您的代码库更加错误和腐烂。
我的感觉是,您通过修补二进制文件以避免 assert
-s 的方法无处可去(除了大失败)。您应该找出违反的原因,并改进代码(删除过时的 assert
,或改进它,或更正 assert
检测到的其他地方的错误)。
关于c++ - 修补 C/C++ 函数以仅返回而不执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32986043/