Reason for my question is that Starman seems to believe the GRUB Legacy author's explanation (see for the following inexplicable code:
7C4B EA507C0000 JMP 0000:7C50 ; Long Jump to the next instruction
; because some bogus BIOSes jump to
; 07C0:0000 instead of 0000:7C00.
When I perform the Intel-specified algorithm for constructing effective addresses on the first memory reference, I multiply 07C0: by 16 (effectively left shifting it four bits or one half-byte). Then I add the offset of :0000 and get the decimal address 31,744.
If I left shift the segment of the second memory reference four bits I still have 0000: and the offset of :7C00 still addresses the location 31,744. So my gut reaction is the author of this GRUB Legacy boot sector code is pulling our leg. Regardless of the form of the memory reference made by any BIOS, if the effective address calculates to decimal 31,744, then it seems there is no problem that this Long Jump is solving.
On the assumption that the code's author merely expressed a bogus physical memory location in a way which seems to be the same physical location as was correct, I started to think about how one would deal with a BIOS that sent one to the wrong address. The five byte Long Jump does not appear to be the solution to anything. Five NOPs would serve the same purpose (in fact, simply beginning the boot sector code five bytes earlier and eliminating the Long Jump would have the same effect as a Long Jump to the next instruction).
If the BIOS jumps to the correct location (7C00), no problem. If the BIOS jumps to a location above 7C00, then no code loaded at 7C00 can fix that problem. If the BIOS jumps to a location between 7C00 and 7C4B, then data stored in that area (or instuctions being interpreted with bytes missing from them) will likely cause a crash. Should the BIOS jump to exactly 7C4B, the TEST instruction will have been over-written (by the Long Jump) and the JNZ to 7C54 will be executed based on the last math performed in the BIOS.
For BIOS jumps below 7C4B, again mis-aligned instructions are likely to cause a crash. With good luck, some portion of the boot sector code will be executed. The results of such execution will depend on exactly what "bogus" memory address the BIOS does jump to. So is the author of this boot sector code pulling our leg with a story about "bogus BIOS's that jump to the wrong location"?
I note in Luke Luo's BLOG, that the GRUB2 boot sector, although different from the GRUB Legacy boot sector, retains this inexplicable Long Jump. So if the original author of the GRUB Legacy boot sector was playing a joke on us, it's a pretty successful joke (it has survived a complete re-write of GRUB). I'm left with the choice of believing an incredible assertion about some un-named BIOS and a solution to such a problem that seems to actually do nothing or believing that the author of the original boot sector was playing a joke on us.
Luke Luo seems to accept the writing of NOP instructions to 7C66 and 7C67, as evidence that he does not have a BIOS that jumps to the wrong location. The GRUB2 boot sector that was written to my Flash Drive by Linux Mint 13, has these same NOPs. However the GRUB2 boot sector written to my laptop's hard drive (by Debian Etch) has a short jump to the next instruction written at 7C66 and 7C67 (note that Luke Luo shows us that the original boot sector stored at /usr/lib/grub/i386-pc/boot.img has the Debian value). Both alternatives have the same effect (execute the instruction that follows them), so both boot sectors work. Neither has the efficiency I would expect in a boot sector where there are only about 450 bytes available for code that must load another sector and execute it (including error messages for when something goes wrong with that simple operation and the eight-byte address of the sector itself).
So am I missing something, or have I identified a kludge that should be eliminated from the GRUB boot sector (to make room for more meaningful code)?
You are missing the difference in actual state of CPU (while the physical address is the same one, that's correct).
When BIOS does
JMP 0000:7C00
:your first instruction is located at
cs=0000, ip=7C00
, and your machine code has to be compiled for this kind of relocation, whenever it does any absolute addressing, like for examplemov ax,cs:[myTable]
(thenmyTable
can be something like0x7F00
).When BIOS does
JMP 07C0:0000
:your first instruction is located at
cs=07C0, ip=0000
, so things likemyTable
will be more like0x0300
.Thus the first long jump at the beginning of code will "normalize" the same physical address 31,744 into expected
cs:ip
form, making the rest of absolute addresses in the bootloader code work correctly.