我正在尝试为我编写的程序制作一种插件架构,并且在我第一次尝试时遇到了问题.是否可以从共享对象中访问主可执行文件中的符号?我认为以下情况会很好:
testlib.cpp:
void foo();
void bar() __attribute__((constructor));
void bar(){ foo(); }
Run Code Online (Sandbox Code Playgroud)
testexe.cpp:
#include <iostream>
#include <dlfcn.h>
using namespace std;
void foo()
{
cout << "dynamic library loaded" << endl;
}
int main()
{
cout << "attempting to load" << endl;
void* ret = dlopen("./testlib.so", RTLD_LAZY);
if(ret == NULL)
cout << "fail: " << dlerror() << endl;
else
cout << "success" << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译:
g++ -fPIC -o testexe testexe.cpp -ldl
g++ --shared -fPIC -o testlib.so testlib.cpp
Run Code Online (Sandbox Code Playgroud)
输出:
attempting …Run Code Online (Sandbox Code Playgroud) 在我的程序中,我有如下代码
/* libname may be a relative path */
void loadLib(char const *libname) {
void *handle = dlopen(libname);
/* ... */
dlclose(handle);
}
Run Code Online (Sandbox Code Playgroud)
在内部/* .. */,我需要读取内存映射文件/proc/self/maps,找到libname映射到的虚拟内存地址,我还需要打开库来查找其中的某些部分.为此,我需要dlopen通过在各个位置搜索找到的绝对名称(例如,在ldconfig缓存文件中).我怎样才能收到该文件名?
这就是我最终得到的结果(是的,这是C++代码,但是C标签对于这个问题dlopen是有意义的,因为它与C++和C一起使用,我的问题适用于两者,POSIX为C指定它).
boost::shared_ptr<void> dl;
if(void *handle = dlopen(libfile, RTLD_LAZY)) {
dl.reset(handle, &dlclose);
} else {
printdlerr();
return -1;
}
/* update sofile to be an absolute file name */
{
struct link_map *map;
dlinfo(dl.get(), RTLD_DI_LINKMAP, &map);
if(!map) {
return -1;
} …Run Code Online (Sandbox Code Playgroud) 我有一个dlopen()用于加载其他模块的应用程序.应用程序和模块使用gcc 4.6构建在Ubuntu 12.04 x86_64上,但是用于i386 arch.然后将二进制文件复制到具有完全相同操作系统的另一台计算机并正常工作.
但是,如果将它们复制到Ubuntu 12.04 i386,则某些(但不是全部)模块无法加载以下消息:
dlopen: cannot load any more object with static TLS
Run Code Online (Sandbox Code Playgroud)
我怀疑这是由__thread变量的使用引起的.但是,这些变量不会在加载的模块中使用 - 仅在加载器模块本身中使用.
有人可以提供任何其他信息,可能是什么原因?
我正在减少__thread变量的数量并优化它们(-ftls-model等等),我只是好奇为什么它不能在几乎相同的系统上工作.
我可以在使用时以编程方式从共享库(仅限Linux)获取所有函数名称的列表dl_open()吗?
我想要这样的东西:
std::vector<std::string> list_all_functions(void *dl) {
//... what can I do here?
}
int main() {
void * dl = dl_open("./mylib.so", RTLD_NOW);
auto functions = list_all_functions(dl);
//...
dl_close(dl);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
示例库(mylib.so)
标题(.h):
extern "C" {
int sum (int a, int b);
}
Run Code Online (Sandbox Code Playgroud)
来源(.c):
int sum (int a, int b) { return a + b; }
Run Code Online (Sandbox Code Playgroud)
我知道的肮脏的黑客:使用nm或objdump实用
使用dlopen加载其他包时可能导致以下错误:
dlopen($(OBJ_DIR)/Test-20091217211256.ob, 6): no suitable image found. Did find:
$(OBJ_DIR)/Test-20091217211256.ob: can't map
Run Code Online (Sandbox Code Playgroud)
在此错误之前,该进程会分配大量内存.
($(OBJ_DIR)在实际路径的错误中替换,使其更清晰).
有没有办法使用其路径找到dylib的版本?我正在寻找接受与dlopen相同的参数的东西.我查看了NSVersionOfRunTimeLibrary,但是从我对文档的阅读看起来它看起来像是获取当前dylib的版本,而不是路径中指定的版本.
谢谢
在使用dlopen加载时,我遇到了一些异常无法正常运行的问题(或者至少,正如我希望的那样;我知道这有问题).我在这里包含一些简化的示例代码.实际情况是myapp = Matlab,myext1 = mexglx matlab扩展,mylib是我的代码在两个扩展之间的共享库(myext1,myext2)
mylib.h
struct Foo { Foo(int a); m_a; }
void throwFoo();
Run Code Online (Sandbox Code Playgroud)
mylib.cpp
#include "mylib.h"
Foo::Foo(int a): m_a(a) {}
void throwFoo() { throw Foo(123); }
Run Code Online (Sandbox Code Playgroud)
myext1.cpp
#include "mylib.h"
#include <iostream>
extern "C" void entrypoint()
{
try { throwFoo(); }
catch (Foo &e) { std::cout << "Caught foo\n"; }
}
Run Code Online (Sandbox Code Playgroud)
myext2.cpp与myext1.cpp相同
MyApp.cpp中
#include <dlfcn.h>
int main()
{
void *fh1 = dlopen("./myext1.so",RTLD_LAZY);
void *fh2 = dlopen("./myext2.so",RTLD_LAZY);
void …Run Code Online (Sandbox Code Playgroud) 经过一些仔细的调试,我发现我的应用程序中存在一个错误,该错误植根于系统框架中,加载了一个有问题的Apple软件包:
/System/Library/CoreServices/MLTEFile.bundle
Run Code Online (Sandbox Code Playgroud)
我相信我没有从这个捆绑的服务中受益,并且怀疑很多应用程序都是.事实上,我通过研究Xcode本身学到了捆绑不能加载到Xcode的内存空间,因为捆绑包不兼容垃圾收集.
理想情况下,我想阻止此捆绑包加载到我的应用程序中.这样做的一种方法是在我自己的应用程序中要求GC,但我不打算这样做.任何人都可以想办法绕过系统框架调用dlopen()这个库的尝试吗?
过去几天我一直在努力解决一个奇怪的问题.我们使用GCC 4.8创建了一些库,它们静态地链接了一些依赖项 - 例如.log4cplus或者提升.对于这些库,我们使用boost-python创建了Python绑定.
每次这样的库使用TLS(就像log4cplus在它的静态初始化中做的那样,或stdlibc ++在抛出异常时也会这样 - 不仅在初始化阶段)整个事件在段错误中崩溃 - 并且每次线程局部变量的地址都为0 .
我尝试了重新编译等所有内容,确保使用-fPIC,确保使用-tls-model = global-dynamic等.没有成功.然后今天我发现这些崩溃的原因是我们链接OpenMP的方式.我们使用"-lgomp"而不是仅仅使用"-fopenmp"来完成此操作.因为我改变了这一切一切正常 - 没有崩溃,没有什么.精细!
但我真的想知道问题的原因是什么.那么在OpenMP中链接这两种可能性有什么区别?
我们在这里安装了一台CentOS 5机器,我们在/ opt/local/gcc48中安装了GCC-4.8,我们也确信来自/ opt/local/gcc48的libgomp和libstdc ++一起使用(DL_DEBUG)用过的).
有任何想法吗?在谷歌上没有找到任何东西 - 或者我使用了错误的关键字:)
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?