프로그래밍/C2013. 8. 7. 21:36

출처: 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 ./library

Symbol 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 생성을 생략 할 수 있다.

Posted by code cat