ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • gcc & 정적 라이브러리 & 동적 라이브러리 & makefile - 1
    Linux Basic 2024. 4. 27. 16:14

     

    리눅스에서 남의 코드를 보다보면 makefile이라는것을 보게 되고

     

    gcc라는것을 접하게 된다.

     

    그러면 .so 파일 .a .o 파일 등 생소한 파일이 보이게 되고....

     

    뭔 말인가 싶고....

     

    아래 글을 참조해서 하나하나 차근 차근 따라 해보자 그러면 리눅스와 GCC 와 Makefile이 익숙해 질것이다.

     

    우선 실습 위주로 작성하고 다음 글에는 명령어에 대해서 적어보자!

     

    https://access.redhat.com/documentation/ko-kr/red_hat_enterprise_linux/8/html/developing_c_and_cpp_applications_in_rhel_8/creating-libraries-with-gcc_creating-c-or-cpp-applications#creating-dynamic-libraries-with-gcc_creating-libraries-with-gcc

     

    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옵션을 사용하는데 아래 링크를 읽고 진행하면된다.

     

    https://access.redhat.com/documentation/ko-kr/red_hat_enterprise_linux/8/html/developing_c_and_cpp_applications_in_rhel_8/creating-libraries-with-gcc_creating-c-or-cpp-applications#the-soname-mechanism_creating-libraries-with-gcc

     

    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
Designed by Tistory.