The reason your code doesn't work is because your first jump instruction is an infinite loop. Think about it. BITS and ORG are not instructions, they're assembler directives, so they get removed from the executable. The first thing the CPU sees when it executes your code is your jump to 0x7c00. Now, where does the BIOS load your program? At 0000:7c00. In short, you're jumping back to the jump instruction.

You misunderstand. Your jump to 0x7c00 is at 0x7c00, so it's jumping to itself; hence, an infinite loop.

The BIOS loads the bootloader to 0x7c00 in memory and then jumps to it. The CPU then blindly executes whatever instruction is there. In your case, the instruction at 0x7c00 tells the CPU to jump to 0x7c00, so it does. Then it executes the instruction there, which tells it to jump to 0x7c00 again, so it does, and so on, ad infinitum. That's why it's not working. Take out jmp 0x7c00 and it should work.

Why are you using hardcoded memory offsets instead of labels, and why did you write "0x10h" (0x10 = 10h)? Also your times directive is wrong, it should be times 512 - ($ - $$) db 0. The BIOS probably isn't even loading the executable because there won't be a boot signature at the 511th byte.

I know that labels and memory offsets are the same, but labels are much easier to use and understand: if you change your code, you don't have to recalculate the offset yourself, labels split your code into neat blocks, it's much easier to figure out where the jump is going when it's to a label and it's generally easier to reason about the flow of control. Using hardcoded offsets when labels are more appropriate is stupid; you're making more work for not only yourself, but everyone who looks at your code. When you ask for help, do you expect people to be sitting there trying to figure out where in your program is FF bytes after the origin? Am I meant to look up an x86 instruction reference to figure out how many bytes each instruction and its arguments takes up in the executable file when it's assembled? Just use labels.

WalkerRoger12 wrote:

labels are accessed via memory itself anyways

No, the labels are removed where you declare them and converted into offsets where you use them. They don't make it into the final executable.