【问题标题】:GCC: Executing Code at "Preinitialization" timeGCC:在“预初始化”时间执行代码
【发布时间】:2012-05-31 03:25:51
【问题描述】:

因此,在 Linux 上,当使用 gcc 编译/链接的 C++ 程序加载其可执行文件时,会发生以下情况:

  1. exec* 系统调用
  2. 已加载 LD 动态库
  3. C++ 静态初始化
  4. main 的入口点

假设我有一些原型函数void f()

是否有某种方式(通过源代码修改、属性、编译器/链接器选项等)将可执行文件与 f 链接起来,以便在第 1 步和第 2 步之间执行?

第 2 步和第 3 步之间呢?

(显然没有标准的方法可以做到这一点,我要求为最新版本的 gcc/linux/x86_64/glibc/binutils 提供平台特定、编译器特定的方式)

【问题讨论】:

  • 第 1 步和第 2 步之间?所以你想在图像准备好运行之前运行一些代码?
  • 不太可能。你还需要它做什么?
  • 加载动态库时,是不是有一些机制可以让它们执行一些代码?我想在此之前执行 f。
  • void __attribute__ ((constructor)) my_init(void);(来自tldp.org/HOWTO/Program-Library-HOWTO/miscellaneous.html
  • 是的,所以这些库构造函数将在“步骤 2”期间执行。

标签: c++ c linux gcc glibc


【解决方案1】:

是的,您可以在 (1) 和 (2) 之间或 (2) 和 (3) 之间执行此操作。第 2 步“加载了 ld 动态库”实际上是通过调用动态链接器 ld.so 来完成的。通常,这将是/lib64/ld-linux-x86-64.so.2 或类似的;它是 glibc 的一部分。但是,路径实际上是在可执行文件中指定的,因此您可以使用任何您想要的路径。

$ readelf -l `which bash`
⋮
Program Headers:
⋮
  INTERP         0x0000000000000238 0x0000000000400238 0x0000000000400238
                 0x000000000000001c 0x000000000000001c  R      1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]

⋮

这是除了做LD_PRELOAD/LD_AUDIT之类的事情。

在(2)和(3)之间,听起来你只是想改变入口点地址。

【讨论】:

  • 我认为这对应用程序不起作用。如果发布者可以修改可执行文件,为什么他需要在运行时链接之前运行东西?只需首先链接到正确的库。
  • @AndyRoss OP 明确表示“通过源修改、属性、编译器/链接器选项等”,所以我认为更改 ELF 解释器字段是可以的。不知道 OP 在做什么;我希望答案是“重魔法”,否则 OP 的理智值得怀疑:-P
【解决方案2】:

基本上没有。 execve() 系统调用将擦除环境。您在地址空间中所做的任何事情都无法在新地址空间中继续存在。您可以将文件描述符(当然,标记为 CLOEXEC 的除外)发送到新进程中,并且可以通过环境传递参数。

... 它为您提供了一些可能做您想做的事情。您可以将 LD_PRELOAD 设置为“首先”加载共享库,在从目标可执行文件运行任何代码之前以及在共享链接器解析任何符号之前。从您的问题中不清楚这是否符合您的要求。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-05
    • 2010-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-01
    • 2013-04-23
    相关资源
    最近更新 更多