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

Posted

技术标签:

【中文标题】是否可以强制 GCC 在 .rodata 中填充字符串常量【英文标题】:Is it possible to force GCC to pad string constants in .rodata 【发布时间】:2015-04-08 18:54:43 【问题描述】:

我正在努力将一些代码移植到比 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 行上触发总线错误。

在我看来,这样做的原因似乎是通过引入第二个字符串常量,定义中的常量被移动,因此它没有对齐。通过注意到如果字符串常量从“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 下编译,这并不严格要求它。自然,将汇编器修改为此具有预期的效果。但是,我看不到让 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/libc 端口处理。对于手动对齐单个字符串,我发现了以下内容:gcc.gnu.org/ml/gcc-help/2011-10/msg00068.html. @fukanchik 只是一个简单的“gcc sample.c”。 @Ulfalizer 恐怕你是对的,但我希望这样的事情是可能的。不过,您必须跳过障碍才能打开对齐检查,这让我担心 glibc 默认情况下不会花太多精力。 gcc 应该自动应用平台所需的对齐方式。尝试使用 gcc -S sample.c 进行编译。这将产生汇编输出,这可能会提供一些线索。 【参考方案1】:

似乎没有任何方法可以做到这一点,至少对于 GCC。测试似乎表明,虽然编译器会对齐整数、双精度等,但由于字符串常量是由字符组成的,而字符数据的对齐方式是在字节边界上,所以编译器觉得没有必要对齐它们。

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

这促使我研究了musl,这是一种替代的 libc 实现,可以在一个项目的基础上简单地安装和使用。strcat 的 musl 版本的 C 源代码在复制单词之前注意复制未对齐的字节一段时间,因此这个特定问题消失了,尽管其他问题自然而然地仍然存在。

【讨论】:

以上是关于是否可以强制 GCC 在 .rodata 中填充字符串常量的主要内容,如果未能解决你的问题,请参考以下文章

强制 GCC 访问带有单词的结构

重定位被截断以适应:R_386_8 针对“.rodata”

使用 GCC 强制自动矢量化

我们如何强制编译器没有结构填充?请解释

如何在x86上使用gcc强制执行内存排序

通过JTAG对比内核启动后text/rodata段内容