76 lines
1.5 KiB
NASM
76 lines
1.5 KiB
NASM
; We need to tell it about main when using c lib functions
|
|
; else it will complain about it during linking
|
|
global main
|
|
|
|
; c library symbols for the compiler (linker doesn't care)
|
|
extern printf
|
|
extern atoi
|
|
|
|
section .data
|
|
; Strings to printf'
|
|
fmt: db '%d + %d = %d',0xA,0x0 ; append with newline and null terminator
|
|
usageMsg: db 'usage: %s first_number second_number',0xA,0x0
|
|
|
|
section .text
|
|
; Note that this will be called by some external function (actually,
|
|
; the compiler will generate its own _start that eventually calls this)
|
|
main:
|
|
push rbp
|
|
mov rbp, rsp
|
|
push rbx
|
|
push r12
|
|
push r13
|
|
push r14
|
|
push r15
|
|
|
|
; main takes an int and a char pointer as arguments
|
|
mov r12, rdi
|
|
mov r13, rsi
|
|
|
|
; This segfaults when moved below the line "jne .fail"
|
|
; Why?
|
|
; Because it stores the float registers on the stack
|
|
; as well. This doesn't seem to be particularly well
|
|
; documented.
|
|
sub rsp, 8 ; allocate 8 bytes = 2 integers
|
|
|
|
cmp r12, 3 ; argc == 3
|
|
jne .fail
|
|
|
|
mov rdi, qword [r13 + 8] ; argv[1]
|
|
call atoi
|
|
mov dword [rsp], eax ; store integer 1
|
|
|
|
mov rdi, qword [r13 + 16] ; argv[2]
|
|
call atoi
|
|
mov dword [rsp + 4], eax ; store integer 2
|
|
|
|
; add the two numbers
|
|
mov ecx, dword [rsp]
|
|
add ecx, dword [rsp + 4]
|
|
|
|
; print the result
|
|
mov rdi, fmt
|
|
mov esi, [rsp]
|
|
mov edx, [rsp + 4]
|
|
call printf
|
|
|
|
; main returns an integer
|
|
xor rax, rax
|
|
jmp .end
|
|
.fail:
|
|
mov rdi, usageMsg
|
|
mov rsi, [r13] ; argv[0] = the executable name
|
|
call printf
|
|
mov rax, 1
|
|
.end:
|
|
pop r15
|
|
pop r14
|
|
pop r13
|
|
pop r12
|
|
pop rbx
|
|
mov rsp, rbp
|
|
pop rbp
|
|
|
|
ret
|