Skip to content

Instantly share code, notes, and snippets.

@dere dere/calc.asm
Last active Sep 13, 2019

Embed
What would you like to do?
A heavily-documented Hello World in x86 assembly
; Allow the linker to find the _start symbol. The linker will begin program execution
; there.
global _start
; Start the .data section of the executable, which stores constants (read-only data)
; It doesn't matter which order your sections are in, I just like putting .data first
section .rodata
; Declare some bytes at a symbol called hello_world. NASM's db pseudo-instruction
; allows either a single byte value, a constant string, or a combination of the two
; as seen here. 0xA = new line, and 0x0 = string-terminating null
hello_world: db "Hello world!", 0xA, 0x0
; Start the .text section, which stores program code
section .text
_start:
enter 0, 0
; save the caller-saved registers (I choose to not save any)
push hello_world ; push the argument to _print_msg
call _print_msg
mov eax, 0x01 ; 0x01 = exit()
mov ebx, 0 ; 0 = no errors
int 0x80
_print_msg:
enter 0, 0
; My function begins here
mov eax, 0x04 ; 0x04 = the write() syscall
mov ebx, 0x1 ; 0x1 = standard output
mov ecx, [ebp+8] ; the string we want to print is the first argument of this function
; at this point we wish to set edx to the length of the string. time to call _strlen
push eax ; save the caller-saved registers (I choose to not save edx)
push ecx
push dword [ebp+8] ; push _strlen's argument, the string argument to _print_msg. NASM
; complains if you do not put a size directive here, and I'm not sure
; why. Anyway, a pointer is a dword (4 bytes)
call _strlen ; eax is now equal to the length of the string
mov edx, eax ; move the length into edx where we wanted it
add esp, 4 ; remove 4 bytes from the stack (one 4-byte char* argument)
pop ecx ; restore caller-saved registers
pop eax
; we're done calling _strlen and setting up the syscall
int 0x80
leave
ret
_strlen:
enter 0, 0 ; save the previous frame's base pointer and adjust ebp
; Here I'd save the callee-saved registers, but I won't be modifying any
; My function begins here
mov eax, 0 ; length = 0
mov ecx, [ebp+8] ; copy the function's first argument (pointer to the first character
; of the string) into ecx (which is caller-saved, so no need to save it)
_strlen_loop_start:
cmp byte [ecx], 0 ; dereference that pointer and compare it to null. Here we have to
; explicitly mention it's a byte since the size of the pointer is
; ambiguous (is it a 4 byte integer? 2? 1?). This is called called a
; Size Directive
je _strlen_loop_end ; jump out of the loop if it is equal to null
add eax, 1 ; add 1 to our return value
add ecx, 1 ; increment to the next character in the string
jmp _strlen_loop_start ; jump back to the start
_strlen_loop_end:
; My function ends here. eax is equal to my function's return value
; Here I'd restore the callee-saved registers, but I didn't save any
leave ; deallocate and restore the previous frame's base pointer
ret
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.