Relocatable Code: How do you do it? 11
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? "
and now: my flippant answer! (Score:1)
This is, of course, an absurdly flippant and condescending answer, given that you already have the hardware in hand and it would be rediculous to go out and spend more money on extra hardware when you can just code around the brokeness of what you have.
However, if it takes you an extra several weeks to code up the relocating linker-loader, and you are paid the average for a good programmer, you will end up spending more on the relocation software that you would have on a real computer. But your boss (or the bookkeepers, at least) probably won't see it that way.
Cheers!
-- Jeff Dutky
a few more remarks (Score:1)
Second, as for shared ELF libraries: you will notice that the poster specified that he is using a 80186 clone (AMD186ED) which is simply an 8086 with some extra peripheral hardware (timers, parrallel I/O, etc.) on chip and a couple extra instructions. It does not implement any of the 80386 extensions that ELF shared most likely relies on. In 80386 protected mode you can have full 32-bit offsets for NEAR jumps, which gives you true position-independant code without having to resort to load-time kludgery. The 8086 and it's real-mode/16-bit bretheren don't have such niceties. Shared ELF stuff is probably not applicable here.
-- Jeff Dutky
Shared libs... (Score:1)
EXE tools (Score:1)
Check out ecos from cygnus (Score:2)
In general, processors have two kinds of addresses for data and instructions: absolute and relative. Absolute is faster since no airithmetic is involved. A
Relative branches are slower because of the arithmetic, but on some machines the instructions can be quite a bit shorter because a full address is not necessary. Of course, this itself may make enough of a speed difference to cancel the arithmetic, and the code size reduction may be worthwhile too. The linker probably has to compute relative distances at link time.
None of this helps directly with your request for BIOS code, but if you want that just to figure out how it copies code, you may not need it. If your processor supports relative addressing, you probably don't. Make sure you can do everything you want with relative addressing. Some processors are troublesome this way, at least memory says so, but I spent 7 years on just m68k, so I'm a bit hazy on others now.
Of course, you may still need absolute addressing if system subroutines are at absolute locations in low or high memory, and if you have memory mapped I/O.
--
Other Techniques (Score:2)
There is an old trick that I've used on 8-bit CPUs. Link the program as an absolute memory image at two different load addresses. Write a program that compares the two images and outputs a relocation list to a file. Then you can use a simple loader that takes an absolute memory image and the relocation list to load the program at any desired address. You should be able to do this with COM files on the 80x86.
relocatable code on x86 (Score:5)
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