如何阻止GCC从obj文件中的字符串文字中删除尾随换行符?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何阻止GCC从obj文件中的字符串文字中删除尾随换行符?相关的知识,希望对你有一定的参考价值。

在Linux下工作,我刚刚遇到了以下问题。 (当然,有人会给我答案,但到目前为止,我没有找到任何简单明了的答案:)

/*compile with gcc -o out.x hello.c*/

#include<stdio.h>

int main()
{
    printf("Hello World2
");
    printf("Hello World3
 ");

 return 0;
}

在Linux下运行以下代码给出两个字符串但结尾字符是不同的:第一个输出以0x0d结尾,而第二个以0x0d,0x0a结尾。

这是由编译器(GCC)完成的,如obj文件中所示:

Contents of section .rodata:
 400610 01000200 48656c6c 6f20576f 726c6432  ....Hello World2
 400620 0d004865 6c6c6f20 576f726c 64330d0a  ..Hello World3..
 400630 2000                                  .              

所以,问题是:

  • 为什么?
  • 我怎样才能避免这种“优化”(!?)

谢谢

答案

在运行时创建格式化输出需要时间; printf呼叫很慢。 GCC知道这一点,所以replaces是调用puts的第一个函数。由于puts自动添加 ,GCC需要从字符串中删除 以进行补偿。

海湾合作委员会这样做是因为它认为printfbuilt-in。因为这对字节输出甚至对write的调用次数没有影响;我强烈建议保持原样。如果你想要禁用它,你可以使用can pass -fno-builtin-printf,但唯一的效果是减慢你的代码,因为它试图不必要地格式化字符串。

另一答案

ask GCC(在Linux / Debian / Sid / x86-64上使用GCC7.2)发出汇编程序更简单。所以我编写了你的​​程序bflash.c

gcc -fverbose-asm -O0 -S bflash.c -o bflash-O0.S

没有优化就可以得到它

gcc -fverbose-asm -O1 -S bflash.c -o bflash-O1.S

获得-O1优化。随意用各种other optimization flags重复实验。

即使没有优化,bflash-O0.S包含:

    .section    .rodata
.LC0:
    .string "Hello World2
"
.LC1:
    .string "Hello World3
 "
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushq   %rbp    #
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp  #,
    .cfi_def_cfa_register 6
# bflash.c:5:     printf("Hello World2
");
    leaq    .LC0(%rip), %rdi    #,
    call    puts@PLT    #
# bflash.c:6:     printf("Hello World3
 ");
    leaq    .LC1(%rip), %rdi    #,
    movl    $0, %eax    #,
    call    printf@PLT  #
# bflash.c:8:  return 0;
    movl    $0, %eax    #, _4
# bflash.c:9: }
    popq    %rbp    #
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main

如你所见,第一个printf已被优化为puts;这是C11标准n1570as-if rule)允许的。顺便说一句,bflash-01.S包含类似的代码。请注意,C11标准已经考虑了当前的优化实践(标准化委员会的许多成员都是编译器实现者)。

BTW Clang 5,作为clang-5.0 -O1 -fverbose-asm -S bflash.c -o bflash-01clang.s调用,执行相同类型的优化。

我怎样才能避免这种“优化”(!?)

关注Daniel H's answer(你可以编译with -ffreestanding,但我不建议这样做)。

或者避免使用printf中的<stdio.h>并实现自己的慢速打印功能。如果您实现自己的打印功能,请以不同的名称命名(因为printf是在C11标准中定义的),也许(如果需要的话)编写您自己的GCC plugin以便按照您的方式进行优化(并且该插件最好是一些免费软件is GPL compatible ,阅读GCC runtime library exception)。

C语言规范(研究n1570)定义了semantics,即编译程序的行为。它不需要任何特定的字节序列出现在可执行文件中(标准中甚至可能没有提到)。如果你需要这样的属性,找到一种不同的编程语言,并放弃所有重要的optimizations GCC正在努力为你做。优化正在制作writing a C compiler difficult(如果你想要一个非优化的编译器,使用GCC以外的其他东西,但接受在性能方面可能损失三倍或更多,w.r.t。使用gcc -O2编译的代码)。

以上是关于如何阻止GCC从obj文件中的字符串文字中删除尾随换行符?的主要内容,如果未能解决你的问题,请参考以下文章

从 fgets() 输入中删除尾随换行符

如何递归删除所有文件的尾随空格?

从Javascript中的字符串中删除尾随字符

如何自动删除vim中的尾随空格

如何删除字符串中的前导零和尾随零? Python

如何删除前导和尾随的空格以及字符串中的多个空格? [复制]