.init/ .finikullanımdan kaldırılmadı. Hala ELF standardının bir parçası ve sonsuza kadar olacağını söyleyebilirim. Kodu .init/ .finikod yüklenir zaman boş / yükleyici / çalışma bağlayıcı tarafından çalıştırılır. Yani her bir ELF yükü (örneğin, paylaşılan bir kütüphane) kodu .initçalıştırılacaktır. Hala aynı şeyi başarmak için bu mekanizmayı kullanmak hala mümkündür __attribute__((constructor))/((destructor)). Eski okul ama bazı faydaları var.
.ctors/ .dtorsMekanizması örneğin system-rtl / loader / linker-script desteği gerektirir. Bu, tüm sistemlerde mevcut olmaktan çok uzaktır, örneğin kodun çıplak metal üzerinde yürütüldüğü derin gömülü sistemler. Yani __attribute__((constructor))/((destructor)), GCC tarafından desteklense bile , onu düzenlemek için bağlayıcıya ve çalıştırmak için yükleyiciye (veya bazı durumlarda önyükleme koduna) bağlı olacağı kesin değildir. Kullanım için .init/ .finiyerine, kolay yolu bağlayıcı bayraklarını kullanmaktır: -init & -fini (GCC komut satırından yani sözdizimi olacaktır -Wl -init my_init -fini my_fini).
Her iki yöntemi de destekleyen sistemde, olası bir fayda, kodun .initönce çalıştırılması .ctorsve kodun .finisonra çalıştırılmasıdır .dtors. Sipariş alakalı ise, başlangıç / çıkış işlevlerini ayırt etmenin en az bir ham ama kolay yoludur.
En büyük dezavantaj, her yüklenebilir modül başına birden fazla _initve bir _finiişleve kolayca sahip olamamanız ve muhtemelen kodu .somotive edilenden daha fazla parçalamanız gerekmesidir. Bir diğeri, yukarıda açıklanan bağlayıcı yöntemini kullanırken, orijinal _init ve _finivarsayılan işlevlerin (tarafından sağlanan crti.o) değiştirilmesidir. Burası genellikle her türlü başlatma işleminin gerçekleştiği yerdir (Linux'ta bu, global değişken atamanın başlatıldığı yerdir). Burada anlatılan bir yol
Yukarıdaki bağlantıda _init(), hala yerinde olduğu için orijinaline basamaklı bir şeye ihtiyaç duyulmadığına dikkat edin. callMontaj ancak çizgi içi x86 anımsatıcı ve montaj (örneğin ARM gibi) birçok başka mimariler için tamamen farklı olmazdı bir işlevi çağırmak olduğunu. Yani kod şeffaf değil.
.init/ .finive .ctors/ .detorsmekanizmaları benzerdir, ancak tam olarak değildir. Kod .init/ .finiishal "olduğu gibi". Yani .init/ içinde birkaç fonksiyona sahip olabilirsiniz .fini, ancak AFAIK'i, birçok küçük .sodosyada kodu bozmadan tamamen şeffaf olarak saf C'ye koymak onları sözdizimsel olarak zordur .
.ctors/ .dtorsFarklı bir şekilde düzenlenir .init/ ' .fini. .ctors/ .dtorsbölümlerinin her ikisi de yalnızca işlevlere işaret eden tablolardır ve "arayan" her işlevi dolaylı olarak çağıran sistem tarafından sağlanan bir döngüdür. Yani döngü arayan mimariye özgü olabilir, ancak sistemin bir parçası olduğu için (eğer varsa) önemli değil.
Aşağıdaki snippet, .ctorsişlev dizisine temelde olduğu gibi yeni işlev işaretçileri ekler __attribute__((constructor))(yöntem birlikte bulunabilir) __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;
Tamamen farklı bir kendi icat ettiği bölüme fonksiyon göstergeleri de eklenebilir. Bu durumda değiştirilmiş bir bağlayıcı komut dosyası ve yükleyiciyi .ctors/ .dtorsdöngüyü taklit eden ek bir işlev gereklidir. Ancak bununla birlikte, yürütme sırası üzerinde daha iyi bir kontrol elde edilebilir, bağımsız değişken ve dönüş kodu işleme eta eklenebilir (Örneğin, bir C ++ projesinde, global kuruculardan önce veya sonra çalışan bir şeye ihtiyaç duymanız faydalı olacaktır).
__attribute__((constructor))/((destructor))Mümkün olduğunca tercih ederim , hile gibi hissetse bile basit ve zarif bir çözüm. Benim gibi çıplak metal kodlayıcılar için, bu her zaman bir seçenek değildir.
Bağlayıcılar ve yükleyiciler kitabında bazı iyi referans .
#define __attribute__(x)) kolayca yapılabilir . Birden fazla özelliğiniz varsa, örneğin,__attribute__((noreturn, weak))yalnızca bir köşeli parantez kümesi olsaydı "makro çıkışı" zor olurdu.