【问题标题】:Any documentation for .init_array function arguments?.init_array 函数参数的任何文档?
【发布时间】:2021-11-17 20:03:55
【问题描述】:

我可以看到很多复制的传说,在 .init_array 部分注册的函数具有命令行参数 argc 和 argv,如 main(),但我无法在网上找到任何实际发布的文档来确认这是案例。

是的,为了清楚起见,函数本身并没有在 .init_array 中“声明”,而是在其中声明了指向该函数的指针,“注册”了该函数,并且在启动期间由某个迭代器调用。问题仍然存在:给我看一些关于该迭代器传入的参数列表的文档。

我的意图是以一种微妙但通常安全的方式从动态库中更改这些参数,因此我想在内存中找到“真正的交易” - 而不是来自 /proc/self/。

欲了解更多信息,请点击以下链接。

一些堆栈溢出知识:Accessing main arguments outside of main on Linux

甚至我最喜欢的 Oracle (docs.oracle.com/cd/E23824_01/html/819-0690/chapter3-8.html) 也只提到函数被调用,但没有承诺可能有什么参数。据我所知,与 elf 和 gcc 文档相同。

在 C/C++ UB 偏执狂的土地上,理想情况下,在我继续之前,我需要确定这是记录在案的行为吗?它存在吗?它可以以某种方式暗示吗?


到目前为止的 cmets/answers 总结:

至少对于 GNU libc,此补丁发生了相关更改:BZ #974。 https://sourceware.org/pipermail/libc-alpha/2005-July/019240.html(在 glibc 的 ChangeLog.old/ChangeLog.16 条目 2005-04-13 H.J. Lu. 中有提及)– 伊恩·雅培

对我来说,这表明 glbc 维护者意识到传递 argc/argv/env 的要求——这不是偶然的——并将其扩展到主要的 exe 注册。它还告诉我们它在该日期之前适用于动态库。

这是一个有趣的问题,这是否会约束其他 libc 实现者遵循该模式。

【问题讨论】:

  • 查看负责调用这些函数的(特定)代码,我会说它们应该是void foo(void)static.grumpycoder.net/pixel/uC-sdk-doc/initfini_8c_source.html
  • 是的,作为函数签名总是安全的 :-)(至少在 C 中,在 pascal 中不是这样)
  • 至少对于 GNU libc,此补丁发生了相关更改:BZ #974。 (在 glibc 的 ChangeLog.old/ChangeLog.16 条目 2005-04-13 H.J. Lu 中有提及。)
  • 谢谢@IanAbbott 这是我想要/需要的有力证据。
  • 从我的角度来看,我想从动态库中获取参数,所以在 2005 年修复主 exe 并不担心。

标签: c gcc elf


【解决方案1】:

我找到了这个interesting article about Linux programs' start-up procedure by Patrick Horgan。但我可能无法保证此来源的正确性。

至少,它解释了.init_array 部分背后的代码:

void __libc_csu_init (int argc, char **argv, char **envp) {
  _init ();

  const size_t size = __init_array_end - __init_array_start;
  for (size_t i = 0; i < size; i++) {
      (*__init_array_start [i]) (argc, argv, envp);
  }
}

看来__libc_csu_init() 函数首先计算.init_array 部分内的元素数量,然后使用参数argcargvenvp 调用每个函数指针。这个函数(__libc_csu_init())在main()之前被调用。

注意:.init_array 部分似乎特定于 ELF 二进制格式。


更新

似乎__libc_csu_init() 的实现(以及更一般地说,.init_array 函数的调用方式)依赖于平台和 libc。

不过,Linux 上的 GLIBC 似乎可以正确调用带有所需参数的函数,正如您在 its source code 中看到的那样。

另外,阅读GLIBC changelog,似乎这种行为是在 2005 年引入的。

【讨论】:

  • 谢谢卢卡。这是一个有用且可读的教程。至少它解释了 .init_array 和 .preinit_array 之间的区别
  • 我试图弄清楚它有多古老...... asm 示例是 32 位的,所以它有点过时了。页面有 (C) 2011 所以没那么旧!
  • @GemTaylor 对于 GNU libc,它似乎可以追溯到 2005-04-13。不确定其他 libc 实现。
  • 我已经用一些附加信息更新了我的答案。 @IanAbbott 没错。
猜你喜欢
  • 2013-04-07
  • 1970-01-01
  • 2011-12-09
  • 2016-08-23
  • 1970-01-01
  • 2019-06-19
  • 1970-01-01
  • 2023-03-24
  • 2011-06-07
相关资源
最近更新 更多