如果库定义了同一符号的多个版本,dlsym(RTLD_NEXT, "symbol")即使旧符号不是默认符号,也会返回旧符号。
例如,libpthread 定义了两个版本的 pthread_cond_broadcast:
$:> nm -g /lib64/libpthread-2.15.so|grep pthread_cond_broadcast
000000000000bfc0 T pthread_cond_broadcast@@GLIBC_2.3.2
000000000000c310 T pthread_cond_broadcast@GLIBC_2.2.5
Run Code Online (Sandbox Code Playgroud)
现在,如果我使用 dlsym(RTLD_NEXT, "pthread_cond_broadcast"),我总是得到 GLIBC_2.2.5 版本而不是 GLIBC_2.3.2 版本。当然,可以使用 dlvsym 来获取默认版本,但是如果需要为大量符号执行此操作,并且其中许多符号具有不同的新/旧版本,则这会变得复杂。
我明白 RTLD_NEXT 不应该总是返回最新的符号以保持兼容性,但为什么不返回默认符号?
有谁知道这背后的原理?
我使用 OS X 10.7 (Lion)、XCode 4.6.3 和 libstdc++ 作为 C++ 标准库。
我的主项目中有这段代码:
共享.cpp:
extern "C" int sharedFun()
{
return 5;
}
Run Code Online (Sandbox Code Playgroud)
在我的副项目中,需要动态加载主项目:
加载器.cpp:
#include <dlfcn.h>
int main(int argc, const char * argv[])
{
void* mainApp = dlopen("mainApp.dylib", RTLD_LAZY);
char* error;
dlsym(mainApp, "sharedFun");
if ((error = dlerror()) != nullptr)
{
....
}
}
Run Code Online (Sandbox Code Playgroud)
纳米输出:
nm -gU mainApp.dylib | grep sharedFun
002a3a10 - 01 0000 FUN _sharedFun
002a3a10 T _sharedFun
Run Code Online (Sandbox Code Playgroud)
dlopen 加载库很好,但 dlsym 返回“符号未找到”。有任何想法吗?
谢谢。
我们有一个链接多个静态库的程序,这些静态库可能定义也可能不定义多个符号,具体取决于编译选项。在 OS X 上,我们使用dlsym(3)NULL 句柄来获取符号地址。但是,在 Linux 上,dlsym(3)始终返回 NULL。
考虑一个简单的程序(来源如下),该程序链接包含一个函数和一个变量的静态库,并尝试打印它们的地址。我们可以检查程序是否包含符号:
$ nm -C test | grep "test\(func\|var\)"
0000000000400715 T testFunc
0000000000601050 B testVar
Run Code Online (Sandbox Code Playgroud)
但是,当程序运行时,两者都找不到:
$ ./test
testVar: (nil)
testFunc: (nil)
Run Code Online (Sandbox Code Playgroud)
我们正在尝试在 Linux 上使用 glibc 实现的dlsym(3)?
(抱歉有空格)
LDFLAGS=-L.
LDLIBS=-Wl,--whole-archive -ltest -Wl,--no-whole-archive -ldl
libtest.o: libtest.c libtest.h
libtest.a: libtest.o
test: test.o libtest.a
clean:
-rm -f test test.o libtest.o libtest.a
Run Code Online (Sandbox Code Playgroud)
#pragma once
extern void *testVar;
extern int testFunc(int);
Run Code Online (Sandbox Code Playgroud)
#include "libtest.h"
void *testVar;
int testFunc(int x) { …Run Code Online (Sandbox Code Playgroud) 我正在尝试编写在运行时加载我的共享对象 (.so) 的最小程序。
不幸的是,尽管进行了错误检查,它还是在运行时挂起 :-(
我对我在源代码级别忽略的内容非常感兴趣。
源代码和运行我的程序的 shell 会话如下。
文件“libsample.c”:
#include <stdio.h>
void sample_check(void)
{
printf("INFO: Function sample_check() called.\n");
}
Run Code Online (Sandbox Code Playgroud)
文件“test.c”:
#include <stdio.h>
#include <dlfcn.h>
typedef void (*sample_func_t) (void);
int main(void)
{
setbuf(stdout, NULL);
setbuf(stderr, NULL);
void* h_lib = dlopen("./libsample.so.1", RTLD_LAZY); // RTLD_LAZY || RTLD_NOW
if (! h_lib)
{
fprintf(stderr, "ERROR(%d): %s\n", __LINE__, dlerror());
return 1;
}
sample_func_t* symver = NULL;
dlerror();
symver = dlsym(h_lib, "sample_check");
char* reter = dlerror();
if (reter)
{
fprintf(stderr, "ERROR(%d): %s\n", __LINE__, reter);
return 1; …Run Code Online (Sandbox Code Playgroud) 在 macOS 上,我使用必须由用户安装的外部框架(用 C 编写)。在 Swift 中,我需要在运行时检查它是否存在,并且我不能使用 #available() 因为它用于与操作系统相关的功能,并且我正在尝试追踪外部框架。另外,NSClassFromString() 没有用,因为它不是 Objective-C 框架。
我一直在尝试了解如何复制 Objective-C 等效项来检查弱链接符号,例如:
if ( anExternalFunction == NULL ) {
// fail graciously
} else {
// do my thing
}
Run Code Online (Sandbox Code Playgroud)
但在 Swift 中,这似乎不起作用:编译器指出,由于 anExternalFunction 不是可选的,所以我总是会得到 != nil,这使得“Swift 有意义”,但对我没有一点帮助。
我找到了两种解决方案,但它们让我的代码变得很糟糕,就像你不会相信的那样:
选项 1,使用名为 isFrameworkAvailable() 的函数创建一个 Objective-C 文件来完成工作,并从 Swift 调用
选项 2,使用以下 Swift 代码实际检查库:
let libHandle = dlopen("/Library/Frameworks/TheLib.framework/TheLib", RTLD_NOW)
if (libHandle != nil) {
if dlsym(libHandle, "anExternalFunction") != nil {
return true
}
}
return false
Run Code Online (Sandbox Code Playgroud)
我一直无法让选项 2 与 RTLD_DEFAULT …
我有一个应用程序动态加载库,动态加载库...
在Windows中,我能够迭代所有加载的模块,寻找我感兴趣的符号.不知道如何在Unix/Linux环境中这样做.我知道我可以使用dlsym(dlopen(0, flag))或dlsym(RTLD_DEFAULT / RTLD_NEXT)前两个符号并知道要搜索的模块的顺序 - 我怎样才能更深入地获得给定符号的所有定义?
我的标题可能不清楚,所以请允许我解释一下。我有一段这样的代码:
void* pluginFile = dlopen(fileName, RTLD_LAZY);
auto function = dlsym(pluginFile, "ExpectedFunction");
Run Code Online (Sandbox Code Playgroud)
如果dlopen返回正确的文件,则可以正常工作。我的问题是何时dlopen找不到文件并返回NULL。当前发生的情况是发出了此调用:
dlsym(0x0, "ExpectedFunction");
Run Code Online (Sandbox Code Playgroud)
问题在于这会在我的项目中返回一个随机函数,称为ExpectedFunction。我以为会发生dlsym,NULL因为传递的句柄是NULL。我无法在线找到这种用例的预期行为。
我的问题是,将NULL句柄传递给时会发生什么dlsym?它会简单地返回NULL还是将其解释为某个位置的句柄0x0?如果本质上是后者,那么我将添加一个检查以确保dlopen suceeded。如果不是,我想知道为什么如果句柄是,它为什么会从另一个库中随机返回一个具有相同名称的函数NULL。
我当前的用例是,我正在加载10个共享库,这些共享库都具有一个函数ExpectedFunction()。但是,如果dlopen使用不存在的共享库的文件名进行调用,它将返回NULL。然后,dlsym将返回指向ExpectedFunction()最后加载的库的指针。
我正在编写一种运行时系统/解释器,我需要做的一件事就是调用位于外部库中的c/c ++函数.
在linux上我使用这些dlfcn.h函数来打开一个库,并调用一个位于其中的函数.问题是,当使用dlsysm()返回的函数指针需要在被调用之前被转换为适当的类型,以便知道函数参数和返回类型,但是如果我在库中调用一些任意函数那么显然我不会在编译时知道这个原型.
所以我要问的是,有没有办法调用动态加载的函数并传递参数,并在不知道它的原型的情况下检索它的返回值?
到目前为止,我已经得出结论没有简单的方法来做到这一点,但我发现的一些解决方法是:
确保我想要加载的所有函数都具有相同的原型,并为这些函数提供一些排序机制来检索参数和返回值.这就是我目前正在做的事情.
使用内联asm将参数压入堆栈,并读取返回值.如果可能的话,我真的想避免这样做!
如果有人有任何想法,那将非常感激.
编辑:
我现在找到了我正在寻找的东西:
"便携式外部函数接口库"
(虽然我承认我原来的问题可以更清楚!)
我花了几天阅读并重新阅读我在这个主题上找到的每一个教程,花了几个小时(甚至几天)在这里浏览相关问题,但我仍然无法让以下工作.如果这是重复的话,请接受我的道歉:我有可能多次看到并重读了重复的问题,但无法理解答案与我的问题的相关性.随着那个...
我正在尝试为我的应用程序实现插件架构.插件编译并作为库安装.在运行时,Application然后使用dlopen()/ dlsym()加载并链接到插件的函数.
想法是插件(库)将实现一组函数以将数据返回到主Application,或者操纵从Application传递的数据.
为了测试这个想法,我试图实现一个函数(插件内部),该函数将返回插件本身的(人类可读)名称(作为std :: string).我认为这将是一件简单的事情....: - /
这是我到目前为止所得到的:
// Plugin.cpp
extern "C" void plugin_name(std::string *name) {
name = new std::string("Example plugin name");
}
// Application.cpp
void* handle = dlopen("libplugin.so", RTLD_LAZY);
typedef void (*plugin_t)(std::string*);
dlerror(); // Reset errors.
plugin_t call_plugin_name = (plugin_t) dlsym(handle, "plugin_name");
// ... Some error handling code.
std::string my_plugin_name;
call_plugin_name(&my_plugin_name);
dlclose(handle);
// More code that displays my_plugin_name.
Run Code Online (Sandbox Code Playgroud)
我已经尝试了许多不同的组合,包括一个看起来更直接(但没有更好的工作)的插件名称返回的组合:
// Plugin.cpp
extern "C" std::string plugin_name(void) {
return std::string("Example plugin name");
}
Run Code Online (Sandbox Code Playgroud)
我知道我很接近:代码编译,应用程序停止崩溃;)
但是,我有一个空的空间,我希望看到实际的插件名称.
到目前为止,我读过的所有教程都非常快速地通过两种方式传递数据的机制:plugin <=> Application.我正在尝试使用"简单"的std :: …
当我尝试编译我的单元测试文件时,我得到'未定义的引用`dlsym'错误.我在Unix系统上读到了(我在Ubuntu 12.04上)将-ldl添加到编译器中,但我尝试使用Zed的Shaw Makefile但仍然没有发生任何事情.这是代码:
CFLAGS=-g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG $(OPTFLAGS)
LIBS=-ldl $(OPTLIBS)
PREFIX?=/usr/local
SOURCES=$(wildcard src/**/*.c src/*.c)
OBJECTS=$(patsubst %.c,%.o,$(SOURCES))
TEST_SRC=$(wildcard tests/*_tests.c)
TESTS=$(patsubst %.c,%,$(TEST_SRC))
TARGET=build/libex29.a
SO_TARGET=$(patsubst %.a,%.so,$(TARGET))
# The Target Build
all: $(TARGET) $(SO_TARGET) tests
dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS)
dev: all
$(TARGET): CFLAGS += -fPIC
$(TARGET): build $(OBJECTS)
ar rcs $@ $(OBJECTS)
ranlib $@
$(SO_TARGET): $(TARGET) $(OBJECTS)
$(CC) -shared -o $@ $(OBJECTS)
build:
@mkdir -p build
@mkdir -p bin
# The Unit Tests
.PHONY: tests
tests: CFLAGS += …Run Code Online (Sandbox Code Playgroud)