Q:

How is struct organized in assembly?

I am trying to figure out, how does compiler pad space between each struct members. In this example:
    struct s{
        int a,b,c;
    };
    struct s get(int a){
        struct s foo = {.a=a,.b=a+1,.c=a+2};
        return foo;
    }

is compiled with cc -S a.c:
    .file   "a.c"
    .text
    .globl  get
    .type   get, @function
get:
.LFB0:
    pushq   %rbp
    movq    %rsp, %rbp
    movl    %edi, -36(%rbp)
    movl    -36(%rbp), %eax
    movl    %eax, -24(%rbp)
    movl    -36(%rbp), %eax
    addl    $1, %eax
    movl    %eax, -20(%rbp)
    movl    -36(%rbp), %eax
    addl    $2, %eax
    movl    %eax, -16(%rbp)
    movq    -24(%rbp), %rax
    movq    %rax, -12(%rbp)
    movl    -16(%rbp), %eax
    movl    %eax, -4(%rbp)
    movq    -12(%rbp), %rax
    movl    -4(%rbp), %ecx
    movq    %rcx, %rdx
    popq    %rbp
    ret
.LFE0:
    .size   get, .-get
    .ident  "GCC: (Debian 8.3.0-6) 8.3.0"
    .section    .note.GNU-stack,"",@progbits

No optimization is used. The question is why is there -36(%rbp) used as first member "reference", when they are arranged sequentially in 
.a == -24(%rbp)
.b == -20(%rbp)
.c == -16(%rbp)

There is no need to make room with -36(%rbp) which compiler uses here. Is it intentionally (as a room or compiler uses the -36(%rbp) as a "reference" to the first member)? 
Also, at the end,
movq    -24(%rbp), %rax  #take first member
movq    %rax, -12(%rbp)  #place it randomly
movl    -16(%rbp), %eax  #take third member
movl    %eax, -4(%rbp)   #place it randomly

Does not make sense, it is not sequential with the initial struct, and the first and third member of the struct are copied randomly in the space the function get had allocated.
What is the convention for structs?

A:

The code you observe is a jumble of three different things: the actual layout of a struct s, the ABI specification of how to return structs from functions, and the anti-optimizations inserted by many compilers in their default mode (equivalent to -O0) to ensure that unsophisticated debuggers can find and change the values of variables while stopped at any breakpoint (see Why does clang produce inefficient asm with -O0 (for this simple floating point sum)? for more about this).
You can cut out the second of these factors by having get write into a struct s * argument, instead of returning a struct by value, and the third by compiling with gcc -O2 -S instead of just gcc -S.  (Also try -Og and -O1; the complex optimizations applied at -O2 can be confusing, too.)  For instance:
$ cat test.c
struct s {
  int a,b,c;
};
void get(int a, struct s *s)
{
  s->a = a;
  s->b = a+1;
  s->c = a+2;
}
$ gcc -O2 -S test.c
$ cat test.s
    .file   "test.c"
    .text
    .p2align 4
    .globl  get
    .type   get, @function
get:
.LFB0:
    .cfi_startproc
    leal    1(%rdi), %eax
    movl    %edi, (%rsi)
    addl    $2, %edi
    movl    %eax, 4(%rsi)
    movl    %edi, 8(%rsi)
    ret
    .cfi_endproc
.LFE0:
    .size   get, .-get
    .ident  "GCC: (Debian 9.3.0-13) 9.3.0"
    .section    .note.GNU-stack,"",@progbits

From this assembly language it should be clearer that a is at offset 0 within struct s, b is at offset 4, and c at offset 8.
Struct layout is specified by the "psABI" (processor-specific application binary interface) for each CPU architecture.  You can read the psABI specs for x86 at https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI.  These also explain how structs are returned from functions. It's also important to know that the layout of a stack frame is only partially specified by the psABI. Some of the "random" offsets in your assembly dump are, in fact, arbitrarily chosen by the compiler.

