.init/ .finiไม่เลิกใช้ มันยังคงเป็นส่วนหนึ่งของมาตรฐานเอลฟ์และฉันกล้าพูดว่ามันจะเป็นตลอดไป โค้ดใน.init/ .finiถูกรันโดยโหลดเดอร์ / รันไทม์ลิงเกอร์เมื่อโค้ดถูกโหลด / ไม่โหลด เช่นในแต่ละโหลดเอลฟ์ (ตัวอย่างเช่นไลบรารีที่แชร์) .initจะถูกเรียกใช้ ยังคงเป็นไปได้ที่จะใช้กลไกนั้นเพื่อให้บรรลุในสิ่งเดียวกันกับ __attribute__((constructor))/((destructor))ก็ยังคงเป็นไปได้ที่จะใช้กลไกที่ว่าเพื่อให้บรรลุเกี่ยวกับสิ่งเดียวกันเช่นเดียวกับมันเป็นโรงเรียนเก่า แต่ก็มีประโยชน์บางอย่าง
.ctors.dtorsกลไก/ ตัวอย่างเช่นต้องการการสนับสนุนโดย system-rtl / loader / linker-script สิ่งนี้ยังห่างไกลจากความแน่นอนที่จะมีอยู่ในทุกระบบเช่นระบบฝังตัวที่ลึกซึ่งโค้ดทำงานบนโลหะเปลือย เช่นแม้ว่า__attribute__((constructor))/((destructor))GCC จะได้รับการสนับสนุน แต่ก็ไม่แน่ใจว่ามันจะทำงานได้หรือไม่ขึ้นอยู่กับตัวเชื่อมโยงเพื่อจัดระเบียบและโหลดเดอร์ (หรือในบางกรณีรหัสบูต) เพื่อเรียกใช้ หากต้องการใช้.init/ .finiแทนวิธีที่ง่ายที่สุดคือการใช้แฟล็กลิงเกอร์: -init & -fini (เช่นจากบรรทัดคำสั่ง GCC ไวยากรณ์จะเป็น-Wl -init my_init -fini my_fini )
ในระบบที่รองรับทั้งสองวิธีประโยชน์ที่เป็นไปได้ประการหนึ่งคือรหัส.initนั้นทำงานก่อนหน้า.ctorsและรหัส.finiหลังจากนั้น.dtorsนั้น ถ้าคำสั่งซื้อนั้นเกี่ยวข้องอย่างน้อยหนึ่งน้ำมันดิบ แต่เป็นวิธีที่ง่ายในการแยกความแตกต่างระหว่างฟังก์ชั่นเริ่มต้น / ออก
ข้อเสียเปรียบที่สำคัญคือคุณไม่สามารถมีได้มากกว่า_initหนึ่ง_finiฟังก์ชันในแต่ละโมดูลที่สามารถโหลดได้ง่ายและอาจจะต้องมีการแยกส่วนของรหัส.soมากกว่าแรงจูงใจ อีกวิธีหนึ่งคือเมื่อใช้วิธีการเชื่อมโยงที่อธิบายไว้ข้างต้นหนึ่งแทนที่ _init เดิมและ_finiฟังก์ชั่นเริ่มต้น (จัดทำโดยcrti.o) นี่คือที่ทุกประเภทของการเริ่มต้นมักจะเกิดขึ้น (บน Linux นี่คือที่การกำหนดตัวแปรทั่วโลกจะเริ่มต้นได้) วิธีที่อธิบายไว้ที่นี่
สังเกตุในลิงค์ด้านบนว่า_init()ไม่จำเป็นต้องมีการเรียงซ้อนกันไปตามต้นฉบับเนื่องจากยังคงใช้งานได้ callในแบบอินไลน์การชุมนุม แต่เป็น 86-ช่วยในการจำและเรียกฟังก์ชั่นจากการชุมนุมจะมีลักษณะที่แตกต่างอย่างสิ้นเชิงสำหรับสถาปัตยกรรมอื่น ๆ อีกมากมาย (เช่น ARM ตัวอย่าง) รหัส Ie ไม่โปร่งใส
.init/ .finiและ.ctors/ .detorsกลไกมีความคล้ายคลึงกัน แต่ไม่มาก รหัสใน.init / .finiรัน "ตามสภาพ" นั่นคือคุณสามารถมีฟังก์ชั่นได้หลายอย่างใน.init/ .finiแต่มันเป็นเรื่องยาก AFAIK ที่จะทำให้พวกเขาอยู่ที่นั่นอย่างโปร่งใส syntactically บริสุทธิ์ C โดยไม่ทำลายรหัสใน.soไฟล์เล็ก ๆมากมาย
.ctors/.dtorsมีการจัดที่แตกต่างกว่า/.init /.fini.ctors.dtors section เป็นเพียงตารางที่มีตัวชี้ไปยังฟังก์ชั่นและ "ตัวเรียก" เป็นลูปที่ระบบจัดเตรียมไว้ให้ซึ่งจะเรียกแต่ละฟังก์ชั่นทางอ้อม เช่น loop-caller นั้นเป็นสถาปัตยกรรมที่เฉพาะเจาะจง แต่เนื่องจากเป็นส่วนหนึ่งของระบบ (หากมีอยู่นั่นคือทั้งหมด) มันไม่สำคัญ
ตัวอย่างต่อไปนี้เพิ่มพอยน์เตอร์ฟังก์ชั่นใหม่ให้กับ.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;
หนึ่งยังสามารถเพิ่มตัวชี้ฟังก์ชั่นไปยังส่วนที่คิดค้นขึ้นเองอย่างสมบูรณ์ สคริปต์ลิงเกอร์ที่ถูกแก้ไขและฟังก์ชั่นเพิ่มเติมที่เลียนแบบตัวโหลด.ctors/ .dtorsวนซ้ำนั้นจำเป็นในกรณีดังกล่าว แต่ด้วยสิ่งนี้เราสามารถควบคุมลำดับการดำเนินการได้ดีขึ้นเพิ่มการโต้แย้งและการจัดการโค้ดส่งคืน (ในโครงการ C ++ ตัวอย่างเช่นมันจะมีประโยชน์หากต้องการบางสิ่งที่ทำงานก่อนหรือหลังตัวสร้างส่วนกลาง)
ฉันต้องการ __attribute__((constructor))/((destructor))ที่เป็นไปได้มันเป็นทางออกที่ง่ายและสง่างามแม้ว่ามันจะรู้สึกเหมือนโกง สำหรับตัวแปลงสัญญาณโลหะเปลือยอย่างตัวฉันนี่ไม่ใช่ตัวเลือกเสมอไป
บางอ้างอิงที่ดีในหนังสือเล่มLinkers และรถตัก
#define __attribute__(x)) หากคุณมีคุณสมบัติหลายอย่างเช่น__attribute__((noreturn, weak))มันยากที่จะ "แมโครออก" หากมีวงเล็บชุดเดียว