青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

loop_in_codes

低調(diào)做技術(shù)__歡迎移步我的獨立博客 codemaro.com 微博 kevinlynx

淺析靜態(tài)庫鏈接原理

靜態(tài)庫的鏈接基本上同鏈接目標(biāo)文件.obj/.o相同,但也有些不同的地方。本文簡要描述linux下靜態(tài)庫在鏈接過程中的一些細節(jié)。

靜態(tài)庫文件格式

靜態(tài)庫遠遠不同于動態(tài)庫,不涉及到符號重定位之類的問題。靜態(tài)庫本質(zhì)上只是將一堆目標(biāo)文件進行打包而已。靜態(tài)庫沒有標(biāo)準(zhǔn),不同的linux下都會有些細微的差別。大致的格式wiki上描述的較清楚:

Global header
-----------------        +-------------------------------
File header 1       ---> | File name
File content 1  |        | File modification timestamp 
-----------------        | Owner ID
File header 2            | Group ID
File content 2           | File mode
-----------------        | File size in bytes
...                      | File magic
                         +-------------------------------

File header很多字段都是以ASCII碼表示,所以可以用文本編輯器打開。

靜態(tài)庫本質(zhì)上就是使用ar命令打包一堆.o文件。我們甚至可以用ar隨意打包一些文件:

$ echo 'hello' > a.txt && echo 'world' > b.txt
$ ar -r test.a a.txt b.txt
$ cat test.a
!<arch>
a.txt/          1410628755  60833 100   100644  6         `
hello
b.txt/          1410628755  60833 100   100644  6         `
world

鏈接過程

鏈接器在鏈接靜態(tài)庫時,同鏈接一般的.o基本相似。鏈接過程大致可以歸納下圖:

總結(jié)為:

  • 所有傳入鏈接器的.o都會被鏈接進最終的可執(zhí)行程序;鏈接.o時,會將.o中的global symbolunresolved symbol放入一個臨時表
  • 如果多個.o定義了相同的global symbol,那么就會得到多重定義的鏈接錯誤
  • 如果鏈接結(jié)束了,unresolved symbol表不為空,那么就會得到符號未定義的鏈接錯誤
  • .a靜態(tài)庫處理本質(zhì)上就是處理其中的每一個.o,不同的是,如果某個.o中沒有一個符號屬于unresolved symbol表,也就是鏈接器此時懷疑該.o沒有必要,那么其就會被忽略

可以通過一些代碼來展示以上過程。在開發(fā)C++程序時,可以利用文件靜態(tài)變量會先于main之前執(zhí)行做一些可能利于程序結(jié)構(gòu)的事情。如果某個.o(包含靜態(tài)庫中打包的.o)被鏈接進程序,那么其文件靜態(tài)變量就會先于main初始化。

// test.cpp
#include <stdio.h>

class Test {
public:
    Test() {
        printf("Test ctor\n");
    }
};

static Test s_test;

// lib.cpp
#include <stdio.h>

class Lib {
public:
    Lib() {
        printf("Lib ctor\n");
    }
};

static Lib s_lib;

// main.cpp
#include <stdio.h>

int main() {
    printf("main\n");
    return 0;
}

以上代碼main.cpp中未引用任何test.cpp``lib.cpp中的符號:

$ g++ -o test test.o lib.o main.o
$ ./test
Lib ctor
Test ctor
main

生成的可執(zhí)行程序執(zhí)行如預(yù)期,其鏈接了test.o``lib.o。但是如果把lib.o以靜態(tài)庫的形式進行鏈接,情況就不一樣了:為了做對比,基于以上的代碼再加一個文件,及修改main.cpp

// libfn.cpp
int sum(int a, int b) {
    return a + b;
}

// main.cpp
#include <stdio.h>

int main() {
    printf("main\n");
    extern int sum(int, int);
    printf("sum: %d\n", sum(2, 3));
    return 0;
}

libfn.olib.o創(chuàng)建為靜態(tài)庫:

$ ar -r libfn.a libfn.o lib.o
$ g++ -o test main.o test.o -lfn -L.
$ ./test
Test ctor
main
sum: 5

因為lib.o沒有被鏈接,導(dǎo)致其文件靜態(tài)變量也未得到初始化。

調(diào)整鏈接順序,可以進一步檢驗前面的鏈接過程:

# 將libfn.a的鏈接放在main.o前面

$ g++ -o test test.o -lfn main.o  -L.
main.o: In function `main':
main.cpp:(.text+0x19): undefined reference to `sum(int, int)'
collect2: ld returned 1 exit status

這個問題遇到得比較多,也有點讓人覺得莫名其妙。其原因就在于鏈接器在鏈接libfn.a的時候,發(fā)現(xiàn)libfn.o依然沒有被之前鏈接的*.o引用到,也就是沒有任何符號在unresolved symbol table,所以libfn.o也被忽略。

一些實踐

在實際開發(fā)中還會遇到一些靜態(tài)庫相關(guān)的問題。

鏈接順序問題

前面的例子已經(jīng)展示了這個問題。調(diào)整庫的鏈接順序可以解決大部分問題,但當(dāng)靜態(tài)庫之間存在環(huán)形依賴時,則無法通過調(diào)整順序來解決。

-whole-archive

-whole-archive選項告訴鏈接器把靜態(tài)庫中的所有.o都進行鏈接,針對以上例子:

$ g++ -o test -L. test.o -Wl,--whole-archive -lfn main.o -Wl,--no-whole-archive
$ ./test
Lib ctor
Test ctor
main
sum: 5

lib.o也被鏈接了進來。-Wl選項告訴gcc將其作為鏈接器參數(shù)傳入;之所以在命令行結(jié)尾加上--no-whole-archive是為了告訴編譯器不要鏈接gcc默認的庫

可以看出這個方法還是有點暴力了。

–start-group

格式為:

--start-group archives --end-group

位于--start-group --end-group中的所有靜態(tài)庫將被反復(fù)搜索,而不是默認的只搜索一次,直到不再有新的unresolved symbol產(chǎn)生為止。也就是說,出現(xiàn)在這里的.o如果發(fā)現(xiàn)有unresolved symbol,則可能回到之前的靜態(tài)庫中繼續(xù)搜索。

$ g++ -o test -L. test.o -Wl,--start-group -lfn main.o -Wl,--end-group
$ ./test
Test ctor
main
sum: 5

查看ldd關(guān)于該參數(shù)的man page還可以一窺鏈接過程的細節(jié):

The specified archives are searched repeatedly until no new undefined references are created. Normally, an archive is searched only once in the order that it is specified on the command line. If a symbol in that archive is needed to resolve an undefined symbol referred to by an object in an archive that appears later on the command line, the linker would not be able to resolve that reference. By grouping the archives, they all be searched repeatedly until all possible references are resolved.

嵌套靜態(tài)庫

由于ar創(chuàng)建靜態(tài)庫時本質(zhì)上只是對文件進行打包,所以甚至可以創(chuàng)建一個嵌套的靜態(tài)庫,從而測試鏈接器是否會遞歸處理靜態(tài)庫中的.o

$ ar -r libfn.a libfn.o
$ ar -r liboutfn.a libfn.a lib.o
$ g++ -o test -L. test.o main.o -loutfn
main.o: In function `main':
main.cpp:(.text+0x19): undefined reference to `sum(int, int)'
collect2: ld returned 1 exit status

可見鏈接器并不會遞歸處理靜態(tài)庫中的文件

之所以要提到嵌套靜態(tài)庫這個問題,是因為我發(fā)現(xiàn)很多時候我們喜歡為一個靜態(tài)庫工程鏈接其他靜態(tài)庫。當(dāng)然,這里的鏈接并非真正的鏈接(僅是打包),這個過程當(dāng)然可以聰明到將其他靜態(tài)庫里的.o提取出來然后打包到新的靜態(tài)庫。

如果我們使用的是類似scons這種封裝更高的依賴項管理工具,那么它是否會這樣干呢?

基于之前的例子,我們使用scons來創(chuàng)建liboutfn.a

# Sconstruct
StaticLibrary('liboutfn.a', ['libfn.a', 'lib.o'])

使用文本編輯器打開liboutfn.a就可以看到其內(nèi)容,或者使用:

$ ar -tv liboutfn.a
rw-r--r-- 60833/100   1474 Sep 14 02:59 2014 libfn.a
rw-r--r-- 60833/100   2448 Sep 14 02:16 2014 lib.o

可見scons也只是單純地打包。所以,在scons中構(gòu)建一個靜態(tài)庫時,再鏈接其他靜態(tài)庫是沒有意義的

參考文檔

posted on 2014-09-15 22:47 Kevin Lynx 閱讀(4309) 評論(2)  編輯 收藏 引用 所屬分類: c/c++

評論

# re: 淺析靜態(tài)庫鏈接原理 2014-09-16 08:52 ccsdu2009

受教了  回復(fù)  更多評論   

# re: 淺析靜態(tài)庫鏈接原理 2014-09-16 09:24 zuhd

最近干貨很多啊  回復(fù)  更多評論   

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产精品久久久久久模特| 一区在线免费| 亚洲综合不卡| 亚洲一区二区在线看| 国产精品三级视频| 久久精品午夜| 免费不卡欧美自拍视频| 亚洲美女视频在线免费观看| 亚洲乱码精品一二三四区日韩在线| 欧美日韩亚洲一区二区三区在线观看| 亚洲性夜色噜噜噜7777| 亚洲欧美韩国| 亚洲国产精品激情在线观看| 亚洲清纯自拍| 国产精品永久免费视频| 蜜乳av另类精品一区二区| 欧美国产日产韩国视频| 亚洲欧美成人一区二区三区| 久久精品人人做人人综合| 日韩视频一区二区| 午夜精品理论片| 亚洲美女在线国产| 午夜国产欧美理论在线播放 | 亚洲青涩在线| 国产精品欧美风情| 欧美成人影音| 国产精品一区二区三区四区| 亚洲大片免费看| 国产精品中文字幕欧美| 欧美激情在线狂野欧美精品| 国产精品久久久一区二区三区| 欧美~级网站不卡| 国产精品一卡二| 亚洲人成亚洲人成在线观看| 国产午夜精品在线| 99一区二区| 亚洲欧洲在线免费| 久久国产精品久久久久久久久久| 一区二区三欧美| 久久综合九色综合网站| 欧美在线视频一区| 欧美网站在线观看| 欧美激情中文字幕一区二区| 国产视频在线观看一区二区三区| 日韩特黄影片| 亚洲精品国产精品国自产在线 | 国产精品欧美日韩| 亚洲黄色av| 精品91免费| 欧美一区二区日韩| 欧美一区二区三区在| 欧美日韩高清区| 亚洲国产精品综合| 亚洲高清在线视频| 久热re这里精品视频在线6| 欧美在线观看视频一区二区三区| 欧美三级视频在线观看| 亚洲精品免费一区二区三区| 亚洲区一区二| 蜜桃伊人久久| 亚洲电影在线| 亚洲毛片在线看| 欧美伦理视频网站| 亚洲人成在线免费观看| 亚洲免费观看在线观看| 欧美国产一区视频在线观看| 亚洲国产成人久久综合| 99www免费人成精品| 欧美国产日韩在线| 日韩视频在线观看国产| 一区二区不卡在线视频 午夜欧美不卡'| 毛片av中文字幕一区二区| 亚洲电影免费观看高清完整版在线观看 | 国产精品久久久久aaaa樱花| 一本色道久久综合亚洲91| 亚洲天堂av在线免费观看| 国产精品igao视频网网址不卡日韩| 99re这里只有精品6| 亚洲一区不卡| 国产日韩亚洲| 美女视频黄免费的久久| 亚洲精品美女久久7777777| 在线一区亚洲| 国产精品自拍网站| 久久久久久夜| 亚洲人成在线影院| 午夜免费电影一区在线观看| 国产日韩精品一区观看 | 亚洲午夜激情网站| 久久精品99国产精品酒店日本| 狠狠色综合一区二区| 欧美阿v一级看视频| 日韩视频中文字幕| 久久久av毛片精品| 亚洲最黄网站| 国产视频在线观看一区二区| 快播亚洲色图| 亚洲影院色无极综合| 老色鬼久久亚洲一区二区| 99精品国产福利在线观看免费 | 久久尤物视频| 中日韩午夜理伦电影免费| 久久久亚洲影院你懂的| 一区二区三区av| 国产一区视频在线观看免费| 欧美激情亚洲自拍| 性久久久久久久| 亚洲欧洲一区二区三区| 久久九九热免费视频| 日韩图片一区| 国外视频精品毛片| 欧美午夜久久久| 美女露胸一区二区三区| 午夜精品久久久久久99热软件| 亚洲第一福利社区| 久久精品一区四区| 亚洲一区二区四区| 亚洲美洲欧洲综合国产一区| 韩国成人精品a∨在线观看| 欧美日韩午夜在线视频| 免费日韩av片| 久久午夜激情| 欧美诱惑福利视频| 亚洲男人的天堂在线观看| 亚洲精品日日夜夜| 亚洲国产成人久久综合一区| 久久免费视频在线| 久久国产精品一区二区| 亚洲欧美成人精品| 亚洲视频中文字幕| av成人老司机| 一本色道久久88综合日韩精品| 亚洲电影在线观看| 在线看视频不卡| 激情久久久久久| 韩国精品一区二区三区| 国产亚洲欧美另类一区二区三区| 国产精品福利网站| 国产精品国产三级国产aⅴ浪潮| 欧美激情第8页| 欧美精品久久久久久久久久| 欧美成人国产va精品日本一级| 久久蜜桃精品| 欧美成人一区二区| 欧美黄污视频| 欧美日韩一区二区免费视频| 欧美另类一区| 国产精品久久久久久久久借妻 | 久久九九精品99国产精品| 欧美影院在线| 久久青青草综合| 欧美成人高清| 欧美色另类天堂2015| 欧美午夜精品理论片a级按摩| 欧美午夜宅男影院在线观看| 国产精品大片wwwwww| 国产精品乱码一区二三区小蝌蚪 | 国产精品国产三级国产专播精品人| 欧美日韩国产黄| 国产精品免费福利| 国产日韩在线一区二区三区| 激情五月综合色婷婷一区二区| 亚洲国产成人精品视频 | 国产精品视频一区二区高潮| 国产农村妇女毛片精品久久莱园子 | 一区二区三区高清视频在线观看| 亚洲午夜一区| 久久精品国产亚洲高清剧情介绍 | aⅴ色国产欧美| 亚洲欧美精品一区| 久久久蜜桃一区二区人| 欧美成人免费视频| 欧美色播在线播放| 国产一区二区电影在线观看| 亚洲国产美女久久久久| 亚洲午夜一区二区三区| 久久久久久电影| 亚洲国产视频a| 午夜精品99久久免费| 蜜乳av另类精品一区二区| 国产精品高潮呻吟视频| 永久域名在线精品| 亚洲伊人网站| 欧美国产激情二区三区| 亚洲午夜国产成人av电影男同| 久久久久国色av免费观看性色| 欧美色图五月天| 亚洲大胆视频| 欧美亚洲在线| 99国产精品久久| 蜜臀av性久久久久蜜臀aⅴ| 国产精品久久| 亚洲免费高清视频| 六月婷婷一区| 亚洲欧美日韩精品久久| 欧美日本不卡| 最新亚洲电影| 久久亚洲精品欧美| 亚洲尤物在线视频观看| 欧美日韩国产丝袜另类|