home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 June
/
SIMTEL_0692.cdr
/
msdos
/
pgmutl
/
val_link.arc
/
LIBRARY.C
< prev
next >
Wrap
Text File
|
1989-02-18
|
13KB
|
308 lines
/* LIBRARY.C */
/*+-------------------------------------------------------------------------+
| |
| process_libraries |
| |
+-------------------------------------------------------------------------+*/
void process_libraries()
BeginDeclarations
file_info_ptr current_lib_file_info;
EndDeclarations
BeginCode
library_processing_start_time = Now;
While library_request_count Exceeds 0
BeginWhile
TraverseList(lib_file_list, current_lib_file_info)
BeginTraverse
process_library(current_lib_file_info);
EndTraverse;
EndWhile;
write_temp_file(0, Null, 0, 0, 0);
file_close_for_write();
return;
EndCode
/*+-------------------------------------------------------------------------+
| |
| process_library |
| |
+-------------------------------------------------------------------------+*/
void process_library(file_info_ptr lib_file)
BeginDeclarations
#define Lib_file (*lib_file)
bit_32 pos;
public_entry_ptr pub;
#define Pub (*pub)
EndDeclarations
BeginCode
While Lib_file.request_count Exceeds 0
BeginWhile
file_open_for_read(lib_file);
Lib_file.pass_count++;
TraverseList(Lib_file.external_list, pub)
BeginTraverse
LoopIf((Pub.type_entry IsNot public_in_library) OrIf
(Not Pub.Library.requested));
pos = Bit_32(Pub.Library.page) * Bit_32(Lib_file.page_size);
file_position(pos);
Lib_file.module_count++;
obj_tmodule();
If Pub.type_entry IsNot internal
Then
linker_error(12, "Library directory error:\n"
"\tLibrary: \"%Fs\"\n"
"\t Module: \"%Fs\"\n"
"\t Offset: %lu\n"
"\t Error: Above module did not resolve \"%Fs\"\n"
"\t when the library directory indicated it "
"would.\n",
Lib_file.filename,
(*tmodule_name).symbol,
pos,
Pub.symbol);
EndIf;
EndTraverse;
file_close_for_read();
EndWhile;
return;
EndCode
#undef Lib_file
#undef Pub
/*+-------------------------------------------------------------------------+
| |
| process_library_directories |
| |
+-------------------------------------------------------------------------+*/
void process_library_directories()
BeginDeclarations
file_info_ptr current_lib_file_info;
EndDeclarations
BeginCode
library_directory_start_time = Now;
public_sort_array = (public_entry_ptr_array)
allocate_memory
(Addr(dynamic_pool),
Bit_32(sizeof(public_entry_ptr)) *
Bit_32(MAX_PUBLICS_IN_LIBRARY));
TraverseList(lib_file_list, current_lib_file_info)
BeginTraverse
process_library_directory(current_lib_file_info);
EndTraverse;
release_pool(Addr(dynamic_pool));
return;
EndCode
/*+-------------------------------------------------------------------------+
| |
| process_library_directory |
| |
+-------------------------------------------------------------------------+*/
void process_library_directory(file_info_ptr lib_file)
BeginDeclarations
#define Lib_file (*lib_file)
bit_16 entry_number;
bit_16 current_block;
library_directory_ptr directory_page;
#define Directory_page (*directory_page)
library_file_header_ptr lib_hdr;
#define Lib_hdr (*lib_hdr)
bit_16 n_directory_blocks;
public_entry_ptr pub;
#define Pub (*pub)
public_entry_ptr_array public_array;
library_symbol_entry_ptr symbol;
bit_16 symbol_count;
bit_16 symbol_index;
#define Symbol (*symbol)
bit_16 *symbol_in_page;
#define Symbol_in_page (*symbol_in_page)
EndDeclarations
BeginCode
lib_hdr = (library_file_header_ptr) object_file_element;
file_open_for_read(lib_file);
file_IO_limit(sizeof(library_file_header_type));
file_read(object_file_element, sizeof(library_file_header_type));
If Lib_hdr.flag IsNot 0xF0
Then
linker_error(4,"File \"%Fs\" is not in LIB file format.\n"
"\tThis file has been ignored.\n",
(*lib_file).filename);
Delete lib_file FromList lib_file_list EndDelete;
file_close_for_read();
return;
EndIf;
Lib_file.page_size = Lib_hdr.page_size + 3;
Lib_file.request_count = 0;
First(Lib_file.external_list) =
Last(Lib_file.external_list) = Null;
n_directory_blocks = Lib_hdr.n_directory_blocks;
file_position(Lib_hdr.directory_position);
file_IO_limit(0);
symbol_count = 0;
public_array = public_sort_array;
For current_block=0;
current_block LessThan n_directory_blocks;
current_block++
BeginFor
file_read(object_file_element, 512);
directory_page = (library_directory_ptr) object_file_element;
For entry_number=0; entry_number LessThan 37; entry_number++
BeginFor
symbol_index =
Directory_page.offset_to_symbol[entry_number] ShiftedLeft 1;
LoopIf(symbol_index IsZero);
symbol = (library_symbol_entry_ptr)
Addr(Directory_page.offset_to_symbol[symbol_index]);
symbol_in_page = (bit_16 *)
Addr(Symbol.symbol[Symbol.length_of_symbol]);
If case_ignore.val
Then
far_to_lower(Symbol.symbol, Symbol.length_of_symbol);
EndIf;
pub = lookup_public(Symbol.length_of_symbol, Symbol.symbol, 0);
/*+-------------------------------------------------------------------------+
| |
| The Microsoft linker does not seem to concern itself with the ambiguity |
| which occurs when more than one library contains a module resolving an |
| external reference. It just seems to take the module from the first |
| library which can resolve the external. This linker behaves in the |
| same manner except it will log when it ignores a module in a library. |
| |
+-------------------------------------------------------------------------+*/
If Pub.type_entry IsNot unused
Then /* Log the ambiguity. */
linker_error(4,"The symbol \"%Fs\" is defined in the libraries\n"
"\t\"%Fs\" and \"%Fs\".\n"
"\tThe latter has been ignored.\n",
Pub.symbol,
(*Pub.Library.lib_file).filename, Lib_file.filename);
Else
Pub.type_entry = public_in_library;
Pub.Library.page = Symbol_in_page;
Pub.Library.lib_file = lib_file;
Pub.Library.requested = False;
If symbol_count NotLessThan MAX_PUBLICS_IN_LIBRARY
Then
linker_error(8,"Limitation of not more than %u public symbols in "
"a library\n"
"\texceeded for library \"%Fs\".\n",
MAX_PUBLICS_IN_LIBRARY,
Lib_file.filename);
EndIf;
*public_array++ = pub;
symbol_count++;
EndIf;
EndFor;
EndFor;
file_close_for_read();
If symbol_count Exceeds 0
Then
sort_directory(0, symbol_count-1);
public_array = public_sort_array;
For entry_number=0; entry_number LessThan symbol_count; entry_number++
BeginFor
Insert *public_array++ AtEnd InList Lib_file.external_list EndInsert;
EndFor;
EndIf;
return;
EndCode
#undef Pub
#undef Lib_file
#undef Lib_hdr
#undef Library_page
#undef Symbol
#undef Symbol_in_page
/*+-------------------------------------------------------------------------+
| |
| sort_directory |
| |
+-------------------------------------------------------------------------+
Well, there is always much ado concerning the best sort method for a
particular application. What is used here is a simple "quick sort".
See Knuth, "Searching and Sorting", page 114 for a description of the
algorithm. What is really important here is why we are sorting. After
the OBJ modules are processed, we must scan the libraries to see what
modules from the library must be included. If the symbols in the
symbol table are in ascending module order, then we will include modules
from the library in ascending order. This may not seem too important
at first glance, but consider that the library will be heavily buffered
and we can reduce I/O overhead by processing modules in the same buffer.
We may not get all the modules in one pass (a module at the end of the
library could require a module at the beginning of the library). However,
experience has shown that all modules from a library can usually be
included in less than three passes. The linker statistics will show
the number of passes for and modules included from each library. If
you want to test this theory, just comment out the sort in the
procedure "process_library_directory" and compare the number of passes
before and after.
Now, all this could be avoided if the librarian had placed the modules
in the library in some sort of an approximation of a topologically
sorted order. (A true topological sort is not usually possible because
relational loops are not all that infrequent.) However, if modules with
relational loops were placed close to each other, it is very likely
that the I/O buffering could cause the library to be fully processed in
one pass. This would improve performance, but it would not insure that
a library could be processed in exactly one pass.
Consider the case where a relational loop occurs with modules which are
not in the same library (this case forces multiple passes). E.G.,
suppose module A1 in library A requires module B1 in library B. Further,
suppose module B1 in turn requires module A2 back in library A. When
processing library A (the first time), we have no way of knowing we also
need A2 until after we process B1 in library B. We then have to go back
to library A and pick up A2. The more this happens, the longer the link
time.*/
void sort_directory(bit_16 left, bit_16 right)
BeginDeclarations
bit_16 i;
bit_16 j;
public_entry_ptr temp;
EndDeclarations
BeginCode
If left NotLessThan right
Then
return;
EndIf;
i = left;
j = right;
While i LessThan j
BeginWhile
While i LessThan j
BeginWhile
If (*public_sort_array[i]).Library.page GreaterThan
(*public_sort_array[j]).Library.page
Then
temp = public_sort_array[i];
public_sort_array[i] = public_sort_array[j];
public_sort_array[j] = temp;
ExitLoop;
EndIf;
j--;
EndWhile;
While i LessThan j
BeginWhile
If (*public_sort_array[i]).Library.page GreaterThan
(*public_sort_array[j]).Library.page
Then
temp = public_sort_array[i];
public_sort_array[i] = public_sort_array[j];
public_sort_array[j] = temp;
ExitLoop;
EndIf;
i++;
EndWhile;
EndWhile;
If i Exceeds 0
Then
sort_directory(left, i-1);
EndIf;
sort_directory(i+1, right);
return;
EndCode