【问题标题】:Overwriting an implementation of function pointer and use for shared library覆盖函数指针的实现并用于共享库
【发布时间】:2017-09-05 23:02:48
【问题描述】:

这是C 的独特情况。

假设我们有一个名为 libfoo.solibbar.so 的库,并且我们在这两个库中使用相同的函数名称 Get_A,假设系统调用了 Get_A

假设 libbar 已加载,然后使用参数 G 调用其 Get_AG 是一个带有一些函数指针的结构,其中一个感兴趣:

(*G)->RegisterBaz

所以在libbarGet_A 的调用中,我们希望改变指向该RegisterBaz 函数的指针,然后通过dlopen + dlsym 调用libfooGet_A 版本。

我尝试过的一件事是直接赋值,但随后出现编译器错误,即 READ ONLY 变量不可赋值,因此我尝试通过指针:

// not void * but actually some function signature typedefed.
void *f_ptr = (*G)->RegisterBaz;
*&f_ptr = r_n;

r_n 是一个普通的 C 函数,与 RegisterBaz 具有相同的签名

r_n我调用RegisterBaz的原始实现

因此,虽然这不会出现段错误,但它最终也不会调用我的包装函数。

【问题讨论】:

    标签: c pointers dll


    【解决方案1】:

    所以当你进行直接赋值时,你可能试图将一个函数赋值给一个 const 函数指针;这显然不是你能做到的。

    另外,在代码中:

    void *f_ptr = (*G)->RegisterBaz;
    *&f_ptr = r_n;
    

    实际上,f_ptr 指向的对象与 (*G)->RegisterBaz 指向的对象相同,因此当您将 f_ptr 更改为 *&(基本上是无操作)时,您根本不会修改 (*G)->RegisterBaz .

    另外,你不能将函数指针分配给对象指针; void * 类型的东西只保证能够保存对象指针。 (INCITS-ISO-IEC 9899-2011 6.3.2.3p7)

    因此,如果出于某种原因您一心想要直接更改 (*G)->RegisterBaz,您可以执行以下操作:

    void (**f_ptr)(void) = (void (**)(void))&((*G)->RegisterBaz);
    *f_ptr = r_n;
    

    但是由于您将通过 (*G)->RegisterBaz 进行调用,您需要确保替换函数签名与 (*G)->RegisterBaz 恰好指向的函数签名相匹配。

    除非f_ptr 的类型是指向"insert signature of called function here" 的指针,否则您也会收到警告。

    我需要重申这不是您通常想要做的事情,因此我不能保证这会奏效。但是如果你死心塌地,这就是你要做的事情(基本上你将 const 函数指针别名为非 const 指针。)

    【讨论】:

    • 嗯,这样做会给我一个段错误。
    • 您是否 100% 确定您要替换的功能提供所有相同的功能?您不能仅仅用自己的库函数替换库函数,并且仅仅因为签名匹配就期望它是花花公子。
    • 签名是对的,可能是哪里出了问题,从哪里开始找线索或者看。 AFAIK 事情对我来说是正确的。
    • 抱歉,我忘记了一个 &,所以试试我编辑的代码。
    • 不幸的是仍然是一个段错误,我在 Android 上这样做,所以也在寻找在命令行上查找 lldb 到应用程序的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-15
    • 1970-01-01
    • 1970-01-01
    • 2013-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多