72 lines
3.4 KiB
ArmAsm
72 lines
3.4 KiB
ArmAsm
|
// ARM 7l - 32 bit arm. Used on 32 bit hardware or 64 bit hardware with 32 bit
|
|||
|
// linux (e.g. most raspbian as of 2022)
|
|||
|
//
|
|||
|
// 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-arm7l.s && ld.gold -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.
|
|||
|
|
|||
|
square:
|
|||
|
// Function entry
|
|||
|
sub sp, sp, #4 // Move stack pointer for locals
|
|||
|
|
|||
|
// Function arguments
|
|||
|
str r0, [sp] // Store return address in stack memory
|
|||
|
// not specifically necessary, but good safety
|
|||
|
// mechanism. We could instead simply ignore
|
|||
|
// the str/ldr operations here and just go
|
|||
|
// for it
|
|||
|
//
|
|||
|
// This would remove memory access completely,
|
|||
|
// but this allows us to demonstrate the
|
|||
|
// general pattern we can use for functions
|
|||
|
|
|||
|
|
|||
|
// Function body
|
|||
|
ldr r0, [sp] // Load first operand with our argument
|
|||
|
mul r1, r0, r0 // Do the multiplication
|
|||
|
mov r0, r1 // Move result to return register
|
|||
|
|
|||
|
// Function exit
|
|||
|
add sp, sp, #4 // Restore stack pointer
|
|||
|
bx lr // Return
|
|||
|
|
|||
|
_start:
|
|||
|
|
|||
|
// https://man7.org/linux/man-pages/man2/syscall.2.html
|
|||
|
// Syscall numbers captured from https://syscalls.w3challs.com/?arch=arm_strong
|
|||
|
// arm syscall table here:
|
|||
|
// https://github.com/torvalds/linux/blob/v4.19/arch/arm/tools/syscall.tbl
|
|||
|
# Hello world to stdout
|
|||
|
mov r7, #4 // System call (sys_write)
|
|||
|
mov r0, #1 // first argument: file handle (stdout)
|
|||
|
ldr r1, =msg // second argument: pointer to message to write
|
|||
|
ldr r2, =len // third argument: message length
|
|||
|
swi #0 // call kernel. We are using Linux's EABI -
|
|||
|
// the embedded application binary interface
|
|||
|
// which is more consistent with the way it is
|
|||
|
// done in other architectures
|
|||
|
|
|||
|
// Square argc
|
|||
|
ldr r0, [sp] // argc is on the stack
|
|||
|
// this is an eightbyte according to table 3.9
|
|||
|
// of the System V AMD64 psABI
|
|||
|
// https://gitlab.com/x86-psABIs/x86-64-ABI
|
|||
|
bl square // Square our argc, result in r0
|
|||
|
// r0 will also be the first argument to sys_exit
|
|||
|
// so no need to load
|
|||
|
|
|||
|
// exit
|
|||
|
mov r7, #1 // system call number (sys_exit)
|
|||
|
swi #0 // call kernel and exit
|