GNU C/C++ __attributes__ GCCの弱い記号と強い記号

9308 ワード

最近いくつかのソースコードを見て、いくつかの使用に遭遇しました_attribute__関数や変数の属性を修飾するコードは、あまり知られていないので、汗をかいています.
 
GCC使用_attribute__キーワードは、コンパイラによるソースコードの最適化に使用される関数、変数、およびデータ型のプロパティを記述します.
関数のプロパティを記述するいくつかの重要なキーワード:
 
void noreturnfun() __attribute__((noreturn));//関数は返されません.
  • void centon() __attribute__((alias("__centon")));//関数の別名を設定します.関数は__です.cencon、別名centon.
  • void main_enter() __attribute__((constructor));//main_enter関数はmain関数に入る前に
  • を呼び出す
  • void main_exit() __attribute__((destructor));//main_exit関数main関数が戻った後に
  • を呼び出す
  • void fun() __attribute__ ((noinline));//fun関数はinline関数として最適化できない
  • void fun() __attribute__ ((section(「specials」)は、通常のtextセグメントではなくspecialsセグメントに関数を配置します.
  • no_instrument_function、constructor、destructorキーワードは、主にソースコードのプロファイリングに使用されます.
  • __attribute_(format(archetype,string-index,first-to-check):format attributeはprintf,scanf,strftime,strfmonタイプ関数のパラメータフォーマットに従ってターゲット関数のタイプを検査する.
  • __attribute_((weak):weak symbol、弱記号.同じグローバル記号が2つ存在すると再定義エラーが発生します.weak attributeを使用すると、weak symbolとnon-weak symbolが同時に存在する場合、linkerはnon-weak symbolを使用します.weak symbolのみ存在する場合はweak symbol.
  • のみを使用します.
  • __attribute_((deprecated):deprecated,廃棄.ソースファイルがどこでもdeprecated attribute関数を使用すると、コンパイラは警告を発行します.
  • __attribute_((aligned(ALIGNMENT):変数または構造体の最小バイト数をbyte単位で指定する.ALIGNMENT:指定バイト数を揃える. 
  • _attribute_((cleanup(cleanup_function):変数の役割ドメインが消失すると、後続のclean_function関数が実行される.
  • __attribute_((packed):変数または構造体を最小の整列方式で変数に対して1 byte整列、フィールドに対してfieldはbit整列を指す. 

  • 上記は一般的ないくつかの属性操作の説明にすぎず、他の使い方については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」と「weak 2」は弱い記号であり、「strong」と「main」は強い記号であり、「ext」は強い記号でも弱い記号でもない.外部変数の参照であるからだ.
    強弱シンボルの概念では、リンクは、複数定義されたグローバルシンボルを次のルールで処理し、選択します.
    ルール1:強いシンボルが複数回定義されることは許されません(つまり、異なるターゲットファイルに同じ名前の強いシンボルが存在してはいけません).複数の強いシンボル定義がある場合、リンクはシンボルの繰り返し定義エラーを報告します.
    ルール2:1つのシンボルがターゲットファイルに強いシンボルであり、他のファイルに弱いシンボルがある場合は、強いシンボルを選択します.
    ルール3:1つのシンボルがすべてのターゲットファイルの中で弱いシンボルである場合、その中で最も占有スペースが大きいものを選択します.たとえば、ターゲットファイル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プログラムの設計では、1つのプログラムが単一スレッドまたはマルチスレッドのモードをサポートできるように設計されている場合、現在のプログラムが単一スレッドのGlibcライブラリにリンクされているか、マルチスレッドのGlibcライブラリにリンクされているか(コンパイル時に-lpthreadオプションがあるか)を弱い参照で判断することができる.を選択して、単一スレッドバージョンのプログラムまたはマルチスレッドバージョンのプログラムを実行します.pthread_create関数の弱い参照をプログラムで定義し、実行時にpthreadライブラリにリンクするかどうかを動的に判断して、マルチスレッドバージョンまたは単一スレッドバージョンを実行するかどうかを決定します.
    #include <stdio.h>
    #include <pthread.h>
    int pthread_create( pthread_t*, const pthread_attr_t*,
    void* (*)(void*), void*) __attribute__ ((weak));
    int main()
    {
        if(pthread_create)
        {
                printf("This is multi-thread version!
    "); // run the multi-thread version // main_multi_thread() } else { printf("This is single-thread version!
    "); // run the single-thread version // main_single_thread() } }

    コンパイルの実行結果は次のとおりです.
    $ gcc pthread.c -o pt
    $ ./pt
    This is single-thread version!
    $ gcc pthread.c -lpthread -o pt
    $ ./pt
    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.