ELF 란 용어를 많이 들어보셨을텐데요, ELF는 Executable and Linking Format의 약어입니다. UNIX / LINUX 기반에서 사용되는 실행 및 링킹 파일 포맷입니다. 지난 글에 이어 이번 글에서는 Symbol Resolution 에 대해 알아보겠습니다.
[이전 글]
2018/08/27 - [Linux/Debugging & Testing] - [ELF] ELF Header
2018/08/29 - [Linux/Debugging & Testing] - [ELF] Segment와 Program Header
2018/09/07 - [Linux/Debugging & Testing] - [ELF] Sections and the Section header table
2018/09/09 - [Linux/Debugging & Testing] - [ELF] Stripping an ELF object
-
이번 글은 대부분 예제로 글을 진행할 예정입니다. 좀 더 이해하기 쉽게 하고자 코드를 이용한 방법을 말씀드립니다. 먼저 예제가 어떤 구조를 띄고있는지 보시죠.
-
-
-
resm 이란 실행파일이 libres.so와 libres2.so를 링킹하고 있는 구조입니다. 그럼 각 소스코드를 살펴보시죠.
-
소스코드의 순서는 좌측으로부터 res2.c, res.c, resm.c 입니다.
resm.c에 프로그램의 시작인 main()함수가 있네요. res.c , res2.c 는 공유 라이브러리로 컴파일되고 최종적으로 resm이 linking하도록 만듭니다. 위와 같이 코드를 작성 후 함께 진행해보실 분들은 함께해주세요. 공유라이브러리 만드는 법을 모르시는 분들은 인터넷에 검색하면 많은 내용들이 나오고 있습니다. 여기서는 따로 다루지 않을 생각이니 별도의 학습 부탁드립니다.
그럼 글만 보시는 분들은 위의 그림에서 어떻게 호출이 될까요? 보다보니 function1()과 function2()가 동일한 이름의 함수와 globInt1, globInt2란 전역변수가 resm.c와 res1.c 모두 존재하네요. 흠, res2.c에서 globInt1, globInt2를 모두 전역변수 참조하여 선언하고 있습니다.. 복잡하네요, 그럼 코드만 보고 결과로 어떤 출력이 나올지 고민해보세요.
main()함수 부터 살펴보면 아래 처럼 호출을 할 것 같네요. function3()을 main에서 호출하면서 res.c에 존재하는 function3이 호출될 것 같습니다. 그 후 function3()에서 function2()를 호출하네요. 그런데 function2()가 두개 존재합니다..? 흠 어떤 파일에 위치한 function2()가 호출될까요?
맞는지 틀렸는지는 중요하지 않습니다. 생각해보고 왜 그럴까 분석해 보는 행동, 노력 자체가 중요한 것이닌깐요! 모두 고민해보셨나요? 그럼 결과를 한번 보시죠. 심볼 정보와 함께 결과는 아래와 같습니다. 심볼정보만 먼저 살펴보시면 GlobInt와 function과 관련해서 동일한 이름의 Symbol이 각각 존재함을 알 수 있습니다. linking한 후 실행하게 되면 어떤결과가 나타날까요?
위의 노란박스를 살펴보면 res.c에서 function3()가 같은 파일내에 존재하는 function2()를 호출하지 않고, resm에 존재하는 function2()를 호출하고 있습니다.!!!!! 왜 라이브러리 내에 존재하는 함수가 아닌 다른 곳에 위치한 함수를 호출하게 되는걸까요? 라이브러리 개발자의 의도는 분명 자신의 함수가 호출되길 바랬을 것 같습니다. 우연치 않게 함수의 이름이 겹쳐버린 것 같은데 위와 같은 문제가 발생하게 됩니다.
function2() 함수 호출 이후의 globInt2 변수 참조하여 출력하는 printf()함수에서도.. resm.c에 선언한 전역변수를 참조하고 있습니다. 원치 않는 결과네요. 그리고 다음엔 function6()이 호출되겠네요.
위에서 언급한 결과 그림에서 보면 function6()에서도 참조하는 globInt2 전역변수를 res.c가 아닌 resm.c에 선언된 전역변수를 참조하고 있네요. 이런 의도치 않은 결과로 인해 문제가 발생하게 되면 문제 해결을 위한 디버깅도 굉장히 힘들어 집니다.
공유라이브러리 개발자들은 이런 문제를 사전에 방지하고자 할 것 입니다. 이러한 문제들은 간단하게 컴파일 옵션만으로도 문제를 해결할 수 있습니다. -Bsymbolic Option 입니다. 해당 옵션에 대한 설명은 아래 인용문으로 대체하겠습니다. 읽어보시면 쉽게 이해되실 거에요.!
- Bsymbolic Option
: When creating a shared library, bind references to global symbols to the definition within the shared library, if any. Normally, it is possible for a program linked against a shared library to override the definition within the shared library. This option is only meaningful on ELF platforms which support shared libraries.
그럼 해당 옵션을 적용 후 실행 결과를 살펴보겠습니다. 정상적으로 동작해야겠죠?
와 결과가 정상적으로 동작합니다. 휴 다행이네요. Symbol Resolution에 대한 개념을 직접적으로 설명은 드리지 않았지만 어느정도 이해를 하신 것 같습니다. 좀 더 복잡한 예제 및 테스트는 직접 해보시면서 확인해보시는 걸 추천드립니다.
감사합니다.
[참고자료]
Tool Interface Standards – Portable Formats Specification, Version 1.1
Self-Service Linux , MarkWilding and Dan Behman
How To Write Shared Libraries, Ulrich DrepperLinking, Randy Bryant and Dave O’Hallaron
https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
http://man7.org/linux/man-pages/man5/elf.5.html
http://egloos.zum.com/recipes/v/5010841
http://www.yolinux.com/TUTORIALS/LibraryArchives-StaticAndDynamic.html
https://en.wikipedia.org/wiki/Weak_symbol
'Linux > Debugging & Testing' 카테고리의 다른 글
[objdump] symbol table column 의미 (0) | 2019.08.21 |
---|---|
[ELF] Stripping an ELF object (0) | 2018.09.09 |
[ELF] Sections and the Section header table (0) | 2018.09.07 |
[ELF] Segment와 Program Header (1) | 2018.08.29 |
[ELF] ELF Header (0) | 2018.08.27 |