.init
/.fini
未被棄用。它仍然是ELF標準的一部分,我敢說這將是永恆的。加載/卸載代碼時,加載器/運行時鏈接器運行代碼.init
/.fini
。即在每個ELF加載(例如共享庫)代碼.init
將運行。仍然可以使用該機制來實現與__attribute__((constructor))/((destructor))
大致相同的功能。這是老派,但它有一些好處。
.ctors
/.dtors
機制例如需要system-rtl/loader/linker-script的支持。這在所有系統上都不可用,例如代碼在裸機上執行的深度嵌入式系統。即即使GDB支持__attribute__((constructor))/((destructor))
,也不確定它是否會運行,因爲鏈接器需要組織它以及加載器(或者在某些情況下使用啓動代碼)來運行它。改爲使用.init
/.fini
,最簡單的方法是使用鏈接器標誌:-init & -fini(即,來自GCC命令行,語法將爲-Wl -init my_init -fini my_fini
)。
在系統支持這兩種方法,一個可能的好處是.init
代碼是.ctors
和代碼前.fini
.dtors
後運行。如果訂單是相關的,那麼至少有一個原始但簡單的方法可以區分init/exit函數。
一個主要缺點是,你不能輕易擁有每每個加載的模塊不止一個_init
和一個_fini
功能,並可能會在比激勵更.so
進行分段代碼。另一個是,當使用上述連接器方法時,將替換原始的_init和_fini
默認功能(由crti.o
提供)。這是通常發生各種初始化的地方(在Linux上,這是全局變量賦值初始化的地方)。解決方法如下here
請注意,在上面的鏈接中,不需要級聯到原始_init()
,因爲它仍然存在。然而,內聯程序集中的call
是x86助記符,並且從程序集調用函數對於許多其他體系結構(例如ARM)看起來完全不同。即代碼不透明。
.init
/.fini
和.ctors
/.detors
機制是類似的,但不完全相同。 .init
/.fini
中的代碼按「原樣」運行。即你可以在.init
/.fini
有幾個函數,但它是AFAIK在語法上很難完全透明地將它們放在純C中,而不會破壞很多小文件中的代碼。
.ctors
/.dtors
的組織結構不同於.init
/.fini
。 .ctors
/.dtors
部分都只是指向函數的指針,而「調用者」是系統提供的循環,它間接調用每個函數。即循環調用者可以是體系結構特定的,但是因爲它是系統的一部分(如果它完全存在),它並不重要。
下段添加的新的函數指針到.ctors
函數數組,主要方式與__attribute__((constructor))
相同並(方法可以與__attribute__((constructor)))
共存。
#define SECTION(S) __attribute__ ((section (S)))
void test(void) {
printf("Hello\n");
}
void (*funcptr)(void) SECTION(".ctors") =test;
void (*funcptr2)(void) SECTION(".ctors") =test;
void (*funcptr3)(void) SECTION(".dtors") =test;
人們也可以函數指針添加到一個完全不同的自在這種情況下需要一個修改後的鏈接描述文件和一個模仿加載程序的附加函數,但是通過它可以更好地控制執行順序,添加in-argument和返回代碼處理eta(在C++項目,例如,如果需要在之前運行的某個或某個項目,它將很有用全球構造函數)。
如果可能,我寧願__attribute__((constructor))/((destructor))
,這是一個簡單而優雅的解決方案,即使它看起來像是作弊。對於像我這樣的裸機編碼器來說,這並不總是一種選擇。
書中的一些很好的參考文獻Linkers & loaders。
雙括號使它們很容易「宏觀」('#define __attribute __(x)')。如果你有多個屬性,例如'__attribute __((noreturn,weak))',如果只有一組括號,就很難「宏觀化」。 –
這不是用'.init/.fini'完成的。 (你可以在一個單獨的翻譯單元中有效地擁有多個構造函數和析構函數,從不在多個單獨的庫中 - 這將如何工作?)相反,在使用ELF二進制格式(Linux等)的平臺上,引用構造函數和析構函數在標題的'.ctors'和'.dtors'部分。的確,在過去,名爲'init'和'fini'的函數將在動態庫加載和卸載(如果它們存在)上運行,但現在不推薦使用,而是由此更好的機制取代。 – ephemient
@ephemient:謝謝,我忘記了新的和改進的做事方式。相應地更新答案。 – janneb