2011-06-22 14 views
11

最終的な質問から始めましょう:gccのCでは、__func__(または同等には、__FUNCTION__)の値を取得できますか? .rodata(または-mrodata=ポイント)またはそのサブセクション以外のセクションでは、特定のコンパイラ生成変数を特定のELFセクションに強制する

十分な説明:

私はログマクロを持って言う:

#define LOG(fmt, ...) log_internal(__FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) 

(その単項文脈で使用される文字列連結演算子##があれば、前にカンマを消費し、__VA_ARGS__リストが空の場合にのみこれにより、引数の有無にかかわらず書式文字列を使用できるようになります)。

マクロは通常次のように使用できます。

void my_function(void) { 
    LOG("foo!"); 
    LOG("bar: %p", &bar); 
} 

log_internalの実装に依存明らかに)印刷されることがあります

foo.c:201(my_function) foo! 
foo.c:202(my_function) bar: 0x12345678 

この場合、フォーマット文字列("foo""bar: %p")とプリプロセッサ文字列("foo.c""my_function")はデータのみを読んで、匿名です自動的に.rodataセクションに配置されます。

しかし、私はそれらを別の場所に移動したいと言います(私は、スピードはRAMのほとんどすべてを実行する組み込みプラットフォームですが、いくつかのものをROMに移動するためにはメモリの制約があります)。それは__FILE__と書式文字列を移動するには、「簡単」だ:

#define ROM_STR(str) (__extension__({static const __attribute__((__section__(".rom_data"))) char __c[] = (str); (const char *)&__c;})) 
#define LOG(fmt, ...) log_internal(ROM_STR(__FILE__), __LINE__, __func__, ROM_STR(fmt), ##__VA_ARGS__) 

評価し、その後、あなたが匿名の文字列に__attribute__を置くことができないので、ROM_STRマクロはそれを過渡名前を与え、特定のセクションにそれを貼付します開始アドレスに移動するので、きれいに置き換えることができます。これは、変数をフォーマット文字列としてLOGに渡そうとすると機能しませんが、そのユースケースを除外します。

通常、同一である匿名の文字列は、コンパイラによって1つの格納場所に結合されるため、1つのファイル内のすべてのインスタンス__FILE__は同じ実行時アドレスを共有します。 ROM_STRの明示的な命名では、各インスタンスは独自の格納場所を取得するため、__FILE__で実際に使用するのは実際には意味がありません。

しかし、私は__func__で使用したいと思います。問題は__func____FILE__と同じ種類の魔法ではないということです。

かのように識別子__func__が暗黙的に翻訳者によって宣言され、すぐに各関数定義の開口ブレース以下、宣言

static const char __func__[] = "function-name"; 
:gccのマニュアル、「文字列として関数名」から

が表示されます。ここで、function-nameは語彙を囲む関数の名前です。この名前は、機能の未装飾の名前です。 ... これらの識別子はプリプロセッサマクロではありません。 GCC 3.3以前とCのみでは、__FUNCTION____PRETTY_FUNCTION__は文字列リテラルとして扱われました。 char配列を初期化するために使うことができ、他の文字列リテラルと連結することができます。 GCC 3.4以降では、__func__のように変数を変数として扱います。

したがって、あなたがROM_STR__func__をラップしている場合、あなたは

error: invalid initializer 

を取得し、あなたが__func__の使用前または後のセクション属性を置くしようとした場合、あなたは

error: expected expression before ‘__attribute__’ 

を取得しますまたは

error: expected ‘)’ before ‘__attribute__’ 

それでは、オープニングの質問に戻ります:自分が選んだセクションに__func__を保存することはできますか?おそらく-fdata-sectionsを使用して、.rodata.__func__.*.rodataの残りから除外するには、リンカスクリプトの魔法を使うことができますか?もしそうなら、リンカスクリプトで除外を使ってグロブするための構文は何ですか?言い換えれば、*(.rodata*)のどこかに - 私はを別の場所に置くことができますが、2つのコピーを取得しないように元のglobを変更して除外する必要があります。

答えて

2

私は最後に-fdata-sectionsビジネスで私自身の質問に答えたようですが、私はGNUリンカを見て分かりませんでした。 ビットを最初に指定している限り、実際に除外を行うグロビングは必要ありません。グロブに一致するセクションには使用済みとしてマークされますので、*(.rodata*)の後のグロブはそれらを二重にカウントして別の場所にコピーしません。私はROM_STRでそれらをタグ付けする必要は全くありません。クール!

-fdata-sectionsは実際には各ファンクション文字列を独自の.rodata.__func__.1234セクションに配置していることに注意してください(数字がどんなパターンに従うかはわかりません)。匿名の文字列も独自のセクションを取得するかどうかはわかりません。そうであれば、同じリンカートリックを使用して、ROM_STRセクション属性マクロの代わりにすべての無名文字列を取り込むことができますが、おそらく悪い考えです。 ROM_STRLOGマクロで使用されるため、ロギングフォーマット文字列にのみ適用されることが保証されています。リンカトリックですべての無名文字列をROMに強制すると、通常のメッセージデータが含まれていて、フラッシュからアクセスするにはランタイムパフォーマンスペナルティを支払うことになります。だから私はそれが可能なのかどうかはわかりませんが、その妥当性はあなたの特定のシステム要件に依存します。

+0

便利な[リンカースクリプトの構文への参照](http://www.xgc.com/manuals/gcc-1750-ug/p5node10.html) –

+1

2015年の時点で、gccはこれを行わなくなりました。参照:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=192 –

3

あなたが望むよりも面白いかもしれない1つのアプローチは、コンパイルとアセンブリの間でセクション名を変更するスクリプトを挿入することです。例:

gcc -fdata-sections -S -o test.s test.c 
sed 's/^\t.section\t\.rodata\.__func__\.[0-9]*/\t.section .rom_data/' -i test.s 
gcc -c test.s 

また、あなたの選択したセクションに__func__宣言を配置する打ち鳴らす変換パスを書き、またはlibbfdを使用して、オブジェクトファイル操作プログラムを書いてみてください。

+0

中間アセンブリファイルのセクションの名前を変更する2つのステップのプロセスは間違いなく機能すると思います。特別な(些細ではない)スマートでは、 '-fdata-sections'なしでビルドした場合、スクリプトは適切なデータを選ぶことさえ可能かもしれません。しかし、私の実験とリンカースクリプトのさらなる読書は、私がこれらのセクションを明示的に配置すると思ったよりずっと簡単であることを示しています。 –

+0

また、BFDへのリンクは+1です。それは多くのことにとって便利なことかもしれません。 –

関連する問題