Robert Spykerman <robert.spykerman@[EMAIL PROTECTED]
> wrote:
>
> Hmm... I used to think that the OS would map each new process into a
> virtual space of its own so every program could start at the same
> address...
That's correct. Relocatable (.o) files are generally assembled as if at
address 0 (IIRC), and then contain relocation information so that the
linker can put them at whatever address it wants. Shared libraries
likewise have to be relocatable. But executables specify fixed virtual
addresses which they are supposed to be loaded at, and don't contain
relocation information.
> Any good ideas where to get a firm grasp of what's going on?
>
> There's a lot of material out there, but if you know of any one
> resource that may help me out the most (both for linux ELF's and mach-
> o's I'm interested in) - that would be great. Simple, a good starter's
> guide that sort of thing ie, dummies guide to linking said binaries.
I'm still not quite clear whether you're having trouble getting Apple's
toolchain to assemble and link a working lina binary, or if you need to
learn the internals of ELF/Mach-O so you can port SAVE-SYSTEM, or both.
I don't know of a tutorial that covers more than one format. The first
few pages of Apple's Mach-O File Format Reference (which I linked to a
few messages back) give a pretty good overview of how an object file is
put together. ELF is pretty similar overall.
And...here are some quick thoughts from me on the subject...
An executable/linking format allows two views of file contents. An
assembler puts code and data in _sections_ (relocation information is
always attached to sections). The linker combines sections into
_segments_ which the program loader maps into memory.
A segment tells the program loader to map a chunk of the file (offset
and length) to a chunk of virtual memory (address and length). If you
want uninitialized memory, you just set the virtual memory length to be
larger than the length you're loading from the file. Virtual memory
addreses must be equal to file offsets modulo the virtual memory page
size (usually 4096) so they can be loaded efficiently with mmap.
In an ELF file, sections and segments are (theoretically) totally
separate views of a file. In fact, under Linux, if you don't want to do
any dynamic linking, you can make an executable that has no sections,
only segments (BSD goes a little crazy about enforcing sanity checks on
executables, so this won't work there).
In a Mach-O file, they're not so separate (segments are composed of
sections), but that's not a big difference. Actually, it looks like
Mach-O is simpler and saner than ELF, so once you figure out what lina
is doing, porting it shouldn't be too hard.
Let's see, what else? I'll start with things I think it's useful to
know if you're assembling and linking with a normal toolchain, and move
toward making your own custom binaries from within Forth.
The assembler sets the permissions (read/write/execute and
initialized/uninitialized) on the sections. The linker never modifies
these, it just combines sections into segments. The assembler generally
won't allow you to change permissions on the default sections (.text,
..data, etc.), but if you define your own sections, you can set them
however you want.
But the linker only looks for the normal sections, so if you want to use
different section names, you have to write a linker script. These can
be very simple: basically you have to set the base address, then tell it
how to combine sections into segments. I have a minimal example of how
to create your own ELF headers using the GNU assembler and linker (on
PPC Linux) at http://qualdan.com/examples/linking/
but it's not
commented at all. The info page for ld does describe linker scripts,
and I can go into detail about it if you're interested. The following
might work for the original lina (replacing ??? with the actual base
address). Probably won't work on BSD though; IIRC .text and .data
segments.
SECTIONS
{
. = ??? + SIZEOF_HEADERS;
.text : { *(forth) }
/DISCARD/ : { *(*) }
}
Usually executables have the same structure in memory as in the file
(though often there is a gap between code and data). And usually the
headers are also mapped into memory. So to SAVE-SYSTEM, you just have
to know where the headers are, store the new (larger) sizes, and then
write everything out to a file.
--Josh


|