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 tsubT: 代表该文件中已经有这个函数的实现代码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