__attribute__((컨스트럭터))는 정확히 어떻게 동작합니까?
그것이 일을 꾸미는 것으로 되어 있는 것은 꽤 분명해 보인다.
- 정확히 언제 운행되죠?
- 왜 괄호가 두 개야?
- 이는?
__attribute__
?? ? 구문구?? - 이거 C? C++로 되나?
- 동작하는 기능은 정적이어야 합니까?
- 제?는 언제?
__attribute__((destructor))
목표 C의 예:
__attribute__((constructor))
static void initialize_navigationBarImages() {
navigationBarImages = [[NSMutableDictionary alloc] init];
}
__attribute__((destructor))
static void destroy_navigationBarImages() {
[navigationBarImages release];
}
- 공유 라이브러리가 로드될 때(일반적으로 프로그램 시작 시) 실행됩니다.
- 이것이 모든 GCC Atribute입니다.아마 함수 호출과 구별하기 위해서입니다.
- GCC 고유의 구문.
- 네, 이것은 C와 C++로 동작합니다.
- 아니요, 함수는 정적일 필요는 없습니다.
- 디스트럭터는 공유 라이브러리가 언로드될 때 실행됩니다(일반적으로 프로그램 종료 시).
따라서 컨스트럭터와 디스트럭터는 각각 컨스트럭터와 디스트럭터 속성으로 마크된 함수에 대한 참조를 포함하는 특별한 섹션(.ctors 및 .dtors on ELF)을 공유 오브젝트 파일에 포함합니다.라이브러리가 로드/다운로드되면 다이내믹 로더 프로그램(ld.so 또는 somesuch)은 이러한 섹션이 존재하는지 확인하고, 존재한다면 참조되는 함수를 호출합니다.
생각해 보면, 통상의 스태틱링커에는 같은 매직이 있기 때문에, 유저가 스태틱링크를 선택하든 다이나믹링크를 선택하든 관계없이, 기동시 또는 셧다운시에 같은 코드가 실행됩니다.
, 이 내용을 잘 알 수 .constructor
★★★★★★★★★★★★★★★★★」destructor
Attribute는 ELF를 사용합니다.여기에 제공된 정보를 요약한 후, 나는 약간의 추가 정보를 취합하여 (위의 마이클 앰브러스로부터 섹션의 예를 빌려) 개념을 설명하고 학습에 도움이 되는 예를 만들었다.이러한 결과는 샘플 출처에 따라 아래에 제시되어 있습니다.
스레드에서 와 같이, 「」는, 「」입니다.constructor
★★★★★★★★★★★★★★★★★」destructor
는 Attribute에 합니다..ctors
★★★★★★★★★★★★★★★★★」.dtors
츠미야세 방법 중 할 수 (1) 이 중 합니다. (1) 이 되다.section
(2성 ( (2)constructor
★★★★★★★★★★★★★★★★★」destructor
(Ambrus 응답 링크 참조) 또는 (3) 인라인 어셈블리콜을 사용합니다.
「 」의 constructor
★★★★★★★★★★★★★★★★★」destructor
Atribut의 로 할당할 수 있습니다.main()
호출되거나 반환된 후에 호출됩니다.priority 값이 낮을수록 실행 priority가 높아집니다(priority가 낮아지면 main()보다 priority가 높아집니다).priority 값은 컴파일러가 구현을 위해 0 ~100의 priority 값을 예약하는 값보다 커야100
합니다.aconstructor
★★★★★★★★★★★★★★★★★」destructor
priority " 먼저 됩니다.constructor
★★★★★★★★★★★★★★★★★」destructor
prioritypriority를 하지 않고 합니다.
속성 하면 'section'에도 있습니다..init
★★★★★★★★★★★★★★★★★」.fini
ELF 코드 섹션은 컨스트럭터 전 및 디스트럭터 후에 각각 실행됩니다. .init
섹션은 함수 참조보다 먼저 실행됩니다(통상대로).
아래의 예에서 각 항목을 설명하려고 했습니다.
#include <stdio.h>
#include <stdlib.h>
/* test function utilizing attribute 'section' ".ctors"/".dtors"
to create constuctors/destructors without assigned priority.
(provided by Michael Ambrus in earlier answer)
*/
#define SECTION( S ) __attribute__ ((section ( S )))
void test (void) {
printf("\n\ttest() utilizing -- (.section .ctors/.dtors) w/o priority\n");
}
void (*funcptr1)(void) SECTION(".ctors") =test;
void (*funcptr2)(void) SECTION(".ctors") =test;
void (*funcptr3)(void) SECTION(".dtors") =test;
/* functions constructX, destructX use attributes 'constructor' and
'destructor' to create prioritized entries in the .ctors, .dtors
ELF sections, respectively.
NOTE: priorities 0-100 are reserved
*/
void construct1 () __attribute__ ((constructor (101)));
void construct2 () __attribute__ ((constructor (102)));
void destruct1 () __attribute__ ((destructor (101)));
void destruct2 () __attribute__ ((destructor (102)));
/* init_some_function() - called by elf_init()
*/
int init_some_function () {
printf ("\n init_some_function() called by elf_init()\n");
return 1;
}
/* elf_init uses inline-assembly to place itself in the ELF .init section.
*/
int elf_init (void)
{
__asm__ (".section .init \n call elf_init \n .section .text\n");
if(!init_some_function ())
{
exit (1);
}
printf ("\n elf_init() -- (.section .init)\n");
return 1;
}
/*
function definitions for constructX and destructX
*/
void construct1 () {
printf ("\n construct1() constructor -- (.section .ctors) priority 101\n");
}
void construct2 () {
printf ("\n construct2() constructor -- (.section .ctors) priority 102\n");
}
void destruct1 () {
printf ("\n destruct1() destructor -- (.section .dtors) priority 101\n\n");
}
void destruct2 () {
printf ("\n destruct2() destructor -- (.section .dtors) priority 102\n");
}
/* main makes no function call to any of the functions declared above
*/
int
main (int argc, char *argv[]) {
printf ("\n\t [ main body of program ]\n");
return 0;
}
출력:
init_some_function() called by elf_init()
elf_init() -- (.section .init)
construct1() constructor -- (.section .ctors) priority 101
construct2() constructor -- (.section .ctors) priority 102
test() utilizing -- (.section .ctors/.dtors) w/o priority
test() utilizing -- (.section .ctors/.dtors) w/o priority
[ main body of program ]
test() utilizing -- (.section .ctors/.dtors) w/o priority
destruct2() destructor -- (.section .dtors) priority 102
destruct1() destructor -- (.section .dtors) priority 101
이 예는 컨스트럭터/파괴자의 동작을 강화하는 데 도움이 되었습니다.다른 사람에게도 도움이 될 것입니다.
.init
/.fini
권장되지 않습니다.그것은 여전히 ELF 규격의 일부이며 나는 감히 영원히 될 것이라고 말할 수 있다.★★★★★★★★★★★★★★★★의 코드.init
/.fini
있는 각 라이브러리) , 즉ELF 코드(예: 공유 라이브러리)에 「」의 「」( 「」)에 대해서, 「」의 「」/「」가 됩니다..init
실행됩니다.이 메커니즘을 사용하여 다음과 같은 작업을 수행할 수 있습니다.__attribute__((constructor))/((destructor))
구식이지만 장점도 있습니다.
.ctors
/.dtors
예를 들어 system-rtl/syslog/linker-script에 의한 지원이 필요합니다.예를 들어 코드가 베어메탈에서 실행되는 딥 임베디드 시스템 등 모든 시스템에서 사용할 수 있는 것은 아닙니다.즉,__attribute__((constructor))/((destructor))
는 GCC에 의해 지원되고 있기 때문에 링커와 로더(또는 경우에 따라서는 부트 코드)에 의해 동작할지는 확실하지 않습니다.사용방법.init
/.fini
대신 가장 쉬운 방법은 링커플래그 -init & -fini(GCC 명령줄에서 구문은-Wl -init my_init -fini my_fini
).
두 가지 방법을 모두 지원하는 시스템에서 가능한 한 가지 이점은 코드 입력입니다..init
에 앞서 실행되다.ctors
및 코드인.fini
끝나고.dtors
순서와 관련된 경우, 이것은 적어도 init/exit 함수를 구별하기 위한 대략적인 방법 중 하나입니다.
가장 큰 단점은 하나 이상을 쉽게 가질 수 없다는 것이다._init
그리고 하나_fini
로딩 가능한 각 모듈별로 기능하며, 아마도 더 많은 코드를 fragment화해야 할 것입니다..so
동기부여보다.또 하나는 위에서 설명한 링커 방식을 사용할 경우 원본 _init 및_fini
디폴트 기능(제공)crti.o
여기서 보통 모든 종류의 초기화가 이루어집니다(Linux에서는 글로벌 변수 할당이 초기화됩니다).이를 위한 방법은 여기에 설명되어 있습니다.
위의 링크에서 원래 링크로의 캐스케이딩에 주의해 주세요._init()
필요없다고 생각합니다.그call
단, 인라인어셈블리에서는 x86-니모닉이며 어셈블리에서 함수를 호출하는 것은 다른 많은 아키텍처(예를 들어 ARM 등)에서는 완전히 다르게 보입니다.즉, 코드가 투명하지 않습니다.
.init
/.fini
그리고..ctors
/.detors
메커니즘은 비슷하지만 완전히 비슷하지는 않습니다.코드 입력.init
/.fini
"있는 그대로" 실행됩니다.즉, 다음과 같은 몇 가지 기능을 사용할 수 있습니다..init
/.fini
단, AFAIK는 구문적으로 코드를 분할하지 않고 완전히 투명하게 C로 배치하는 것이 어렵습니다..so
파일을 표시합니다.
.ctors
/.dtors
와는 다르게 조직되어 있다.init
/.fini
..ctors
/.dtors
섹션은 둘 다 함수에 대한 포인터가 있는 테이블일 뿐이고, "sublic"은 각 함수를 간접적으로 호출하는 시스템에서 제공하는 루프입니다.즉, 루프 호출기는 아키텍처에 따라 다를 수 있지만, 시스템의 일부이기 때문에(존재하는 경우) 문제가 되지 않습니다.
다음 스니펫은 새로운 함수 포인터를 에 추가합니다..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 & loaders"라는 책에 좋은 참고 자료가 있습니다.
여기 이 편리하지만 보기 흉한 구조를 어떻게, 왜, 언제 사용하는지에 대한 구체적인 예가 있습니다.
Xcode는 "global" "user default" 를 사용하여 다음 중 하나를 결정합니다.XCTestObserver
좌초된 콘솔로 마음을 터트리고 있습니다.
이 예에서는...내가 이 psuedo-라이브러리를 암묵적으로 장전할 때... libdemure.a
테스트 대상의 깃발을 통해...
OTHER_LDFLAGS = -ldemure
저는...
부하중(즉, 언제)
XCTest
테스트 번들을 로드합니다). "기본값"을 덮어씁니다.XCTest
'수업' 수업...(을 통해)constructor
기능) PS: 제가 알기로는..여기서 행해진 모든 것은 우리 반 안에서 같은 효과를 낼 수 있다'고 말했다.+ (void) load { ... }
방법.테스트 실행...이 경우, 로그의 무의미한 장황함이 적어집니다(요청 시 통지).
'글로벌' 반환
XCTestObserver
깨끗한 상태로..다른 사람을 망치지 않도록XCTest
시류에 편승하지 않은 달리기(일명 링크)libdemure.a
)이러한경우는역대적으로이러한경우가있었을것같습니다.dealloc
하지만 그 늙은 여자를 건드리기 시작할 생각은 없어
그래서...
#define USER_DEFS NSUserDefaults.standardUserDefaults
@interface DemureTestObserver : XCTestObserver @end
@implementation DemureTestObserver
__attribute__((constructor)) static void hijack_observer() {
/*! here I totally hijack the default logging, but you CAN
use multiple observers, just CSV them,
i.e. "@"DemureTestObserverm,XCTestLog"
*/
[USER_DEFS setObject:@"DemureTestObserver"
forKey:@"XCTestObserverClass"];
[USER_DEFS synchronize];
}
__attribute__((destructor)) static void reset_observer() {
// Clean up, and it's as if we had never been here.
[USER_DEFS setObject:@"XCTestLog"
forKey:@"XCTestObserverClass"];
[USER_DEFS synchronize];
}
...
@end
링커 플래그가 없으면...(패션경찰들이 쿠퍼티노에게 보복을 요구하고 있지만 애플의 디폴트(채무불이행)는 여기서 우세하다.)
와 함께-ldemure.a
링커 플래그...(이해할 수 있는 결과, 헐떡임)"고맙습니다.constructor
/destructor
"... 군중의 환호성")
여기 또 다른 구체적인 예가 있다.공유 라이브러리용입니다.공유 라이브러리의 주요 기능은 스마트 카드 리더와 통신하는 것이지만 UDP를 통해 런타임에 '구성 정보'를 수신할 수도 있습니다. UDP는 초기 시 반드시 시작해야 하는 스레드에 의해 처리됩니다.
__attribute__((constructor)) static void startUdpReceiveThread (void) {
pthread_create( &tid_udpthread, NULL, __feigh_udp_receive_loop, NULL );
return;
}
도서관은 C로 쓰여져 있었다.
언급URL : https://stackoverflow.com/questions/2053029/how-exactly-does-attribute-constructor-work
'programing' 카테고리의 다른 글
값이 null인 경우 직렬화 중에 필드를 무시하도록 잭슨에게 지시하려면 어떻게 해야 합니까? (0) | 2022.08.02 |
---|---|
객체 지향 C++ 코드용 C 래퍼 API 개발 (0) | 2022.08.02 |
Vue 2용 Vue 3 텔레포트 (0) | 2022.08.01 |
조건부로 송신 버튼을 무효로 하는 방법을 설명합니다. (0) | 2022.08.01 |
Java Void 참조 유형에 사용? (0) | 2022.08.01 |