0x100 byte bare metal hex editor
return
return
One of the first remotely substantial things I wrote in 16-bit x86 assembly, happened to be exactly 256 bytes (minus the padding + boot signature). I would do things quite a bit differently now, but it’s fun to look back on..
Maybe I’ll rewrite it someday.
; nasm hexedit.asm -o hexedit
; qemu-system-i386 -drive format=raw,file=hexedit
;
; to measure file size without the signature, comment out the last two lines.
;
; controls:
; hjkl move cursor
; e edit at cursor (esc to exit)
; g move cursor to address
; x execute code at cursor
bits 16
org 7C00h
push 0x7c00
start:
pop si
; set vga 80x25 text mode
mov ax, 0x0002
int 0x10
; hide cursor
mov ah, 1
mov cx, 2607h
int 0x10
main_loop:
call draw_screen
; read key
xor ah, ah
int 0x16
; cursor left
cmp al, 'h'
jne .next_1
dec si
.next_1:
; cursor down
cmp al, 'j'
jne .next_2
add si, 16
.next_2:
; cursor up
cmp al, 'k'
jne .next_3
sub si, 16
.next_3:
; cursor right
cmp al, 'l'
jne .next_4
inc si
.next_4:
; edit memory
cmp al, 'e'
jne .next_5
call edit_mode
.next_5:
; goto addr
cmp al, 'g'
jne .next_6
call goto_addr
.next_6:
; execute code at cursor
cmp al, 'x'
jne .next_7
push si
push start
jmp si
.next_7:
; reset mode indicator
mov BYTE [es:79*2], ' '
jmp main_loop
; al - ascii hex digit -> nibble
x_digit:
sub al, '0'
x_digit_sub:
cmp al, 10
jl .is_not_x
add al, 10 - ('a' - '0')
.is_not_x:
ret
edit_mode:
mov WORD [es:79*2], (0xF << 8) | 'E'
.loop:
call read_hex_byte
test ah, ah
jz .continue
ret
.continue:
mov [si], al
inc si
call draw_screen
jmp .loop
goto_addr:
mov WORD [es:79*2], (0xF << 8) | 'G'
call read_hex_byte
xchg dh, al
call read_hex_byte
xchg dl, al
mov si, dx
ret
; ah - nonzero on fail
; al - byte read
read_hex_byte:
; read byte
xor ah, ah
int 0x16
sub al, '0'
jns .continue
ret
.continue:
call x_digit_sub
xchg bl, al
xor ah, ah
int 0x16
call x_digit
shl bl, 4
add al, bl
xor ah, ah
ret
; al - nibble
; ah - style
put_vga_nibble:
add al, '0'
cmp al, '0' + 10
jl .is_not_x
add al, 'A' - '0' - 10
.is_not_x:
stosw
ret
; al - byte
; ah - style
put_vga_byte:
mov bl, al
shr al, 4
call put_vga_nibble
xchg bl, al
and al, 0xF
call put_vga_nibble
ret
; si = src addr
draw_screen:
push 0xB800
pop es
mov bp, si
and si, 0xFFF0
sub si, 16*12
; vga dest ptr
mov di, 0
mov cx, 25
.draw_row:
mov dx, si
xchg al, dh
mov ah, 0x3
call put_vga_byte
xchg al, dl
call put_vga_byte
add di, 4
xchg cx, dx
mov cx, 16
.draw_char:
cmp bp, si
sete ah
add ah, ah
lodsb
add ah, 7
call put_vga_byte
add di, 2
loop .draw_char
add di, 52
xchg cx, dx
loop .draw_row
mov si, bp
ret
times 510-($-$$) db 0
dw 0xAA55