I have this short hello world program:
static const char* msg = "Hello world";
.string "Hello world"
.type msg, @object
.size msg, 4
.type main, @function
.cfi_offset 5, -8
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
movl msg, %eax
movl %eax, (%esp)
movl $0, %eax
.cfi_def_cfa 4, 4
.size main, .-main
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
The absolute bare minimum that will work on the platform that this appears to be, is
.globl main main: pushl $.LC0 call puts addl $4, %esp xorl %eax, %eax ret .LC0: .string "Hello world"
But this breaks a number of ABI requirements. The minimum for an ABI-compliant program is
.globl main .type main, @function main: subl $24, %esp pushl $.LC0 call puts xorl %eax, %eax addl $28, %esp ret .size main, .-main .section .rodata .LC0: .string "Hello world"
Everything else in your object file is either the compiler not optimizing the code down as tightly as possible, or optional annotations to be written to the object file.
.cfi_* directives, in particular, are optional annotations. They are necessary if and only if the function might be on the call stack when a C++ exception is thrown, but they are useful in any program from which you might want to extract a stack trace. If you are going to write nontrivial code by hand in assembly language, it will probably be worth learning how to write them. Unfortunately, they are very poorly documented; I am not currently finding anything that I think is worth linking to.
It is probably worth mentioning that in the "AT&T" assembly syntax used (by default) by GCC and GNU binutils, there are three kinds of lines: A line with a single token on it, ending in a colon, is a label. (I don't remember the rules for what characters can appear in labels.) A line whose first token begins with a dot, and does not end in a colon, is some kind of directive to the assembler. Anything else is an assembly instruction.