GCCの強い記号と弱い記号と強い参照と弱い参照
5048 ワード
1.強い記号と弱い記号
1.1 u-bootとkernelの_weak指令
u-boot
およびkernel
は、関数を定義するために__weak
を比較的一般的に使用する.include\linux\compiler-gcc.h
において__weak
は、以下のように定義される.#define __weak __attribute__((weak))
GCC
が__attribute__((weak))
命令で定義した関数または変数を弱符号(Weak Symbol)と呼ぶが、実際にはこの命令の大部分は関数を定義するために使用され、変数を定義するために使用されることは少ない.コンパイラのデフォルト関数と初期化されたグローバル変数は強いシンボル(Strong Symbol)、初期化されていないグローバル変数は弱いシンボル(Weak Symbol)です.
1.2強い記号と弱い記号のリンク規則
<>第3章では,この強弱記号のリンク規則をよくまとめた.
強弱シンボルの概念に対して、リンクは次のルールに従って、複数回定義されたグローバルシンボルを処理し、選択します.
int a=0
など)が複数回定義されている場合、コンパイラはmultiple definition
のエラーを報告し、比較的一般的です.複数回定義されたグローバル関数も、関数名もシンボル変数であるため、その後定義された関数体を指すだけでなく、この変数は読み取り専用であり、変更できません.これも、関数名を変数に割り当てることができますが、関数名に値を割り当てることができない理由です.
u-boot
とkernel
の中で最もよく使われるテクニックです.まず、
__weak
のu-boot
のファイルヘッダなど、プラットフォームに関係のないコードにboard_f.c
の属性の関数を定義します.__weak void coloured_LED_init(void) {}
__weak void red_led_on(void) {}
__weak void red_led_off(void) {}
__weak void green_led_on(void) {}
__weak void green_led_off(void) {}
__weak void yellow_led_on(void) {}
__weak void yellow_led_off(void) {}
__weak void blue_led_on(void) {}
__weak void blue_led_off(void) {}
これらの
led
に関連する機能が必要であれば、関連するファイルでこれらの関数を再定義して実装すればよい.例えば、ファイルled
でマクロgpio_led.c
が開いたときにCONFIG_GPIO_LED_STUBS
を呼び出してこれらの関数を再実装する.2.強引用と弱引用
<>第三章では、強引用と弱引用についても説明した.
弱参照と強参照現在私たちが見ている外部ターゲットファイルに対するシンボル参照は、ターゲットファイルが最終的に実行可能ファイルにリンクされている場合、それらは正しく決定されなければならない.このシンボルの定義が見つからないと、リンクはシンボルが定義されていないエラーを報告し、これを強適用(Strong Reference)と呼ぶ.これに対応して、弱い参照を処理する際に、その記号に定義がある場合、リンクはその記号の参照を決定する弱い参照(Weak Reference)がある.シンボルが定義されていない場合、リンクは参照に対してエラーを報告しません.リンクが強い参照と弱い参照を処理するプロセスはほとんど同じですが、定義されていない弱い参照では、リンクはエラーとは思いません.一般に、未定義の弱い参照の場合、リンクはデフォルトで0、またはプログラムコードが認識できるように特別な値です.
__led_set
では、GCC
拡張キーワードを使用して、外部関数への参照を弱い参照として宣言することができます.たとえば、次のコードがあります.__attribute__ ((weakref)) void foo();
int main()
{
foo();
}
__attribute__((weakref))
はリンクエラーを報告しない実行可能ファイルにコンパイルできます.しかし、この実行可能ファイルを実行すると、実行エラーが発生します.GCC
関数がmain
関数を使用しようとすると、foo
関数のアドレスが0であるため、不正なアドレスアクセスエラーが発生する.1つの改善例は、__attribute__ ((weakref)) void foo();
int main()
{
if (foo) foo();
}
この弱い記号と弱い参照は、ライブラリで定義された弱い記号がユーザー定義の強い記号で上書きされ、プログラムがカスタムバージョンのライブラリ関数を使用できるようにするなど、ライブラリにとって非常に有用である.あるいは、プログラムはいくつかの拡張機能モジュールの参照を弱い参照として定義することができ、拡張モジュールをプログラムに接続すると、機能モジュールは正常に使用することができます.いくつかの機能モジュールを削除すると、プログラムも正常にリンクできますが、対応する機能が欠けているだけで、プログラムの機能がより簡単に切り取られ、組み合わせられます.
foo
とu-boot v2016.09
のコードを専門にチェックしたが,弱いインデックスを用いて関数を定義する場合は見つからず,あまり一般的ではないことが分かった.4.その他
弱符号(Weak Symbol)および弱参照については、
linux v3.3-3.8
ツールチェーンGNU
対GCC
言語文法の拡張のみであり、C
自体の言語特性ではない.マイクロソフトのC
といえば、弱い記号や弱い参照特性はサポートされていません.