주제 : 리눅스에서 라이브러리 사용하기
학습목표 : 리눅스에서 사용하는 라이브러리를 만들 수 있고 라이브러리가 어떤 건지 알 수 있으면 좋겠다.
참고 사이트 :
http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/C/Documents/Make_Library
http://www.hanbit.co.kr/network/view.html?bi_id=1013
라이브러리 : 특정한 코드를 포함하고 있는 컴파일된 파일. 오브젝트 파일들을 모아 놓은 것.
o 라이브러리의 종류
- 정적라이브러리 : 컴파일시에 적재된다.
- 공유라이브러리 : 프로그램이 시작될 때 적재된다. (런타임) ---> 윈도우에서 dll
- 동적라이브러리 : 프로그램 시작중 특정한 때에 적재된다.
** windows
정적라이브러리 : ~.lib 동적라이브러리 : ~.dll
** linux
정적라이브러리 : ~.a 동적(공유)라이브러리 : ~.so
o 소스파일 hello.c 를 실행파일 hello 로 컴파일하는 과정
c 컴파일러 : cc1
어셈블러 : as
링커 : ld , collect2
소스파일 --> 전처리된파일 --> 어셈블리파일 --> 목적파일 --> 실행파일
hello.c hello.i hello.s hello.o hello
gcc -E hello.c gcc -S hello.i gcc -c hello.s gcc -o hello hello.o
-----------------> --------------> -------------> --------------->
gcc --save-temps -o hello hello.c
-------------------------------------------------------------------->
전처리 과정 컴파일 과정 어셈블 과정 링킹 과정
(컴파일러) (컴파일러) (어셈블러) (링커)
(gcc -E) cc1 as collect2, ld
<----------------------------------------
디스어셈블 과정(objdump)
리버싱, 리버스엔지니어링, 역공학
리버스코드엔지니어링, RCE
<---------------------------------------------------------------
디컴파일 과정
===========================================================================
LAB1> main.c 소스를 각 단계별로 컴파일 해보자.
- gcc 에서 save-temps 를 이용하면 각 단계별로 작성된 파일을 얻을 수 있다.
- gcc --save-temps -o main main.c
# vi main.c
-- main.c --
#include <stdio.h>
int main()
{
printf("Hello C! \n");
return 0;
}
-- main.c --
#mkdir library ; cd library
- 각 단계별로 컴파일하기
# gcc -E main.c -o main.i
# gcc -S main.i
# gcc -c main.s
# gcc -o main main.o
# ./main
#ldd main ( -> 가지고 있는 라이브러리들이 출력된다. 의존관계를 알려준다.)
Hello C!
===========================================================================
===========================================================================
LAB2> main.c 에 함수 func1() 을 추가해보자.
- 소스파일에서 한번에 컴파일해서 실행파일을 얻고 싶다면 아래와 같이 한다.
- gcc -o main main.c
# vi main.c
-- main.c --
#include <stdio.h>
void func1();
int main(){
printf("Hello C! \n"); // printf()정의가 라이브러리로 따로 외부에 파일로 존재한다.
func1();
return 0;
}
void func1(){
printf("func1 call \n");
}
-- main.c --
# gcc -E main.c -o main.i
# gcc -S main.i
# gcc -c main.s
# gcc -o main main.o
# ./main
Hello C!
func1 call
===========================================================================
===========================================================================
LAB3> main.c 에 함수 func2() 을 추가해보자.
# vi main.c
-- main.c --
#include <stdio.h>
void func1();
void func1();
int main(){
printf("Hello C! \n"); // printf()정의가 라이브러리로 따로 외부에 파일로 존재한다.
func1();
return 0;
}
void func1(){
printf("func1 call \n");
}
void func2(){
printf("func2 call \n");
}
-- main.c --
# gcc -E main.c -o main.i
# gcc -S main.i
# gcc -c main.s
# gcc -o main main.o
# ./main
Hello C!
func1 call
func2 call
===========================================================================
===========================================================================
LAB4> main.c 에 함수 func2() 를 Object 파일로 분리해보자.
# vi main.c
-- main.c --
#include <stdio.h>
void func1();
void func2();
int main()
{
printf("Hello C! \n");
func1();
func2();
return 0;
}
-- main.c --
# vi func1.c
-- func1.c --
#include <stdio.h>
void func1(){
printf("func1 call \n");
}
-- func1.c --
# vi func2.c
-- func2.c --
#include <stdio.h>
void func2(){
printf("func2 call \n");
}
-- func2.c --
- func1.o, func2.o, main.o 의 object 파일을 생성한다.
# gcc -c func1.c
# gcc -c func2.c
# gcc -c main.c
- 생성한 object 파일들을 결합하여 main 이라는 실행파일을 생성한다.
# gcc -o main main.o func1.o func2.o
# ./main
Hello C!
func1 call
func2 call
===========================================================================
===========================================================================
LAB6> 정적라이브러리를 아래 조건에 맞추어 생성해보자.
( 정적라이브러리로 생성된 파일은 라이브러리가 삭제되도 실행 된다. <---> 동적(공유)는 실행이 안된다.)
라이브러리 모여있는 디렉토리 : /lib /usr/lib
라이브러리명 : lib라이브러리명.[a,so]
정적라이브러리 : libksw.a
동적라이브러리 : libksw.so
ex) 표준라이브러리
: /usr/lib/libc.a, /usr/lib/libc.so
libz.a, libz.so : 압축에 관한 라이브러리
-- 조건 --
라이브러리명 : libmy.a
-- 조건 --
-- 참고 --
- 아카이브 파일은 ar 뿐만이 아니라 tar 로도 만들 수 있다.
- # tar cvf libmy2.a func1.o func2.o
- # tar tvf libmy2.a
- 라이브러리와 같이 컴파일할 때는 아래와 같이 사용한다.
- 옵션 설명 : -o <실행파일명> -l<라이브러리명> -L<라이브러리의 경로명>
- # gcc -o main main.c -lmy -L.
>> libmy.a 에서 앞에 lib와 뒤에 .a는 생략하고 my만 적는다
>> c 라이브러리는 기본이기 때문에 추가하지 않는다.
- main.c 안에 fun1(), fun2(), printf() 함수가 있으므로
- 실제 컴파일은 gcc -o main main.c -lmy -L. -lc -L/usr/lib 와 같이 해야하지만
- 기본적으로 c 라이브러리는 아래와 같이 생략이 가능하다.
- # gcc -o main main.c -lmy -L.
- # ls -l /usr/lib/libc.a
- -rw-r--r-- 1 root root 3016658 2월 22 2012 /usr/lib/libc.a
-- 참고 --
-- 순서 --
1. 정적라이브러리 파일을 생성한다.
- ar 명령어로 func1.o func2.o 파일을 가진 libmy.a 라는 아카이브 파일을 생성한다.
#make clean
#make func1
#make func2
#ar rcv libmy.a func1.o func2.o
#ar t libmy.a
2. main.c 를 라이브러리와 같이 컴파일한다.
-- 순서 --
1. 정적라이브러리 파일을 생성한다.
- ar 명령어로 func1.o func2.o 파일을 가진 libmy.a 라는 아카이브 파일을 생성한다.
# ar rcv libmy.a func1.o func2.o
# ar t libmy.a
func1.o
func2.o
2. main.c 를 라이브러리와 같이 컴파일한다.
- 만약 object 파일이 많을때는 gcc -o main main.c func1.o func2.o ... 처럼
- 파일들을 일일히 나열할 수 없으므로 object 파일들을 하나의 아카이브 파일안에
- 넣어두고 사용하는 것이 좋다. 결국 이것이 라이브러리를 만드는 주 목적이다.
# make clean
# gcc -o main main.c <-- X
# gcc -o main main.c libmy.a <-- O
# gcc -o main2 main.c -lmy -L. <-- O
===========================================================================
===========================================================================
LAB7> 공유라이브러리를 아래 조건에 맞추어 생성해보자.
-- 참고 --
o 공유라이브러리 사용하기
- 공유라이브러리는 실행시에 라이브러리를 적재하고 프로그램을 실행하므로 프로그램을 배포할때는 공유라이브러리도 함께 배포되어야 한다. 그렇지 않을경우 공유라이브러리를 찾을수 없다는 메시지를 출력하면서 프로그램 실행이 중단된다.
o 공유라이브러리를 인식하는 세 가지 방법
- 1. 기본 라이브러리 디렉토리에 공유라이브러리를 넣는 방법 : /usr/lib, /lib (ksw X)
=> root 가 아닌 guest는 불가
- 2. 공유라이브러리가 있는 디렉토리를 설정파일에 등록하는 방법 : /etc/ld.so.conf (ksw X)
=> root 가 아닌 guest는 불가
- 3. 공유라이브러리가 있는 디렉토리를 환경변수로 등록하는 방법 : LD_LIBRARY_PATH (ksw O)
- LD_LIBRARY_PATH 을 지정하는 방법은 쉘에서의 PATH 변수와 동일하다.
- : 을 기준으로 공유라이브러리가 있는 경로를 나열하면 된다.
- LD_LIBRARY_PATH=디렉토리명:디렉토리명:디렉토리명:...
- LD_LIBRARY_PATH 를 export 하는 이유는 LD_LIBRARY_PATH 의 변수를 환경변수로 만들기 위해서
- 쉘에서 만드는 변수는 모두 지역변수다.
- 지역변수로 만든 변수명을 다른쪽으로 가져가기 위해서는 환경변수로 만들어야 한다.
- 환경변수는 전역변수의 내용을 가지고 있다.
- 환경변수를 만드는 명령어는 export 이다.
- ex) export LD_LIBRARY_PATH=.
-- 순서 --
1. 공유라이브러리 형식으로 컴파일한다.
2. 공유라이브러리를 생성한다.
3. main.c 를 라이브러리와 같이 컴파일한다.
4. main 을 실행한다.
-- 순서 --
1. 공유라이브러리 형식으로 컴파일한다.
- 컴파일시 -fPIC 옵션이 추가된다. (PIC : 포지션 인디펜던트 코드)
#make clean
#rm -f libmy.a
# gcc -fPIC -c func1.c
# gcc -fPIC -c func2.c
2. 공유라이브러리를 생성한다. (so : shared object)
# gcc -shared -W1,-soname,libmy.so.1 -o libmy.so.1.0.1 func1.o func2.o (실행파일 형태로 생성)
# ln -s libmy.so.1.0.1 libmy.so.1
# ln -s libmy.so.1 libmy.so
# ls -l lib*
-rw-r--r-- 1 root root 1908 Sep 4 21:51 libmy.a
lrwxrwxrwx 1 root root 10 Sep 4 22:16 libmy.so -> libmy.so.1
lrwxrwxrwx 1 root root 14 Sep 4 22:16 libmy.so.1 -> libmy.so.1.0.1
-rwxr-xr-x 1 root root 4268 Sep 4 22:08 libmy.so.1.0.1
3. main.c 를 라이브러리와 같이 컴파일한다.
- 같은 디렉토리에 정적라이브러리(libmy.a) 와 공유라이브러리(libmy.so) 파일이
- 동시에 존재한다면 먼저 공유라이브러리를 우선순위로 컴파일한다.
# gcc -o main main.c -lmy -L.
4. main 을 실행한다.
- 공유라이브러리를 찾을 수 없을때 나오는 에러 메세지
# ./main
./main: error while loading shared libraries: libmy.so: cannot open shared object file: No such file or directory
%%%%%%%%%%%%%%%%%%%%%여기까지 수업함%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- 공유라이브러리가 있는 현재 디렉토리를 LD_LIBRARY_PATH 에 설정하고 실행한다.
# LD_LIBRARY_PATH=. ./main
Hello C!
func1 call
func2 call
- LD_LIBRARY_PATH 변수가 계속 유지 되지 못해서 에러가 발생된다면
- LD_LIBRARY_PATH 변수가 계속 유지될 수 있도록 export 명령어를 사용하면 된다.
# ./main
./main: error while loading shared libraries: libmy.so: cannot open shared object file: No such file or directory
# export LD_LIBRARY_PATH
# ./main
Hello C!
func1 call
func2 call
- 공유라이브러리 설정파일에 등록하는 방법
- 공유라이브러리가 있는 디렉토리를 적어주고 ldconfig 명령어를 실행한다.
# vi /etc/ld.so.conf
-- /etc/ld.so.conf --
/root/programming
-- /etc/ld.so.conf --
- ldconfig 명령어를 실행하면 /etc/ld.so.cache 파일이 업데이트가 된다.
- 따라서 공유라이브러리로 컴파일한 파일을 실행할때 이 파일의 경로를 참고한다.
# ldconfig
# file /etc/ld.so.cache
/etc/ld.so.cache: data
# strings /etc/ld.so.cache | grep programm
/root/programming/libmy.so.1.0.1
/root/programming/libmy.so.1
/root/programming/libmy.so
# ./main
Hello C!
func1 call
func2 call
- /etc/ld.so.conf 를 이용하는 방법
# unset LD_LIBRARY_PATH
# ./main
./main: error while loading shared libraries: libmy.so: cannot open shared object file: No such file or directory
# cat /etc/ld.so.conf
include ld.so.conf.d/*.conf
# pwd
/root/library
# pwd >> /etc/ld.so.conf
# cat /etc/ld.so.conf
include ld.so.conf.d/*.conf
/root/library
# ./main
./main: error while loading shared libraries: libmy.so: cannot open shared object file: No such file or directory
# ldconfig
# ./main
Hello C!
func1 call
func2 call
- /usr/lib 디렉토리를 이용하는 방법
# cat /etc/ld.so.conf
include ld.so.conf.d/*.conf
# ldconfig
# ./main
./main: error while loading shared libraries: libmy.so: cannot open shared object file: No such file or directory
# mv libmy.so* /usr/lib -v
`libmy.so' -> `/usr/lib/libmy.so'
`libmy.so.1' -> `/usr/lib/libmy.so.1'
`libmy.so.1.0.1' -> `/usr/lib/libmy.so.1.0.1'
# ./main
Hello C!
func1 call
func2 call
===========================================================================
**C -> Unix/Windows system programming -> Win32API programming -> .........
'Linux > C' 카테고리의 다른 글
[linux] 사용자 정보 구하기 (0) | 2015.04.24 |
---|---|
[linux] gdb 사용하기 (0) | 2015.04.17 |
[VS] 차량번호 분류 (1) | 2011.09.19 |
[VS] 영문한글 글자수 세기 (0) | 2011.09.19 |
[VS] 네모찍기 (0) | 2011.09.14 |