Chandra wrote:But it's upto the assembler to pass the address of the label GDTStart as an operand to the LGDT instruction, when spitting the final binary. And if I'm not wrong, it uses one of the segment register(as it is) and then supplies the offset portion equivalent to memory location of GDTStart. Now since the offset is already specified by the ORG directive, all we need to do is make sure all the segment registers are properly set so that segment:offset references necessarily point to the linear address of the GDT in memory. If that's done, the final address passed would be a valid linear address.
No, no, no. DOS is not a bootloader that loads your code at a fixed physical address, but an OS that supports some (neanderthal form of) multitasking and can have multiple programs loaded in memory at once. It can do that because programs expect DOS to set CS/DS/ES to the location where it loads the program. That trick makes all 16-bit offsets correct independent of where the program was loaded and thus avoids all need for linking at run time (something you still need to do for DOS .EXE files).
The flipside of this is that you can not assume what the value of CS/DS is and that the assembler or linker cannot possibly generate physical addresses (after all, it does not know DS and therefore can't compute the needed segment * 16 + offset). Specifically, segment will never ever be zero, since that would imply that your code doubles as the interrupt vector table.
Even worse, suggesting to change CS/DS at runtime shows your lack of real-mode experience. Changing segment registers does not magically move the actual data in physical memory, and so the location of the GDT and GDTR will still be at initial segment * 16 + offset. Which is that very physical address you don't know at link time.
Homework for Chandra: write a bootloader that also works when it isn't loaded at 0x7C00 but rather any unused location in RAM. Your task will be to load sector 2 of the boot drive directly after the bootloader. The only thing you know is that it jumps to the first byte in it (which can be
any CS and
any IP). To make it easy, you may assume SS:SP already points to a valid stack not overlapping anything else. At least, please refrain from contributing to discussion until you have tested an implementation of this exercise, or you tested and confirmed a working fix for the OP's program.