반응형


`__attribute__((constructor))`를 사용한 간단한 예제를 보여드릴게요.

## 개념 설명

`__attribute__((constructor))`는 GCC/Clang 확장으로, **shared library가 로드될 때 자동으로 실행**되는 함수를 지정합니다.

- `dlopen()` 또는 링크 시 로드 시점에 호출
- `main()` 보다 먼저 실행
- 반대로 `__attribute__((destructor))`는 unload 시 실행

---

## 파일 구조

```
mylib/
├── mylib.cpp       # shared library
├── mylib.h
└── main.cpp        # 사용하는 쪽
```

---

## mylib.h

```cpp
#pragma once

#ifdef __cplusplus
extern "C" {
#endif

void mylib_hello();

#ifdef __cplusplus
}
#endif
```

---

## mylib.cpp

```cpp
#include <stdio.h>
#include "mylib.h"

// 라이브러리 로드 시 자동 실행
__attribute__((constructor))
static void mylib_init() {
    printf("[mylib] constructor: library loaded!\n");
}

// 라이브러리 언로드 시 자동 실행
__attribute__((destructor))
static void mylib_fini() {
    printf("[mylib] destructor: library unloaded!\n");
}

void mylib_hello() {
    printf("[mylib] hello() called\n");
}
```

---

## main.cpp (정적 링크 방식)

```cpp
#include <stdio.h>
#include "mylib.h"

int main() {
    printf("[main] main() start\n");
    mylib_hello();
    printf("[main] main() end\n");
    return 0;
}
```

---

## main_dlopen.cpp (동적 로드 방식)

`dlopen()`으로 런타임에 명시적으로 로드하는 경우:

```cpp
#include <stdio.h>
#include <dlfcn.h>

int main() {
    printf("[main] before dlopen\n");

    // 라이브러리 로드 → 이 시점에 constructor 호출됨
    void* handle = dlopen("./libmylib.so", RTLD_LAZY);
    if (!handle) {
        fprintf(stderr, "dlopen error: %s\n", dlerror());
        return 1;
    }

    printf("[main] after dlopen\n");

    // 함수 포인터 획득
    typedef void (*hello_fn)();
    hello_fn fn = (hello_fn)dlsym(handle, "mylib_hello");
    if (fn) fn();

    printf("[main] before dlclose\n");

    // 라이브러리 언로드 → destructor 호출됨
    dlclose(handle);

    printf("[main] after dlclose\n");
    return 0;
}
```

---

## 빌드 & 실행

```bash
# shared library 빌드
g++ -shared -fPIC -o libmylib.so mylib.cpp

# ── 방법 1: 정적 링크 ──
g++ -o main_static main.cpp -L. -lmylib -Wl,-rpath,.
./main_static

# ── 방법 2: dlopen ──
g++ -o main_dl main_dlopen.cpp -ldl
./main_dl
```

---

## 예상 출력

**정적 링크:**
```
[mylib] constructor: library loaded!   ← main() 이전
[main] main() start
[mylib] hello() called
[main] main() end
[mylib] destructor: library unloaded! ← main() 이후
```

**dlopen:**
```
[main] before dlopen
[mylib] constructor: library loaded!   ← dlopen() 시점
[main] after dlopen
[mylib] hello() called
[main] before dlclose
[mylib] destructor: library unloaded! ← dlclose() 시점
```

---

## 우선순위 지정 (여러 constructor가 있을 때)

```cpp
__attribute__((constructor(101))) void init_first()  { /* 먼저 실행 */ }
__attribute__((constructor(102))) void init_second() { /* 나중 실행 */ }
```

숫자가 작을수록 먼저 실행됩니다. `0~100`은 시스템 예약이므로 `101` 이상 사용을 권장합니다.

반응형