是否可以强制 GCC 在 .rodata 中填充字符串常量
Is it possible to force GCC to pad string constants in .rodata
我正在努力将一些代码移植到对齐要求比 x86 更严格的环境中,但由于这个原因,我暂时 changing/testing 在 x86 Linux 机器上由于硬件访问等原因,更容易。
我已经将 运行 的第一个问题提炼成以下简明示例:
#include <stdio.h>
#include <string.h>
#define BUFFER_SIZE 1024
#define DMQUOTE_LOG "DMQUOTELOG"
void aFunction (const char *configPath)
{
char LogFilename[BUFFER_SIZE] __attribute ((aligned));
// printf ("A\n");
strcpy (LogFilename, configPath);
strcat (LogFilename, DMQUOTE_LOG);
printf ("Log: %s\n", LogFilename);
}
int main (int argc, char **argv)
{
__asm__("pushf\n"
"orl [=10=]x40000, (%esp)\n"
"popf");
aFunction ("");
return 0;
}
运行 此代码按原样提供了预期的输出。但是,取消注释其他 printf 会导致在 strcat 行上触发总线错误。
在我看来,原因似乎是通过引入第二个字符串常量,定义中的常量被移动,因此它没有对齐。这是因为注意到如果字符串常量从 "A\n" 更改为 "AAA\n",一切都会再次工作(并且 gcc 神奇地将对 printf 的调用替换为对 puts 的调用,并从常量中删除 \n ).
有没有什么好的方法可以让 gcc 在它插入到 .rodata 部分的所有字符串常量之间插入额外的填充,以便正确对齐?
[编辑]
如下面的 fucanchik 所述,上面的 .rodata 部分是什么(启用了额外的 printf):
.file "sample.c"
.section .rodata
.LC0:
.string "A"
.LC1:
.string "DMQUOTELOG"
.LC2:
.string "Log: %s\n"
.text
.globl aFunction
...
没有强制对齐,这是有道理的,因为我是在 x86 下编译的,x86 并不严格要求它。自然地,将汇编程序修改为此具有预期的效果。但是,我看不到让 gcc 在运行中自行应用它的方法。不过,如果在一般情况下 glibc 本身无法处理 运行 这种模式,这当然可能没有实际意义。
.file "sample.c"
.section .rodata
.LC0:
.string "A"
.align 4,0
.LC1:
.string "DMQUOTELOG"
.LC2:
.string "Log: %s\n"
.text
.globl aFunction
...
似乎没有任何方法可以做到这一点,至少在 GCC 中是这样。测试似乎表明,虽然编译器会对齐整数、双精度数等,但由于字符串常量由字符组成,而字符数据的对齐是在字节边界上,编译器觉得不需要对齐它们。
这个总线错误的细节似乎表明 glibc 使用优化的例程,一次复制数据字而不先检查对齐(没有查看源代码,我不知道这是不是真的然而)。
这让我开始研究 musl,一个替代的 libc 实现,它很容易按项目安装和使用 basis.The strcat 的 musl 版本的 C 源代码注意复制一次复制单词之前未对齐的字节,因此这个特定的问题消失了,尽管自然而然地其他问题仍然存在。
我正在努力将一些代码移植到对齐要求比 x86 更严格的环境中,但由于这个原因,我暂时 changing/testing 在 x86 Linux 机器上由于硬件访问等原因,更容易。
我已经将 运行 的第一个问题提炼成以下简明示例:
#include <stdio.h>
#include <string.h>
#define BUFFER_SIZE 1024
#define DMQUOTE_LOG "DMQUOTELOG"
void aFunction (const char *configPath)
{
char LogFilename[BUFFER_SIZE] __attribute ((aligned));
// printf ("A\n");
strcpy (LogFilename, configPath);
strcat (LogFilename, DMQUOTE_LOG);
printf ("Log: %s\n", LogFilename);
}
int main (int argc, char **argv)
{
__asm__("pushf\n"
"orl [=10=]x40000, (%esp)\n"
"popf");
aFunction ("");
return 0;
}
运行 此代码按原样提供了预期的输出。但是,取消注释其他 printf 会导致在 strcat 行上触发总线错误。
在我看来,原因似乎是通过引入第二个字符串常量,定义中的常量被移动,因此它没有对齐。这是因为注意到如果字符串常量从 "A\n" 更改为 "AAA\n",一切都会再次工作(并且 gcc 神奇地将对 printf 的调用替换为对 puts 的调用,并从常量中删除 \n ).
有没有什么好的方法可以让 gcc 在它插入到 .rodata 部分的所有字符串常量之间插入额外的填充,以便正确对齐?
[编辑]
如下面的 fucanchik 所述,上面的 .rodata 部分是什么(启用了额外的 printf):
.file "sample.c"
.section .rodata
.LC0:
.string "A"
.LC1:
.string "DMQUOTELOG"
.LC2:
.string "Log: %s\n"
.text
.globl aFunction
...
没有强制对齐,这是有道理的,因为我是在 x86 下编译的,x86 并不严格要求它。自然地,将汇编程序修改为此具有预期的效果。但是,我看不到让 gcc 在运行中自行应用它的方法。不过,如果在一般情况下 glibc 本身无法处理 运行 这种模式,这当然可能没有实际意义。
.file "sample.c"
.section .rodata
.LC0:
.string "A"
.align 4,0
.LC1:
.string "DMQUOTELOG"
.LC2:
.string "Log: %s\n"
.text
.globl aFunction
...
似乎没有任何方法可以做到这一点,至少在 GCC 中是这样。测试似乎表明,虽然编译器会对齐整数、双精度数等,但由于字符串常量由字符组成,而字符数据的对齐是在字节边界上,编译器觉得不需要对齐它们。
这个总线错误的细节似乎表明 glibc 使用优化的例程,一次复制数据字而不先检查对齐(没有查看源代码,我不知道这是不是真的然而)。
这让我开始研究 musl,一个替代的 libc 实现,它很容易按项目安装和使用 basis.The strcat 的 musl 版本的 C 源代码注意复制一次复制单词之前未对齐的字节,因此这个特定的问题消失了,尽管自然而然地其他问题仍然存在。