[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: shared libraries for MiNT
A Proposal for Implementing Shared Libraries
I think I've finally figured out a "good" way to implement shared
libraries (i.e. low overhead, doesn't need VM, requires few changes
to existing applications). Here's my proposal; please let me know what
you think. (In case it isn't obvious, this is *very* far from being
cast in stone :-). I do think we need to do shared libraries soon,
though.)
A shared library will be implemented as a DRI format object file, with
the GST long name symbol table. A program linked with shared libraries
will have the same format, but with an additional header prepended
which gives the names and version numbers of the shared libraries it
requires.
I really think we need to have an object format that includes separate
segments for blockdata, blockbss, and maybe even blocktext for constant
arrays & structures. That's the only way to insure enough breathing space
while using 16 bit offsets.
Both the libraries and the programs will be compiled to use
register A5 as a base register (e.g. when compiled with gcc they will
be compiled with -mbaserel). They need not be position independent;
the libraries will appear at the same virtual address (determined at
load time) in every process, and programs will be relocated at load
time by the kernel.
Just a minor note, a5 is unusable for this purpose because it is zeroed
by Supexec. The current baserel stuff uses a4.
The data and bss segments of a given shared library will always be
located at the same (relative) offset in the data/bss area of
a program using that library. (Note that I'm going to call the
"data/bss area" just the "data segment" from here on in, because the
bss is just a special part of the data segment from the kernel's point
of view.)
I don't understand how this can be enforced without collisions. Is the load
address & size of the data section stored in the respective library? What
happens if the library is revised and the data section changes in size? Also,
it seems that trying to deal with gaps from unused libraries will be messy...
Finally, what about library code referencing data symbols that are external
to the library? (I think e.g. curses references some of termcap's variables...)
Is this scheme going to only support Atari-generated libraries, or will anyone
be able to write a shared library?
Does this make sense? The key thing is that since everyone is using
register A5 as a base register, the libraries can always find their
data (at the particular fixed offset into the data segment assigned to
them).
It certainly has that advantage. My previous scheme involved resetting the
base register on a per-library basis, but I couldn't figure out how to cope
with libraries that called each other, or called back into user code (like
bsearch or qsort, for example...).
The disadvantage of this scheme is that once more than 64K of data is
filled up, libraries and/or programs that use 16 bit offsets will be
in trouble. There are ways around this, of course.
Another disadvantage is that program load times will be longer, since
the kernel is going to have to do the relocation and symbol resolving.
Meaning that executables must never be stripped, as well, right? And, just
to clarify, this is not an attempt at providing dynamic loading and linking
as well, is it? (Oh, I see, you can strip any resolved symbols, of course,
and only leave the unresolved ones in a program file...)
An alternative would be to use something like Sun's global offset table.
That scheme is slower, though, since it adds another layer of indirection
to variable references.
Please let me know your thoughts on this matter.
Perhaps if we ate up yet another address register for a per-library base
register. Allow the data segment to be sized and located dynamically, with
the location stored in the main program's data region, and passed into (say)
a3 before entering a library routine. This pretty much requires stub routines
to be linked into every program, as well as any library that calls another
library. The stub will pull the correct base pointer to use from the main
program's a4 base, and restore the old register before returning. The easiest
way to deal with this is to assign fixed offsets from the program's base
pointer for each library's private base pointer. Still can't get away from
assigning some kind of fixed resource to each library, I guess.
Something else to establish that could help this discussion - is gnulib.a
treated as a single library, or does it get broken up into smaller functional
groups?
-- Howard