不要這樣做;讓你的編譯器和鏈接器按照他們認爲合適的方式填寫這些部分。
而是用合適的function attributes標記你的函數,以便編譯器和鏈接器將它們放在正確的部分。
例如,
static void before_main(void) __attribute__((constructor));
static void after_main(void) __attribute__((destructor));
static void before_main(void)
{
/* This is run before main() */
}
static void after_main(void)
{
/* This is run after main() returns (or exit() is called) */
}
還可以分配一個優先級(比如說,__attribute__((constructor (300)))
),101和65535(含)之間的整數,與第一具有較小優先級編號運行功能。
請注意,爲了說明,我標記了功能static
。也就是說,這些函數在文件範圍外是不可見的。這些功能不需要被導出的符號自動調用。
爲了測試,我建議保存在單獨的文件下面,說tructor.c
:
#include <unistd.h>
#include <string.h>
#include <errno.h>
static int outfd = -1;
static void wrout(const char *const string)
{
if (string && *string && outfd != -1) {
const char *p = string;
const char *const q = string + strlen(string);
while (p < q) {
ssize_t n = write(outfd, p, (size_t)(q - p));
if (n > (ssize_t)0)
p += n;
else
if (n != (ssize_t)-1 || errno != EINTR)
break;
}
}
}
void before_main(void) __attribute__((constructor (101)));
void before_main(void)
{
int saved_errno = errno;
/* This is run before main() */
outfd = dup(STDERR_FILENO);
wrout("Before main()\n");
errno = saved_errno;
}
static void after_main(void) __attribute__((destructor (65535)));
static void after_main(void)
{
int saved_errno = errno;
/* This is run after main() returns (or exit() is called) */
wrout("After main()\n");
errno = saved_errno;
}
,所以你可以編譯並鏈接任何程序或庫的一部分。要將其編譯爲共享庫,請使用
gcc -Wall -Wextra -fPIC -shared tructor.c -Wl,-soname,libtructor.so -o libtructor.so
,您可以使用
LD_PRELOAD=./libtructor.so some-command-or-binary
功能保持errno
不變干預它到任何動態鏈接的命令或二進制,但它不應該在實踐中關係,並使用低級別write()
系統調用來將消息輸出到標準錯誤。最初的標準錯誤被複制到一個新的描述符中,因爲在許多情況下,標準錯誤本身在最後一個全局析構函數 - 我們的析構函數 - 運行之前被關閉。
(有些偏執的二進制文件,通常是安全敏感的,接近於他們不知道所有的描述,所以你可能不看到在所有情況下After main()
消息。)
這是奇怪的...關於你的第一個問題 - 我的GDB顯示初始化函數不會運行在所有。 – MByD
在標準庫初始化足夠讓put工作之前,單元部分很可能運行。你爲什麼不嘗試一些沒有依賴關係的東西,比如設置一個全局變量,以查看單元函數是否實際運行。 –