参照元†
- 関数や変数の名前をカーネルのシンボルテーブルに登録する。
- 他のモジュールから名前が見えるようになる。
- 関数内で宣言しても正常に動作しない。
- sym
- カーネルのシンボルテーブルに登録したいシンボルを指定する。
- sec
- シンボルテーブルを表すセクション(__ksymtab)に追加する文字列を指定する。
- 今のところ "_gpl", "_gpl_future" が使われている。
返り値†
#ifndef __GENKSYMS__
- __GENKSYMS__ が宣言されていないときに有効である。
#define __EXPORT_SYMBOL(sym, sec) \
extern typeof(sym) sym; \
- シンボルがオブジェクト外部にあるかもしれないと宣言(extern 宣言)する。
これによって別のオブジェクトで定義されている関数もリンク時に解決、
エクスポートできる。たぶん。
- なのでエクスポート専用のソースファイルが書けるはずです。
- typeof は gcc の拡張構文で、指定した変数の型を表す。
__CRC_SYMBOL(sym, sec) \
static const char __kstrtab_##sym[] \
- ここからステートメント開始 ----------
- シンボル名を定義する。
- ## はトークン連結演算子で、トークン同士を繋いで一つのトークンにする。
- 例えば __EXPORT_SYMBOL(hogehoge, "") なら sym に hogehoge を渡した
ことになるので、__kstrtab_hogehoge[] が宣言される。
__attribute__((section("__ksymtab_strings"))) \
- __attribute__ ディレクティブは gcc の拡張構文である。
コンパイラへの命令を書く場合に用いる。
- 上記の変数を __ksymtab_strings セクションに置きなさい、
とコンパイラに伝える。
= MODULE_SYMBOL_PREFIX #sym; \
- ここまでが 1つのステートメント ----------
- # はトークンを文字列リテラルに変換する演算子である。
プリプロセッサがシンボル名を勝手に " " で囲ってくれると思えば簡単?
- MODULE_SYMBOL_PREFIX は "" である。
- 連続する文字列リテラルは連結される(C の規則)ので、
例えば sym => hogehoge だとすると生成される文字列は "hogehoge" である。
static const struct kernel_symbol __ksymtab_##sym \
- ここからステートメント開始 ----------
- シンボルテーブルの要素を定義する。
__used \
- __attribute__( (__used) ) を理解できない古いコンパイラのために宣言する。
- 最適化で消されないため、そして「変数/関数が未使用」の警告を抑えるために使う。
__attribute__((section("__ksymtab" sec), unused)) \
- __ksymtab セクションに配置する。
sec に何か渡した(例: hoge)場合はその名前を
連結したセクション(例: __ksymtabhoge)に配置される。
- unused でも used でも同じはずだが、古い gcc(3.4 未満)だと
変数に対して __attribute__( (used) ) を宣言できないらしい。
= { (unsigned long)&sym, __kstrtab_##sym }
- ここまでが 1つのステートメント ----------
- シンボルテーブルの 1要素を定義する。
- まとめ
- sym: エクスポートすべきシンボル
- __kstrtab_##sym: カーネルが使うシンボルの名前 -> __ksymtab_strings セクションへ
- __ksymtab_##sym: シンボルテーブルの要素(シンボルのポインタと、名前のタプル) -> __ksymtab セクションへ
コメント†