YiFei YiFei - 3 months ago 13
C Question

Difference at assembly level of printf from cstdio and iostream

So this question is just out of curiosity.
I have some tiny program:

#include <some_header>
void print(){ printf("abc"); } // don't care about main, I'm not gonna run it


Then I compiled it to assembly, with once
some_header
=>
iostream
and another time
some_header
=>
cstdio
with gcc.godbolt.org (6.1 for x86_64) with
-O3 -pedantic -std=c++14
. Look at this:

.LC0:
.string "abc"
print(): (iostream) or (both included)
movl $.LC0, %edi
xorl %eax, %eax
jmp printf
subq $8, %rsp
movl std::__ioinit, %edi
call std::ios_base::Init::Init()
movl $__dso_handle, %edx
movl std::__ioinit, %esi
movl std::ios_base::Init::~Init(), %edi
addq $8, %rsp
jmp __cxa_atexit
print(): (cstdio)
movl $.LC0, %edi
xorl %eax, %eax
jmp printf


There's a significant difference between them, and they're identical for the first three lines, so why do
iostream
need such amount of code to clean up or what are those lines just doing? OR just to say that godbolt is unreliable upon this task?




Also it seems that standard doesn't guarantee that printf is accessible from
iostream
, should this be relied upon?

Answer

Your print function compiles to a pretty much the same assembly code in both cases. The additional lines you see are to initialise and de-initialise iostream library. You may see that clearly if you remove the optimisation flag -O3. Here is a complete listing with iostream included and optimisation switched off.

std::piecewise_construct:
        .zero   1
.LC0:
        .string "abc"
print():
        pushq   %rbp
        movq    %rsp, %rbp
        movl    $.LC0, %edi
        movl    $0, %eax
        call    printf
        nop
        popq    %rbp
        ret
__static_initialization_and_destruction_0(int, int):
        pushq   %rbp
        movq    %rsp, %rbp
        subq    $16, %rsp
        movl    %edi, -4(%rbp)
        movl    %esi, -8(%rbp)
        cmpl    $1, -4(%rbp)
        jne     .L4
        cmpl    $65535, -8(%rbp)
        jne     .L4
        movl    std::__ioinit, %edi
        call    std::ios_base::Init::Init()
        movl    $__dso_handle, %edx
        movl    std::__ioinit, %esi
        movl    std::ios_base::Init::~Init(), %edi
        call    __cxa_atexit
.L4:
        nop
        leave
        ret
        pushq   %rbp
        movq    %rsp, %rbp
        movl    $65535, %esi
        movl    $1, %edi
        call    __static_initialization_and_destruction_0(int, int)
        popq    %rbp
        ret
Comments