/* AMD64 ilo, (c) 2023 Christopher Leonard, MIT License */ .global main .extern open, read, write, close, exit, lseek /* rax: top of stack */ /* rbx: data stack */ /* rbp: jump table address */ /* r12: address stack */ /* r13: instruction pointer */ /* r14: opcode shift register */ /* r15: memory */ .bss .align 8 blocks: .skip 8 /* name of blocks file (ilo.blocks) */ rom: .skip 8 /* name of image (ilo.rom) */ dstack: .skip 32*4 astack: .skip 256*4 a: .skip 4 /* other variables for misc. purposes */ b: .skip 4 f: .skip 4 s: .skip 4 d: .skip 4 l: .skip 4 memory: .skip 65536*4 .section .rodata default_blocks: .asciz "ilo.blocks" default_rom: .asciz "ilo.rom" io_table: .byte 0 .byte iob-ioa .byte ioc-ioa .byte iod-ioa .byte ioe-ioa .byte iof-ioa .byte iog-ioa .byte ioh-ioa .text rdonly: mov $0, %esi /* O_RDONLY */ call open mov %eax, %edi ret wronly: mov $1, %esi /* O_WRONLY */ call open mov %eax, %edi ret load_image: mov rom(%rip), %rdi call rdonly or %eax, %eax jz 1f mov %r15, %rsi mov $65536 * 4, %edx call read call close xor %eax, %eax lea dstack-4(%rip), %rbx lea astack-4(%rip), %r12 xor %r13d, %r13d 1: ret save_image: push %rax mov rom(%rip), %rdi call wronly or %eax, %eax jz 1f mov %r15, %rsi mov $65536 * 4, %edx call write call close 1: pop %rax ret block_read: mov (%rbx), %esi # Get the block number shl $12, %esi # Multiply by 4096 (block size) xor %edx, %edx # SEEK_SET mov %rax, %rdi # File descriptor (from %rax) call lseek # Call lseek mov $4096, %edx # Number of bytes to read lea (%r15, %r8, 4), %rsi # Buffer location call read # Call read mov -4(%rbx), %esi # Retrieve value from the stack sub $8, %rbx # Update the stack pointer ret block_write: mov (%rbx), %esi # Get the block number shl $12, %esi # Multiply by 4096 (block size) xor %edx, %edx # SEEK_SET mov %rax, %rdi # File descriptor (from %rax) call lseek # Call lseek mov $4096, %edx # Number of bytes to read lea (%r15, %r8, 4), %rsi # Buffer location call write mov -4(%rbx), %esi # Retrieve value from the stack sub $8, %rbx # Update the stack pointer ret .align 32 table: ret .align 32 li: add $4, %rbx inc %r13d mov %eax, (%rbx) mov (%r15,%r13,4), %eax ret .align 32 du: add $4, %rbx mov %eax, (%rbx) ret .align 32 dr: mov (%rbx), %eax sub $4, %rbx ret .align 32 sw: xchg (%rbx), %eax ret .align 32 pu: add $4, %r12 mov %eax, (%r12) mov (%rbx), %eax sub $4, %rbx ret .align 32 po: add $4, %rbx mov %eax, (%rbx) mov (%r12), %eax sub $4, %r12 ret .align 32 ju: lea -1(%eax), %r13d mov (%rbx), %eax sub $4, %rbx ret .align 32 ca: add $4, %r12 mov %r13d, (%r12) lea -1(%eax), %r13d mov (%rbx), %eax sub $4, %rbx ret .align 32 cc: cmpl $0, (%rbx) jz 1f add $4, %r12 mov %r13d, (%r12) lea -1(%eax), %r13d 1: mov -4(%rbx), %eax sub $8, %rbx ret .align 32 cj: cmpl $0, (%rbx) jz 1f lea -1(%eax), %r13d 1: mov -4(%rbx), %eax sub $8, %rbx ret .align 32 re: mov (%r12), %r13d sub $4, %r12 ret .align 32 eq: cmp %eax, (%rbx) sete %al movzbl %al, %eax neg %eax sub $4, %rbx ret .align 32 ne: cmp %eax, (%rbx) setne %al movzbl %al, %eax neg %eax sub $4, %rbx ret .align 32 lt: cmp %eax, (%rbx) setl %al movzbl %al, %eax neg %eax sub $4, %rbx ret .align 32 gt: cmp %eax, (%rbx) setg %al movzbl %al, %eax neg %eax sub $4, %rbx ret .align 32 fe: mov (%r15,%rax,4), %eax ret .align 32 st: mov (%rbx), %ecx mov %ecx, (%r15,%rax,4) mov -4(%rbx), %eax sub $8, %rbx ret .align 32 ad: add (%rbx), %eax sub $4, %rbx ret .align 32 su: sub (%rbx), %eax neg %eax sub $4, %rbx ret .align 32 mu: mull (%rbx) sub $4, %rbx ret .align 32 di: mov %eax, %ecx mov (%rbx), %eax cdq idiv %ecx mov %edx, (%rbx) ret .align 32 an: and (%rbx), %eax sub $4, %rbx ret .align 32 or: or (%rbx), %eax sub $4, %rbx ret .align 32 xo: xor (%rbx), %eax sub $4, %rbx ret .align 32 sl: mov %eax, %ecx mov (%rbx), %eax sub $4, %rbx shl %cl, %eax ret .align 32 sr: mov %eax, %ecx mov (%rbx), %eax sub $4, %rbx sar %cl, %eax ret .align 32 cp: mov %eax, %ecx mov (%rbx), %edi mov -4(%rbx), %esi sub $8, %rbx lea (%r15,%rdi,4), %rdi lea (%r15,%rsi,4), %rsi cmp %eax, %eax repe cmpsd sete %al movzbl %al, %eax neg %eax ret .align 32 cy: mov %eax, %ecx mov (%rbx), %edi mov -4(%rbx), %esi mov -8(%rbx), %eax sub $12, %rbx lea (%r15,%rdi,4), %rdi lea (%r15,%rsi,4), %rsi repe movsd ret .align 32 io: mov %eax, %ecx mov (%rbx), %eax sub $4, %rbx cmp $7, %ecx ja 1f lea io_table(%rip), %rdx movzbl (%rdx,%rcx), %ecx lea ioa(%rip), %rdx add %rdx, %rcx jmp *%rcx 1: ret ioa: push %rax mov %rsp, %rsi /* buffer pointer */ mov $1, %edx /* write one byte */ mov $1, %edi /* file descriptor (stdout) */ call write pop %rax mov (%rbx), %eax sub $4, %rbx ret xiob: add $4, %rbx mov %eax, (%rbx) push %rax xor %edi, %edi /* file descriptor (stdin) */ mov %rsp, %rsi /* buffer pointer */ mov $1, %edx /* read one byte */ call read pop %rax ret iob: add $4, %rbx mov %eax, (%rbx) xor %edi, %edi # %edi = 0 (stdin) lea a(%rip), %rsi # Load address of 'a' into %rsi (buffer) mov $1, %edx # %edx = 1 (read one byte) call read # Call libc read: read(0, a, 1) movzx a(%rip), %eax # Move the byte from 'a' into %eax (zero-extend) ret ioc: mov %eax, %r8d mov blocks(%rip), %rdi mov $0, %rsi mov $0, %rdx call open /* open file (read-only) */ call block_read call close mov %esi, %eax ret iod: mov %eax, %r8d mov blocks(%rip), %rdi mov $1, %rsi mov $0, %rdx call open /* open file (write-only) */ call block_write call close mov %esi, %eax ret ioe: jmp save_image iof: call load_image xor %rax, %rax xor %r13, %r13 jmp _execute iog: mov $65536, %r13d ret ioh: add $8, %rbx mov %eax, -4(%rbx) lea astack-4(%rip), %rdx neg %edx lea 4*32-8(%rbx,%rdx), %rax shr $2, %eax mov %eax, (%rbx) lea (%r12,%rdx), %rax shr $2, %eax ret main: xor %eax, %eax lea memory(%rip), %r15 lea dstack-4(%rip), %rbx lea astack-4(%rip), %r12 xor %r13d, %r13d lea table(%rip), %rbp mov 8(%rsp), %rcx or %rcx, %rcx jz 1f mov 16(%rsp), %rcx or %rcx, %rcx jz 1f mov %rcx, blocks(%rip) mov 24(%rsp), %rcx or %rcx, %rcx jz 2f mov %rcx, rom(%rip) jmp 3f 1: lea default_blocks(%rip), %rcx mov %rcx, blocks(%rip) 2: lea default_rom(%rip), %rcx mov %rcx, rom(%rip) 3: call load_image _execute: jmp 3f .align 64 2: mov (%r15,%r13,4), %r14d movzbl %r14b, %edi shr $8, %r14d cmp $29, %edi ja 1f shl $5, %edi add %rbp, %rdi call *%rdi 1: movzbl %r14b, %edi shr $8, %r14d cmp $29, %edi ja 1f shl $5, %edi add %rbp, %rdi call *%rdi 1: movzbl %r14b, %edi shr $8, %r14d cmp $29, %edi ja 1f shl $5, %edi add %rbp, %rdi call *%rdi 1: mov %r14d, %edi cmp $29, %edi ja 1f shl $5, %edi add %rbp, %rdi call *%rdi 1: inc %r13 3: cmp $65536, %r13 jl 2b xor %edi, %edi call exit /* exit program */