엄범


소멸자

.dtors

```
080495f4 d __DTOR_END__
```
소멸자로 프로그램이 종료되기 전에 여기에 명시되어 있는 주소(함수)가 호출된다.
`` __DTOR_END__``의 위치는 nm을 사용해도 좋고 readelf나 objdump로 확인해도 좋다.

.fini_array

gcc 4.7 이상 버전은 .ctors .dtors를 사용하지 않는 대신 다음을 사용한다.
```
  [18] .init_array       INIT_ARRAY       0000000000600e10  00000e10
       0000000000000008  0000000000000000  WA       0     0     8
  [19] .fini_array       FINI_ARRAY       0000000000600e18  00000e18
       0000000000000008  0000000000000000  WA       0     0     8

gdb-peda$ x/12x 0x600e18
   0x600e18:       0x00000000004004a0
gdb-peda$ x/4i 0x4004a0
   0x4004a0 <__do_global_dtors_aux>:
```
종료될 때 `` 0x600e18``위치에 있는 함수가 실행되므로, 저 위치의 값을 변경해주면 된다.

GCC __attribute__((constructor / destructor))

*nix에는 windows의 DllMain()에 대응되는 함수가 없다.

그러나 GCC의 `` constructor / destructor`` attribute로 비슷한 효과를 낼 수 있다.

`` constructor`` attribute가 붙은 함수는 프로그램이 시작되면서나, shared library가 loading되면서 바로 호출된다. (생성자)

`` destructor`` attribute가 붙은 함수는 프로그램이 종료되면서나, dlclose()되면서 바로 호출된다. (소멸자)

```c

__attribute__((constructor))

void constructorPrint(){

        printf("Ok, loaded\n\n");

}


void normalPrint(){

        printf("normalPrint\n\n");

}

```

<.so가 로딩되면서 constructorPrint()가 바로 호출된다.>


__attribute__((destructor)) 호출 시퀀스 bt

```
main에서 ret하면 __libc_start_main으로 나가게 된다.

#0  0xb7e1f72e in __libc_start_main (main=0x8048433 <main>, argc=1, argv=0xbffff184, 
    init=0x8048470 <__libc_csu_init>, fini=0x80484d0 <__libc_csu_fini>, rtld_fini=0xb7feb210 <_dl_fini>, 
    stack_end=0xbffff17c) at libc-start.c:289
#1  0x08048341 in _start ()

__libc_start_main에서
...
   0xb7e1f735 <+229>: call   0xb7e35c90 <__GI_exit>
-> ...
   0xb7e35cac <+28>: call   0xb7e35b70 <__run_exit_handlers>
-> ...
   0xb7e35c51 <+225>: call   *%edx (%edx = _dl_fini의 주소)
->

(gdb) disas
Dump of assembler code for function _dl_fini:
...
   0xb7feb3fa <+490>: mov    %edi,%ecx
   0xb7feb3fc <+492>: shr    $0x2,%eax
   0xb7feb3ff <+495>: test   %eax,%eax
   0xb7feb401 <+497>: je     0xb7feb41c <_dl_fini+524>
   0xb7feb403 <+499>: mov    %esi,-0x28(%ebp)
   0xb7feb406 <+502>: mov    %ecx,%edi
   0xb7feb408 <+504>: mov    %eax,%esi
   0xb7feb40a <+506>: lea    0x0(%esi),%esi
   0xb7feb410 <+512>: call   *-0x4(%edi,%esi,4)        //destructor 호출
...

(gdb) info reg edi
edi            0x8049f08 134520584

(gdb) x/4x 0x8049f08
0x8049f08: 0x080483d0 0x0804841b 0x00000000 0x00000001
* 08049f08 t __do_global_dtors_aux_fini_array_entry
  080483d0 t __do_global_dtors_aux
  0804841b T des
```
아무튼, 실제로 소멸자 호출이 이루어지는건 `` _dl_fini``이므로 뭔가 조정하고 싶다면 `` _dl_fini``에서 어디를 참조하는지를 알아보면 된다.



_init(), _fini()

``c void _init(), void _fini()``를 이용해 생성자, 소멸자를 정의할 수 있으나 요즘에는 안쓴다.
이를 사용하려면 컴파일 시 gcc에 -nostartfiles 옵션을 줘야 한다. 옵션을 안주고 그냥 컴파일 하려 하면 multiple definition 에러가 발생하는데, 이는 이미 _init과 _fini가 startfile에 정의되어 있기 때문이다.
-nostartfiles 옵션을 주면 아예 _init과 _fini 둘 다 정의되지 않기 때문에 한쪽만 사용하는 것은 불가능 하고 둘 다 정의해야 한다.
```
(gdb) disas
Dump of assembler code for function _dl_fini:
...
   0xb7feb410 <+512>: call   *-0x4(%edi,%esi,4)        //destructor 호출
   0xb7feb414 <+516>: sub    $0x1,%esi
   0xb7feb417 <+519>: jne    0xb7feb410 <_dl_fini+512>
   0xb7feb419 <+521>: mov    -0x28(%ebp),%esi
   0xb7feb41c <+524>: mov    0x54(%esi),%edx
   0xb7feb41f <+527>: test   %edx,%edx
   0xb7feb421 <+529>: je     0xb7feb42a <_dl_fini+538>
   0xb7feb423 <+531>: mov    (%esi),%eax
   0xb7feb425 <+533>: add    0x4(%edx),%eax
   0xb7feb428 <+536>: call   *%eax                      //_fini() 호출
...
```


'OS > LINUX & UNIX' 카테고리의 다른 글

[*-nix] 패키지 관련 및 OS update & upgrade  (0) 2017.04.13
[procfs_search.h] 메모리에서 특정 값의 주소 찾기  (0) 2017.03.08
생성자, 소멸자 low-level  (0) 2017.01.13
secure-execution mode  (0) 2017.01.11
ltrace & strace  (0) 2017.01.07
/proc/<pid>/maps  (2) 2017.01.04