from-scratch/stages/hex1/elf.asm
2026-06-05 08:15:21 +02:00

151 lines
3.8 KiB
NASM

;; Program that takes an output file to which it writes elf64 headers and the contents of a second file which is assumed to be a text section.
die:
mov rax, 60 ; syscall: exit
mov rdi, 0 ; status: 0
syscall
ret
fopen:
mov rax, 2 ; syscall: open
mov rsi, 0 ; flags: O_RDONLY
mov rdx, 0 ; mode
syscall
ret
fopen_write:
mov rax, 2 ; syscall: open
mov rsi, 0x241 ; flags: O_WRONLY | O_CREAT | O_TRUNC
mov rdx, 0o644 ; mode: rw-r--r--
syscall
ret
;; rdi: fd
;; rsi: buffer
fstat:
mov rax, 5 ; syscall: fstat
syscall
ret
fsize:
push rdi
push rsi
call fstat
pop rsi
pop rdi
mov rax, [rsi + 48] ; st_size
ret
;; rdi: src
;; rsi: dst
;; rdx: len
memcpy:
.memcpy_loop:
test rdx, rdx
jz .memcpy_done
mov al, byte [rdi]
mov byte [rsi], al
inc rsi
inc rdi
dec rdx
jmp .memcpy_loop
.memcpy_done:
ret
;; variables:
;; +0 buffer: [u8; 0x1000]
;; +0x1000 bytes_read: u32
;; +0x1004 in_size: u32
;; +0x1008 in_fd: u32
;; +0x100c out_fd: u32
;; +0x1010 argc: u32
;; +0x1018 argv: *const *const u8
global _start
_start:
mov eax, dword [rsp] ; argc
lea rbx, [rsp + 8] ; argv
sub rsp, 0x4000 ; reserve stack space
mov r15, rsp ; r15 = pointer to our state
mov dword [r15 + 0x1010], eax ; store argc
mov qword [r15 + 0x1018], rbx ; store argv
cmp eax, 3
jl die
;; open output file
mov rdi, [r15 + 0x1018] ; rdi = argv
add rdi, 8 ; rdi = argv[1]
mov rdi, [rdi] ; rdi = pointer to argv[1]
call fopen_write
mov dword [r15 + 0x100c], eax ; store out_fd
;; open input file and get size
mov rdi, [r15 + 0x1018] ; rdi = argv
add rdi, 16 ; rdi = argv[2]
mov rdi, [rdi] ; rdi = pointer to argv[2]
call fopen
mov dword [r15 + 0x1008], eax ; store in_fd
mov edi, eax ; rdi = in_fd
lea rsi, [r15] ; rsi = pointer to statbuf
call fsize
mov dword [r15 + 0x1004], eax ; store in_size
;; copy elf header to scratch space
mov rdi, 0x400000
mov rsi, r15
mov rdx, 0x40
call memcpy
;; copy program header to scratch space
mov rdi, 0x400040
lea rsi, [r15 + 0x40]
mov rdx, 0x38
call memcpy
;; write p_filesz and p_memsz to 0x78 + in_size
mov rax, 0x78
add eax, dword [r15 + 0x1004] ; rax = 0x78 + in_size
mov dword [r15 + 0x60], eax ; write p_filesz
mov dword [r15 + 0x68], eax ; write p_memsz
;; write e_entry to point at 0x40 + 0x38 + in_size - 5
sub rax, 5
add rax, 0x400000
mov dword [r15 + 24], eax ; write e_entry
;; write Ehdr and Phdr to output file
mov edi, dword [r15 + 0x100c] ; rdi = out_fd
mov rsi, r15 ; rsi = buffer
mov rdx, 0x78 ; size of Ehdr + Phdr
mov rax, 1 ; syscall: write
syscall
;; copy text section from input file to output file
.copy_loop:
mov edi, dword [r15 + 0x1008] ; rdi = in_fd
mov rsi, r15 ; rsi = pointer to buffer
mov rdx, 0x1000 ; rdx = size of buffer
mov rax, 0 ; syscall: read
syscall
test rax, rax
jle die
mov dword [r15 + 0x1000], eax ; store number of bytes read
mov edi, dword [r15 + 0x100c] ; rdi = out_fd
mov rsi, r15 ; rsi = pointer to buffer
mov edx, dword [r15 + 0x1000] ; rdx = number of bytes read
mov rax, 1 ; syscall: write
syscall
cmp dword [r15 + 0x1000], 0x1000 ; if we read less than 0x1000 bytes, we are done
je .copy_loop
call die