• <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>

            大龍的博客

            常用鏈接

            統計

            最新評論

            GCC中的弱符號與強符號

            我們經常在編程中碰到一種情況叫符號重復定義。多個目標文件中含有相同名字全局符號的定義,那么這些目標文件鏈接的時候將會出現符號重復定義的錯誤。比如我們在目標文件A和目標文件B都定義了一個全局整形變量global,并將它們都初始化,那么鏈接器將A和B進行鏈接時會報錯:
            1 b.o:(.data+0x0): multiple definition of `global'
            2 a.o:(.data+0x0): first defined here

             

                    這種符號的定義可以被稱為強符號(Strong Symbol)。有些符號的定義可以被稱為弱符號(Weak Symbol)。
            對于C/C++語言來說,編譯器默認函數和初始化了的全局變量為強符號,未初始化的全局變量為弱符號。我們也可以通過GCC的"__attribute__((weak))"來定義任何一個強符號為弱符號。注意,強符號和弱符號都是針對定義來說的,不是針對符號的引用。比如我們有下面這段程序:
            extern int ext;
            int weak;
            int strong = 1;
            __attribute__((weak)) weak2 = 2;
            int main()
            {
                    return 0;
            }

             
            上面這段程序中,"weak"和"weak2"是弱符號,"strong"和"main"是強符號,而"ext"既非強符號也非弱符號,因為它是一個外部變量的引用。
            針對強弱符號的概念,鏈接器就會按如下規則處理與選擇被多次定義的全局符號:
            規則1:不允許強符號被多次定義(即不同的目標文件中不能有同名的強符號);如果有多個強符號定義,則鏈接器報符號重復定義錯誤。
            規則2:如果一個符號在某個目標文件中是強符號,在其他文件中都是弱符號,那么選擇強符號。
            規則3:如果一個符號在所有目標文件中都是弱符號,那么選擇其中占用空間最大的一個。比如目標文件A定義全局變量global為int型,占4個字節;目標文件B定義global為double型,占8個字節,那么目標文件A和B鏈接后,符號global占8個字節(盡量不要使用多個不同類型的弱符號,否則容易導致很難發現的程序錯誤)。

            弱引用和強引用 

            目前我們所看到的對外部目標文件的符號引用在目標文件被最終鏈接成可執行文件時,它們須要被正確決議,如果沒有找到該符號的定義,鏈接器就會報符號未定義錯誤,這種被稱為強引用(Strong Reference)。與之相對應還有一種弱引用(Weak Reference),在處理弱引用時,如果該符號有定義,則鏈接器將該符號的引用決議;如果該符號未被定義,則鏈接器對于該引用不報錯。鏈接器處理強引用和弱引用的過程幾乎一樣,只是對于未定義的弱引用,鏈接器不認為它是一個錯誤。一般對于未定義的弱引用,鏈接器默認其為0,或者是一個特殊的值,以便于程序代碼能夠識別。
            在GCC中,我們可以通過使用"__attribute__((weakref))"這個擴展關鍵字來聲明對一個外部函數的引用為弱引用,比如下面這段代碼:
            1 __attribute__ ((weakref)) void foo();
            2 int main()
            3 {
            4         foo();
            5 }
            6

             
            我們可以將它編譯成一個可執行文件,GCC并不會報鏈接錯誤。但是當我們運行這個可執行文件時,會發生運行錯誤。因為當main函數試圖調用foo函數時,foo函數的地址為0,于是發生了非法地址訪問的錯誤。一個改進的例子是:
            1 __attribute__ ((weakref)) void foo();
            2 int main()
            3 {
            4         if (foo)
            5                foo();
            6 }
            7

             
                  這種弱符號和弱引用對于庫來說十分有用,比如庫中定義的弱符號可以被用戶定義的強符號所覆蓋,從而使得程序可以使用自定義版本的庫函數;或者程序可以對某些擴展功能模塊的引用定義為弱引用,當我們將擴展模塊與程序鏈接在一起時,功能模塊就可以正常使用;如果我們去掉了某些功能模塊,那么程序也可以正常鏈接,只是缺少了相應的功能,這使得程序的功能更加容易裁剪和組合。
                  在Linux程序的設計中,如果一個程序被設計成可以支持單線程或多線程的模式,就可以通過弱引用的方法來判斷當前的程序是鏈接到了單線程的Glibc庫還是多線程的Glibc庫(是否在編譯時有-lpthread選項),從而執行單線程版本的程序或多線程版本的程序。我們可以在程序中定義一個pthread_create函數的弱引用,然后程序在運行時動態判斷是否鏈接到pthread庫從而決定執行多線程版本還是單線程版本:
             1 #include <stdio.h>
             2 #include <pthread.h>
             3 int pthread_create( pthread_t*, const pthread_attr_t*,
             4 void* (*)(void*), void*) __attribute__ ((weak));
             5 int main()
             6 {
             7     if(pthread_create)
             8     {
             9             printf("This is multi-thread version!\n");
            10             // run the multi-thread version
            11             // main_multi_thread()
            12     }
            13     else
            14     {
            15             printf("This is single-thread version!\n");  
            16             // run the single-thread version
            17             // main_single_thread()
            18     }
            19 }
            20

             
            編譯運行結果如下:
            1 $ gcc pthread.c -o pt
            2 $ ./pt
            3 This is single-thread version!
            4 $ gcc pthread.c -lpthread -o pt
            5 $ ./pt
            6 This is multi-thread version!

             

            在GCC的官方文檔中,對weak和weakref的描述如下:
            http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html#Function-Attributes

            weak
            The weak attribute causes the declaration to be emitted as a weak symbol rather than a global. This is primarily useful in defining library functions which can be overridden in user code, though it can also be used with non-function declarations. Weak symbols are supported for ELF targets, and also for a.out targets when using the GNU assembler and linker.

            weakref
            weakref ("target")
            The weakref attribute marks a declaration as a weak reference.
            Without arguments, it should be accompanied by an alias attribute naming the target symbol. Optionally, the target may be given as an argument to weakref itself. In either case, weakref implicitly marks the declaration as weak. Without a target, given as an argument to weakref or to alias, weakref is equivalent to weak.
            1     static int x() __attribute__ ((weakref ("y")));
            2     /* is equivalent to... */
            3     static int x() __attribute__ ((weak, weakref, alias ("y")));
            4     /* and to... */
            5     static int x() __attribute__ ((weakref));
            6     static int x() __attribute__ ((alias ("y")));

             
                
            A weak reference is an alias that does not by itself require a definition to be given for the target symbol. If the target symbol is only referenced through weak references, then the becomes a weak undefined symbol. If it is directly referenced, however, then such strong references prevail, and a definition will be required for the symbol, not necessarily in the same translation unit.
            The effect is equivalent to moving all references to the alias to a separate translation unit, renaming the alias to the aliased symbol, declaring it as weak, compiling the two separate translation units and performing a reloadable link on them.
            At present, a declaration to which weakref is attached can only be static.

            posted on 2010-05-23 21:50 大龍 閱讀(818) 評論(0)  編輯 收藏 引用

            精品无码久久久久久久久久| 久久超乳爆乳中文字幕| 欧美精品福利视频一区二区三区久久久精品 | 香蕉久久av一区二区三区| 97久久天天综合色天天综合色hd| 99久久精品无码一区二区毛片 | 欧美精品福利视频一区二区三区久久久精品| 久久久青草青青国产亚洲免观| 亚洲精品无码成人片久久| 久久线看观看精品香蕉国产| 欧美与黑人午夜性猛交久久久| av无码久久久久久不卡网站| 亚洲精品成人久久久| 青青热久久综合网伊人| 亚洲午夜无码久久久久| 日本高清无卡码一区二区久久| 国产精品久久久久久久久鸭| 麻豆精品久久久久久久99蜜桃| 国产99久久久久久免费看| 狠狠色丁香久久婷婷综合五月| 一97日本道伊人久久综合影院| 亚洲乱亚洲乱淫久久| 久久国产热精品波多野结衣AV| 久久无码专区国产精品发布| 手机看片久久高清国产日韩 | 国产亚洲美女精品久久久2020| 久久综合日本熟妇| 亚洲日韩欧美一区久久久久我| 久久久久久国产精品美女| 久久国产成人精品国产成人亚洲| 久久精品九九亚洲精品天堂| 2021久久国自产拍精品| 99久久久精品免费观看国产| 色综合久久中文字幕无码| 亚洲色欲久久久综合网东京热| 精品国产99久久久久久麻豆| 久久精品国产亚洲AV蜜臀色欲| 亚洲精品午夜国产VA久久成人| 欧美亚洲色综久久精品国产| 人妻无码αv中文字幕久久| 久久精品中文字幕无码绿巨人|