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:我做错了什么,一个简单的工作示例会是什么样子?

问题二:有没有什么陷阱或者场景不能使用这个模式?(例如共享库)

更新:

在尝试调试此问题的过程中,我添加了以下行(并包括 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 回答