To the best of my knowledge, x86-64 requires the stack to be 16-byte aligned before a call, while gcc with -m32 doesn't require this for main. 
I have the following testing code:
.data
intfmt:         .string "int: %d\n"
testint:        .int    20
.text
.globl main
main:
    mov     %esp, %ebp
    push    testint
    push    $intfmt
    call    printf
    mov     %ebp, %esp
    ret
Build with as --32 test.S -o test.o && gcc -m32 test.o -o test. I am aware that syscall write exists, but to my knowledge it cannot print ints and floats the way printf can.
After entering main, a 4 byte return address is on the stack. Then interpreting this code naively, the two push calls each put 4 bytes on the stack, so call needs another 4 byte value pushed to be aligned.
Here is the objdump of the binary generated by gas and gcc:
0000053d <main>:
 53d:   89 e5                   mov    %esp,%ebp
 53f:   ff 35 1d 20 00 00       pushl  0x201d
 545:   68 14 20 00 00          push   $0x2014
 54a:   e8 fc ff ff ff          call   54b <main+0xe>
 54f:   89 ec                   mov    %ebp,%esp
 551:   c3                      ret    
 552:   66 90                   xchg   %ax,%ax
 554:   66 90                   xchg   %ax,%ax
 556:   66 90                   xchg   %ax,%ax
 558:   66 90                   xchg   %ax,%ax
 55a:   66 90                   xchg   %ax,%ax
 55c:   66 90                   xchg   %ax,%ax
 55e:   66 90                   xchg   %ax,%ax
I am very confused about the push instructions generated.
- If two 4 byte values are pushed, how is alignment achieved?
- Why is 0x2014 pushed instead of 0x14? What is 0x201d?
- What does call 54beven achieve? Output ofhdmatchesobjdump. Why is this different in gdb? Is this the dynamic linker?
B+>│0x5655553d <main>                       mov    %esp,%ebp                      │
   │0x5655553f <main+2>                     pushl  0x5655701d                     │
   │0x56555545 <main+8>                     push   $0x56557014                    │
   │0x5655554a <main+13>                    call   0xf7e222d0 <printf>            │
   │0x5655554f <main+18>                    mov    %ebp,%esp                      │
   │0x56555551 <main+20>                    ret  
Resources on what goes on when a binary is actually executed are appreciated, since I don't know what's actually going on and the tutorials I've read don't cover it. I'm in the process of reading through How programs get run: ELF binaries.
 
    