Wednesday, January 19, 2011

Shared Library on Linux - Eng & Kor


Static Library  vs Shared Library


The last step to develop program needs linking. Linking is a kind procedure of assembling fragments which are necessary to program. Each fragment necessary to program can be stored as a library and it can be static or shared library.
Static library copies all elements necessary to program into executable file when it is linking but shared library loads necessary elements to main memory when the program executes.
Following is describing the difference between static and shared library.
--
프로그램을 만드는 마지막 단계에서 링크 과정을 거친다링크란 프로그램에 필요한 조각들을 모으는 과정을 말한다. 프로그램에 필요한 조각들은 라이브러리 형태로 보관되어질 있는데 라이브러리는 정적 라이브러리(Static Library) 공유 라이브러리(Shared Library) 나뉘어 진다.
 정적 라이브러리(Static Library) 링크 프로그램이 필요한 모든 부분들을 실행파일에 복사하며 공유 라이브러리(Shared Library) 프로그램 실행 시에  필요한 부분이 메모리에 적재된다. 아래의 그림은 정적 라이브러리와  공유 라이브러리의 차이를 보여준다.
--


                        Figure 1. Use of Static and Shared Libraries

Shared Library Names

Below is shared library naming format.
“lib” + name of the library + “so” + “.” + version number
ex)libc.so.1.2
You may see one shared library has two soft link in shared library directory.
Suppose you built libfoo.so.1.2 and added some more feature on the library and version up libfoo.so.1.3. You may need to increase version number every time you add new feature, and the problem is that you also need to update document. But if you have symbolic link libfoo.so.1 for libfoo.so.1.x you don't need to update document every time when you update library. Also you don't need to change make file.

There are three type of files.
SONAME: symbolic link to real file name (libfoo.so.xx).
REAM NAME: real file name (libfoo.so.1.xx).
LINKE NAME: symbolic name when you need to link (libfoo.so).

ldconfig analyses shared library directory and create SONAME and set /etc/ld.so.cache.
--
공유 라이브러리(Shared Library) 이름은 아래와 같은 형식을 갖는다.
 “lib” + name of the library + “so” + “.” + version number
) libc.so.1.2

공유 라이브러리(Shared Library) 저장되어있는 디렉터리에서 파일리스트를 보면 하나의 파일에 두개의 소프트링크가 연결되어있는 것을 있다. 그런가에 대해 설명해 보겠다.
예를 들어 libfoo.so.1.2 라는 라이브러리를 만들었다고 가정하자. 라이브러리에 추가할 사항이 있어서 추가를   libfoo.so.1.3으로 버전을 올린다. 계속 라이브러리 내용이 변경 때마다  버전 번호는 데이트 것이다. 문제는 도큐먼트시에 라이브러리가 데이트 때마다  문서내용을 바꿔주어야 한다. 그런데 라이브러리 데이트 때마다  항상 libfoo.so.1 이란 심볼릭 링크를 걸어준다면 문서에는 libfoo.so.1 이란 이름만 적어주면 데이트   때마다 도큐먼트에서 라이브러리 파일 이름을 바꿔줄 필요가 없을 것이다. 링크 때도 마찬가지로 libfoo.so.1.xx 버전에서 libboo.so.2.xx버전으로 업그레이드 파일 이름이 바뀌므로 항상 다시 compile 링크를 해야 된다 . 도큐먼트에서와 마찬가지로 데이트 때마다 libfoo.so 라는 심볼릭 링크를 걸어주면 libfoo.so라는 파일을 한번만 링크 시켜주면 다시 compile 링크를 필요가 없어진다.
정리를 하면 다음의 개의 파일이 존재한다.
SONAME: REAL NAME 대한 심볼릭 링크이다.(libfoo.so.xx)
REAL NAME: 실제 코드를 가지고있는 파일 이름이다.(libfoo.so.1.xx)
LINKER NAME:링크할 필요한 파일이다.(libfoo.so)
ldconfig 프로그램은 디렉터리에 존재하는 파일들을 점검한 실제 REAL NAME 심볼릭 링크로써 SONAME 생성하며 동시에 캐쉬 파일인 /etc/ld.so.cache 세팅한다.
--

Filesystem Placement

GNU standard recommends to install all library files in /usr/local/lib when you release source code.
FHS(Filesystem Hierachy Standard) recommends to install all library files in /usr/lib and in /lib if it's necessary for startup and in /usr/local/lib if it is not system libraries.
--
GNU standard source code 배포 모든 라이브러리 파일을 /usr/local/lib 설치할 것을 권장한다.
FHS(Filesystem Hierarchy Standard) 모든 라이브러리 파일은 /usr/lib 설치할 것을 권장하며 startup 필요한 라이브러리 파일들은 /lib 시스템 라이브러리가 아닌 것은 /usr/local/lib 설치할 것을 권장한다.
--

How Libraries are Used

GNU glibc based system loads /lib/ld-linux.x which includes all shared libraries necessary to executable binary when  ELF format binary executable file executes. Its search order is stored in /etc/ld.so.conf.
ldconfig reads /etc/ld.so.conf and creates symbolic link automatically for all necessary shared libraries and saves the modification in /etc/ld.so.cache to improve library searching speed.
--
GNU glibc기반의 시스템은 ELF 형식의 이진 실행 파일이 실행될 /lib/ld-linux.x(x 버전번호) 적재되어 실행되는데 로더는 프로그램에서 사용되는 모든 공유 라이브러리를 찾아서 적재한다. 찾는데 필요한 순서는 /etc/ld.so.conf 저장되어있다.
ldconfig 프로그램은 /etc/ld.so.conf 읽어서 모든 필요한 라이브러리에 대해 심볼릭 링크를 자동으로 생성시켜 주며 이러한  변경사항을 /etc/ld.so.cache 저장하여 다음부터는 파일을 읽어서 프로그램 시작시 속도를 향상시킨다.
--

Environment Variables

Loader will search library LD_LIBRARY_PATH first that system default library directory. If you want to override specific function you can create object file and set LD_PRELOAD then this file will override specific function.
--
LD_LIBRARY_PATH 환경변수를 설정하면 로더는 시스템의 기본 라이브러리가 위치한 디렉터리 보다 먼저 LD_LIBRARY_PATH에서 설정된 경로를 먼저 찾는다. 만약 특정한 함수만을 오버라이드 하려면 오버라이딩 오브젝트 파일을 생성 뒤에 LD_PRELOAD 설정해서 있다. , 파일에 있는 함수들이 기존 함수를 오버라이드 한다.
--



Creating a Shared Library


Create file as below.
[project@pluto ShLib]$ cat print_hello.c
#include
 void print_hello(void)
{
        printf("hello world from shared library\n");
}
[project@pluto ShLib]$

Create object file.
[project@pluto ShLib]$ gcc -c -fPIC print_hello.c
[project@pluto ShLib]$ ls
print_hello.c  print_hello.o
[project@pluto ShLib]$

-fPIC(“position independent code”)


Create shared library.
[project@pluto ShLib]$ gcc -shared -Wl,-soname,libprint_hello.so.1 -o libprint_
hello.so.1.0.1 print_hello.o
[project@pluto ShLib]$ ls
libprint_hello.so.1.0.1  print_hello.c  print_hello.o
        -shared        :option for shared library.
        -Wl,-soname,libprint_hello.so.1        :option for linker.

Copy library into /usr/lib.
[root@pluto ShLib]# cp libprint_hello.so.1.0.1 /usr/lib

Run ldconfig
[root@pluto ShLib]# ldconfig

Symbolic links are created automatically.
[root@pluto lib]# pwd
/usr/lib
[root@pluto lib]# ls -l libprint_hello*
lrwxrwxrwx   1 root     root           23 Nov 24 15:59 libprint_hello.so.1 -> libprint_hello.so.1.0.1
-rwxr-xr-x   1 root     root         5585 Nov 24 15:57 libprint_hello.so.1.0.1
[root@pluto lib]#

Let's copy to other directory.
[root@pluto lib]# pwd
/usr/lib
 [root@pluto lib]# rm libprint_hello*



If it's not in system shared library, try as below.
[root@pluto ShLib]# ldconfig -n /home/project/lib
[root@pluto ShLib]# ls -l /home/project/lib
total 6
lrwxrwxrwx   1 root     users          23 Nov 24 16:07 libprint_hello.so.1 -> libprint_hello.so.1.0.1
-rwxr-xr-x   1 project  users        5585 Nov 24 16:05 libprint_hello.so.1.0.1
[root@pluto ShLib]#


Create one more link.
[project@pluto lib]$ ln -s libprint_hello.so.1.0.1 libprint_hello.so
[project@pluto lib]$ l
./  ../  libprint_hello.so@  libprint_hello.so.1@  libprint_hello.so.1.0.1*
[project@pluto lib]$

Create code as below.
[project@pluto ShLib]$ cat hello.c
#include
int main(int argc, char *argv[])
{
        print_hello();
}
[project@pluto ShLib]$

It will print message as following since it can't find library in system default directory.
[project@pluto ShLib]$ gcc -o hello hello.c
/tmp/cc9IAGFB.o: In function `main':
/tmp/cc9IAGFB.o(.text+0x4): undefined reference to `print_hello'
[project@pluto ShLib]$

Specify library directory and library name when it compiles.
컴파일시 디렉터리 명과 라이브러리 이름을 명시한다.
[project@pluto ShLib]$ gcc -o hello hello.c -L/home/project/lib -lprint_hello
[project@pluto ShLib]$ l
./             ../  hello*  hello.c  libprint_hello.so.1.0.1*  print_hello.c
print_hello.o


It will print error message that can't find library.
기본 디렉토리에 공유 라이브러리가 없기 때문에 찾을 없다는 메시지가 나온다.
[project@pluto ShLib]$ ./hello
./hello: error in loading shared libraries: libprint_hello.so.1: cannot open shared object file: No such file or directory


You can set your own shared library path.
다음과 같이 설정하면 설정된 디렉터리부터 검사한다.
[project@pluto ShLib]$ LD_LIBRARY_PATH=/home/project/lib
[project@pluto ShLib]$ export LD_LIBRARY_PATH
[project@pluto ShLib]$ echo $LD_LIBRARY_PATH
/home/project/lib


Run.
정상적으로 실행된다.
[project@pluto ShLib]$ ./hello
hello world from shared library
[project@pluto ShLib]$





Other Useful Tools


   ldd: List Dynamic Dependencies

[project@pluto ShLib]$ ldd hello

        libprint_hello.so.1 => /home/project/lib/libprint_hello.so.1 (0x2aac0000)
        libc.so.6 => /lib/libc.so.6 (0x2aac7000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x2aaab000)

nm:라이브러리 내의 모든 심볼을 출력해준다.
[project@pluto ShLib]$ nm ../lib/libprint_hello.so
00001874 A _DYNAMIC
00001840 A _GLOBAL_OFFSET_TABLE_
00001834 ? __CTOR_END__
00001830 ? __CTOR_LIST__
0000183c ? __DTOR_END__
00001838 ? __DTOR_LIST__
0000182c ? __EH_FRAME_BEGIN__
0000182c ? __FRAME_END__
         U ___brk_addr@@GLIBC_2.0
00001914 A __bss_start
         U __curbrk@@GLIBC_2.0
         w __deregister_frame_info@@GLIBC_2.0
00000784 t __do_global_ctors_aux
000006a4 t __do_global_dtors_aux
         U __environ@@GLIBC_2.0
         w __gmon_start__
         w __register_frame_info@@GLIBC_2.0
00001914 A _edata
0000192c A _end
000007d8 A _etext
000007d8 ? _fini
00000604 ? _init
         U atexit@@GLIBC_2.0
00001828 d completed.3
00000700 t fini_dummy
0000182c d force_to_data
0000182c d force_to_data
00000714 t frame_dummy
000006a0 t gcc2_compiled.
000006a0 t gcc2_compiled.
00000780 t gcc2_compiled.
000007d8 t gcc2_compiled.
00000758 t gcc2_compiled.
00000748 t init_dummy
000007b4 t init_dummy
00001914 b object.8
00001824 d p.2
00000758 T print_hello
         U printf@@GLIBC_2.0
[project@pluto ShLib]$