【发布时间】:2011-04-18 00:11:18
【问题描述】:
我正在编写一些代码,将一些数据结构存储在一个特殊命名的二进制部分中。这些都是相同结构的所有实例,它们分散在许多 C 文件中,并且不在彼此的范围内。通过将它们全部放在命名部分中,我可以遍历所有这些。
在 GCC 中,我使用 _attribute_((section(...)) 加上一些特殊命名的外部指针,这些指针由链接器神奇地填充。这是一个简单的例子:
#include <stdio.h>
extern int __start___mysection[];
extern int __stop___mysection[];
static int x __attribute__((section("__mysection"))) = 4;
static int y __attribute__((section("__mysection"))) = 10;
static int z __attribute__((section("__mysection"))) = 22;
#define SECTION_SIZE(sect) \
((size_t)((__stop_##sect - __start_##sect)))
int main(void)
{
size_t sz = SECTION_SIZE(__mysection);
int i;
printf("Section size is %u\n", sz);
for (i=0; i < sz; i++) {
printf("%d\n", __start___mysection[i]);
}
return 0;
}
我试图弄清楚如何在 MSVC 中执行此操作,但我画的是空白。我从编译器文档中看到,我可以使用 __pragma(section(...)) 声明该部分,并使用 __declspec(allocate(...)) 声明该部分中的数据,但我看不到如何获得在运行时指向节的开始和结束的指针。
我在网上看到了一些与在 MSVC 中执行 _attribute_((constructor)) 相关的示例,但这似乎是针对 CRT 的黑客行为,而不是获取指针的一般方法到部分的开头/结尾。有人有什么想法吗?
【问题讨论】:
-
请问您为什么要首先控制二进制部分命名?
-
这是一个高性能的检测框架。想象一下 printf(format, args...) 调用,其中所有格式字符串都存储在二进制部分中,唯一记录的是参数和查找值。参数替换发生在后处理中。
-
一个更好的例子是一个程序,它允许您通过重新链接而不是重新编译(并且可能重新生成一些代码)来添加模块。如果您可以将整个部分视为某个结构的数组,那么您可以对其进行迭代并对每个条目执行一些操作,例如调用
cur_entry[i]->init(&cur_entry)。通过这样做,您还可以使用有关内存使用模式的特殊知识来优化分页和缓存局部性。通常与 Windows 无关(据我所知),但这也可能是哈佛架构处理器所必需的。 -
是的,我的日志机制工作方式类似。特殊部分是包含检测点的所有元数据的大型结构数组。我希望能够遍历这个数组以转储所有元数据以供以后在后期处理中使用。
-
我也在使用这种结构来运行单元测试。通过这种方式,我不需要知道系统中所有模块的“主”函数,但每个模块都声明了存储在特殊部分中的 unittest 结构。 main 函数以与 Andrew B 示例中的 main() 函数相同的方式遍历所有这些结构。
标签: c visual-c++ gcc linker