是否可以强制GCC填充.rodata中的字符串常量

时间:2015-04-08 18:54:43

标签: c gcc memory-alignment

我正在努力将一些代码移植到比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
...

1 个答案:

答案 0 :(得分:1)

似乎没有办法实现这一点,至少对于GCC来说。测试似乎表明虽然编译器会对齐整数,双精度等,因为字符串常量是由字符组成的,字符数据的对齐是在字节边界上,编译器觉得不需要对齐它们。

这个总线错误的细节似乎表明glibc使用优化的例程,一次复制数据字而不先检查对齐(没有查看源,我不知道这是否真实不过)。

这促使我调查了musl,这是一个替代的libc实现,很容易在项目的基础上逐个安装和使用.strcat的musl版本的C源代码在复制之前需要复制未对齐的字节一次一个字,因此这个特殊的问题就会消失,尽管其他人仍然存在。