我在共享库中替换了operator newoperator delete
我想要当我在此共享库上执行dlopen时,使用共享库中operator newoperator delete的替换版本(而不是运行dlopen()的二进制文件中的版本)。
为此,我将-Bsymbolic选项传递给链接器,但似乎不起作用。

这是MWE:

main.cpp

#include <dlfcn.h>

#include <iostream>

#include "library.h"

int main(int argc, const char* argv[])
{
    std::cout << "going call library function" << std::endl;

    using func_t = decltype(library_function);
    auto handle = dlopen("./libshared.so", RTLD_NOW);
    auto fnc = reinterpret_cast<func_t*>(dlsym(handle, "library_function"));
    fnc();
    dlclose(handle);
}


#ifndef LIBRARY_H
#define LIBRARY_H

extern "C" void library_function();

#endif // LIBRARY_H

library.cpp:
#include <iostream>
#include <string>

extern "C" void library_function()
{
    std::string str;

    str.resize(10);

    std::cout << "inside library function: " << str.size() << std::endl;
}

new.cpp
#include <iostream>
#include <new>

void* operator new(std::size_t size)
{
    std::cout << "operator new from shared library" << std::endl;

    void* ptr = malloc(size);

    if(!ptr) throw std::bad_alloc();

    return ptr;
}

void* operator new(std::size_t size, const std::nothrow_t&) noexcept
{
    std::cout << "operator new from shared library" << std::endl;

    return malloc(size);
}

void* operator new[](std::size_t size)
{
    return ::operator new(size);
}

void* operator new[](std::size_t size, const std::nothrow_t& nothrow) noexcept
{
    return ::operator new(size, nothrow);
}

void operator delete(void* ptr) noexcept
{
    std::cout << "operator delete from shared library" << std::endl;

    return free(ptr);
}

void operator delete(void* ptr, std::size_t size) noexcept
{
    ::operator delete(ptr);
}

void operator delete(void* ptr, const std::nothrow_t&) noexcept
{
    return ::operator delete(ptr);
}

void operator delete(void* ptr, std::size_t size, const std::nothrow_t&) noexcept
{
    return ::operator delete(ptr);
}

void operator delete[](void* ptr) noexcept
{
    return ::operator delete(ptr);
}

void operator delete[](void* ptr, std::size_t size) noexcept
{
    return ::operator delete(ptr);
}

void operator delete[](void* ptr, const std::nothrow_t&) noexcept
{
    return ::operator delete(ptr);
}

void operator delete[](void* ptr, std::size_t size, const std::nothrow_t&) noexcept
{
    return ::operator delete(ptr);
}

生成文件:
all:
    c++ -std=c++14 -g2 -O0 -shared -fPIC -o libshared.so library.cpp new.cpp -Wl,-Bsymbolic

    c++ -std=c++14 -g2 -O0 main.cpp -o main -ldl

主输出:
$ ./main
going call library function
inside library function: 10

预期输出:输出包含“从共享库中新建运算符(operator)”,“从共享库中删除运算符(operator)”。

第二个问题-当我显式链接到该库时,如何实现相同的行为(-lshared为main.cpp)。

更新:

看来链接器实际上在不使用-Bsymbolic的情况下进行了更改。
考虑共享库w /和w / o diffreadelf -r-Bsymbolic:
-Relocation section '.rela.plt' at offset 0xeb0 contains 20 entries:
+Relocation section '.rela.plt' at offset 0xeb0 contains 15 entries:
   Offset          Info           Type           Sym. Value    Sym. Name + Addend
-000000202018  002700000007 R_X86_64_JUMP_SLO 00000000000014b7 operator new(unsigned long, std::nothrow_t const&) + 0
-000000202020  000300000007 R_X86_64_JUMP_SLO 0000000000000000 _ZNSt7__cxx1112basic_s@GLIBCXX_3.4.21 + 0
-000000202028  003000000007 R_X86_64_JUMP_SLO 000000000000142c operator new(unsigned long) + 0
-000000202030  000600000007 R_X86_64_JUMP_SLO 0000000000000000 std::ios_base::Init::Init@GLIBCXX_3.4 + 0
-000000202038  000700000007 R_X86_64_JUMP_SLO 0000000000000000 malloc@GLIBC_2.2.5 + 0
-000000202040  003100000007 R_X86_64_JUMP_SLO 000000000000153f operator delete(void*) + 0
-000000202048  000800000007 R_X86_64_JUMP_SLO 0000000000000000 __cxa_atexit@GLIBC_2.2.5 + 0
-000000202050  000b00000007 R_X86_64_JUMP_SLO 0000000000000000 _ZStlsISt11char_traits@GLIBCXX_3.4 + 0
-000000202058  000c00000007 R_X86_64_JUMP_SLO 0000000000000000 _ZNSt7__cxx1112basic_s@GLIBCXX_3.4.21 + 0
-000000202060  000d00000007 R_X86_64_JUMP_SLO 0000000000000000 free@GLIBC_2.2.5 + 0
-000000202068  000f00000007 R_X86_64_JUMP_SLO 0000000000000000 _ZNSt7__cxx1112basic_s@GLIBCXX_3.4.21 + 0
-000000202070  002e00000007 R_X86_64_JUMP_SLO 00000000000016b8 std::exception::exception() + 0
-000000202078  001200000007 R_X86_64_JUMP_SLO 0000000000000000 std::basic_ostream<char, std::char_traits<char> >::operator<<(unsigned long)@GLIBCXX_3.4 + 0
-000000202080  002f00000007 R_X86_64_JUMP_SLO 00000000000016d6 std::bad_alloc::bad_alloc() + 0
-000000202088  001500000007 R_X86_64_JUMP_SLO 0000000000000000 __stack_chk_fail@GLIBC_2.4 + 0
-000000202090  001600000007 R_X86_64_JUMP_SLO 0000000000000000 __cxa_allocate_excepti@CXXABI_1.3 + 0
-000000202098  001700000007 R_X86_64_JUMP_SLO 0000000000000000 _ZNKSt7__cxx1112basic_@GLIBCXX_3.4.21 + 0
-0000002020a0  001800000007 R_X86_64_JUMP_SLO 0000000000000000 __cxa_throw@CXXABI_1.3 + 0
-0000002020a8  001900000007 R_X86_64_JUMP_SLO 0000000000000000 std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))@GLIBCXX_3.4 + 0
-0000002020b0  001c00000007 R_X86_64_JUMP_SLO 0000000000000000 _Unwind_Resume@GCC_3.0 + 0
+000000202018  000300000007 R_X86_64_JUMP_SLO 0000000000000000 _ZNSt7__cxx1112basic_s@GLIBCXX_3.4.21 + 0
+000000202020  000600000007 R_X86_64_JUMP_SLO 0000000000000000 std::ios_base::Init::Init@GLIBCXX_3.4 + 0
+000000202028  000700000007 R_X86_64_JUMP_SLO 0000000000000000 malloc@GLIBC_2.2.5 + 0
+000000202030  000800000007 R_X86_64_JUMP_SLO 0000000000000000 __cxa_atexit@GLIBC_2.2.5 + 0
+000000202038  000b00000007 R_X86_64_JUMP_SLO 0000000000000000 _ZStlsISt11char_traits@GLIBCXX_3.4 + 0
+000000202040  000c00000007 R_X86_64_JUMP_SLO 0000000000000000 _ZNSt7__cxx1112basic_s@GLIBCXX_3.4.21 + 0
+000000202048  000d00000007 R_X86_64_JUMP_SLO 0000000000000000 free@GLIBC_2.2.5 + 0
+000000202050  000f00000007 R_X86_64_JUMP_SLO 0000000000000000 _ZNSt7__cxx1112basic_s@GLIBCXX_3.4.21 + 0
+000000202058  001200000007 R_X86_64_JUMP_SLO 0000000000000000 std::basic_ostream<char, std::char_traits<char> >::operator<<(unsigned long)@GLIBCXX_3.4 + 0
+000000202060  001500000007 R_X86_64_JUMP_SLO 0000000000000000 __stack_chk_fail@GLIBC_2.4 + 0
+000000202068  001600000007 R_X86_64_JUMP_SLO 0000000000000000 __cxa_allocate_excepti@CXXABI_1.3 + 0
+000000202070  001700000007 R_X86_64_JUMP_SLO 0000000000000000 _ZNKSt7__cxx1112basic_@GLIBCXX_3.4.21 + 0
+000000202078  001800000007 R_X86_64_JUMP_SLO 0000000000000000 __cxa_throw@CXXABI_1.3 + 0
+000000202080  001900000007 R_X86_64_JUMP_SLO 0000000000000000 std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))@GLIBCXX_3.4 + 0
+000000202088  001c00000007 R_X86_64_JUMP_SLO 0000000000000000 _Unwind_Resume@GCC_3.0 + 0

使用-Bsymbolic进行构建时,似乎操作符new / operator delete没有标记为可重定位-因此必须使用内部版本吗?

更新:
的确,我在调用运算符new时看到了不同:

w / o -Bsymbolic调用通过PLT和GOT进行:
   0x000000000000109c <+28>:    callq  0xed0 <_Znam@plt>

带-Bsymbolic调用不会通过PLT和GOT进行:
   0x0000000000000f7c <+28>:    callq  0x110a <operator new[](unsigned long)>

更新:

实际上,似乎调用了操作符new / operator delete的正确版本。 GDB中的步骤说明对此进行了说明。问题是运算符<
更新:

看来问题是由以下事实引起的:当我在std::string上调用resize时-符号是从二进制文件而不是库中使用的。在内部std::string调整大小函数中,对操作符new的调用被路由到其本地定义-这就是为什么我看不到替换操作符new / operator delete的原因。
当我直接使用库中的运算符new / operator delete时,它开始工作。

更新:

是的,当与libstdc++(libc++)静态链接时,问题消失了。

最佳答案

提供的示例确实有效。
问题是问题的验证方案(通过调用std::string resize方法分配内存)是错误的。因为PLT / GOT会动态将对resize方法的调用路由到二进制文件的版本。二进制中的std::string调整大小方法将调用其自己的operator new / operator delete(不是共享库中的版本)。
为了解决这个问题,我们可以使用libstdc++(-static-libstdc++)进行静态编译。

关于c++ - 链接器选项-Bsymbolic,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40791074/

10-09 06:38
查看更多