7

The bootloader will anyway load it at that address? Why specify this to the program?

Mat
  • 202,337
  • 40
  • 393
  • 406
pflz
  • 1,891
  • 4
  • 26
  • 32
  • 2
    I'm going to go out on a limb here and venture that with that statement, absolute addresses compiled into the binary will be correct. – Lasse V. Karlsen Apr 10 '11 at 10:05

4 Answers4

2

What the ORG pseudo instruction does is to tell the assembler to add this offset to all absolute addresses mentioned. For example if you write "MOV AX,my_string" and my_string gets located 1234 bytes into the code, then the assembler generates "MOV AX,7c00h+1234". Less commonly it is also used the other way around to calculate a relative address (such as for a short jump) from a an absolute address given.

Fabel
  • 1,711
  • 14
  • 36
2

You don't have a choice here. Read this article:

http://en.wikibooks.org/wiki/X86_Assembly/Bootloaders

From the above URL, BIOS (which is effectively PC hardware) will make the jump to memory at 0000:7c00 to continue execution in 16-bit mode.

And to quote from above:

A bootloader runs under certain conditions that the programmer must appreciate in order to make a successful bootloader. The following pertains to bootloaders initiated by the PC BIOS:

  • The first sector of a drive contains its boot loader.
  • One sector is 512 bytes — the last two bytes of which must be 0xAA55 (i.e. 0x55 followed by 0xAA), or else the BIOS will treat the drive as unbootable.
  • If everything is in order, said first sector will be placed at RAM address 0000:7C00, and the BIOS's role is over as it transfers control to 0000:7C00. (I.e. it JMPs to that address)

So from bootup, if u want the CPU to start executing your code, it has to be located in memory at 0000:7c00. And this part of the code is loaded from the first sector the harddisk - also done by hardware. And it is only the first sector which is loaded, the remaining of other parts of the code then have to be loaded by this initial "bootloader".

More information here (on harddisk bootup sector and the 7c00 feature):

http://www.ata-atapi.com/hiwdos.html

http://www.ata-atapi.com/hiwmbr.html

Please don't confuse with the starting up mode of the CPU - the first instruction it will fetch and execute is at physical address 0xfffffff0 (see page 9-5):

http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-3a-part-1-manual.pdf

and at this stage it is executing non-volatile (meaning you cannot reprogram it easily, and thus not part of bootloader's responsibility) BIOS code.

Update: 6 Oct 2015

But this BIOS code does have some variation (as highlighted by Michael Petch) - some BIOS will load from 07c0:0000 instead of 0000:7c00, and as extracted from "grub" bootloader source code as well:

.globl _start; _start:
        /*
         * _start is loaded at 0x7c00 and is jumped to with CS:IP 0:0x7c00
         */

        /*
         * Beginning of the sector is compatible with the FAT/HPFS BIOS
         * parameter block.
         */

        jmp     after_BPB
        nop     /* do I care about this ??? */

after_BPB:

/* general setup */
        cli             /* we're not safe here! */
boot_drive_check:
        jmp     1f
        testb   $0x80, %dl
        jnz     1f
        movb    $0x80, %dl
1:
        /*
         * ljmp to the next instruction because some bogus BIOSes
         * jump to 07C0:0000 instead of 0000:7C00.
         */
        ljmp    $0, $ABS(real_start)
Peter Teoh
  • 6,337
  • 4
  • 42
  • 58
  • 3
    I've downvoted this mainly because it isn't required that ORG be 7C00. It is convenient to do it because you can use segment registers of 0x0000. But you can use an ORG 0 if you set up the code in the bootloader to load DS(ES and if need be CS) with segment 0x07C0. If you set a segment to 0x07C0 your ORG is zero because segment:offset(0x07C0:0x0000) is physical address 0x00007C00 (0x07C0<<4+0). Similarly you could use ORG 0x5BD0 if you load an appropriate segment value into _DS_. In that case you'd use a segment of 0x2030 . (0x2030<<4)+0x5BD0 = physical address 0x00007C00 – Michael Petch Sep 25 '15 at 15:46
  • You say _Please don't confuse with the starting up mode of the CPU - the first instruction it will fetch and execute is at physical address 0xfffffff0_ This is true on 80386+, but on an 8086/8088/80286 it starts @ 0xffff0 . – Michael Petch Sep 25 '15 at 16:13
  • It has to be 7C00 necessarily, because the BIOS (which is read-only, and you cannot program that will force the CPU to jump to 0000:7c000. Yes, you can always load DS with segment 0x7c0, but who is doing that? The CPU got redirected to jump to 0000:7c00 by the BIOS, and someone must be there to give the CPU the next instructions to execute? Not sure if you have done hardware debugger before, but I have actually step through from the VGA bios (which starts at c000:0000) all the way into 0000:7c00, and you cannot change this BIOS part. – Peter Teoh Oct 06 '15 at 00:11
  • More links to you help yourself: (1) http://www.bandwidthco.com/whitepapers/datarecovery/vanalysis/partition/mbr-bios/Master%20Boot%20Record%20and%20Partition%20Table.pdf (good coverage on MBR loading direct into 0000:7c00 and you cannot change that!!) (2)http://www.coresecurity.com/system/files/corelabs-ekoparty-2012-VGA_Persistent_Rootkit.pdf (page 40) (3)https://www.blackhat.com/presentations/bh-europe-07/Kumar/Whitepaper/bh-eu-07-Kumar-WP-apr19.pdf (which explained how POST jump to 7c00, and POST is the BIOS part). – Peter Teoh Oct 06 '15 at 00:14
  • 2
    Having been working on real hardware creating real bootloaders since about 1985 when I was playing with Wendin PCNX and PCDOS I know the reality. It was also very useful to be on compuserve and be in discussions at the time. When IBMDOS 1.1 shipped IBM (they ported DOS from CP/M) they didn't set the segment to explicitly. When DOS 2.x shipped (IBM rewrote DOS basically from scratch) this particular bug was fixed in their bootloader. Microsoft DOS 3.3 (circa 1983) also made sure the registers were explicitly set – Michael Petch Oct 06 '15 at 00:18
  • 2
    The compuserve forums had many discussions about the ambiguity in how the BIOS would jump to a particular physical location but didn't specify that the segment (in CS:IP) even had to be 0x0000. Many BIOS manufacturers in the 90s started jumping to `0x07C0:0000h` and some antiquated versions of DOS (1.1) and ones that didn't catch on started to fail. It then became very common knowledge that you must not assume much besides the contents of `dl` and the fact you'd be in real mode (or unreal mode on a 386). – Michael Petch Oct 06 '15 at 00:22
  • 1
    In the early 2000s when Bochs was being developed they too were far jumping to 0x07C0:0000 (like many BIOS manufacturers) and they had people complaining their bootloaders wouldn't work. – Michael Petch Oct 06 '15 at 00:25
  • 1
    There is a difference between writing a bootloader from an academic perspective and targeting a *particular* VM/emulator/physical hardware but the shortcuts academics seem to take and teach doesn't necessarily make for the most portable mechanism. Anyone who is looking to write a real bootloader will know not to make any assumptions because they understand the ramifications. I should note that in PCDOS 2.1 not only did they explicitly set all the registers that included _CS_ and they would do equivalent _FAR JMP_ to a local label 0x0000:0x7C00+offset to set _CS_ to 0. – Michael Petch Oct 06 '15 at 00:29
  • I say _equivalent_ because what they actually do is copy the bootloader down to lower memory just above the BDA and do a FAR JMP there (with a CS of 0) to continue execution. – Michael Petch Oct 06 '15 at 00:31
  • If you don't believe anything I am saying, then I suggest you get your hands on a iBM DOS 1.1 and then a 2.1 image. If you disassemble the bootloaders you will observe these fundamental changes. If you take MSSOS 3.3 you will discover MS didn't make assumptions either. My memory may be going but I know that it specifically doesn't make any assumptions, but an earlier version may have done it correctly too. – Michael Petch Oct 06 '15 at 00:40
  • 1
    As well if you look carefully even on well known sites like [OSDev Wiki](http://wiki.osdev.org/Entering_Long_Mode_Directly) (and the Grub source code) and you'll see things like `Some BIOS' may load us at 0x0000:0x7C00 while other may load us at 0x07C0:0x0000. Do a far jump to fix this issue, and reload CS to 0x0000.` . They too are making it clear to people to be aware that you can't assume even CS contains 0. in fact it could be ANY of the possible combinations where ((segment<<4)+offset) = physical address 0x00007c00 – Michael Petch Oct 06 '15 at 00:48
  • Cool, I don't your wide experience Sir, salute to you!! Just have one board and one time of debugging from VGA to BIOS to bootloader, and a recent one though (5years back). I have updated your comments into the write-up above, THANK YOU SIR! – Peter Teoh Oct 06 '15 at 01:08
  • 3
    Not a problem at all. I just want people who might copy and paste code on SO to have it more likely to work across platforms. I have removed my down vote and upvoted your answer. A lot of people get caught by this across environments and then come to SO wondering why their code doesn't work as expected. – Michael Petch Oct 06 '15 at 01:11
0

You have not given any context for this question. But I will attempt to give some form of answer.

When the program is executed after being loaded into memory the program must be located somewhere, imagine this is address 7C00. The processor starts excuting somewhere, in your case most likely 7C00. The ORG statement is telling the assembler that addresses for the following instructions will appear at this address.

Why not 0? Well, your processor may want other things at those addresses, ie. interrupt vectors.

The datasheet for your processor will give you more information on its startup sequence.

Good luck.

From a quick goodle...

http://f.osdev.org/viewtopic.php?f=1&t=9543

Angelom
  • 2,413
  • 1
  • 15
  • 8
  • 1
    It is possible to start bootloader at address 0 (i.e.: `org 0`) when you set your code segment to 07C0. Then the segment will start at 7C00 and its first offset (0) will be at the address 07C0:0000 which is 7C00 physically. It could be achieved by far-jumping to that address just one instruction after the jump, to set the CS:IP registers properly. Then you can copy CS to DS and ES too if you want your data be offset 0 from the beginning of the 07C0th segment. – SasQ Jun 17 '12 at 19:27
  • SasQ, please read my comments above - you really cannot change this 7c00, as it is fixed by the BIOS hardware that load from MBR into 7c00 memory, and is also fixed by the jump from BIOS into 7c00 to continue the execution. – Peter Teoh Oct 06 '15 at 00:20
-2

I also very confused about it. It looks like it depends on your code and link arguments. If you look at the boot.S in grub2, it has no ".org 0" or ".org 0x7c00".

I also wrote a simple bootloader code. What I use is ".org 0", but I can remove it without breaking the function. My code is build like this:

all:

    i686-elf-as -o boot.o boot.S
    i686-elf-ld --oformat=binary -Ttext=0x0 -o boot.bin boot.o
APC
  • 144,005
  • 19
  • 170
  • 281
ffcactus
  • 152
  • 8