Relocatable Code: How do you do it?
Aras Vaichas asks:
"I am designing the kernel software for a radio modem. The processor is an AMD186ED - 1MB address space split evenly between DRAM and FLASH/SRAM. Initially I was going to port FreeBSD to it but after scouring the FreeBSD kernel code discovered that there was too much 80386 code there (memory manager, etc). This makes life a little more difficult so I am going with another commercially available realtime operating system. My problem is that I want to implement a Flash File System and be able to execute programs (EXE style) from it. How does the BIOS in a PC relocate the EXE file? This is done via a BIOS call and therefore the code is in the BIOS. Does anyone have or know where I can get the (any flavour of) BIOS source code? "
You are pretty well screwed if you want to do position independant code on iAPx86 processors prior to the 80386, because of the glorious fun we call Segmented Memory.
On the 8088/8086/80186/80286 and compatibles, you have essentially two kinds of jump instructions: short jumps that add a 8-bot or 16-bit offset to the IP register but do not affect the CS register (remember, your full instruction counter is the 20-bit sum IP+16*CS), and far jumps that replace both the IP and the CS with new values, but do not allow relative addressing.
So you see, you can either have position independant code (jumps addressed from the current IP) or you can have more than 64k of code, but not both. The way around this is to use far jumps in your executable files and modify the target addresses when you load the code into memory at runtime.
I rather doubt that there is a BIOS call to relocate the executable file. I've written a multitasking OS for 8086's, and I don't remember there being such a BIOS call. In fact, I had to write a relocating linking loader myself, so I feel pretty comfortable saying there is no such beast in the motherboard BIOS. You are probably confusing the MS-DOS BIOS (loaded from the file BIOS.SYS on the boot disk) with the motherboard BIOS (contained in ROM). The basics of an .EXE relocating linking loader are, however, pretty simple:
In their header, .EXE files have a table of the offsets of all absolute addresses in the program that are in need of relocation. All you do is, once you have loaded the .EXE into it's new home in RAM, go through the table and add the new base address of the program in RAM to each indicated address in the program image in memory.
There is a reasonable explaination of the .EXE file format and the relocation process on pages 83-85 of the Microsoft MS-DOS Programmer's Reference (Microsoft Press, ISBN 1-55615-546-8, US$27.95) and on page 307 of Disecting DOS (Michael Podanoffsky, Addison Wesley, ISBN 0-201-62687-X, US$39.95)
The Podanoffsky book will provide you with real code to perform this bit of sorcery, but I will quote from the M$ book, since it should be considered more authoritative:
The preceeding excerpt refers to a memory structure that contains the contents of the .EXE header file. In C structure notation the header looks like this: (in this case, int is 16-bits)
struct EXEHEADER {int exSignature;
int exEstraBytes;
int exPages;
int exRelocItems;
int exHeaderSize;
int exMinAlloc;
int exMacAlloc;
int exInitSS;
int exInitSP;
int exCheckSum;
int exInitIP;
int exInitCS;
int exRelocTable;
int exOverlay;
}
DISCLAIMER: If the OS you are using uses a different executable file format, all of the above is inaccurate, but may be helpfull for purely theoretic purposes, since anything running in x86 real mode needs to be able to solve this bit of kludgery.
-- Jeff Dutky