74 lines
3.6 KiB
ArmAsm
74 lines
3.6 KiB
ArmAsm
|
# gold linker has smallest binary size. others probably can emit smaller
|
|||
|
# binaries with custom linker scripts. Their default ones
|
|||
|
# are not optimized for hello world programs
|
|||
|
# as hello-riscv64.s && ld -s -n -o hello a.out
|
|||
|
.data # section declaration
|
|||
|
msg:
|
|||
|
.string "All your codebase is belong to us\n" # output string
|
|||
|
|
|||
|
len = . - msg # length of output string
|
|||
|
|
|||
|
.text # section declaration
|
|||
|
# we must export the entry point to the ELF linker or
|
|||
|
.global _start # loader. They conventionally recognize _start as their
|
|||
|
# entry point. Use ld −e foo to override the default.
|
|||
|
|
|||
|
# RISC-V register reference:
|
|||
|
# https://xuanxuanblingbling.github.io/assets/pic/riscv/register.png
|
|||
|
# RISC-V instruction cheat sheet:
|
|||
|
# https://risc-v.guru/instructions/
|
|||
|
|
|||
|
square:
|
|||
|
# Function entry
|
|||
|
addi sp, sp, -32 # Move stack pointer for locals
|
|||
|
# 32 bytes gives us (32/8 =) 4 64 slots to use
|
|||
|
# We will only store our return address/frame pointer
|
|||
|
sd ra, 24(sp) # Store return address in stack memory
|
|||
|
sd s0, 16(sp) # Store frame pointer in stack memory
|
|||
|
addi s0, sp, 32 # Capture original stack pointer in s0
|
|||
|
# Interpret as s0 = sp + 32
|
|||
|
|
|||
|
# Function arguments
|
|||
|
sw a0, -20(s0) # Save first argument (num) to stack
|
|||
|
# Be aware that we're now subtracting rather
|
|||
|
# than adding because we just changed s0
|
|||
|
# A long version of this would be sd a0, -24(s0)
|
|||
|
|
|||
|
# Function body
|
|||
|
lw a0, -20(s0) # Load first argument (num) from stack
|
|||
|
# This save/load is to make sure we have a copy
|
|||
|
# of the original argument, which is not important
|
|||
|
# here, but would be if this was a more serious
|
|||
|
# function. We could just have easily comment
|
|||
|
# out both instructions and avoid memory access
|
|||
|
|
|||
|
mulw a0, a0, a0 # Actually do the multiplication.
|
|||
|
|
|||
|
# Function exit
|
|||
|
ld ra, 24(sp) # Restore return address from stack
|
|||
|
ld s0, 16(sp) # Restore frame pointer from stack memory
|
|||
|
addi sp, sp, 32 # Restore stack pointer
|
|||
|
ret # Return
|
|||
|
|
|||
|
_start:
|
|||
|
|
|||
|
# https://man7.org/linux/man-pages/man2/syscall.2.html
|
|||
|
# https://github.com/torvalds/linux/blob/v4.17/include/uapi/asm-generic/unistd.h
|
|||
|
# Hello world to stdout
|
|||
|
li a7, 64 # System call (sys_write)
|
|||
|
li a0, 1 # first argument: file handle (stdout)
|
|||
|
lla a1, msg # second argument: pointer to message to write
|
|||
|
li a2, len # third argument: message length
|
|||
|
scall # call kernel
|
|||
|
|
|||
|
# Square argc
|
|||
|
ld a0, (sp) # argc is on the stack
|
|||
|
# https://www.reddit.com/r/RISCV/comments/p2na17/command_line_arguments_in_assembly/
|
|||
|
call square # Square our argc, result in a0
|
|||
|
# a0 will also be the first argument to sys_exit
|
|||
|
# so no need to load
|
|||
|
|
|||
|
# exit
|
|||
|
li a7, 93 # system call number (sys_exit)
|
|||
|
scall # call kernel and exit
|