강좌 & 팁
글 수 2,412
2011.08.06 21:46:51 (*.138.143.120)
44331
C 코딩을 하다 보면 특이한 함수를 볼때가 있다.
함수안에서 함수를 선언하는 경우이다.
이러한 경우에 해당 함수가 어떻게 생성되고 실행되는지 한번 살펴보고
trampoline 이라고 불리는 것이 무엇인지 알아본다.
간단한 함수예제와 수행 결과를 먼저 본다.
1 #include <stdio.h>
2 #include <string.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <fcntl.h>
6 #include <dirent.h>
7 #include <unistd.h>
8 #include <assert.h>
9 #include <sys/vfs.h>
10 #include <sys/wait.h>
11
12
13 void other(void (*funcp) () )
14 {
15 funcp();
16
17 printf("inner is %p\n", funcp);
18 }
19
20 int outer(void)
21 {
22 int a = 10;
23
24 void inner(void)
25 {
26 printf("outer's a is %d\n", a);
27 }
28
29 other(inner);
30
31 }
32
33
34 int main(int argc, char **argv)
35 {
36 outer();
37 }
38
39
main 함수는 outer() 를 호출하고 있다. 그런데 outer 함수안에는 inner 라는 함수가 선언되어 있다.
그리고 나서 other 함수에 inner 를 매개변수로하여 호출하는데,
other 라는 외부함수는 함수포인터를 인자로 받아서 단순히 수행해주기만 한다.
구조적으로 보면 main -> outer() -> other(inner) -> inner() 와 같은 연결 고리를 갖는다.
그런데 함수안에서 선언된 코드에서는 a 라는 변수의 값을 사용하고 있다.
최종단계에서 함수포인터를 매개변수로 실행시키는 단계에서 a 라는 변수의 위치는 inner 가 선언된 위치에서
특정할수 없는 문제가 생긴다. 실행하는 순간에서야 실제 a 변수의 위치를 알수 있다는 문제가 생긴다.
따라서 outer() 는 inner 함수를 스택에 생성하고 a 라는 변수에 접근하게 된다.
이렇게 생성된 코드를 트램펄린이라고 한다
그 이유는 탄력적으로 작은 기능을 수행하고 곧바로 제어를 넘기기 때문이다.
자, 그럼 수행 결과를 한번 보자.
[root@falinux ~]$ /mnt/nfs/sample/a.out
outer's a is 10
inner is 0xbe9b4ac0
예상한때로 inner 의 함수포인터는 스택에 있다.
한번 변형을 통해 검증을 해 보자.
만약 inner 함수에서 a 라는 변수를 사용하지 않는 경우는 어떻게 될까?
그 결과는 아래와 같다.
[root@falinux ~]$ /mnt/nfs/sample/a.out
hello
inner is 0x8410
보통 함수를 선언한 것과 같이 code 영역에 함수가 위치하게 된다.
C 언어의 ISO표준규격에는 함수내에 다른 함수를 정의할수 없도록 되어 있다.
이 기능은 GCC 의 독립적인 기능이다.
또한 스택에 코드를 생성하는 것은 보안상 문제를 내포하고 있다.
익히 유명한 스택오버플로우를 발생시켜 조작된 명령을 실행할수 있기 때문이다.
OS 에서는 스택에서 코드를 실행하는 것을 허용하지 않는데 GCC 에서는 스택에서 실행이 될수 있도록
해당 오브젝트에 대해서 특별한 섹션헤더를 붙이게 된다.
참조및 출처 : Binary Hacks - O'REILLY