gcc - .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 机器上进行。
解决方案
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_alignment
。align_variable
(在 varasm.c 中)使用此函数将大于 8 字节的字符串对齐到 8 字节到 32 字节之间,具体取决于它们的大小(gcc 内部在 64 到 256 位之间)。
之后,您可以在assemble_variable
(varasm.c) 中看到,仅当对齐大于默认情况下 1 字节(gcc 内部为 8 位)时才调用ASM_OUTPUT_ALIGN
which print 。.align
BITS_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_variable
align_variable
因此,如果您声明一个大小等于或大于 8 个字节的字符串,它将被对齐。.align x
根据字符串的大小,您将看到8 到 32 个字节之间的 x 。正如@Peter Cordes 所说,它在装配时会更加明显。
推荐阅读
- javascript - 从 AWS Amplify Graphql API 过滤数据
- r - 如何根据单独变量中的名称选择 df 列?
- sequelize.js - Sequelize:禁用创建外键约束
- excel - 无法使用vba更改任务栏中的excel图标
- android - 将图像从文件系统拖放到Firefox浏览器?(或任何浏览器)在 android 平板电脑
- python - 如何使用 GitPython 进行浅层克隆
- python - 将 locust 与 pytest 一起使用
- c++ - 我们可以在 C++ 命名空间下的 Gtest 中模拟或包装函数调用吗
- active-directory - 打开电脑上网时,虚拟机无法与虚拟机域控制器通信
- go - 在 GRPC 中处理 IO 等待状态下的 goroutine 的优雅方式