So I am very annoyed right now that this took 3 hours to find and fix. I was writing an assembly function to print out a FAT12 file name. They are stored like this: 8 bytes for the name, 3 for the extension, both padded with spaces. So build.sh is stored like this (where "_" is space, for clarity): [BUILD _ _ _ SH _ ] Or KERNEL.SYS is stored like this [KERNEL _ _ SYS] And I needed a function to turn this into BUILD.SH or KERNEL.SYS and print it.
Load character
If it is the 9th character loaded, load a "." instead and decrement the string pointer
If the loaded character is a space, skip printing
Print the loaded character if it is not skipped
If this was the 12th character printed, we are done
And here was the code I originally wrote to do this:
print_filename:
push ds
mov ds, ax
mov si, bx
mov cx, 0
mov ah, 0x0E
.print_filechar:
inc cx
lodsb ; Loads the character at SI into AL and increments SI
cmp cx, 9
jne .no_dot
mov al, "."
dec si
.no_dot:
cmp al, " "
je .print_filechar
int 0x10 ; Prints the character stored in AL
cmp cx, 12
je .done
jmp .print_filechar
.done:
pop ds
ret
See how if the character loaded is a space, it jumps back to the .print_filechar label? When that happens, it inadvertently skips the check to see if the last character has been printed. (cmp cx, 12) Now I didn't notice this at first because I was printing KERNEL.SYS, and so the last character was an S. But when I tried printing BUILD.SH, the last stored character is a space, so it doesn't check if it has printed all 12 characters, and it tries to print the next one. After this cx will never again be 12, and so it just keeps going until CX rolls back over to 0. Anyway, I fixed it with this updated code that now appears to be working correctly:
print_filename:
push ds
mov ds, ax
mov si, bx
mov cx, 0 ; Since the fat12 directory entry doesn't have a line terminator, count bytes
mov ah, 0x0E
.print_filechar:
inc cx
lodsb
cmp cx, 9 ; The 9th character should be a .
jne .no_dot
mov al, "." ; If it is the 9th character printed it should be a dot
dec si ; Decrement si becuase we already loaded the character but are not using it
.no_dot:
cmp al, " "
je .skip_char ; Spaces are only used for padding here so we can safely skip it
int 0x10
.skip_char:
cmp cx, 12
je .done
jmp .print_filechar
.done:
pop ds
Anyway, good luck debugging guys!