美文网首页
Liunx链接库生成与链接原理

Liunx链接库生成与链接原理

作者: 小小混世魔王 | 来源:发表于2019-05-17 17:25 被阅读0次

Android是一种基于Linux的开放源代码的操作系统,在之前写的OpenCV人脸校验,人脸识别文中https://www.jianshu.com/p/b833d0d8af80。文中提到Liunx平台下怎么编译so库问题。接下啦我们就来具体看看单个C文件的编译过程。

1.gcc 编译步骤

以hello.c文件为例

#include<stdio.h>
#define TAG "yang"

void main()
{
   printf("hello world %s",TAG);
}

gcc -o hello hello.c 

通过gcc -o hello hello.c命令 经过一系列的操作将hello.c文件编译打包成一个hello的可执行项目。.c文件-->可执行文件经历了哪些步骤呢?接下來把gcc编译打包成执行文件过程拆开。
1.预处理阶段:

gcc -E -o hello.i hello.c

通过gcc -E的命令将.c文件生成.i文件。用vim查看.i文件的内容,发现.i文件的内容非常的多,从中复制一段

  省略代码多行.........

extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
# 868 "/usr/include/stdio.h" 3 4

# 2 "hello.c" 2




# 5 "hello.c"
void main()
{
   printf("hello world %s","yang");
}

上面内容看到 stdio.h 的内容都插到文件里去了,包括printf()函数里面的TAG 已近替换上了具体的字符串“yang”。可以得知gcc编译的第一阶段预处理阶段是将源文件中引入的头文件进行展开,define的清除,注释的删除,包括宏定义的替换等。
2.编译阶段:

gcc -S -o hello.s hello.i

执行gcc -S命令将.i文件编成.s文件,查看.s文件的内容如下

        .file   "hello.c"
        .section        .rodata
.LC0:
        .string "yang"
.LC1:
        .string "hello world %s"
        .text
        .globl  main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        leaq    .LC0(%rip), %rsi
        leaq    .LC1(%rip), %rdi
        movl    $0, %eax
        call    printf@PLT
        nop
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .ident  "GCC: (Ubuntu 7.2.0-8ubuntu3.2) 7.2.0"
        .section        .note.GNU-stack,"",@progbits

相比.i文件.s文件内容又少了,但是似乎我们看的并不是太懂。gcc -S这个过程将c代码翻译成汇编代码包括词法分析、语法分析、语义分析等。
3.汇编阶段

gcc -c hello.o -o hello.s

这个时候我们在去查看文件发现是乱码。这个过程将第二阶段生产的汇编代码编译成机器可执行的指令。
4.链接阶段(链接静态库,动态库)

gcc -o hello hello.o

由于源文件会用到其他库的函数,在这个过程会去计算逻辑地址,合并数据段等。

2.静态库与动态库

2.1静态库的制作
以mathUtils,c为例编译成.a静态库。

#include<stdio.h>

int add(int a,int b) {

     return a+b;

}

2.1.1生成目标.o文件

gcc -c mathUtils.c -o mathUtils.o 此过程生成.o文件但是不会去链接库。

2.1.2将目标文件进行打包

ar cvr myMathUtils.a mathUtils.o

2.1.3这样静态库就生成了。接着以来看看怎么使用链接这个静态库。以statictest.c为例

#include<stdio.h>
#include "mathUtils.c"

void main(){
    int a = 10;
    int b = 10;
    int result = add(a,b);
    printf("result = %d",result);

}

将statictest.c编译成.o文件不去链接

gcc -c statictest.c -o statictest.o

接下来我们就去链接myMathUtils.a库

gcc -o statictest statictest.o libmathUtils.a

这个过程链接libmathUtils.a库并生成可执行文件statictest 。
statictest 运行效果


statictest.jpg

2.1.4链接静态库的原理:
objdump 反汇编

objdump -S statictest > test.txt
反汇编.png

可以看到我标记的红色的重要地方,这些就是链接过程中计算逻辑地址(相对的地址),main()函数调用add()函数 是 callq 64a <add>固定地址值,指向 000000000000064a <add> 地址,也就是add函数的相对地址。
通过分析可以得出,一个项目引入静态库中的函数,就相当于拷贝了静态库中的函数。所以编译过的项目,即使没有静态库,项目也是可以运行的。
静态库的缺点:
(1)同一个模块被多个模块链接时,那么这个模块在磁盘和内存中都有多个副本,导致很大一部分空间被浪费了。
(2)当程序的任意一个模块发生更新时,整个程序都要重新链接。

2.2动态库的制作:
2.2.1 将 .c文件生成与位置无关的目标.o文件

gcc -c mathUtils.c -o mathUtils.o -fPIC

2.2.2使用 gcc -shared 制作动态库

gcc -shared mathUtils.o -o libmathUtils.so

2.2.3 编译sharedtest.c 不去链接.so库

gcc -c sharedtest.c -o sharedtest.o

2.2.4链接动态库并生成可执行文件

gcc -o sharedtest sharedtest.o libmathUtils.so

2.2.5动态库链接原理:
我们依旧使用上图(反汇编图)来分析动态库的链接原理,上面我们在main()函数中用到了printf()函数,调用时是callq 520 < printf@plt> 。
Plt(延迟绑定),程序引用了动态库,在没有运行程序时链接函数的地址是不确定的,要运行程序就必须先加载动态库与动态链接器到进程地址空间,系统运行可执行文件之前,会将控制权交给动态链接器,由它完成所有的动态链接工作以后再把控制权交给可执行文件。这样就链接到函数地址。
动态库的缺点:
(1)链接的过程是在程序运行之后开始的,并经过链接器一系列的寻址,才能链接到函数,会导致程序运行效率变慢。

小结:

上面介绍单个c文件的编译过程,对于整个项目包含许多c文件,编译项目采用Makefile文件。Makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译。Makefile的编写基于单个文件编译过程。通过Makefile可以实现编译的自动化。

相关文章

  • Liunx链接库生成与链接原理

    Android是一种基于Linux的开放源代码的操作系统,在之前写的OpenCV人脸校验,人脸识别文中https:...

  • Linux链接库

    动态链接库(共享链接库) 杂项 生成.o文件 生成.so 使用动态库 静态链接库 杂项 生成.a 查看.a 使用静态库

  • 静态链接库

    如何创建静态链接库 vs新建项目,选择静态链接库 在项目文件中新建 .cpp 文件与.h 文件 项目编译生成后会产...

  • JNI的静态注册和动态注册,及输出乱码解决

    [TOC] clang 生成动态链接库 命令介绍 不同操作系统的动态链接库后缀不相同 Windows里动态链接库后...

  • 操作系统 - 存储管理

    存储器工作原理 程序链接 链接库 静态链接 程序装载到内存和运行前链接 动态链接 内存一边装载程序一边链接,生成可...

  • iOS应用版本之动态更新

    步骤说明 步骤如下: 制作framework 生成framework动态链接库 远程下载到动态链接库到沙盒 如何引...

  • makefile-动态链接库(*.so)

    目录文件 hello.c hello.h 生成动态链接库libhello.so main.c 内容 使用动态链接库...

  • C# 静态调用C++ 生成的dll,即非托管dll

    C++文集板块有一节《C++ 如何生成一个DLL动态链接库》已经讲述了,C++如何生成一个动态链接库CPPDLLD...

  • 在Qt中创建和使用静态链接库

    扫盲 静态链接库是什么? 将自己设计的类导出为二进制形式的可执行代码。静态链接库有两种形式 MSVC编译器生成的文...

  • 静态链接库与动态链接库

    通常,对函数库的链接是放在编译时期(compile time)完成的。所有相关的对象文件(object file,...

网友评论

      本文标题:Liunx链接库生成与链接原理

      本文链接:https://www.haomeiwen.com/subject/bllbaqtx.html