FEAT Added subroutines to the list of skills taught in this tutorial.
This commit is contained in:
parent
3b1f0e9a3d
commit
127e5c0b71
|
@ -6,3 +6,5 @@ hello32
|
|||
hello64
|
||||
counted-hello32
|
||||
counted-hello64
|
||||
subroutine-hello32
|
||||
subroutine-hello64
|
||||
|
|
8
Makefile
8
Makefile
|
@ -23,5 +23,13 @@ counted-hello64: counted-hello64.s ## Build the 32 bit version of Project 3
|
|||
nasm -f elf64 counted-hello64.s
|
||||
ld -o counted-hello64 counted-hello64.o
|
||||
|
||||
subroutine-hello32: subroutine-hello32.s ## Build the 32 bit version of Project 3
|
||||
nasm -f elf subroutine-hello32.s
|
||||
ld -m elf_i386 -o subroutine-hello32 subroutine-hello32.o
|
||||
|
||||
subroutine-hello64: subroutine-hello64.s ## Build the 32 bit version of Project 3
|
||||
nasm -f elf64 subroutine-hello64.s
|
||||
ld -o subroutine-hello64 subroutine-hello64.o
|
||||
|
||||
clean: ## Delete all built and intermediate features
|
||||
rm -f hello32 hello64 counted-hello32 counted-hello64 *.o
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
;; Hello World Program #1
|
||||
;; Compile with: nasm -f elf hello.s
|
||||
;; Link with: ld -m elf_i386 -o hello hello.o
|
||||
;; Run with: ./hello
|
||||
|
||||
;; sys/unistd_32.h
|
||||
%define SYS_write 4
|
||||
%define SYS_exit 1
|
||||
|
||||
;; unistd.h
|
||||
%define STDOUT 1
|
||||
|
||||
section .data
|
||||
msg db "Okay, so we're doing 32-bit subroutines now, huh?", 0Ah, 00h
|
||||
|
||||
section .text
|
||||
global _start
|
||||
|
||||
_start:
|
||||
mov eax, msg ; Put the address of our message into eax.
|
||||
call strlen ; call the function strlen. We're using EAX as our argument.
|
||||
|
||||
mov edx, eax ; We know printit wants these two
|
||||
mov eax, msg
|
||||
call printit
|
||||
call exit
|
||||
|
||||
strlen:
|
||||
push ebx ; Push ebx onto the stack, since the calling scope
|
||||
; will probably want its state restored correctly, right?
|
||||
mov ebx, eax
|
||||
|
||||
strlen_next:
|
||||
cmp byte [eax], 0
|
||||
jz strlen_done
|
||||
inc eax
|
||||
jmp strlen_next
|
||||
|
||||
strlen_done:
|
||||
sub eax, ebx ; Straight from the counted-hello file
|
||||
pop ebx ; restore EBX for the calling scope, which is
|
||||
; expecting its answer in eax
|
||||
ret
|
||||
|
||||
;; Takes EAX as the address of the message and EDX as the
|
||||
;; length, and prints them. Restores all used registers
|
||||
;; when finished.
|
||||
printit:
|
||||
push eax
|
||||
push ebx
|
||||
push ecx
|
||||
mov ecx, eax
|
||||
mov ebx, STDOUT
|
||||
mov eax, SYS_write
|
||||
int 80h
|
||||
pop ecx
|
||||
pop ebx
|
||||
pop eax
|
||||
ret
|
||||
|
||||
;; Since this terminates the program, I'm not worried about
|
||||
;; managing the stack correctly.
|
||||
exit:
|
||||
mov ebx, 0
|
||||
mov eax, SYS_exit
|
||||
int 80h
|
|
@ -0,0 +1,66 @@
|
|||
;; Hello World Program #1
|
||||
;; Compile with: nasm -f elf hello.s
|
||||
;; Link with: ld -m elf_i386 -o hello hello.o
|
||||
;; Run with: ./hello
|
||||
|
||||
;; sys/unistd_32.h
|
||||
%define SYS_write 1
|
||||
%define SYS_exit 60
|
||||
|
||||
;; unistd.h
|
||||
%define STDOUT 1
|
||||
|
||||
section .data
|
||||
msg db "Okay, so we're doing 64-bit subroutines now, huh?", 0Ah, 00h
|
||||
|
||||
section .text
|
||||
global _start
|
||||
|
||||
_start:
|
||||
mov rsi, msg ; Put the address of our message into rax.
|
||||
call strlen ; call the function strlen. We're using RAX as our argument.
|
||||
;; At this point, RDX is length and RSI still points to the source.
|
||||
;; The differences here make me wonder if my understanding of the 32-bit
|
||||
;; version are incorrect, since now the two fields that matter are
|
||||
;; already populated.
|
||||
;;
|
||||
;; Note that this is non-standard. RAX is usually assumed to hold
|
||||
;; the return value, but I'm cheating by knowing that printit
|
||||
;; wants the result of strlen in RDX. Whether this is exploitable
|
||||
;; in a compiler (you know, that whole "choosing registers"
|
||||
;; question) is something to ponder.
|
||||
|
||||
call printit
|
||||
call exit
|
||||
|
||||
strlen:
|
||||
mov rdx, rsi
|
||||
|
||||
strlen_next:
|
||||
cmp byte [rdx], 0
|
||||
jz strlen_done
|
||||
inc rdx
|
||||
jmp strlen_next
|
||||
|
||||
strlen_done:
|
||||
sub rdx, rsi
|
||||
ret
|
||||
|
||||
;; Takes RDI as the address of the message and RDX as the length,
|
||||
;; and prints them. Restores all used registers when finished.
|
||||
printit:
|
||||
push rdi
|
||||
push rax
|
||||
mov rdi, STDOUT ; using STDOUT (see definition above)
|
||||
mov rax, SYS_write ; Using WRITE in 32-bit mode?
|
||||
syscall
|
||||
pop rax
|
||||
pop rdx
|
||||
pop rdi
|
||||
|
||||
;; Since this terminates the program, I'm not worried about
|
||||
;; managing the stack correctly.
|
||||
exit:
|
||||
mov rdi, 0
|
||||
mov rax, SYS_exit
|
||||
syscall
|
Loading…
Reference in New Issue