Details Of Hello World in macOS Catalina
details_of_helloWorld
In depth look at details of C hello world in macOS Catalina
Our basic program (ignore the size and nmemb nonsense, I was just playing around):
#include <stdio.h>
int main() {
fwrite("Hello, world!\n", 128, 15, stdout);
return 0;
}
Using gcc -S hello.c -o hello.s
will give us
.section __TEXT,__text,regular,pure_instructions
.build_version macos, 10, 15 sdk_version 10, 15, 4
.globl _main ## -- Begin function main
.p2align 4, 0x90
_main: ## @main
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
subq $16, %rsp
movq ___stdoutp@GOTPCREL(%rip), %rax
movl $0, -4(%rbp)
movq (%rax), %rcx
leaq L_.str(%rip), %rdi
movl $128, %esi
movl $15, %edx
callq _fwrite
xorl %r8d, %r8d
movq %rax, -16(%rbp) ## 8-byte Spill
movl %r8d, %eax
addq $16, %rsp
popq %rbp
retq
.cfi_endproc
## -- End function
.section __TEXT,__cstring,cstring_literals
L_.str: ## @.str
.asciz "Hello, world!\n"
.subsections_via_symbols
The first few lines are pretty basic.
.section __TEXT,__text,regular,pure_instructions
.build_version macos, 10, 15 sdk_version 10, 15, 4
.globl _main ## -- Begin function main
.p2align 4, 0x90
.section __TEXT,__text
is Apple’s way of defining a .text
section.
regular (S_REGULAR) A regular section may contain any kind of data and gets no special processing from the link editor. This is the default section type. Examples of regular sections include program instructions or initialized data.
The next line is just some build information about OS version, etc. .build_version macos, 10, 15 sdk_version 10, 15, 4
. The .globl _main
declaration is used for making the _main
symbol external so the linker knows what to look for when marking the entry point. The align piece simply explains where the next align-expression boundary is. In this case it’s every 16-byte alignments with 0x90 as the filling between the current location and the next alignment.
Finally we get onto the actual program.
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
We begin by saving the frame pointer by pushing quadword %rbp
onto the stack. We then move the stack pointer %rsp
into the %rbp
register. The q
in these instructions means a quadword operation (64bit).
subq $16, %rsp
movq ___stdoutp@GOTPCREL(%rip), %rax
movl $0, -4(%rbp)
movq (%rax), %rcx
leaq L_.str(%rip), %rdi
We then pad the stack with 16 bytes. I’m assuming because we defined p2align as 2^4 = 16. We then use the Global Offset Table to get stdout and place it into our result register. Then we store the immediate value 0 at 4 bytes from our stack pointer. Then we place the stdout reference in the 4th argument register, %rcx
. We then load up our string into the first argument register (%rdi
).
movl $128, %esi
movl $15, %edx
callq _fwrite
We push our other arguments of 128 and 15 into their respective registers, and call our print function.
xorl %r8d, %r8d
The XOR simply zeros out the %r8d
register.
movq %rax, -16(%rbp) ## 8-byte Spill
movl %r8d, %eax
addq $16, %rsp
popq %rbp
retq
We store the result register at another 16byte offset. We then zero out the %eax
register; reset our stack pointer back to the beginning, pop off our frame pointer and return. Our hello world program is now done.