即使“-nostdlib”不存在,如何运行构造函数选项已定义

发布于 2024-10-13 09:32:28 字数 409 浏览 2 评论 0原文

我有一个包含构造函数的动态库。

__attribute__ ((constructor))
void construct() {
    // This is initialization code
}

该库是使用 -nostdlib 选项编译的,我无法更改它。因此,库中没有 .ctor.dtor 部分,并且构造函数不会在库加载时运行。

正如所写那里应该即使在这种情况下也可以采取特殊措施来允许运行构造函数。您能告诉我该怎么做以及如何做吗?

I have a dynamic library that contains a constructor.

__attribute__ ((constructor))
void construct() {
    // This is initialization code
}

The library is compiled with -nostdlib option and I cannot change that. As a result there are no .ctor and .dtor sections in library and the constructor is not running on the library load.

As written there there should be special measures that allow running the constructor even in this case. Could you please advice me what and how that can be done?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

铁憨憨 2024-10-20 09:32:28

为什么需要构造函数?与我一起工作的大多数程序员(包括我自己)都拒绝使用具有全局构造函数的库,因为它们常常会在输入 main 时弄乱程序的初始状态,从而引入错误。我能想到的一个具体例子是OpenAL,它在仅仅链接时就破坏了程序,即使它从未被调用。我不是该项目中处理此错误的人,但如果我没记错的话,它与对 ALSA 的破坏以及后来破坏主程序对 ALSA 的使用有关。

如果您的库具有重要的全局状态,请查看是否可以简单地使用全局结构和初始值设定项。不过,您可能需要添加带有一些指针的标志,以指示它们是指向分配的内存还是静态内存。另一种方法是将初始化推迟到第一次调用,但这可能会产生线程安全问题,除非您使用 pthread_once 或类似的方法。

Why do you need constructors? Most programmers I work with, myself included, refuse to use libraries with global constructors because all too often they introduce bugs by messing up the program's initial state when main is entered. One concrete example I can think of is OpenAL, which broke programs when it was merely linked, even if it was never called. I was not the one on the project who dealt with this bug, but if I'm not mistaken it had something to do with mucking with ALSA and breaking the main program's use of ALSA later.

If your library has nontrivial global state, instead see if you can simply use global structs and initializers. You might need to add flags with some pointers to indicate whether they point to allocated memory or static memory, though. Another method is to defer initialization to the first call, but this can have thread-safety issues unless you use pthread_once or similar.

绿萝 2024-10-20 09:32:28

嗯,错过了没有 .ctor 和 .dtor 部分的部分......忘记这一点。

#include <stdio.h>
#include <stdint.h>

typedef void (*func)(void);

__attribute__((constructor))
void func1(void) {
     printf("func1\n");
}

__attribute__((constructor))
void func2(void) {
     printf("func2\n");
}

extern func* __init_array_start;

int main(int argc, char **argv)
{
     func *funcarr = (func*)&__init_array_start;
     func f;
     int idx;

     printf("start %p\n", *funcarr);

     // iterate over the array
     for (idx = 0; ; ++idx) {
          f = funcarr[idx];

          // skip the end of array marker (0xFFFFFFFF) on 64 bit it's twice as long ;)
          if (f == (void*)~0)
               continue;

          // till f is NULL which indicates the start of the array
          if (f == NULL)
               break;

          printf("constructor %p\n", *f);
          f();
     }

     return 0;
}

这给出了:

Compilation started at Fri Mar  9 09:28:29

make test && ./test
 cc     test.c   -o test
 func2
 func1
 start 0xffffffff
 constructor 0x80483f4
 func1
 constructor 0x8048408
 func2

如果您在大端系统上运行,可能您需要交换继续和中断,但我不完全确定。

但就像 R.. 所说,在库中使用静态构造函数对于使用库的开发人员来说并不是那么好:p

Hmm missed the part that there where no .ctor and .dtor sections... forget about this.

#include <stdio.h>
#include <stdint.h>

typedef void (*func)(void);

__attribute__((constructor))
void func1(void) {
     printf("func1\n");
}

__attribute__((constructor))
void func2(void) {
     printf("func2\n");
}

extern func* __init_array_start;

int main(int argc, char **argv)
{
     func *funcarr = (func*)&__init_array_start;
     func f;
     int idx;

     printf("start %p\n", *funcarr);

     // iterate over the array
     for (idx = 0; ; ++idx) {
          f = funcarr[idx];

          // skip the end of array marker (0xFFFFFFFF) on 64 bit it's twice as long ;)
          if (f == (void*)~0)
               continue;

          // till f is NULL which indicates the start of the array
          if (f == NULL)
               break;

          printf("constructor %p\n", *f);
          f();
     }

     return 0;
}

Which gives:

Compilation started at Fri Mar  9 09:28:29

make test && ./test
 cc     test.c   -o test
 func2
 func1
 start 0xffffffff
 constructor 0x80483f4
 func1
 constructor 0x8048408
 func2

Probably you need to swap the continue and break if you are running on an Big Endian system but i'm not entirely sure.

But just like R.. stated using static constructors in libraries is not so nice to the developers using your library :p

岁吢 2024-10-20 09:32:28

在某些平台上,生成 .init_array/.fini_array 部分以包含所有全局构造函数/析构函数。你可以用它。

On some platforms, .init_array/.fini_array sections are generated to include all global constructors/destructors. You may use that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文