Low Level Hacking: How structs look in memory.

I wanted to verify something so I did a proof of concept example. I know in C arrays are a contiguous bytes of memory and there really is no boundaries at that level, just pure memory. I was pretty sure structs looked the same way but I wanted to test to be sure.. I also found something interesting along the way.

The examples below were compiled on MacOS Sierra 64-bit using gcc/as.

struct.c

#include <stdio.h>

int main(void)
{
	struct myStruct
	{
		int id;
		char *name;
	};

	struct myStruct test;
	test.id = 4;
	test.name = "bacon";

	return 0;

}

Then to get the assembly output, we use gcc -S struct.c

       .section        __TEXT,__text,regular,pure_instructions
        .macosx_version_min 10, 11
        .globl  _main
        .align  4, 0x90
_main:                                  ## @main
        .cfi_startproc
## BB#0:
        pushq   %rbp
Ltmp0:
        .cfi_def_cfa_offset 16
Ltmp1:
        .cfi_offset %rbp, -16
        movq    %rsp, %rbp
Ltmp2:
        .cfi_def_cfa_register %rbp
        xorl    %eax, %eax
        leaq    L_.str(%rip), %rcx
        movl    $0, -4(%rbp)
        movl    $4, -24(%rbp)
        movq    %rcx, -16(%rbp)
        popq    %rbp
        retq
        .cfi_endproc

        .section        __TEXT,__cstring,cstring_literals
L_.str:                                 ## @.str
        .asciz  "bacon"


.subsections_via_symbols

This confirms what I thought in the beginning (that structs in memory are just a vast amount of memory), but it made me question why we’re using the offset of -16(%rbp) for the 6-byte string and -24(%rbp) for a 4-byte signed integer with the value of 4. (Note 6-bytes because we need to include the null byte in a C string. I had to go back and correct this.. easy to forget!)

Since this is a 64-bit system, the pointer are 8-bytes and the integer is also 8-bytes, hence why the offsets on the stack are 8-bytes apart. Please note that your hardware may have a different pointer size so be sure to reference that if in question.

64-bit version

leaq    L_.str(%rip), %rcx  ; Load address of string "bacon"
movl    $0, -4(%rbp)  ;; Return Code for function, 4 bytes padded
movl    $4, -24(%rbp) ;; 8-bytes 
movq    %rcx, -16(%rbp) ;;8-bytes for the pointer which points to a string containing 6 characters (including '\0').

32-bit version

** Using gcc -m32 -S struct.c

 
 leal L_.str-L0$pb(%eax), %eax ; load address of string "bacon"
 movl $0, -4(%ebp)    ; return value , 4bytes
 movl $4, -16(%ebp)   ; test.id = 4, 4 bytes
 movl %eax, -12(%ebp) ; test.name = "bacon"