加载可执行文件或执行库

fox*_*cub 9 linux executable glibc shared-libraries dlopen

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 上执行的共享对象(动态库)。

我有两个问题:

  1. 如果我想传递命令行参数怎么办?如何修改此解决方案以使其接受arc,argv
  2. 还有其他选择吗?

Emp*_*ian 6

很难猜测是什么促使了如此彻底的改变

事实并非如此:它从来没有正常工作过。

这破坏了很多代码

该代码已经以微妙的方式被破坏了。现在你会得到一个明确的指示,表明它不起作用。

还有其他选择吗?

不这样做吗?

dlopen可执行文件可以解决什么问题?

如果这是一个真正的问题,请打开 GLIBC bugzilla 功能请求,解释该问题并请求支持的机制来实现所需的结果。

更新:

至少说一下为什么“它从来没有正常工作过”。是一些琐碎的事情,比如可执行文件之间可能发生全局冲突,还是真实的事情?

线程局部变量就是一个不能正常工作的例子。不管你认为它们是“真实的”还是假的,我不知道。

这是代码:

// foo.c
#include <stdio.h>

__thread int var;

__attribute__((constructor))
static void init()
{
  var = 42;
  printf("foo.c init: %d %p\n", var, &var);
}

int bar() {
  printf("foo.c bar:  %d %p\n", var, &var);
  return var;
}

int main()
{
  printf("foo.c main: %d %p bar()=%d\n", var, &var, bar());
  return 0;
}
Run Code Online (Sandbox Code Playgroud)
gcc -g foo.c -o foo -Wl,-E -fpie -pie && ./foo
foo.c init: 42 0x7fb5dfd7d4fc
foo.c bar:  42 0x7fb5dfd7d4fc
foo.c main: 42 0x7fb5dfd7d4fc bar()=42
Run Code Online (Sandbox Code Playgroud)
// main.c
// Error checking omitted for brevity
#include <dlfcn.h>
#include <stdio.h>

int main()
{
  void *h1 = dlopen("./foo", RTLD_LOCAL|RTLD_LAZY);
  int (*bar)(void) = dlsym(h1, "bar");

  printf("main.c: %d\n", bar());
  return 0;
}
Run Code Online (Sandbox Code Playgroud)
gcc -g main.c -ldl && ./a.out
foo.c init: 42 0x7fb7305da73c
foo.c bar:  0 0x7fb7305da73c    <<< what?
main.c: 0                       <<< what?
Run Code Online (Sandbox Code Playgroud)

这是使用GNU C Library (Debian GLIBC 2.28-10) stable release version 2.28.

底线:这从来都不是为了工作而设计的,而你只是碰巧没有踩到许多地雷,所以你认为它正在工作,而事实上你正在练习未定义的行为。