생성자, 소멸자 low-level
소멸자
.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 |
secure-execution mode (0) | 2017.01.11 |
ltrace & strace (0) | 2017.01.07 |
/proc/<pid>/maps (2) | 2017.01.04 |