I want to check my understanding of the following bootloader code:
BITS 16
start:
mov ax, 07C0h ; Set up 4K stack space after this bootloader
add ax, 288 ; (4096 + 512) / 16 bytes per paragraph
mov ss, ax
mov sp, 4096
mov ax, 07C0h ; Set data segment to where we're loaded
mov ds, ax
mov si, text_string ; Put string position into SI
call print_string ; Call our string-printing routine
jmp $ ; Jump here - infinite loop!
text_string db 'This is my cool new OS!', 0
print_string: ; Routine: output string in SI to screen
mov ah, 0Eh ; int 10h 'print char' function
.repeat:
lodsb ; Get character from string
cmp al, 0
je .done ; If char is zero, end of string
int 10h ; Otherwise, print it
jmp .repeat
.done:
ret
times 510-($-$$) db 0 ; Pad remainder of boot sector with 0s
dw 0xAA55 ; The standard PC boot signature
Here's my understanding of the code:
mov ax, 07C0h:
- Memory address can be obtained from the stack segment value (stored in the ss registers) and offset (which is stored in the sp register). You obtain the address by doing the following: stack segment value x 16 + offset value.
- We're using segment 07C0h to set up space in our code. So when 07C0h is offset with 0, it will reference to address to 0x7C00. BIOS attempts to boot code from 0x7C00. An example of code that is copied in 0x7C00 is the MBR.
- Each segment increments in blocks of 16 bytes, so 07C0h will give you address range 0x7C00-0x7C0F. The next segment 07C1h will give you address 0x7C10-0x7C1F.
add ax, 288
- To set up a 4K stack space after the bootloader, we need to add 288 obtained from (4096 + 512)/16 bytes per paragraph. The decimal value 288 is equal to 120h.
- The value stored in the ax register now is 08e0h which I've obtained by: 07c0h + 120h = 08e0h (120h is decimal 288).
mov ss, ax
- Copy the value in register ax into the ss register. The offset now contains segment: 08e0h.
mov sp, 4096
- The offset value is 4096 which is 0x1000h. The ss:sp pair gives the value 08e0:1000.
- The bottom of the stack starts at memory address 0x8e00 and top of the stack is at 0x9e00 (from 0x8e00 + 0x1000 = 0x9e00).
Here's a diagram of the code in memory and the space allocated as below.
Note: the bootloader and the memory reference in this diagram are most likely incorrect, I am assuming that it won't be sequential and the assembler will compile the machine code differently. However, the start of the code will be starting at the lower memory address (0x7C00) and the boot signature will start at the higher address (0xaa55 disk signature starts at 0x7c0:0x1fe (physical address 0x7c0*16 + 0x1fe=0x7dfe) which are the last two bytes of the first 512 byte sector which runs from 0x7c0:0x0000 to 0x7c0:0x200(0x7C32 which is the end of the 512 bytes)).
It strange to see space allocated are two blocks of 4096 bytes though: one for the stack and the other contains the code and data. I suspect I am missing something here.
following bootloader code:
It's missing info how it will set up relative address of assembled code, i.e. how the local offsets will be calculated. Usually bootloaders start with org 0x7C00
to make it explicit the code expects to be started at cs:ip = 0000:7C00
. But would you do that, the ds=07C0
would be wrong, that one suggests the code expects the offsets be assembled as if it starts at 07C0:0000
instead of 0000:7C00
. While both addresses target the identical physical memory address, the segment:offset pairs are different then.
Each segment increments in blocks of 16 bytes, so 07C0h will give you address range 0x7C00-0x7C0F. The next segment 07C1h will give you address 0x7C10-0x7C1F.
Each segment gives you 64kiB range, although the start address advances only by 16 bytes, so there's lot of overlap between segments and you can address the same physical address by many combinations. I.e. ds=07C0
gives you window into physical memory range 07C00-17BFF
.
Then your conversions of values to hexadecimal are wrong (see also Michael comments), 288 = 0x120, and 4096 = 0x1000, but you correctly conclude there's 512B of bootloader code (single sector of block device), 4096B of spare space, and then 4096B of stack space. Would you fill up the stack by pushing more than 4096 bytes into it, it will not hit the spare space after code, but will wrap around to 08E0:FFFE
(well above the original start of stack).
I am assuming that it won't be sequential and the assembler will compile the machine code differently.
Quite opposite, instructions and defined bytes in the source code are emitted sequentially in the resulting machine code. Use the "listing" command line switch to see yourself how the assembler emits machine code for particular lines. Would you for example move the text_string db 'This is my cool new OS!', 0
line at the beginning after BITS 16
directive, that text would be then at the beginning of machine code, loaded and executed by BIOS at/from 0000:7C00
address, executing the text bytes as instructions.
来源:https://stackoverflow.com/questions/52127149/understanding-of-boot-loader-assembly-code-and-memory-locations