首页 > 解决方案 > 在 OSX/iOS 上使用 Clang 获取部分的地址

问题描述

很长一段时间以来,我一直在使用链接器部分来注册在运行时使用的元素。我发现这是一种制作通用和可扩展界面的简单方法。一个特别有用的用例是单元测试或多功能工具(例如busybox),因此可以执行以下操作:

$ ./tool <handler>

其中handler是一个简单的字符串,在运行时通过遍历链接器部分“查找”。这样,您的解析器就不必“知道”支持哪些命令。它只是在专用于它们的链接器部分中找到它们的处理程序,或者没有。

对于 GCC,我一直在做类似的事情(你也可以用 Clang 来做):

#define __tool __attribute__((__section__("tools")))

然后我要注册的每个处理程序都会获得一个简单的结构(根据需要包含更多或更少的信息)

struct tool {
    const char *name;
    const char *help;
    int (*handler)(int argc, char **argv);
}

然后,对于每个工具,您只需执行以下操作(通常方便地包装在宏中):

int example_tool0(int argc, char **argv)
{
    return -1;
}

static const struct tool example_tool0 = {
    .name = "exmaple_tool0",
    .help = "usage: ...",
    .handler = example_tool0
};

__tool static const struct tool *ptr = &example_tool0;

并使用了这样的:

$ ./tool example_tool0

并且由于__tool,以这种方式注册的每个指针都被打包到一个可以遍历的链接器部分中。

现在,在 GCC 上,链接器为每个部分创建两个魔术变量:__start_SECTION__stop_SECTION. 因此,要“遍历”我们所有注册的处理程序,您只需获取本节的大小,除以指针的大小,然后strncmp针对结构中的名称(在本例中)。


以上只是说,如何使用基于 OSX/iOS Clang 的工具链来完成?我宁愿不使用自定义链接器脚本来实现这个看似简单的操作。

有没有办法在 OSX 上做到这一点?我通过在该部分的开头和结尾注册一个空条目来解决这个问题。但是这样做需要强制对象文件的链接顺序。

虽然 OSX/iOS 使用 Clang 作为其平台编译器,但它们不使用 LLVM 链接器。相反,无论出于何种原因,他们都实现了自己的ld64(开源)。因此,它可能不被支持。我没有轻易man ld在 OSX 上看到任何内容,但它有点信息密集。

供 ELF 和 GCC 参考

标签: ioscmacoslinkerclang

解决方案


所以这已经被其他人回答了。我确实搜索过,但我一定错过了这个答案。实际上,我之前已经多次寻找这个问题的答案,但肯定从未使用过正确的词。

https://stackoverflow.com/a/22366882/2446071

总之,显然链接器支持自己定义这些所需符号的语法:

extern char __start_SECTION __asm("section$start$SEGMENT$SECTION");
extern char __stop_SECTION  __asm("section$end$SEGMENT$SECTION");

推荐阅读