手动生成动态库

下面的内容叙述了如何从源码分阶段编译一个动态库。起源是需要修改函数名,但是函数名无法在源码中更改(因为函数签名问题)

  1. 首先生成 Makefile 文件

    cmake -B build -G'Unix Makefiles'
  2. 然后生成相关预编译文件:

    cd build/src
    make memalloc.i
  3. 从预编译文件生成汇编文件:

    cd CMakeFiles/memalloc.dir
    c++ -S memalloc.cpp.i -o memalloc.s -fPIC -shared
    -fPIC 用来生成位置无关代码,这意味着汇编代码中全部使用相对位置跳转。因此此参数在生成汇编文件的时候就需要加上
  4. 修改相关的函数名:

    sed -i 's/mem_alloc/malloc/g' memalloc.s
    sed -i 's/mem_free/free/g' memalloc.s
    sed -i 's/mem_calloc/calloc/g' memalloc.s
    sed -i 's/mem_realloc/realloc/g' memalloc.s
  5. 编译成动态库

    c++ memalloc.s --shared -o memalloc.so
    • 这里使用 c++ 而不是 gcc 是因为尽管 使用 gcc 也能通过编译 但是 gcc 不会自动连接 libstdc++ 库,从而导致运行时错误:

      undefined symbol: __gxx_personality_v0
    • 另一个问题是如果在此步骤的命令行中加入了 -c 参数,就会出现错误:

      so: only ET_DYN and ET_EXEC can be loaded

然后可以使用 readelf 查看函数存在的符号

readelf -s memalloc.so
另一种说法是使用 objdump 读取符号,但是这种方式读取的符号是有冗余的。最好的办法就是使用 readelf

未定义符号

未定义符号的情况以下几种:

  • 函数定义但是无实现。

  • 函数实现了但是编译器裁剪掉了。

第一种情况一般是忘记实现亦或是忘记将源文件加入编译文件列表。在这种情况下,编译器看到了函数声明因而编译成功,但是链接时找不到符号导致失败。

第二种情况一般发生在 MSVC 忘记添加导出宏,抑或是由静态库合成动态库时未使用符号被裁剪掉了。

Last moify: 2023-12-15 04:28:35
Build time:2025-07-18 09:41:42
Powered By asphinx