출처: http://www.technovelty.org/code/why-symbol-visibility-is-good.html
ELF 는 프로그램의 심볼을 관리하는데 있어서 두가지 방법이 있는데, 그중 하나가 symbol binding 이다.
symbol binding에는 크게 다음의 두가지 종류가 있다.
1. Global binding
2. Local binding
Global 바인딩은 현재 빌드되는 file 밖에까지의 visibility scope을 가지고 있다.(즉 외부참조가 가능하다고 할 수 있겠다)
Local 바인딩은 반대로 local scope(static)을 가지고 있다. 추가로 weak의 경우 global가 같으나 overriding이 가능하다고 볼 수 있겠다.
다음의 예를 보자.
sym.c
컴파일 해보면,(참고로 gcc -c는 컴파일/어셈블은 하되, 링크는 하지 말라는 소리이다)
$ gcc -o sym -c sym.c
$ readelf -s sym
Symbol table '.symtab' contains 11 entries:
Num: Value Size Type Bind Vis Ndx Name
...
5: 00000000 6 FUNC LOCAL DEFAULT 1 local
8: 00000006 6 FUNC GLOBAL DEFAULT 1 global
9: 0000000c 6 FUNC WEAK DEFAULT 1 weak
위에서 말한 바와 같이 LOCAL, GLOBAL, WEAK으로 각각 분류된 것을 볼 수 있다.
다음의 경우를 보자.
This is all well and good, but starts breaking down when you want to load many different modules and keep strict API's (such as, say, dynamic libraries!).
Consider that for two files to share a common function, the function must end up with a global visibility.
file1.c
file2.c
file1 & file2는 같은 함수를 공유 하는데, 보면 알겠지만 common의 경우 함수 내부에서만 사용되고 있어, 외부로 노출 할 필요가 없는 함수이다.
컴파일 후 내용을 보면 다음과 같다.
$ gcc -shared -fPIC -o libfile file1.c file2.c
$ readelf --syms libfile
Symbol table '.symtab' contains 55 entries:
Num: Value Size Type Bind Vis Ndx Name
...
48: 000005fc 6 FUNC GLOBAL DEFAULT 12 common
50: 00000604 11 FUNC GLOBAL DEFAULT 12 func
앞서 말했듯이, common의 경우 외부로 노출할 필요가 없음에도 GLOBAL 바인딩되어 있는 것을 볼 수 있다.
링킹도 잘 되고 동작성에 문제 없으나, 이렇게 외부로 노출 될 필요가 없는 경우를 대비해 ELF는 심볼에 대한 visibility를 제공한다.
이 visibility에는 default, protected, hidden 혹은 internal이 있다.
가장 안전한 방법으로는 전부 hidden으로 세팅하고(-fvisibility=hidden) 필요 시에,
file1.c
file2.c
$ gcc -fvisibility=hidden -shared -fPIC -o library file1.c file2.c
$ readelf --syms ./librarySymbol table '.symtab' contains 55 entries:
Num: Value Size Type Bind Vis Ndx Name
48: 000003cc 5 FUNC LOCAL HIDDEN 12 common
54: 000003d4 29 FUNC GLOBAL DEFAULT 12 func
이렇게 되면 dynamic loader는 더 이상 common쪽에 접근을 허용치 않는다.
참고로 이러한 방식은 퍼포먼스 향상에도 도움을 준다. 보통 심볼이 override됐을 때, dynamic loader가 function을 제대로 가리킬 수 있도록 컴파일러는 program lookup table(PLT)를 생성해야 한다. 그러나 위와 같이 한다면 PLT 생성을 생략 할 수 있다.
'프로그래밍 > C' 카테고리의 다른 글
c precedence table (0) | 2013.11.23 |
---|---|
typedef struct 안에서 스스로를 참조 할 때 주의점 (0) | 2013.11.19 |
typedef 와 static 을 동시에 사용 못하는 이유 (0) | 2012.11.24 |
인라인 어셈블리 (0) | 2012.09.25 |
include guard에 대해서 (0) | 2012.09.24 |