靜態鏈接和動態鏈接
1.實例代碼
//add.c
#include"tmath.h" int tadd(int x,int y) { return x+y; } int tsub(int x,int y) { return x-y; }
//mul.c #include"tmath.h" int tmul(int x, int y) { return x*y; } int tdiv(int x,int y) { return x/y; }
//main.c #include<stdio.h> #include"tmath.h" int main(void) {int a = 8; int b = 2; printf("%d + %d = %d\n",a,b,tadd(a,b)); printf("%d - %d = %d\n",a,b,tsub(a,b)); printf("%d * %d = %d\n",a,b,tmul(a,b)); printf("%d / %d = %d\n",a,b,tdiv(a,b)); return 0; }
nm 二進制文件 ./a.out main.o [email protected]:~/unixc/day02$ nm add.o 0000000000000000 T tadd 0000000000000014 T tsub [email protected]:~/unixc/day02$ nm mul.o 0000000000000013 T tdiv 0000000000000000 T tmul [email protected]:~/unixc/day02$ nm main.o 0000000000000000 T main U printf U tadd U tdiv U tmul U tsub
T: 代表該文件中已經有這個函數的實現代碼
U: 代表該文件中使用了這個函數,但是沒有這個函數代碼的實現
有的函數在編譯的時候發生了鏈接,這個鏈接稱為靜態鏈接
有的函數在代碼加載到內存執行的時候,才發生鏈接,這個鏈接成為動態鏈接,也可以稱為延遲綁定。printf()在a.out中認為U
2.程序已經為目標文件的時候,需要和運行時文件鏈接,什麽是運行時文件
gcc *.o -v 查看鏈接的整個過程
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crti.o
/usr/lib/gcc/x86_64-linux-gnu/5/crtbegin.o
-L/usr/lib/gcc/x86_64-linux-gnu/5
-L/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu
-L/usr/lib/gcc/x86_64-linux-gnu/5/../../../../lib -L/lib/x86_64-linux-gnu
-L/lib/../lib
-L/usr/lib/x86_64-linux-gnu
-L/usr/lib/../lib
-L/usr/lib/gcc/x86_64-linux-gnu/5/../../..
add.o main.o mul.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed
/usr/lib/gcc/x86_64-linux-gnu/5/crtend.o
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crtn.o
crt1.o crti.o crtend.o ...
程序的入口是_start
而C程序的入口是main函數
C程序是函數構成,main函數和其他函數一樣,理清一個程序就需要清理函數之間的調用和被調用的關系
特定的操作系統有特定的框架和_start入口
2. 靜態庫的制作和使用
1.生成obj文件
gcc -c add.c mul.c
[email protected]:~/unixc/day02$ gcc -c add.c mul.c
[email protected]:~/unixc/day02$ ls
add.c add.o mul.c mul.o
2.生成靜態庫文件
ar -r libtmath.a add.o mul.o //libtmath.a 庫名為tmath,在前面加個lib,以.a為後綴
[email protected]:~/unixc/day02$ ar -r libtmath.a *.o
ar: creating libtmath.a
[email protected]:~/unixc/day02$ ls
add.c add.o libtmath.a mul.c mul.o
3.將目標文件和庫文件鏈接成可執行文件
gcc main.c -L. -ltmath
-L 指示庫文件所在的文件路徑
-l 指示庫文件
-I 指定頭文件的位置,Include
[email protected]:~/unixc/day02$ gcc main.c -L. -lpmath
[email protected]:~/unixc/day02$ ls
add.c add.o a.out libpmath.a main.c mul.c mul.o .h
[email protected]:~/unixc/day02$ a.out
8 + 2 = 10
8 - 2 = 6
8 * 2 = 16
8 / 2 = 4
3.動態庫的制定和使用
1.gcc -fPIC -c *.c
//這樣生成的是動態鏈接的目標文件,和靜態鏈接的目標文件不一樣
2.gcc -shared -o libptmath.so *.o //庫名為ptmath
3.gcc main.c -Lsrc -lptmath -Isrc
在這一步之前先要把動態庫文件加入到搜索路徑
4.如何查看可執行文件依賴哪些動態庫文件?
ldd 可執行程序
[email protected]:~/unixc$ ldd a.out
linux-vdso.so.1 => (0x00007ffeb9fc1000)
libptmath.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f61ada8c000)
/lib64/ld-linux-x86-64.so.2 (0x000055611599d000)
[email protected]:~/unixc$ echo $LD_LIBRARY_PATH
[email protected]:~/unixc$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:src
[email protected]:~/unixc$ echo $LD_LIBRARY_PATH
:src
[email protected]:~/unixc$ a.out
8 + 2 = 10
8 - 2 = 6
8 * 2 = 16
8 / 2 = 4
[email protected]:~/unixc$ ldd a.out
linux-vdso.so.1 => (0x00007fffcb7fe000)
libptmath.so => src/libptmath.so (0x00007f9657d02000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9657920000)
/lib64/ld-linux-x86-64.so.2 (0x000055628211d000
另外一種方法是sudo mv libptmath.so /lib
靜態鏈接和動態鏈接