【发布时间】:2016-09-27 15:38:59
【问题描述】:
我正在使用 GCC 并试图让链接器从自定义部分中的不同文件创建数据对象数组。我已将此部分添加到链接器脚本中:
.mydata :
{
__mydata_start = .;
KEEP (*(.mydata))
__mydata_end = .;
}
这是我的数据结构:
struct my_type_t {
unsigned char a;
size_t b;
void *c;
const void *d;
const void *e;
const char *f;
};
我在 64 位平台上,sizeof(struct my_type_t) 给出 48。但是,链接器似乎想将这些结构对齐到 64 字节。
我的声明:
struct my_type_t a1 __attribute__((section(".mydata"))) = {
1, 2, (void *)3, (void *)4, (void *)5, (void *)6,
};
struct my_type_t a2 __attribute__((section(".mydata"))) = {
7, 8, (void *)9, (void *)10, (void *)11, (void *)12,
};
链接器输出:
$ gcc -o ldtest ldtest.c -Wl,-Tlink.ld
$ objcopy -Obinary -j .mydata ldtest mydata
$ hd mydata
00000000 01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 |................|
00000010 03 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 |................|
00000020 05 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000040 07 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 |................|
00000050 09 00 00 00 00 00 00 00 0a 00 00 00 00 00 00 00 |................|
00000060 0b 00 00 00 00 00 00 00 0c 00 00 00 00 00 00 00 |................|
如果我改为将其声明为数组:
struct my_type_t a1[2] __attribute__((section(".mydata"))) = {
{
1, 2, (void *)3, (void *)4, (void *)5, (void *)6,
},
{
7, 8, (void *)9, (void *)10, (void *)11, (void *)12,
},
};
没有填充,正如预期的那样:
00000000 01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 |................|
00000010 03 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 |................|
00000020 05 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 |................|
00000030 07 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 |................|
00000040 09 00 00 00 00 00 00 00 0a 00 00 00 00 00 00 00 |................|
00000050 0b 00 00 00 00 00 00 00 0c 00 00 00 00 00 00 00 |................|
为什么链接器会添加超出编译器认为必要的额外填充,我该如何摆脱它?
【问题讨论】:
-
"为什么链接器要添加额外的填充..." - 为什么不呢?标准中没有关于不同对象的特定放置的要求。它与兼容的 C 代码完全无关。关于“如何摆脱它”,您已经有了答案。我认为没有问题。
-
正如我所指定的,这些对象位于不同的文件中,因此我无法从中创建数组。但是,我想将它们视为 C 代码中的数组。 C认为大小是48,所以如果我增加一个指向第一个的指针,它将指向填充,而不是下一个的开始。
-
“但是,我想将它们视为 C 代码中的数组” - 这是未定义的行为。听起来像一个 XY 问题。必须有不同的方法,例如指针表。
-
这是 Linux 为允许不同的驱动程序和子系统注册 init 函数所做的。在循环它们进行初始化时,它将它们视为一个数组,这正是我想要做的。如果链接器只是随意插入填充字节,他们将无法依赖这种机制。
-
试试
SUBALIGN(0)。