I am very new to assembly and everything related to it. I know just the basics of how the registers work and how to use basic operations on them. I was following along cfenollosa/os-tutorial (github) and was trying to figure out where the boot sector is located and how to print a character by directing addressing. I was able to print the character using the conventional square brackets. But while trying to pre calculate the address of the label, I am getting the wrong result sometimes blank outputs or random gibberish character.
I tried to read around and I understood that, Labels dynamically allot the address for any data but is there no way to find this? If possible please break it down as low as you can. Thank you.
[org 0x7c00]
mov bx, 0x7c00
mov al, [bx + 0x2d] ; Load character from offset 0x2d
mov ah, 0x0e ; BIOS teletype function
int 0x10 ; Print the character
jmp $ ; Infinite loop
the_secret: ; Pad to reach offset 0x2d
db 'X' ; Place 'X' at offset 0x2d
times 510-($-$$) db 0 ; Pad the rest of the boot sector
dw 0xaa55 ; Boot signature
Expecting to understand how labels work and if addressing them by pre calculating their address is possible or not.
0
It is possible but tedious. You would have to determine the machine code for every instruction before the character. That’s what you have the assembler for. I have asked nasm
for a listing instead:
1 [org 0x7c00]
2
3 00000000 BB007C mov bx, 0x7c00
4 00000003 8A472D mov al, [bx + 0x2d] ; Load character from offset 0x2d
5 00000006 B40E mov ah, 0x0e ; BIOS teletype function
6 00000008 CD10 int 0x10 ; Print the character
7
8 0000000A EBFE jmp $ ; Infinite loop
9
10 the_secret: ; Pad to reach offset 0x2d
11 0000000C 58 db 'X' ; Place 'X' at offset 0x2d
12
13 0000000D 00<rept> times 510-($-$$) db 0 ; Pad the rest of the boot sector
14 000001FE 55AA dw 0xaa55 ; Boot signature
You can see line 11 is your character and it’s at offset 0000000C
(or count the bytes in the third column). So you could use [bx+0xc]
or just [0x7c0c]
directly. Also note you did not initialize ds
so it might not be zero and your code depends on that for accessing the correct physical address.
2
From
mov bx, 0x7c00 mov al, [bx + 0x2d] ; Load character from offset 0x2d
I take it that you want your character to reside at 0x7C2D specifically.
The solution is already in the program!
The BIOS 0xAA55 signature also has to reside at a particular address: 0x7DFE which is equivalent to offset 510 from the start of the bootsector. You managed to do this via times 510-($-$$) db 0
. Why don’t you do it similarly for your character?
In the_secret: ; Pad to reach offset 0x2d
you mention in the comment for the label that you would “Pad to reach offset 0x2d” but you don’t actually perform the padding.
Simply write times 0x2D-($-$$) db 0
.
[org 0x7C00]
xor ax, ax ; Setup for DS in accordance with ORG 0x7C00
mov ds, ax
mov bx, 0x7C00
mov al, [bx + 0x002D] ; Load character from offset 0x2D
mov ah, 0x0E ; BIOS teletype function
int 0x10 ; Print the character
jmp $ ; Infinite loop
the_secret: ; This label is now redundant!
times 0x2D-($-$$) db 0 ; Pad to reach offset 0x2D
db 'X' ; Place 'X' at offset 0x2D
times 510-($-$$) db 0 ; Pad the rest of the boot sector
dw 0xAA55 ; Boot signature
An even easier place to retrieve the character from could be right before the signature. That is also where many bootloaders would keep their data for easy referencing using known offset addresses.
[org 0x7C00]
xor ax, ax ; Setup for DS in accordance with ORG 0x7C00
mov ds, ax
mov bx, 0x7C00
mov al, [bx + 509] ; Load character from offset 509
mov ah, 0x0E ; BIOS teletype function
int 0x10 ; Print the character
jmp $ ; Infinite loop
times 509-($-$$) db 0 ; Pad to reach offset 509
db 'X' ; Place 'X' at offset 509
dw 0xAA55 ; Boot signature at offset 510