Liunx链接库生成与链接原理

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可以实现编译的自动化。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容