動機

看bpf時突然想起來,整理一下

行前工具

  • compiler: gcc
  • 看elf的工具: readelf 或 objdump
  • 單純看symbol: nm

compile流程

  1. compile: code -> object code
    • 前面其實還有preprocesser展開,但先當成一起的
    • 從高階語言變成低階語言
  2. assemble: object code -> binary(relocatable, 又名object file)
    • 從低階語言變成binary
    • 但在其他檔案的code怎麼找到他們?
  3. linking: binary(relocatable, 又名object file) -> binary(real exe)
    • 把其他object file整理起來
    • 算位置並填上binary去 (relocate)

ELF

kernel就是從ELF去看或找

  • 有什麼code
  • 有什麼symbol、要去哪找
  • 大小、長度多少
  • 資料的讀取權限
  • debug info

類型有

  • relocatable(o)
  • executable
  • shared obj(so)
  • core(core dump)

詳細的可以看這邊

所以生出exe的過程可以看成改寫ELF的過程

linking

  • linking
    • 把很多object file和在一起
    • 確認symbol在不在,處理各個symbol
    • 依據symbol的來源分成兩種
      • static linking
        • symbol實際定義都在object file中
          • 只要排好給位置就好(relocate)
        • 所以
          • static lib其實就是把object file黏成一個
          • 如果改code要重算
          • static加越多,最後出來的exe越大
      • dynamic linking
        • symbol不在object file中,所以
          • 執行時要往外找 (先找到先用)
            • 等到要load lib時,linker一樣會做relocate,不過與static不同,看PIC
          • 編譯時
            • 有找到就編過
            • symbol會標上dynamic
        • 所以
          • 編dynamic lib需要特別一點
            • 因為每個proc就算call同一種code,內部addr也會不同
              • Position-independent Code(PIC),兩個case
                • code都在同一個檔案
                  • 直接算相對位置
                • 需要其他lib
                  • linker在載入lib時會填Global Offset Table
                  • 裡面會有其他lib的位置,等要call就去查,再跳
          • 可以開心地換lib
          • 大家可以共用
          • 可以在runtime做load!! (dlopen, dlsym, dlerror, dlclose)

實際試試看

compile+assemble

main.c,但沒有p1, p2的宣告

void main() {
  p1();
}

gcc -c main.c

main.c: In function ‘main’:
main.c:4:5: warning: implicit declaration of function ‘p1’ [-Wimplicit-function-declaration]
    4 |     p1();
      |     ^~

把p1補上去

void p1();
void main() {
  p1();
}

static linking

a.c

#include <stdio.h>
void p1(){
  puts("static");
}

同樣編成object file gcc -o a.c

開編 gcc -o main main.o a.o

如果想模擬一下static lib ar rcs liba.a a.o 編的語法是 gcc -o main -L. -la 其中-L是lib要去哪裡找,-l是lib的名稱

在linux,lib都是lib<libname>.??

nm

先用nm看有什麼symbol,有puts與p1

bee314@DESKTOP-259SCE7:~$ nm main
0000000000003dc8 d _DYNAMIC
0000000000003fb8 d _GLOBAL_OFFSET_TABLE_
0000000000002000 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
0000000000002184 r __FRAME_END__
0000000000002010 r __GNU_EH_FRAME_HDR
0000000000004010 D __TMC_END__
0000000000004010 B __bss_start
                 w __cxa_finalize@@GLIBC_2.2.5
0000000000004000 D __data_start
0000000000001100 t __do_global_dtors_aux
0000000000003dc0 d __do_global_dtors_aux_fini_array_entry
0000000000004008 D __dso_handle
0000000000003db8 d __frame_dummy_init_array_entry
                 w __gmon_start__
0000000000003dc0 d __init_array_end
0000000000003db8 d __init_array_start
00000000000011f0 T __libc_csu_fini
0000000000001180 T __libc_csu_init
                 U __libc_start_main@@GLIBC_2.2.5
0000000000004010 D _edata
0000000000004018 B _end
00000000000011f8 T _fini
0000000000001000 t _init
0000000000001060 T _start
0000000000004010 b completed.8060
0000000000004000 W data_start
0000000000001090 t deregister_tm_clones
0000000000001140 t frame_dummy
0000000000001149 T main
000000000000115e T p1
                 U puts@@GLIBC_2.2.5
00000000000010c0 t register_tm_clones

readelf & objdump

編出來後用objdumpreadelf看dynsym,會看到這裡的dynsym是puts

bee314@DESKTOP-259SCE7:~$ readelf -r main

Relocation section '.rela.dyn' at offset 0x520 contains 8 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000003db8  000000000008 R_X86_64_RELATIVE                    1140
000000003dc0  000000000008 R_X86_64_RELATIVE                    1100
000000004008  000000000008 R_X86_64_RELATIVE                    4008
000000003fd8  000100000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_deregisterTMClone + 0
000000003fe0  000300000006 R_X86_64_GLOB_DAT 0000000000000000 __libc_start_main@GLIBC_2.2.5 + 0
000000003fe8  000400000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
000000003ff0  000500000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_registerTMCloneTa + 0
000000003ff8  000600000006 R_X86_64_GLOB_DAT 0000000000000000 __cxa_finalize@GLIBC_2.2.5 + 0

Relocation section '.rela.plt' at offset 0x5e0 contains 1 entry:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000003fd0  000200000007 R_X86_64_JUMP_SLO 0000000000000000 puts@GLIBC_2.2.5 + 0
bee314@DESKTOP-259SCE7:~$ objdump -T main

main:     file format elf64-x86-64

DYNAMIC SYMBOL TABLE:
0000000000000000  w   D  -UND*  0000000000000000              _ITM_deregisterTMCloneTable
0000000000000000      DF -UND*  0000000000000000  GLIBC_2.2.5 puts
0000000000000000      DF -UND*  0000000000000000  GLIBC_2.2.5 __libc_start_main
0000000000000000  w   D  -UND*  0000000000000000              __gmon_start__
0000000000000000  w   D  -UND*  0000000000000000              _ITM_registerTMCloneTable
0000000000000000  w   DF -UND*  0000000000000000  GLIBC_2.2.5 __cxa_finalize

ldd

最後用ldd看有連結到那些lib,就是最基本的

bee314@DESKTOP-259SCE7:~$ ldd main
        linux-vdso.so.1 (0x00007fffde0c8000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0db9050000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f0db926d000)

dynamic linking

b.c

void p1() {
  puts("dynamic");
}

編成shared lib gcc -o libb.so -fPIC -shared b.c

開編 gcc -o main -L. -lb

之後執行下去

./main: error while loading shared libraries: libb.so: cannot open shared object file: No such file or directory

這是找不到shared lib,所以

  • 把libb.so放到預設路徑
  • 加找的路徑

這裡直接幫他加找的路徑 LD_LIBRARY_PATH=. ./main

nm

nm看有什麼symbol,少了puts

bee314@DESKTOP-259SCE7:~$ nm main
0000000000003db8 d _DYNAMIC
0000000000003fb8 d _GLOBAL_OFFSET_TABLE_
0000000000002000 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
000000000000214c r __FRAME_END__
0000000000002004 r __GNU_EH_FRAME_HDR
0000000000004010 D __TMC_END__
0000000000004010 B __bss_start
                 w __cxa_finalize@@GLIBC_2.2.5
0000000000004000 D __data_start
0000000000001100 t __do_global_dtors_aux
0000000000003db0 d __do_global_dtors_aux_fini_array_entry
0000000000004008 D __dso_handle
0000000000003da8 d __frame_dummy_init_array_entry
                 w __gmon_start__
0000000000003db0 d __init_array_end
0000000000003da8 d __init_array_start
00000000000011d0 T __libc_csu_fini
0000000000001160 T __libc_csu_init
                 U __libc_start_main@@GLIBC_2.2.5
0000000000004010 D _edata
0000000000004018 B _end
00000000000011d8 T _fini
0000000000001000 t _init
0000000000001060 T _start
0000000000004010 b completed.8060
0000000000004000 W data_start
0000000000001090 t deregister_tm_clones
0000000000001140 t frame_dummy
0000000000001149 T main
                 U p1
00000000000010c0 t register_tm_clones

readelf & objdump

同樣用objdumpreadelf看dynsym,這邊只剩下p1,而沒有puts了

bee314@DESKTOP-259SCE7:~$ readelf -r main

Relocation section '.rela.dyn' at offset 0x528 contains 8 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000003da8  000000000008 R_X86_64_RELATIVE                    1140
000000003db0  000000000008 R_X86_64_RELATIVE                    1100
000000004008  000000000008 R_X86_64_RELATIVE                    4008
000000003fd8  000100000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_deregisterTMClone + 0
000000003fe0  000200000006 R_X86_64_GLOB_DAT 0000000000000000 __libc_start_main@GLIBC_2.2.5 + 0
000000003fe8  000300000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
000000003ff0  000500000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_registerTMCloneTa + 0
000000003ff8  000600000006 R_X86_64_GLOB_DAT 0000000000000000 __cxa_finalize@GLIBC_2.2.5 + 0

Relocation section '.rela.plt' at offset 0x5e8 contains 1 entry:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000003fd0  000400000007 R_X86_64_JUMP_SLO 0000000000000000 p1 + 0
bee314@DESKTOP-259SCE7:~$ objdump -T main

main:     file format elf64-x86-64

DYNAMIC SYMBOL TABLE:
0000000000000000  w   D  -UND*  0000000000000000              _ITM_deregisterTMCloneTable
0000000000000000      DF -UND*  0000000000000000  GLIBC_2.2.5 __libc_start_main
0000000000000000  w   D  -UND*  0000000000000000              __gmon_start__
0000000000000000      DF -UND*  0000000000000000              p1
0000000000000000  w   D  -UND*  0000000000000000              _ITM_registerTMCloneTable
0000000000000000  w   DF -UND*  0000000000000000  GLIBC_2.2.5 __cxa_finalize

ldd

ldd看連結到那些lib,多了libb.so,雖然找不到

bee314@DESKTOP-259SCE7:~$ ldd main
        linux-vdso.so.1 (0x00007fffc4a8a000)
        libb.so => not found
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5a07ce0000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f5a07efa000)

ldd好看一點,把libb.so移到/lib/x86_64-linux-gnu/(抄libc.so.6)

bee314@DESKTOP-259SCE7:~$ ldd main
        linux-vdso.so.1 (0x00007fffeb59a000)
        libb.so => /lib/x86_64-linux-gnu/libb.so (0x00007fe732bc0000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe7329c0000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fe732be1000)

Ref

Dynamic Linking Position-independent Code(PIC)