构建一个 .so 这也是一个可执行文件 [英] building a .so that is also an executable

查看:63
本文介绍了构建一个 .so 这也是一个可执行文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以大家可能都知道 glibc 的 /lib/libc.so.6 可以像普通的可执行文件一样在 shell 中执行,在这种情况下,它会打印其版本信息并退出.这是通过在 .so 中定义入口点来完成的.在某些情况下,将其用于其他项目也可能很有趣.不幸的是,您可以通过 ld 的 -e 选项设置的低级入口点有点太低级了:动态加载器不可用,因此您无法调用任何适当的库函数.由于这个原因,glibc 在这个入口点通过裸系统调用实现了 write() 系统调用.

So everyone probably knows that glibc's /lib/libc.so.6 can be executed in the shell like a normal executable in which cases it prints its version information and exits. This is done via defining an entry point in the .so. For some cases it could be interesting to use this for other projects too. Unfortunately, the low-level entry point you can set by ld's -e option is a bit too low-level: the dynamic loader is not available so you cannot call any proper library functions. glibc for this reason implements the write() system call via a naked system call in this entry point.

我现在的问题是,谁能想出一种很好的方法,如何从该入口点引导一个完整的动态链接器,以便可以访问其他 .so 的函数?

My question now is, can anyone think of a nice way how one could bootstrap a full dynamic linker from that entry point so that one could access functions from other .so's?

推荐答案

更新 2: 参见 Andrew G Morgan 稍微复杂一点的解决方案,该解决方案适用于任何 GLIBC(该解决方案也用于 libc.so.6 本身(自永远),这就是为什么您可以将其作为 ./libc.so.6 运行(以这种方式调用时会打印版本信息)).

Update 2: see Andrew G Morgan's slightly more complicated solution which does work for any GLIBC (that solution is also used in libc.so.6 itself (since forever), which is why you can run it as ./libc.so.6 (it prints version info when invoked that way)).

更新 1:这不再适用于较新的 GLIBC 版本:

Update 1: this no longer works with newer GLIBC versions:

./a.out: error while loading shared libraries: ./pie.so: cannot dynamically load position-independent executable


2009 年的原始答案:


Original answer from 2009:

使用 -pie 选项构建共享库似乎可以为您提供所需的一切:

Building your shared library with -pie option appears to give you everything you want:

/* pie.c */
#include <stdio.h>
int foo()
{
  printf("in %s %s:%d
", __func__, __FILE__, __LINE__);
  return 42; 
}
int main() 
{ 
  printf("in %s %s:%d
", __func__, __FILE__, __LINE__);
  return foo(); 
}


/* main.c */
#include <stdio.h>

extern int foo(void);
int main() 
{ 
  printf("in %s %s:%d
", __func__, __FILE__, __LINE__);
  return foo(); 
}


$ gcc -fPIC -pie -o pie.so pie.c -Wl,-E
$ gcc main.c ./pie.so


$ ./pie.so
in main pie.c:9
in foo pie.c:4
$ ./a.out
in main main.c:6
in foo pie.c:4
$

附言glibc 通过系统调用实现 write(3) 因为它没有其他地方可以调用(它已经是最低级别).这与能够执行 libc.so.6 无关.

P.S. glibc implements write(3) via system call because it doesn't have anywhere else to call (it is the lowest level already). This has nothing to do with being able to execute libc.so.6.

这篇关于构建一个 .so 这也是一个可执行文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆