.init
/ .fini
더 이상 사용되지 않습니다. 그것은 여전히 ELF 표준의 일부이며 나는 그것이 영원히 될 것이라고 감히 말할 것입니다. 코드 입력 .init
/ .fini
로드는 코드가로드 / 언로드 될 때 로더 / 런타임 링커에 의해 실행됩니다. 즉, 각 ELF로드 (예 : 공유 라이브러리) 코드 .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 등) 많은 다른 아키텍처에 완전히 다를 것에서 함수를 호출합니다. 즉 코드가 투명하지 않습니다.
.init
/ .fini
와 .ctors
/ .detors
메카니즘은 비슷하지만 꽤 아닙니다. 에서 코드 .init
/ .fini
실행은 "있는 그대로". 즉 , .init
/에 여러 함수를 가질 수 .fini
있지만 AFAIK는 많은 작은 .so
파일의 코드를 손상시키지 않고 순수한 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;
완전히 다른 자체 발명 된 섹션에 함수 포인터를 추가 할 수도 있습니다. 이 경우 수정 된 링커 스크립트와 로더 .ctors
/ .dtors
루프를 모방 한 추가 기능 이 필요합니다. 그러나 그것으로 실행 순서를 더 잘 제어하고 인수 내 추가 및 코드 처리 에타를 추가 할 수 있습니다 (예를 들어 C ++ 프로젝트에서는 전역 생성자 전후에 무언가가 필요한 경우 유용합니다).
나는 __attribute__((constructor))/((destructor))
가능한 곳을 선호합니다 . 속임수처럼 느껴지는 간단하고 우아한 솔루션입니다. 나와 같은 베어 메탈 코더의 경우 항상 옵션이 아닙니다.
링커 & 로더 책에서 좋은 참고 자료 .
#define __attribute__(x)
) 할 수 있습니다. 예를 들어, 속성이 여러 개인__attribute__((noreturn, weak))
경우 괄호 집합이 하나만 있으면 "매크로 아웃"하기가 어렵습니다.