also possible:
at least a few DOS-era compilers had mechanisms for creating DLL-like
libraries. this may be a possibility, but one will need to investigate this.
but, assuming dynamic linking:
now, the big fun in this case, is not the loading/relocation, but the MZ-EXE
file format.
for example, the format lacks a symbol table (I think, but I have hardly
really investigated the MZ-EXE format).
The .LIB format is a collection of relocatable object modules, which
have a hashed symbol table and a name header in each module.
Name header:
vvv QUOTE vvv
82H LHEADR--LIBRARY MODULE HEADER RECORD
========================================
Description
-----------
This record is very similar to the THEADR record. It is used to
indicate the name of a module within a library file (which has an
internal organization different from that of an object module).
History
-------
This record type was defined in the original Intel specification with
the same format but with a different purpose, so its use for libraries
should be considered a Microsoft extension.
Record Format
-------------
1 2 1 <-String Length-> 1
82 Record String Name String Checksum
Length Length
NOTE: In LINK, THEADR, and LHEADR records are handled identically.
See Appendix 2 for a complete description of Microsoft's library
file format.
^^^ UNQUOTE ^^^
Symbol Table Hashing:
vvv QUOTE vvv
Dictionary
----------
The remaining blocks in the library compose the dictionary. The number
of blocks in the dictionary is given in the library header. Note that
there should always be a prime number of blocks in the dictionary.
The dictionary is a hashed index to the library. Public symbols are
essentially hashed twice, though in fact, both hash indexes are
produced simultaneously. The first hash index, the block index, is
used to determine a block within the dictionary in which to place the
symbol. The second hash index, the bucket index, is used to choose a
bucket within the block for the symbol. Blocks always have 37 buckets;
they are the first 37 bytes of each block. If a bucket is full, it
contains a nonzero value that points to the text of the symbol. To
actually find the symbol, take the bucket value, multiply it by two,
and use the resulting number as a byte offset from the beginning of
the block.
Collisions (that is, two or more distinct symbols hashing to the same
block and bucket in the dictionary) are resolved by a technique known
as linear open addressing. At the same time the hash indexes are
produced, two hash deltas are also produced. If a symbol collides with
a symbol already installed in the dictionary, the librarian attempts
to find an empty bucket for it by adding the bucket delta to the
bucket index and using the result mod 37 as a new bucket index. If
this new bucket index points to a bucket that is empty, the librarian
will install the symbol in that bucket. If the bucket is not empty,
the delta is applied repeatedly until an empty bucket is found or
until it is determined that there are no empty buckets on the block.
If the latter is the case, the block delta is added to the block
index, and the result mod the number of blocks in the dictionary is
used as a new block index. With the new block index and the original
bucket index, the sequence is repeated until an empty bucket on some
block is found.
The number of blocks and the number of buckets are prime so that no
matter what values of hash indexes and deltas are produced for a
symbol, in the worst case, all possible block-bucket combinations will
be tried. Once a free block-bucket pair has been found for a symbol,
the pair and information concerning its place of definition must be
installed. Since a bucket is a single byte pointing into a 512-byte
block, the bucket can give at best a word offset within that block.
Thus, symbol entries within a dictionary must start on word
boundaries. Since bytes 0 through 36 of each dictionary block make up
the hash table, the first symbol entry will begin at byte 38
(decimal).
^^^ UNQUOTE ^^^
.... but I would not be surprised if in reading the symbol table, it
should be possible to read it and then sort it yourself.