-
gcc & 정적 라이브러리 & 동적 라이브러리 & makefile - 1Linux Basic 2024. 4. 27. 16:14
리눅스에서 남의 코드를 보다보면 makefile이라는것을 보게 되고
gcc라는것을 접하게 된다.
그러면 .so 파일 .a .o 파일 등 생소한 파일이 보이게 되고....
뭔 말인가 싶고....
아래 글을 참조해서 하나하나 차근 차근 따라 해보자 그러면 리눅스와 GCC 와 Makefile이 익숙해 질것이다.
우선 실습 위주로 작성하고 다음 글에는 명령어에 대해서 적어보자!
2.3. GCC를 사용하여 라이브러리 만들기 Red Hat Enterprise Linux 8 | Red Hat Customer Portal
Access Red Hat’s knowledge, guidance, and support through your subscription.
access.redhat.com
https://isuetracker.tistory.com/285
리눅스 라이브러리 만들기 (정적,동적)
리눅스 환경에서 라이브러리 만드는 방법입니다. 샘플 코드 mysum.h int mysum(int a, int b); mysum.c #include "mysum.h" int mysum(int a, int b) { return a+b; } 오브젝트 파일 만들기 (.o) gcc를 통해서 오브젝트 파일을
isuetracker.tistory.com
우선 아래 예는 위 사이트를 참조했음을 알립니다.
시작하기 앞서
Makefile은 tab을 기반으로 띄어쓰기를 합니다.
에러가 났을때 확인해보면 tab대신에 space가 있음을 확인 할 수 있습니다.
mul.c
#include <stdio.h> int mul(int b) { int a; for(a = 1; a < 10; a++) { printf("%d * %d = %d\n", b, a, a * b); } return 0; }
mul.h
int mul(int b);
main.c
#include "mul.h" #include <stdio.h> extern int mul(int b); int main() { int a; int b; printf("출력할 단의 숫자를 입력해 주세요"); scanf("%d", &b); mul(b); return 0; }
위 3개의 파일로 시작 해보겠습니다.
1. 정적 라이브러리 실습 및 Makefile 생성
gcc는 c 코드 object --> 라이브러리 --> 실행파일 이런 순으로 사용된다고 이해해보자!!
gcc -c mul.c -o mul_a.o ar rc libmul_a.a mul_a.o gcc -o simplecalc_a main.c -L./ -lmul_a ./simplecalc_a
위 처럼 실행하면 실행 할 수 있습니다.
정적 라이브러리이므로 simplecalc_a 에 다 포함되어 있습니다.
object 파일과 라이브러리를 제거 하고 다시 실행되는지 해보겠습니다.
rm -f *.o rm -f libmul_a.a ./simplecalc_a
mul.c mul_a.o mul_a.a simplecalc_a main.c main.o mul.h 위에서 실행한것을 Makefile로 만들어 보겠습니다.
CC = gcc CFLAG = OBJS = mul.o main.o mul.o : mul.c $(CC) $(CFLAG) -c $< main.o : main.c $(CC) $(CFLAG) -c $< main: main.o mul.o ar rc libmul_a.a mul.o $(CC) -o simplecalc_a main.o -L./ -lmul_a clean: rm -f $(OBJS)
위 처럼 하면 make main을 치면 simplecalc_a 파일이 생성될것 입니다.
target 은 main 인데 실행파일이름은 simplecalc_a이므로 같이 main으로 변경하면
즉 아래처럼 변경하면 좀 더 깔끔한것 같습니다.
CC = gcc CFLAG = OBJS = mul.o main.o libmul_a.a EXE = main mul.o : mul.c $(CC) $(CFLAG) -c $< main.o : main.c $(CC) $(CFLAG) -c $< $(EXE): main.o mul.o ar rc libmul_a.a mul.o $(CC) -o $@ $< -L./ -lmul_a clean: rm -f $(OBJS) $(EXE)
make main 을 치고
ldd main을 쳐 봅시다.
정적 라이브러리로 연결했으므로 동적 라이브러리에 libmul_a.a 가 보이지 않습니다.
$ldd main linux-vdso.so.1 (0x00007ffdc07e1000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007791c5a00000) /lib64/ld-linux-x86-64.so.2 (0x00007791c5db3000)
l
objdump -p libmul_a.a 를 쳐보면
$objdump -p libmul_a.a In archive libmul_a.a: mul.o: file format elf64-x86-64
mul.o 가 라이브러이에 있는 것을 확인 할 수 있습니다.
2. 동적 라이브러리 실습 및 Makefile 생성
이번에는 동적 라이브러 실습을 해보겠습니다.
make clean하고 아래처럼 칩니다.
gcc -c mul.c -fPIC -o mul_so.o gcc -shared -o libmul_so.so mul_so.o gcc -o main main.c -L./ -lmul_so ./main
실행 해보면 잘 되는것을 확인 할 수 있을 것이다.
그리고 ldd main을 쳐 보면
linux-vdso.so.1 (0x00007da56a023000) libmul_so.so (0x00007da56a013000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007da569c00000) /lib64/ld-linux-x86-64.so.2 (0x00007da56a025000)
위 처럼 libmul_so.so 파일이 있음을 확인 할 수 있다.
makefile로 위 예제를 만들어 보자!
CC = gcc LDFLAGS = -fPIC OBJS = mul.o main.o libmul_so.so EXE = main CFLAGS = -shared mul.o : mul.c $(CC) -c $< $(LDFLAGS) main.o : main.c $(CC) -c $< $(LDFLAGS) $(EXE): main.o mul.o $(CC) $(CFLAGS) -o libmul_so.so mul.o $(CC) -o $@ $< -L./ -lmul_so clean: rm -f $(OBJS) $(EXE)
동적라이브러리로 연결했기때문에 아래 처럼 치면 에러나면서 실행이 안됨을 확인 할 수 있다.
rm -f *.o rm -f *.so ./main $./main: error while loading shared libraries: libmul_so.so: cannot open shared object file: No such file or directory
3. 동적 라이브러리 실습 및 Makefile 생성 - 2
라이브러리 버전관리를 위해서 soname옵션을 사용하는데 아래 링크를 읽고 진행하면된다.
2.3. GCC를 사용하여 라이브러리 만들기 Red Hat Enterprise Linux 8 | Red Hat Customer Portal
Access Red Hat’s knowledge, guidance, and support through your subscription.
access.redhat.com
아래처럼 치면 똑 같이 main 이 실행되는것을 알수 있을것이다.
gcc -c mul.c -fPIC -o mul_so.o gcc -shared -o libmul_so.so.1.0 -Wl,-soname,libmul_so.so.1 mul_so.o ln -s libmul_so.so.1.0 libmul_so.so.1 ln -s libmul_so.so.1 libmul_so.so gcc -o main main.c -L./ -lmul_so
위에서 궁금한것은 ln -s libmul_so.so.1.0 libmul_so.so 라고 치면 왜 안되지 라는 궁금증이 생길것이다.
즉 아래 처럼 치면
gcc -c mul.c -fPIC -o mul_so.o gcc -shared -o libmul_so.so.1.0 -Wl,-soname,libmul_so.so.1 mul_so.o ln -s libmul_so.so.1.0 libmul_so.so gcc -o main main.c -L./ -lmul_so $ ./main: error while loading shared libraries: libmul_so.so.1: cannot open shared object file: No such file or directory
libmul_so.so.1를 열 수 없다고 나온다.
위 예제도 makefile 로 만들면
CC = gcc LDFLAGS = -fPIC OBJS = mul.o main.o *.so libmul_so.so.1.0 libmul_so.so.1 EXE = main CXXFLAGS = -shared mul.o : mul.c $(CC) -c $< $(LDFLAGS) main.o : main.c $(CC) -c $< $(LDFLAGS) $(EXE): main.o mul.o $(CC) $(CXXFLAGS) -o libmul_so.so.1.0 -Wl,-soname,libmul_so.so.1 mul.o ln -s libmul_so.so.1.0 libmul_so.so.1 ln -s libmul_so.so.1 libmul_so.so $(CC) -o $@ $< -L./ -lmul_so clean: rm -f $(OBJS) $(EXE)
위 처럼 될것이다.
ldd main을 치면 libmul_so.so 가 아닌 libmul_so.so.1 이 동적라이브러리로 연결되어 있는것을 확인 할 수 있다.
$ldd main linux-vdso.so.1 (0x00007fff65db2000) libmul_so.so.1 (0x000076d192665000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x000076d192400000) /lib64/ld-linux-x86-64.so.2 (0x000076d192671000)
$ objdump -p libmul_so.so libmul_so.so: file format elf64-x86-64 Program Header: LOAD off 0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**12 filesz 0x0000000000000538 memsz 0x0000000000000538 flags r-- LOAD off 0x0000000000001000 vaddr 0x0000000000001000 paddr 0x0000000000001000 align 2**12 filesz 0x0000000000000175 memsz 0x0000000000000175 flags r-x LOAD off 0x0000000000002000 vaddr 0x0000000000002000 paddr 0x0000000000002000 align 2**12 filesz 0x00000000000000d4 memsz 0x00000000000000d4 flags r-- LOAD off 0x0000000000002e00 vaddr 0x0000000000003e00 paddr 0x0000000000003e00 align 2**12 filesz 0x0000000000000228 memsz 0x0000000000000230 flags rw- DYNAMIC off 0x0000000000002e10 vaddr 0x0000000000003e10 paddr 0x0000000000003e10 align 2**3 filesz 0x00000000000001d0 memsz 0x00000000000001d0 flags rw- NOTE off 0x00000000000002a8 vaddr 0x00000000000002a8 paddr 0x00000000000002a8 align 2**3 filesz 0x0000000000000020 memsz 0x0000000000000020 flags r-- NOTE off 0x00000000000002c8 vaddr 0x00000000000002c8 paddr 0x00000000000002c8 align 2**2 filesz 0x0000000000000024 memsz 0x0000000000000024 flags r-- 0x6474e553 off 0x00000000000002a8 vaddr 0x00000000000002a8 paddr 0x00000000000002a8 align 2**3 filesz 0x0000000000000020 memsz 0x0000000000000020 flags r-- EH_FRAME off 0x0000000000002010 vaddr 0x0000000000002010 paddr 0x0000000000002010 align 2**2 filesz 0x000000000000002c memsz 0x000000000000002c flags r-- STACK off 0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**4 filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw- RELRO off 0x0000000000002e00 vaddr 0x0000000000003e00 paddr 0x0000000000003e00 align 2**0 filesz 0x0000000000000200 memsz 0x0000000000000200 flags r-- Dynamic Section: NEEDED libc.so.6 SONAME libmul_so.so.1 INIT 0x0000000000001000 FINI 0x0000000000001168 INIT_ARRAY 0x0000000000003e00 INIT_ARRAYSZ 0x0000000000000008 FINI_ARRAY 0x0000000000003e08 FINI_ARRAYSZ 0x0000000000000008 GNU_HASH 0x00000000000002f0 STRTAB 0x00000000000003c0 SYMTAB 0x0000000000000318 STRSZ 0x0000000000000085 SYMENT 0x0000000000000018 PLTGOT 0x0000000000004000 PLTRELSZ 0x0000000000000018 PLTREL 0x0000000000000007 JMPREL 0x0000000000000520 RELA 0x0000000000000478 RELASZ 0x00000000000000a8 RELAENT 0x0000000000000018 VERNEED 0x0000000000000458 VERNEEDNUM 0x0000000000000001 VERSYM 0x0000000000000446 RELACOUNT 0x0000000000000003 Version References: required from libc.so.6: 0x09691a75 0x00 02 GLIBC_2.2.5
위 예제를 보면 SONAME 이 libmul_so.so.1로 되어 있는것을 볼 수 있다.
4. 동적 라이브러리 실습 및 Makefile 생성 - 3(hooking 연습)
https://freddiekim.tistory.com/14
LD_PRELOAD
리눅스에 LD_PRELOAD라는 예약어가 있다. 동적 라이브러리를 먼저 참조할 수 있도록 제공하는 기능이다. 정적 라이브러리는 내가 해보니 잘 안된다. 이론적으로 생각해봐도 정적 라이브러리 형식
freddiekim.tistory.com
예전에 LD_PRELOAD를 이용한 hooking 연습을 했다.
응용 해보자!
hooking 이란? 기존에 내가 만든 라이브러리를 참조하는것이 아니라 LD_PRELOAD에 연결해놓은 라이브러리를 먼저 참조해서 함수바꿔치기를 하는 것이다.
게임등...hacking에도 사용됨.
여기서는 함수의 연산시간을 계산하는 용도로 사용해봅시다.
mul_hook.c 파일 만든 후
#define _GNU_SOURCE #include <stdio.h> #include <dlfcn.h> #include <time.h> int mul(int b) { clock_t start, end; double cpu_time_used; int c; int (*new_mul)(int b); new_mul = dlsym(RTLD_NEXT, "mul"); start = clock(); c = new_mul(b); end = clock(); cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC; printf("mul()=%d took %f milliseconds to execute \n",c, cpu_time_used*1e3); return c; }
아래 처럼 hooking 이 제대로 된것을 볼 수 있다.
$gcc -c mul_hook.c $gcc -fPIC -shared -o libmul_hook.so mul_hook.o $LD_PRELOAD=${PWD}/libmul_hook.so ./main 출력할 단의 숫자를 입력해 주세요9 9 * 1 = 9 9 * 2 = 18 9 * 3 = 27 9 * 4 = 36 9 * 5 = 45 9 * 6 = 54 9 * 7 = 63 9 * 8 = 72 9 * 9 = 81 mul()=0 took 0.026000 milliseconds to execute
위 예제를 Makefile로 만들어 보면 아래와 같다.
CC = gcc LDFLAGS = -fPIC OBJS = mul.o main.o *.so libmul_so.so.1.0 libmul_so.so.1 EXE = main CFLAGS = -shared mul.o : mul.c $(CC) -c $< $(LDFLAGS) main.o : main.c $(CC) -c $< $(LDFLAGS) mul_hook.o : mul_hook.c $(CC) -c $< $(LDFLAGS) $(EXE): main.o mul.o mul_hook.o $(CC) $(CFLAGS) -o libmul_so.so.1.0 -Wl,-soname,libmul_so.so.1 mul.o ln -s libmul_so.so.1.0 libmul_so.so.1 ln -s libmul_so.so.1 libmul_so.so $(CC) -o $@ $< -L./ -lmul_so $(CC) $(CFLAGS) -o libmul_hook.so mul_hook.o $(LDFLAGS) clean: rm -f $(OBJS) $(EXE)
$make main
$LD_PRELOAD=${PWD}/libmul_hook.so ./main
출력할 단의 숫자를 입력해 주세요9
9 * 1 = 9
9 * 2 = 18
9 * 3 = 27
9 * 4 = 36
9 * 5 = 45
9 * 6 = 54
9 * 7 = 63
9 * 8 = 72
9 * 9 = 81
mul()=0 took 0.024000 milliseconds to execute위 처럼 잘 나오는 것을 확인 할 수 있다.
gcc, 정적라이브러리, 동적라이브러리, makefile 만들기, hook 연습까지 알아봤다.
이 정도면 익숙해졌을것이다.
반응형'Linux Basic' 카테고리의 다른 글
sftp server 설정 (0) 2024.05.15 gcc & LD_PRELOAD & 동적 라이브러리 & makefile -2 (0) 2024.04.29 cmake on linux (0) 2023.09.17 onnx docker 사용하기 (0) 2023.07.16 ONNX 무작정 따라하기 (0) 2023.07.16