.init
Saya .fini
tidak ditinggalkan. Itu masih bagian dari standar ELF dan saya berani mengatakan itu akan selamanya. Kode di .init
/ .fini
dijalankan oleh loader / runtime-linker ketika kode dimuat / dibongkar. Yakni pada setiap beban ELF (misalnya pustaka bersama) di .init
akan dijalankan. Masih mungkin untuk menggunakan mekanisme itu untuk mencapai hal yang sama dengan __attribute__((constructor))/((destructor))
. Ini sekolah tua tetapi memiliki beberapa manfaat.
.ctors
/ .dtors
mekanisme misalnya memerlukan dukungan oleh skrip sistem-rtl / loader / linker. Ini jauh dari pasti untuk tersedia di semua sistem, misalnya sistem tertanam di mana kode dieksekusi pada bare metal. Yaitu bahkan jika __attribute__((constructor))/((destructor))
didukung oleh GCC, tidak pasti itu akan berjalan karena terserah linker untuk mengaturnya dan ke loader (atau dalam beberapa kasus, kode boot) untuk menjalankannya. Untuk menggunakan .init
/ .fini
sebagai gantinya, cara termudah adalah dengan menggunakan tanda tautan: -init & -fini (yaitu dari baris perintah GCC, sintaksnya adalah -Wl -init my_init -fini my_fini
).
Pada sistem yang mendukung kedua metode, salah satu manfaat yang mungkin adalah bahwa kode masuk .init
dijalankan sebelum .ctors
dan kode masuk .fini
setelahnya .dtors
. Jika pesanan relevan, itu setidaknya satu cara kasar tetapi mudah untuk membedakan antara fungsi init / exit.
Kelemahan utama adalah bahwa Anda tidak dapat dengan mudah memiliki lebih dari satu _init
dan satu _fini
fungsi per setiap modul yang dapat dimuat dan mungkin harus memecah kode menjadi lebih .so
dari termotivasi. Lain adalah bahwa ketika menggunakan metode linker yang dijelaskan di atas, satu menggantikan fungsi _init asli dan _fini
default (disediakan oleh crti.o
). Di sinilah segala macam inisialisasi biasanya terjadi (di Linux ini adalah di mana tugas variabel global diinisialisasi). Cara yang dijelaskan di sini
Perhatikan di tautan di atas bahwa cascading ke aslinya _init()
tidak diperlukan karena masih ada. Namun call
dalam perakitan inline adalah x86-mnemonic dan memanggil fungsi dari perakitan akan terlihat sangat berbeda untuk banyak arsitektur lainnya (seperti ARM misalnya). Yaitu kode tidak transparan.
.init
/ .fini
dan .ctors
/ .detors
mekanisme serupa, tetapi tidak cukup. Kode dalam .init
/ .fini
berjalan "apa adanya". Yaitu Anda dapat memiliki beberapa fungsi di .init
/ .fini
, tetapi secara sintaksis AFAIK sulit untuk menempatkannya di sana sepenuhnya secara transparan dalam C murni tanpa memecah kode dalam banyak .so
file kecil .
.ctors
Saya .dtors
terorganisir secara berbeda dari .init
/ .fini
. .ctors
/ .dtors
Bagian keduanya hanya tabel dengan pointer ke fungsi, dan "pemanggil" adalah loop yang disediakan sistem yang memanggil setiap fungsi secara tidak langsung. Yaitu loop-caller bisa arsitektur spesifik, tetapi karena itu bagian dari sistem (jika ada sama sekali yaitu) tidak masalah.
Cuplikan berikut menambahkan pointer fungsi baru ke .ctors
array fungsi, terutama dengan cara yang sama __attribute__((constructor))
(metode dapat hidup berdampingan dengan __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;
Satu juga dapat menambahkan fungsi pointer ke bagian yang diciptakan sendiri sepenuhnya berbeda. Skrip linker yang dimodifikasi dan fungsi tambahan yang meniru loader .ctors
/ .dtors
loop diperlukan dalam kasus tersebut. Tetapi dengan itu orang dapat mencapai kontrol yang lebih baik atas urutan eksekusi, menambahkan argumen dan mengembalikan eta penanganan kode (Dalam proyek C ++ misalnya, akan berguna jika membutuhkan sesuatu yang berjalan sebelum atau setelah konstruktor global).
Saya lebih suka __attribute__((constructor))/((destructor))
jika memungkinkan, ini adalah solusi sederhana dan elegan bahkan rasanya seperti curang. Untuk coders bare-metal seperti saya, ini tidak selalu menjadi pilihan.
Beberapa referensi bagus di buku Linker & loader .
#define __attribute__(x)
). Jika Anda memiliki beberapa atribut, misalnya,__attribute__((noreturn, weak))
akan sulit untuk "makro keluar" jika hanya ada satu set tanda kurung.