shared library, strace, ldconfig, ldd, gcc, strings, od, nm, c++filt, readelf 본문

Programming

shared library, strace, ldconfig, ldd, gcc, strings, od, nm, c++filt, readelf

halatha 2009. 8. 17. 18:31
2009/08/17 - [Programming] - diff, find, md5sum, patch
2009/08/17 - [Programming] - find, grep, ctags, cscope, global


shared library compile
-fpic: small & fast, maybe restricted according to the platform
-fPIC: large & slow, platform independent
-shared: shared library 생성
-W1: 링커에 대한 option. 여기서는 shared library의 이름을 libhello.so.1으로 지정

shared library의 path를 찾지 못하는 경우 발생하는 error. 시스템 호출 추적기인 strace로 추적하면 shared library 적재 과정에서 발생하는 문제 원인을 쉽게 파악할 수 있음

runtime linker가 shared library를 탐색하기 위해 참조하는 환경 변수는 LD_LIBRARY_PATH. 그러므로,
1. LD_LIBRARY_PATH 설정
2. libhello.so.1.0.1이 libhello.so.1을 가리키도록 symbolic link 설정(compile 과정에서 soname을 붙였으므로)
아랫 부분은 compile할 때 shared library를 직접 명시하는 대신 -lxxxx로 줄여서 사용하는 방법
1. symbolic link 생성
2. -L option으로 link 과정에 필요한 library path를 넘겨줌

자신의 library를 system에 설치하려면
1. /usr/lib과 같은 표준 시스템 라이브러리 경로에 복사한 후 ldconfig 명령으로 cache를 갱신



shared library의 dependency 파악

objdump -p
-p: object file의 header information을 출력하는 option으로
1. objdump가 ELF file에서 dynamic section을 읽어 SONAME으로 지정한 library name을 출력
2. version 참조 영역을 읽어 필요한 version 정보 출력

readelf
-d: dynamic section을 출력

ldd



정의된 symbod이 없다는 link error가 발생하는 경우 특정 symbol이 들어있는 library를 찾고 싶은 경우가 있다. 여기서는 libhello.c와 흡사한 libhello2.c를 만들고 libhello2.so.1.0.1 file을 생성한 후, libhello.so.1.0.1과 libhello2.so.1.0.1을 대상으로 hello_로 시작하는 symbol을 찾아본다.

strings: 특정 shared library의 string을 탐색
--print-file-name: file name 출력

od: binary file dump
strings는 ASCII character가 특정 개수 이상 연속되면 string으로 인식
od는 '\0'으로 끝나는 string만 추적 가능
$ od -An -s -v libhello*.so.1.0.1 | grep hello_

od는 file 출력 option이 없으므로, file name을 보려면 shell script를 이용
$ for p in libhello*.so.1.0.1; do echo "--- $p"; od -An -s $p | grep hello_; done

nm: object file에서 symbol name을 출력. symbol type을 출력해 strings나 od보다 더 정확하게 symbol type을 알 수 있음
-A(--print-file-name): file name 출력
$ nm libhello*.1.0.1 | grep hello_
hello_animal과 hello_person은 text(code) section에 위치하는 symbol임을 알 수 있음

symbol type
A: absolute address로 정해진 symbol
B: BSS(초기화되지 않은 데이터섹션)에 들어있는 symbol
D: 초기화된 데이터섹션에 들어있는 symbol
G: 초기화된 데이터섹션에 들어있는 (작은) symbol
N: debugging symbol
R: read only section에 있는 symbol
S: 초기화되지 않은 데이터섹션에 들어있는 (작은) symbol
T: text(code) section에 들어있는 symbol
U: undefined symbol




nm으로 살펴보면 hello.cpp 내부에서는 _hello_person이 아니라 _Z12hello_personPc를 정의하고 있어 link가 안되고 있음

원래 이름을 c++filt로 출력하면 hello_person으로 입력이 되어 있으므로 서로간의 함수 이름이 불일치해 문제가 발생하고 있다
c++ code에서 extern 선언 뒤에 "C"를 붙이고, compile 후 nm으로 살펴보면 symbol name이 hello_person으로 되고 정상적으로 link가 되는 것을 알 수 있다
주의할 점은 매개변수 정보가 빠지기 때문에 잘못된 매개변수를 받아들이도록 선언된 함수도 문제없이 link가 된다는 점인데, header file등에 함수 선언을 설정하면 compile 과정에서 문제를 찾을 수 있으므로 예방이 가능하다



ldd: 실제로는 shell script이며 program을 실행하기 전 LD_TRACE_LOADED_OBJECTS라는 environmental variable을 1로 설정후 dynamic linker에게 넘긴다

교차 개발 환경에서 ldd를 사용하는 경우 실행 권한이 없으면 문제가 생기는 이유가 이것 때문이다. 실제로 ldd를 사용하지 않고 LD_TRACE_LOADED_OBJECTS=1로 정의한 후 명령을 수행해도 ldd와 동일한 결과를 얻을 수 있다

$ LD_TRACE_LOADED_OBJECTS=1 /bin/ls

실행 파일과는 달리 dynamic library는 실행이 불가능하므로 이 방법으로는 shared library 자체의 의존성을 파악하기는 힘들다. 하지만 runtime linker를 사용하는 편법이 있다.

$ LD_TRACE_LOADED_OBJECTS=1 /lib/ld-linux.so.2 ./libhello.so

shared library와 관련한 세부 동작 원리를 파악하기 위해 strace를 이용할 수 있다고 설명했는데, LD_DEBUG라는 좀 더 강력한 방법도 있다

$ LD_DEBUG=files /bin/ls

시스템 공유 라이브러리를 오염시키지 않기 위해 별도 공유 라이브러리 경로를 유지하고 싶은 경우가 있다. 이 경우 ld.so 환경 설정 파일과 디렉토리를 수정해서 라이브러리 경로를 추가하면 된다. 예를 들어 X11R6의 경우 /usr/X11R6/lib에 라이브러리가 들어있는데, /etc/ld.so.conf.d/xorg-x11-i386.conf에 경로를 지정하는 방법을 사용하고 있다.

$ cat /etc/ld.so.conf

$ ls -al /etc/ld.so.conf.d

symbol name을 분석하기 위한 궁극적인 방법은 ELF 형식에서 직접 정보를 추출하는 readelf이다.

C++ compiler가 매개변수 정보를 포함하도록 symbol name을 변경하는 방법은 다양하기 때문에 경우에 따라 특정 compiler가 만든 C++ object file을 다른 compiler가 만든 C++ object file과 link하지 못할 수도 있다.

$ nm hello.o | c++filt로 C++ symbol name을 원래 정의대로 돌렸는데, 실제로는 nm 내부에서 option을 줘서 처리할 수도 있다

함수마다 extern "C"를 붙이는 것은 귀찮으므로 다음과 같이 전체 code를 영역으로 지정할 수 있다
#ifdef __cplusplus
#extern "C" {
#endif
// 원래 code
#ifdef __cplusplus
}
#endif

참고
linker: http://en.wikipedia.org/wiki/Linker
'Binary Hacks: 해커가 전수하는 테크닉 100선', 사토루 타카바야시 외 공저, 진명조 역, ITC: 2장 오브젝트 파일 HACK에서 각종 utility를 소개
'리눅스 문제 분석과 해결', 박재호/이해영 역, 에이콘 출판사 2006년: 9장 ELF, 부록 A에서 각종 utility 소개
'Linkers and Loaders': http://www.iecc.com/linker
C++ symbol naming: http://en.wikipedia.org/wiki/Name_mangling, http://kegel.com/mangle.html, http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html
리눅스 공유 라이브러리 운영과 생성방법 설명: http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html
Comments