如何编译ELF二进制文件以便它可以作为动态库加载? [复制]

2023-12-21

这是理论问题。我知道也许最佳实践是使用共享库。但我遇到了这个问题,似乎无法在任何地方找到答案。

如何构造代码并以 ELF 格式编译 C/C++ 程序以便可以加载dlopen()?

例如,如果一个可执行文件包含某个函数的实现int test()我想从我的程序中调用这个函数(最好是得到函数的结果),如果可能的话,我将如何去做呢?

在伪代码中我可以将其描述如下:

ELF可执行源码:

void main() {
    int i = test();
    printf("Returned: %d", i);//Prints "Returned: 5"
}

int test() {
    return 5;
}

外部程序:

// ... Somehow load executable from above
void main() {
    int i = test();
    printf("Returned: %d", i);//Must print "Returned: 5"
}

ELF http://www.sco.com/developers/devspecs/gabi41.pdf可执行文件不可重定位,并且它们通常编译为在相同的起始地址(x86_64 为 0x400000)处启动,这意味着从技术上讲,不可能将其中两个加载到同一地址空间中。

你可以做的是:

  • 编译你想要的可执行文件dlopen()作为可执行共享库(-pie)。从技术上讲,这个文件是一个 ELF 共享对象,但可以执行。您可以检查该程序是否是 ELF 可执行文件或 ELF 共享对象readelf -h my_program or file my_program。 (作为奖励,通过将程序编译为共享对象,您将能够从 ASLR 中受益)。

  • 通过将主程序编译为共享对象(以便将其加载到虚拟地址空间中的另一个位置),您应该能够动态链接其他可执行文件。 GNU 动态链接器不想dlopen一个可执行文件,因此您必须自己进行动态链接(您可能不想这样做)。

  • 或者,您可以使用链接描述文件链接其中一个可执行文件以使用另一个基地址。和以前一样,您必须自己完成动态链接器的工作。

解决方案 1:将动态加载的可执行文件编译为 PIE

被调用的可执行文件:

// hello.c
#include <string.h>
#include <stdio.h>

void hello()
{
  printf("Hello world\n");
}

int main()
{
  hello();
  return 0;
}

调用者可执行文件:

// caller.c
#include <dlfcn.h>
#include <stdio.h>

int main(int argc, char** argv)
{
  void* handle = dlopen(argv[1], RTLD_LAZY);
  if (!handle) {
    fprintf(stderr, "%s\n", dlerror());
    return 1;
  }
  void (*hello)() = dlsym(handle, "hello");
  if (!hello) {
    fprintf(stderr, "%s\n", dlerror());
    return 1;
  }
  hello();
  return 0;
}

试图让它发挥作用:


$ gcc -fpie -pie hello.c -o hello
$ gcc caller.c -o caller
$ ./caller ./hello
./hello: undefined symbol: hello
  

原因是当你将hello编译为PIE时,动态链接器不会将hell符号添加到动态符号表中(.dynsym):


$ readelf -s 
Symbol table '.dynsym' contains 12 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000200     0 SECTION LOCAL  DEFAULT    1 
     2: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab
     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.2.5 (2)
     4: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (2)
     5: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     6: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
     7: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
     8: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@GLIBC_2.2.5 (2)
     9: 0000000000200bd0     0 NOTYPE  GLOBAL DEFAULT   24 _edata
    10: 0000000000200bd8     0 NOTYPE  GLOBAL DEFAULT   25 _end
    11: 0000000000200bd0     0 NOTYPE  GLOBAL DEFAULT   25 __bss_start

Symbol table '.symtab' contains 67 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
[...]
    52: 0000000000000760    18 FUNC    GLOBAL DEFAULT   13 hello
[...]
  

为了解决这个问题,您需要通过-E标记为ld(参见@AlexKey的回答):


$ gcc -fpie -pie hello.c -Wl,-E hello.c -o hello
$ gcc caller.c -o caller
$ ./caller ./hello
Hello world
$ ./hello
Hello world
$ readelf -s ./hello
Symbol table '.dynsym' contains 22 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
[...]
    21: 00000000000008d0    18 FUNC    GLOBAL DEFAULT   13 hello
[...]
  

一些参考资料

了解更多信息,4. 动态加载(DL)库 http://tldp.org/HOWTO/Program-Library-HOWTO/dl-libraries.html来自程序库指南是开始阅读的好地方。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何编译ELF二进制文件以便它可以作为动态库加载? [复制] 的相关文章

随机推荐

  • Rails - 如何“合并”或将值附加到 URL 内的数组?

    我正在尝试在 URL 中传递一个数组 该数组工作正常 但我想知道如何插入或删除某些值 例如 我有一个链接 如下所示 http localhost 3000 pins genre ids 1 2 3 我想构建一组可以在此 URL 数组中插入或
  • 在 ASP.NET 内部运行 ASP.NET MVC 时,会话为 NULL

    如果我创建一个 ASP NET Web 应用程序项目 然后使用像这样定义的默认路由向其添加 ASP NET MVC 2 routes MapRoute Default Route name controller action id URL
  • 使用 JS 检测 MacOS、iOS、Windows、Android 和 Linux 操作系统 [重复]

    这个问题在这里已经有答案了 如何使用 JavaScript 检测 MacOS X iOS Windows Android 和 Linux 操作系统 我学到了很多关于window navigator对象及其属性 platform appVer
  • 客户端 JavaScript 应用程序和服务器端 HTTP API 之间的身份验证?

    我已经构建了一些通过 HTTP 工作的服务器端 API 仅适用于我的客户端应用程序 那么 是否可以在客户端和服务器端之间对应用程序进行身份验证 以及如何做 有两种选择 Sessions HTTP认证 会话背后的想法是 服务器向客户端发送一个
  • 使用 MS Graph API C# 读取用户电子邮件

    我正在尝试使用 MS Graph API 读取特定邮箱中的电子邮件 var client await GetClient getting a client with client id secret var users await clie
  • ASP.Net 转发器 item.DataItem 为 null

    在网页中 加载时 我用两个表填充数据集以及这些表之间的关系 然后将数据加载到具有嵌套转发器的转发器中 用户单击按钮后也可能发生这种情况 数据从 SQL 数据库加载 转发器数据源设置为回发后的数据集 但是 当 ItemDataBound 发生
  • 甲骨文。在两个过程中重用游标作为参数

    让我们创建两个测试程序 CREATE OR REPLACE PROCEDURE Aaaa Test1 pDog SYS REFCURSOR IS TYPE tDogRec is record objid varchar2 7 lim num
  • 布局类似于放射状菜单

    我必须设计这样的东西并为每个块添加点击事件 我应该如何继续 任何人都可以指导我吗 我知道现在回复已经太晚了 但这适用于那些现在在项目中需要此类功能的开发人员 看看这个演示项目github https github com beaucolli
  • 如何拒绝来自 iframe 的网站访问?

    我注意到一些网站出于安全原因拒绝从 iFrame 访问其注册和登录页面 我认为这是个好主意 我想知道他们需要什么设置才能做到这一点 因为我想在我的网站上做同样的事情 该网站是用 Java 构建的 并在 Apache Tomcat 上运行 如
  • 在 64 位 VBA 中使用 TaskDialogIndirect

    问题描述 我尝试让代码在 64 位 VBA 下工作 而在 32 位 VBA 下工作正常 它与通用控件任务对话框有关 我使用 Microsoft Access 但问题在其他 VBA 主机中应该是相同的 一个部分在 32 位和 64 位 VBA
  • Html.ImageGetter

    任何人都可以帮我解决如何使用 Html ImageGetter 使用 html 图像 src 标签显示图像吗 和例子或很好的教程 要首先从文本文件中的应用程序资源获取图像 请插入一个 html 图像标签 如下所示 img src my im
  • C# - 检查给定的 url 是文件还是目录?

    我有一个方法可以输入 http ftp 或本地路径 通过输入 url 我需要确定它是文件还是目录 Path GetExtension url 几乎可以正常工作 但如果目录以 有 开头以它的名字命名 那么这个检查就会失败 还有其他方法可以检查
  • Pylint 错误消息:“E1101:模块‘lxml.etree’没有‘strip_tags’成员’”

    我正在尝试lxml http lxml de 第一次使用 python 进行个人项目 我正在尝试使用 etree strip tags 从一些源代码中剥离标签 https stackoverflow com questions 468131
  • 有没有办法将资源的属性解析延迟到“执行”阶段?

    我有两个 LWRP 第一个涉及创建磁盘卷 对其进行格式化并将其安装在虚拟机上 我们将此称为资源cloud volume 第二个资源 它的作用并不重要 需要新格式化卷的 UUID 这是必需的属性 我们将调用此资源foobar 资源cloud
  • 如何检测两个 Golang net.IPNet 对象是否相交?

    如何检测两个Golang之间是否存在交集网络 IPNet https golang org pkg net IPNet物体 也就是如何检查both如果第一个网络是第二个网络的子网OR如果第二个网络是第一个网络的子网 Go 是否提供了任何实用
  • 绘制显示颗粒百分比的等高线

    我试图制作类似于此图的内容 这是一个等值线图 代表两个数据集中包含的 68 95 99 7 的颗粒 到目前为止 我已经尝试实现高斯 KDE 估计 并将这些粒子高斯绘制在轮廓上 文件添加到这里https www dropbox com sh
  • swing 中的 javafx 异常“工具包未初始化”

    我读过这篇文章 JavaFx 2 x Swing 不在 FX 应用程序线程上 https stackoverflow com questions 12182592 javafx 2 x swing not on fx application
  • 对于带有锚点的链接,HttpClient 出现 400 错误

    这是我的代码 DefaultHttpClient client new DefaultHttpClient HttpGet request new HttpGet url HttpResponse response client execu
  • 迭代器性能契约(以及在非集合上的使用)

    如果您所做的只是简单的一次迭代 即仅hasNext and next no remove 您是否能保证每次操作的线性时间性能和 或摊销恒定成本 这是否在Iterator到处签约 有没有数据结构 JavaCollection哪些不能在线性时间
  • 如何编译ELF二进制文件以便它可以作为动态库加载? [复制]

    这个问题在这里已经有答案了 这是理论问题 我知道也许最佳实践是使用共享库 但我遇到了这个问题 似乎无法在任何地方找到答案 如何构造代码并以 ELF 格式编译 C C 程序以便可以加载dlopen 例如 如果一个可执行文件包含某个函数的实现i