首页 > 解决方案 > .rodata 中字符串对齐和填充的混淆

问题描述

使用这个简单的 C 程序

const char s1[] = "hello",
           s2[] = "there";

并使用gcc -c a.c -O0 -o a.o

产生.rodata包含以下内容:

'hello\x00there\x00'

,这是我所期望的。每个字符串占用 6 个字节,共 12 个字节。


但是,如果我将第二个字符串更改为"there s",如下所示:

const char s1[] = "hello",
           s2[] = "there s";

,.rodata包含以下内容:

'hello\x00\x00\x00there s\x00'

将额外的 2 个空填充字节添加到s1.

我假设添加它们是为了将第一个字符串与 8 字节边界对齐(因为我在 64 位平台上)——尽管我可能错了?

然后我的问题出现了——为什么在第一个例子中没有这样做?为什么不在每个字符串的末尾添加 2 个额外的填充字节以使它们达到 8 字节边界?


所有示例均在 amd64/linux/gcc 机器上进行。

标签: gccx86-64elfmemory-alignmentzero-padding

解决方案


Internally, GCC calculates alignment in bits, converting to bytes for printing a .align directive. In this answer I'll use bytes for everything with the corresponding internal alignment in bits between parentheses.

开始时,两个字符串都对齐 1 个字节(gcc 内部为 8 位)。你可以肯定地看到gimple。

如果你看一下 i386 移植。你会看到它DATA_ALIGNMENT被定义为ix86_data_alignmentalign_variable(在 varasm.c 中)使用此函数将大于 8 字节的字符串对齐到 8 字节到 32 字节之间,具体取决于它们的大小(gcc 内部在 64 到 256 位之间)。

之后,您可以在assemble_variable(varasm.c) 中看到,仅当对齐大于默认情况下 1 字节(gcc 内部为 8 位)时才调用ASM_OUTPUT_ALIGNwhich print 。.alignBITS_PER_UNIT

您可以在 https://github.com/gcc-mirror/gcc/blob/master/gcc/config/i386/i386.h 中找到定义DATA_ALIGNMENT您可以 在https://github.com/gcc-mirror/gcc/ 中找到blob/master/gcc/config/i386/i386.c 你可以在https://github.com/gcc-mirror/gcc/blob/master/gcc/varasm.c中找到
ix86_data_alignment
assemble_variablealign_variable

因此,如果您声明一个大小等于或大于 8 个字节的字符串,它将被对齐。.align x根据字符串的大小,您将看到8 到 32 个字节之间的 x 。正如@Peter Cordes 所说,它在装配时会更加明显。


推荐阅读