add x86 ISA assembly
This commit is contained in:
parent
12a16991fb
commit
b652bc257a
76
hello-amd64.s
Normal file
76
hello-amd64.s
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
# 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 --64 hello-amd64.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.
|
||||||
|
|
||||||
|
# https://stackoverflow.com/questions/3683144/linux-64-command-line-parameters-in-assembly
|
||||||
|
# https://wiki.cdot.senecacollege.ca/wiki/X86_64_Register_and_Instruction_Quick_Start
|
||||||
|
square:
|
||||||
|
pushq %rbp # Save rbp - this must be restored at end of call
|
||||||
|
movq %rsp, %rbp # Update base pointer from current stack pointer
|
||||||
|
movq %rdi,-8(%rbp) # Move 1st argument (rdi) into stack memory
|
||||||
|
# This is not strictly necessary here, but
|
||||||
|
# is done as a way to demonstrate generic handling
|
||||||
|
# of arguments
|
||||||
|
movq -8(%rbp), %rax # Move stack memory into rax for multiplication
|
||||||
|
imulq -8(%rbp), %rax # Do multiplication
|
||||||
|
# The above 3 instructions could be done with the
|
||||||
|
# following 2 instructions instead in such a simple
|
||||||
|
# case:
|
||||||
|
#movq %rdi, %rax # Move 1st argument (rdi) to rax for processing
|
||||||
|
|
||||||
|
#imulq %rax, %rax # Do multiplication
|
||||||
|
popq %rbp # Restore rbp for return (eax/rax has return val)
|
||||||
|
retq # Return
|
||||||
|
|
||||||
|
_start:
|
||||||
|
|
||||||
|
# write our string to stdout
|
||||||
|
# https://man7.org/linux/man-pages/man2/syscall.2.html
|
||||||
|
# https://filippo.io/linux-syscall-table/
|
||||||
|
# https://github.com/torvalds/linux/blob/master/arch/x86/entry/syscalls/syscall_64.tbl
|
||||||
|
movq $1,%rax # system call number (sys_write)
|
||||||
|
movq $1,%rdi # first argument: file handle (stdout)
|
||||||
|
movq $msg,%rsi # second argument: pointer to message to write
|
||||||
|
movq $len,%rdx # third argument: message length
|
||||||
|
syscall # call kernel
|
||||||
|
# argc is stored in (%rsp)
|
||||||
|
# this is an eightbyte according to table 3.9
|
||||||
|
# of the System V AMD64 psABI
|
||||||
|
# https://gitlab.com/x86-psABIs/x86-64-ABI
|
||||||
|
#
|
||||||
|
# It is a bit questionable here whether the
|
||||||
|
# upper 32 bits of rdi are cleared when moving
|
||||||
|
# into edi, but this instruction is generated
|
||||||
|
# from compilers, which leads me to "yes".
|
||||||
|
# Documentation also states this (with some exceptions):
|
||||||
|
#
|
||||||
|
# When executing MOV Reg, Sreg, the processor
|
||||||
|
# copies the content of Sreg to the 16 least
|
||||||
|
# significant bits of the general-purpose register.
|
||||||
|
# The upper bits of the destination register
|
||||||
|
# are zero for most IA-32 processors (Pentium
|
||||||
|
# Pro processors and later) and all Intel 64
|
||||||
|
# processors, with the exception that bits 31:16
|
||||||
|
# are undefined for Intel Quark X1000 processors,
|
||||||
|
# Pentium and earlier processors.
|
||||||
|
#
|
||||||
|
# Above language pulled from MOV documentation
|
||||||
|
# in Vol 2B, Chapter 4:
|
||||||
|
# https://www.intel.com/content/dam/develop/public/us/en/documents/325462-sdm-vol-1-2abcd-3abcd.pdf
|
||||||
|
#
|
||||||
|
movl (%rsp),%edi # See: https://wiki.cdot.senecacollege.ca/wiki/X86_64_Register_and_Instruction_Quick_Start
|
||||||
|
callq square # Square our argc, result in %eax
|
||||||
|
movq %rax,%rdi # mov %eax to the first syscall argument (exit code)
|
||||||
|
movq $60,%rax # system call number (sys_exit)
|
||||||
|
syscall # call kernel and exit
|
47
hello-x86-32.s
Normal file
47
hello-x86-32.s
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
# as --32 hello-x86-32.s && ld.gold -m32 -s -n -o hello a.out
|
||||||
|
.data # section declaration
|
||||||
|
msg:
|
||||||
|
.string "All your codebase is belong to us\n" # our dear string
|
||||||
|
|
||||||
|
len = . - msg # length of our dear 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.
|
||||||
|
|
||||||
|
# https://stackoverflow.com/questions/3683144/linux-64-command-line-parameters-in-assembly
|
||||||
|
# https://wiki.cdot.senecacollege.ca/wiki/X86_64_Register_and_Instruction_Quick_Start
|
||||||
|
square:
|
||||||
|
pushl %ebp # Save ebp - this must be restored at end of call
|
||||||
|
movl %esp, %ebp # Update base pointer from current stack pointer
|
||||||
|
# 8 bytes above ebp is our first parameter
|
||||||
|
# (4 bytes above is our return address)
|
||||||
|
# In this case, _start is not explictly adding
|
||||||
|
# our parameter to the stack as that is being
|
||||||
|
# done prior to us being exec'd in the first place
|
||||||
|
# There is a good diagram of this in the calling
|
||||||
|
# convention section on https://www.cs.virginia.edu/~evans/cs216/guides/x86.html
|
||||||
|
movl 8(%ebp), %eax # Move stack memory into eax for multiplication
|
||||||
|
imull 8(%ebp), %eax # Do multiplication
|
||||||
|
popl %ebp # Restore rbp for return (eax/rax has return val)
|
||||||
|
ret # Return
|
||||||
|
|
||||||
|
_start:
|
||||||
|
|
||||||
|
# Linux syscalls for 32 bit:
|
||||||
|
# https://github.com/torvalds/linux/blob/master/arch/x86/entry/syscalls/syscall_32.tbl
|
||||||
|
# write our string to stdout
|
||||||
|
movl $4,%eax # system call number (sys_write)
|
||||||
|
movl $1,%ebx # first argument: file handle (stdout)
|
||||||
|
movl $msg,%ecx # second argument: pointer to message to write
|
||||||
|
movl $len,%edx # third argument: message length
|
||||||
|
int $0x80 # call kernel and exit
|
||||||
|
# argc is stored in (%esp)
|
||||||
|
movl (%esp),%edi # See: https://wiki.cdot.senecacollege.ca/wiki/X86_64_Register_and_Instruction_Quick_Start
|
||||||
|
# The above instruction is part of the calling convention,
|
||||||
|
# so left here, but it's useless/unnecessary and can be removed
|
||||||
|
call square # Square our argc, result in %eax
|
||||||
|
movl %eax,%ebx # mov %eax to the first syscall argument (exit code)
|
||||||
|
movl $1,%eax # system call number (sys_exit)
|
||||||
|
int $0x80 # call kernel
|
Loading…
Reference in New Issue
Block a user