我正在努力将一些代码移植到比x86具有更严格的对齐要求的环境中,但我暂时在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 $0x40000, (%esp)\n"
"popf");
aFunction ("");
return 0;
}
按原样运行此代码可提供预期的输出。但是,取消注释其他printf会导致在strcat线上触发总线错误。
在我看来,好像这样做的原因是通过引入第二个字符串常量,来自define的常量被移位,以便它不对齐。通过注意到如果字符串常量从“A \ n”更改为“AAA \ n”,一切都可以正常工作(并且神奇地gcc用调用puts来取代对printf的调用来放置和删除常量\ 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下编译,这并不严格要求它。当然,将汇编程序修改为具有期望的效果。但是,我无法看到让gcc自动应用它的方法。如果glibc本身无法处理在一般情况下以此模式运行,这当然可能没有实际意义。
.file "sample.c"
.section .rodata
.LC0:
.string "A"
.align 4,0
.LC1:
.string "DMQUOTELOG"
.LC2:
.string "Log: %s\n"
.text
.globl aFunction
...
答案 0 :(得分:1)
似乎没有办法实现这一点,至少对于GCC来说。测试似乎表明虽然编译器会对齐整数,双精度等,因为字符串常量是由字符组成的,字符数据的对齐是在字节边界上,编译器觉得不需要对齐它们。
这个总线错误的细节似乎表明glibc使用优化的例程,一次复制数据字而不先检查对齐(没有查看源,我不知道这是否真实不过)。
这促使我调查了musl,这是一个替代的libc实现,很容易在项目的基础上逐个安装和使用.strcat的musl版本的C源代码在复制之前需要复制未对齐的字节一次一个字,因此这个特殊的问题就会消失,尽管其他人仍然存在。