所以每个人都可能知道glibc /lib/libc.so.6可以在shell中执行,就像普通的可执行文件一样,在这种情况下它可以打印出版本信息并退出.这是通过在.so中定义入口点来完成的.对于某些情况,将其用于其他项目可能会很有趣.不幸的是,您可以通过ld的-e选项设置的低级入口点有点太低级:动态加载器不可用,因此您无法调用任何正确的库函数.因此,glibc通过此入口点中的裸系统调用实现write()系统调用.
我现在的问题是,任何人都可以想到一个很好的方法,如何从该入口点引导一个完整的动态链接器,以便可以访问其他.so的函数?
我需要从另一个程序调用一个函数.如果其他程序是库,我可以简单地使用dlopen和dlsym来获取函数的句柄.不幸的是,其他程序是Unix可执行程序,并且将其构建为库不是一种选择.在可执行文件上尝试dlopen()会显示以下错误消息:
dlopen([...]/testprogram, 1): no suitable image found. Did find:
[...]/testprogram: can't map
这并不奇怪,因为dlopen用于库,而不是可执行文件.有没有办法让dlopen和dlsym使用可执行文件?如果没有,是否有另一种方法可以达到同样的目的?
SO有大量 关于如何执行库或动态加载可执行文件的问题。据我所知,所有答案都归结为:将可执行文件编译为位置无关代码并使用. 这非常有效,并且在 macOS 上仍然有效,直到glibc 最近发生更改,明确禁用了PIE。例如,此更改现在出现在 ArchLinux 上当前版本的 glibc (2.30) 中,并且尝试位置无关的可执行文件会出现错误:“无法动态加载位置无关的可执行文件”。dlopendlopendlopen
很难猜测是什么促使了如此彻底的改变,破坏了如此多的代码和有用的用例。(Patchwork 和 Bugzilla 的解释对我来说没有多大意义。)但是现在有一个问题:如果你想创建一个同时也是动态库的可执行文件该怎么办,反之亦然?
其中一条评论链接了一个解决方案。在这里为后代复制它:
#include <stdio.h>
#include <unistd.h>
const char service_interp[] __attribute__((section(".interp"))) = "/lib/ld-linux-x86-64.so.2";
extern "C" {
void lib_entry(void)
{
printf("Entry point of the service library\n");
_exit(0);
}
}
Run Code Online (Sandbox Code Playgroud)
编译生成g++ -shared test-no-pie.cpp -o test-no-pie -Wl,-e,lib_entry一个也可以在 Linux 上执行的共享对象(动态库)。
我有两个问题:
arc,argv?我遇到了错误的符号解析问题.我的主程序用dlopen加载一个带dlopen的共享库和一个符号.程序和库都是用C语言库代码编写的
int a(int b)
{
return b+1;
}
int c(int d)
{
return a(d)+1;
}
Run Code Online (Sandbox Code Playgroud)
为了使它在64位机器上运行,-fPIC在编译时传递给gcc.
该计划是:
#include <dlfcn.h>
#include <stdio.h>
int (*a)(int b);
int (*c)(int d);
int main()
{
void* lib=dlopen("./libtest.so",RTLD_LAZY);
a=dlsym(lib,"a");
c=dlsym(lib,"c");
int d = c(6);
int b = a(5);
printf("b is %d d is %d\n",b,d);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果程序未使用-fPIC编译,则一切运行正常,但在使用-fPIC编译程序时,它会因分段错误而崩溃.调查导致发现崩溃是由于符号a的错误解决.无论是从库还是主程序(后者是通过在主程序中注释掉调用c()的行获得的),都会在调用a时发生崩溃.
调用c()本身时没有问题,可能是因为c()不是由库本身在内部调用,而a()既是库内部使用的函数,也是库的API函数.
编译程序时,一个简单的解决方法是不使用-fPIC.但这并不总是可行的,例如当主程序的代码必须在共享库本身时.另一种解决方法是将指针重命名为其他功能.但我找不到任何真正的解决方案.
用RTLD_NOW替换RTLD_LAZY没有帮助.