diff options
Diffstat (limited to 'hex.e')
| -rw-r--r-- | hex.e | 72 |
1 files changed, 45 insertions, 27 deletions
diff --git a/hex.e b/hex.e index fd283ca..d1c4e31 100644 --- a/hex.e +++ b/hex.e @@ -21,88 +21,106 @@ ~ : This is the start routine, the first thing that runs when the ELF loads. ~ : indent current-offset L!' cold-start - ~ The basic registers preserved across syscalls are rbx, rsp, rbp. - ~ To avoid redundant moves, we store the buffer pointer in rbx just once, - ~ and keep it there. We've made sure our load origin fits in 32 bits, so we - ~ can use imm32 for that. We're going to want to do an indirect load from - ~ it, so we can't use rbp for this. + ~ : The basic registers preserved across syscalls are rbx, rsp, rbp. + ~ : To avoid redundant moves, we store the buffer pointer in rbx just once, + ~ : and keep it there. We've made sure our load origin fits in 32 bits, so + ~ : we can use imm32 for that. We're going to want to do an indirect load + ~ : from it, so we can't use rbp for this. L@' buffer L@' origin + :rbx mov-reg64-imm32 + ~ : blank-line current-offset L!' input-loop-start L@' read-byte call-rel-imm32-from-here + ~ : blank-line - ~ If the length is 0, we got EOF. If it's less than zero, we got a read - ~ error. Either way, we exit. This is a signed comparison, as it needs to - ~ be. + ~ : If the length is 0, we got EOF. If it's less than zero, we got a read + ~ : error. Either way, we exit. This is a signed comparison, as it needs to + ~ : be. 0 :rax cmp-reg64-imm8 L@' exit :cc-equal jmp-cc-rel-imm8-from-here L@' read-error :cc-less jmp-cc-rel-imm8-from-here + ~ : blank-line - ~ Now that the length is handled, retrieve the input byte. + ~ : Now that the length is handled, retrieve the input byte. :rbx :rax mov-reg64-indirect-reg64 + ~ : blank-line - ~ If it's space or linefeed, skip it (go back to the loop start). + ~ : If it's space or linefeed, skip it (go back to the loop start). 0x20 :rax cmp-reg64-imm8 ~ ASCII space L@' input-loop-start :cc-equal jmp-cc-rel-imm8-from-here 0x0a :rax cmp-reg64-imm8 ~ ASCII linefeed L@' input-loop-start :cc-equal jmp-cc-rel-imm8-from-here - ~ If it's a comment, skip the whole thing. + ~ : If it's a comment, skip the whole thing. 0x7e :rax cmp-reg64-imm8 ~ ASCII tilde L@' skip-comment :cc-equal jmp-cc-rel-imm8-from-here + ~ : blank-line - ~ Decode the value, or exit with an error. + ~ : Decode the value, or exit with an error. L@' decode-nibble call-rel-imm32-from-here + ~ : blank-line - ~ We use rbp as a place to stash the high nibble. + ~ : We use rbp as a place to stash the high nibble. :rax :rbp mov-reg64-reg64 4 :rbp rol-reg64-imm8 + ~ : blank-line - ~ Now we read another byte. + ~ : Now we read another byte. L@' read-byte call-rel-imm32-from-here + ~ : blank-line - ~ Handle the length. A second hex digit is required here. + ~ : Handle the length. A second hex digit is required here. 0 :rax cmp-reg64-imm8 L@' unexpected-eof :cc-equal jmp-cc-rel-imm8-from-here L@' read-error :cc-less jmp-cc-rel-imm8-from-here + ~ : blank-line - ~ Now that the length is handled, retrieve the input byte. + ~ : Now that the length is handled, retrieve the input byte. :rbx :rax mov-reg64-indirect-reg64 + ~ : blank-line - ~ Decode the value, or exit with an error. + ~ : Decode the value, or exit with an error. L@' decode-nibble call-rel-imm32-from-here + ~ : blank-line - ~ We OR in the low nibble. + ~ : We OR in the low nibble. :rax :rbp or-reg64-reg64 + ~ : blank-line - ~ Output the byte. We reuse the buffer as a place to store it. + ~ : Output the byte. We reuse the buffer as a place to store it. :rbp :rbx mov-indirect-reg64-reg64 :rbx :rsi mov-reg64-reg64 ~ buffer pointer 1 :rdx mov-reg64-imm32 ~ buffer length 1 :rax mov-reg64-imm32 ~ syscall number for sys-write 1 :rdi mov-reg64-imm32 ~ file descriptor 1 is stdout syscall + ~ : blank-line - ~ Back to the start of the loop. + ~ : Back to the start of the loop. L@' input-loop-start jmp-rel-imm8-from-here + ~ : blank-line current-offset L!' skip-comment - ~ Read a byte for the comment. + ~ : Read a byte for the comment. L@' read-byte call-rel-imm32-from-here + ~ : blank-line - ~ Handle the length. We're allowed to end in a comment. + ~ : Handle the length. We're allowed to end in a comment. 0 :rax cmp-reg64-imm8 L@' exit :cc-equal jmp-cc-rel-imm8-from-here L@' read-error :cc-less jmp-cc-rel-imm8-from-here + ~ : blank-line - ~ Now that the length is handled, retrieve the input byte. + ~ : Now that the length is handled, retrieve the input byte. :rbx :rax mov-reg64-indirect-reg64 + ~ : blank-line - ~ If it's linefeed, the comment is over. + ~ : If it's linefeed, the comment is over. 0x0a :rax cmp-reg64-imm8 ~ ASCII linefeed L@' input-loop-start :cc-equal jmp-cc-rel-imm8-from-here + ~ : blank-line - ~ We're still in the comment, keep handling it. + ~ : We're still in the comment, keep handling it. L@' skip-comment jmp-rel-imm8-from-here ~ : deindent ; @@ -119,11 +137,11 @@ ~ : This is the routine named "read-byte". ~ : indent current-offset L!' read-byte - ~ We use self-xor as a concise way to set registers to zero. + ~ : We use self-xor as a concise way to set registers to zero. :rax :rax xor-reg64-reg64 ~ syscall number for sys-read :rdi :rdi xor-reg64-reg64 ~ file descriptor 0 is stdin :rbx :rsi mov-reg64-reg64 ~ buffer pointer - ~ We read one byte at a time, because it makes the loop structure simple. + ~ : We read one byte at a time, because it makes the loop structure simple. 1 :rdx mov-reg64-imm32 ~ buffer length syscall ret |