1

特定のリンカ セクションを使用してハンドラのレジストリを作成するプロジェクトをいくつか見てきました (次の例は、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_tablehandler_table_end指していることですが、これはなぜですか?

4

1 に答える 1

0

が配置されているセクションの名前を変更handler_table_endすると、問題が解決します。

完全なコードは次のようになります。

#include <stdio.h>

#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. NOW IN A NEW SECTION
__asm__(".section     \".my.handler_table.data.end\",\"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() {
    for (handler_table_entry *entry = handler_table;
            entry != handler_table_end; entry++)
        printf("%s -> %d\n", entry->name, entry->val);

    return 0;
}
于 2013-11-15T21:06:40.503 に答える