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

时间:2018-01-03 15:53:23

标签: linux gcc printf newline carriage-return

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

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

#include<stdio.h>

int main()
{
    printf("Hello World2\r\n");
    printf("Hello World3\r\n ");

 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                                  .              

所以,问题是:

  • 为什么?
  • 我如何避免这种&#34;优化&#34;(!?)

由于

2 个答案:

答案 0 :(得分:5)

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

GCC这样做是因为它认为printfbuilt-in。因为这对字节输出<甚至对write的调用次数无影响;我强烈建议保持原样。如果您 想要禁用它,则can pass -fno-builtin-printf,但唯一的效果是在尝试不必要地格式化字符串时减慢代码速度。

答案 1 :(得分:3)

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\r"
.LC1:
    .string "Hello World3\r\n "
    .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\r\n");
    leaq    .LC0(%rip), %rdi    #,
    call    puts@PLT    #
# bflash.c:6:     printf("Hello World3\r\n ");
    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以外的其他东西,但接受性能损失可能是三倍或更多,wrt代码用gcc -O2编译) 。