特定のリンカ セクションを使用してハンドラのレジストリを作成するプロジェクトをいくつか見てきました (次の例は、eCos の ahttpd 統合からのものです)。
アイデアは、異なるコンパイル ユニットからのエントリを同じグローバル レジストリにホックすることが可能でなければならないということです。
以下は、このパターンを機能させようとした単純な例ですが、プログラムの終了コードが 0 であり、3 であると予想していたため、明らかに何かが間違っています。
コードは移植可能である必要はありません。唯一のターゲットは Linux での GCC です。
これが私が試したことです:
#define HANDLER_TABLE_ENTRY(__var, __name, __val) \
handler_table_entry __var \
__attribute__((section (".my.handler_table.data"))) \
__attribute__((used)) = { __name, __val }
struct handler_table_entry {
const char *name;
int val;
} __attribute__((aligned(8)));
// Beginning of section
__asm__(".section \".my.handler_table.data\",\"aw\"\n"
".globl handler_table\n"
".type handler_table,object\n"
".p2align 3\n"
"handler_table:\n"
".previous\n" );
// End of section
__asm__(".section \".my.handler_table.data\",\"aw\"\n"
".globl handler_table_end\n"
".type handler_table_end,object\n"
".p2align 3\n"
"handler_table_end:\n"
".previous\n" );
// Making the sections accessible from C
extern "C" handler_table_entry handler_table[];
extern "C" handler_table_entry handler_table_end[];
// Adding entries to the different sections. This may be done from different
// compilations unites
HANDLER_TABLE_ENTRY(entry_a, "entry_a", 10);
HANDLER_TABLE_ENTRY(entry_b, "entry_b", 20);
HANDLER_TABLE_ENTRY(entry_c, "entry_c", 30);
int main() {
// Count the number of entries and return the value
int cnt = 0;
for (handler_table_entry *entry = handler_table;
entry != handler_table_end; entry++)
cnt ++;
return cnt; // returns 0, but I expected 3
}
コンパイル:
g++ foo.cxx -o foo
実行とテスト:
$ ./foo && echo $?
0
質問 1:私は何を間違えましたか? また、単純な作業例はどのようになりますか?
質問 2:このパターンを使用できない落とし穴やシナリオはありますか? (例: 共有ライブラリ)
アップデート:
この問題をデバッグしようとするプロセスで、次の行を追加しました(stdio.hを含めました)
printf("0x%p 0x%p\n", (void *)handler_table, (void *)handler_table_end);
コンパイル コマンドを次のように変更しました。
gcc -static -O0 -g -o foo foo.c
プログラムを実行すると、次の出力が得られます。
$ ./foo
0x0x6b7650 0x0x6b7650
そして、objdump
これが言わなければならないことです:
$ objdump -d --section=.my.handler_table.data foo
foo: file format elf64-x86-64
Disassembly of section .my.handler_table.data:
00000000006b7650 <__TMC_END__>:
6b7650: 64 a1 48 00 00 00 00 00 10 00 00 00 00 00 00 00 d.H.............
00000000006b7660 <entry_2>:
6b7660: 6c a1 48 00 00 00 00 00 20 00 00 00 00 00 00 00 l.H..... .......
00000000006b7670 <entry_3>:
6b7670: 74 a1 48 00 00 00 00 00 30 00 00 00 00 00 00 00 t.H.....0.......
明らかに問題は とが同じ場所handler_table
をhandler_table_end
指していることですが、これはなぜですか?