diff --git a/.gitignore b/.gitignore index f20917a..4411f23 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ hello32 hello64 counted-hello32 counted-hello64 +subroutine-hello32 +subroutine-hello64 diff --git a/Makefile b/Makefile index 446b0e6..8804791 100644 --- a/Makefile +++ b/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 diff --git a/subroutine-hello32.s b/subroutine-hello32.s new file mode 100644 index 0000000..d4a7505 --- /dev/null +++ b/subroutine-hello32.s @@ -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 diff --git a/subroutine-hello64.s b/subroutine-hello64.s new file mode 100644 index 0000000..dafc3d1 --- /dev/null +++ b/subroutine-hello64.s @@ -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