首页 > 代码库 > 静态链接和动态链接

静态链接和动态链接

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
        
            gaojia@Inspiron:~/unixc/day02$ nm add.o
            0000000000000000 T tadd
            0000000000000014 T tsub
            gaojia@Inspiron:~/unixc/day02$ nm mul.o
            0000000000000013 T tdiv
            0000000000000000 T tmul
            gaojia@Inspiron:~/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

  gaojia@Inspiron:~/unixc/day02$ gcc -c add.c mul.c
  gaojia@Inspiron:~/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为后缀

  gaojia@Inspiron:~/unixc/day02$ ar -r libtmath.a *.o
  ar: creating libtmath.a
  gaojia@Inspiron:~/unixc/day02$ ls
  add.c  add.o  libtmath.a  mul.c  mul.o

  3.将目标文件和库文件链接成可执行文件

  gcc main.c -L. -ltmath

  -L  指示库文件所在的文件路徑

  -l  指示库文件
  -I  指定头文件的位置,Include

  gaojia@Inspiron:~/unixc/day02$ gcc  main.c -L. -lpmath
  gaojia@Inspiron:~/unixc/day02$ ls
  add.c  add.o  a.out  libpmath.a  main.c  mul.c  mul.o  .h
  gaojia@Inspiron:~/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 可执行程序
       gaojia@Inspiron:~/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)

    gaojia@Inspiron:~/unixc$ echo $LD_LIBRARY_PATH
    gaojia@Inspiron:~/unixc$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:src
    gaojia@Inspiron:~/unixc$ echo $LD_LIBRARY_PATH
    :src
    gaojia@Inspiron:~/unixc$ a.out
    8 + 2 = 10
    8 - 2 = 6
    8 * 2 = 16
    8 / 2 = 4

    gaojia@Inspiron:~/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

    

  

 

  

静态链接和动态链接