home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 September
/
Simtel20_Sept92.cdr
/
msdos
/
pgmutl
/
val_link.arc
/
ORDER.C
< prev
next >
Wrap
Text File
|
1989-02-18
|
26KB
|
649 lines
/* ORDER.C */
/*
order_expression:: term {('or' | '+' | '|') term}
term:: factor {('and' | '*' | '&') factor}
factor:: ('!' | '~' | '-' | 'not')* primary
primary:: 'true' |
'false' |
('segment' '[' name ']' ) |
('class' '[' name ']' ) |
('group' '[' name ']' ) |
( '(' order_expression ')' )
*/
/*+-------------------------------------------------------------------------+
| |
| align_active_segment |
| |
+-------------------------------------------------------------------------+*/
void align_active_segment()
BeginDeclarations
bit_32 gap;
lseg_ptr lseg;
#define Lseg (*lseg)
bit_32 mask;
public_entry_ptr pub;
#define Pub (*pub)
EndDeclarations
BeginCode
If (*Active_segment.lsegs.first).align IsZero
Then /* Don't align absolute segments */
return;
EndIf;
Active_segment.highest_uninitialized_byte = 0L;
TraverseList(Active_segment.lsegs, lseg)
BeginTraverse
LoopIf(Lseg.align Is absolute_segment);
If Active_segment.combine Is common_combine
Then /* Finally, we know how big the common area is, so allocate
memory for it. */
Lseg.data = allocate_memory(Addr(static_pool), Lseg.length);
EndIf;
mask = align_mask[Lseg.align];
gap = AlignmentGap(next_available_address, mask);
next_available_address += gap;
Lseg.address = next_available_address;
next_available_address += Lseg.length;
If Lseg.highest_uninitialized_byte IsNotZero
Then
highest_uninitialized_byte =
Active_segment.highest_uninitialized_byte =
Lseg.address + Lseg.highest_uninitialized_byte;
EndIf;
EndTraverse;
Active_segment.address = (*Active_segment.lsegs.first).address;
Active_segment.length = (*Active_segment.lsegs.last).address +
(*Active_segment.lsegs.last).length -
Active_segment.address;
If Active_segment.highest_uninitialized_byte IsZero
Then
Active_segment.highest_uninitialized_byte =
(*Active_segment.lsegs.first).address;
EndIf;
If (Active_segment.owning_group IsNotNull) AndIf
((*Active_segment.owning_group).first_segment IsNull)
Then
(*Active_segment.owning_group).first_segment = active_segment;
EndIf;
If (DOSSEG.val IsTrue) AndIf
(Active_segment.owning_group IsNotNull) AndIf
((*Active_segment.owning_group).group_name Is DGROUP_lname)
Then
If (edata_segment IsNull) AndIf
(Active_segment.class_name Is BSS_lname)
Then
edata_segment = active_segment;
pub = lookup_public(6, (byte *) "_edata", 0);
If (Pub.type_entry Is external) OrIf (Pub.type_entry Is unused)
Then
Pub.type_entry = internal;
Pub.Internal.group = Active_segment.owning_group;
Pub.Internal.lseg = Active_segment.lsegs.first;
Pub.Internal.frame = 0;
Pub.Internal.offset = 0;
Else
linker_error(4, "Could not generate symbol \"_edata\" "
"when \"/DOSSEG\" set\n"
"because it was explicitly defined.\n");
EndIf;
EndIf;
If (end_segment IsNull) AndIf
(Active_segment.class_name Is STACK_lname)
Then
end_segment = active_segment;
pub = lookup_public(4, (byte *) "_end", 0);
If (Pub.type_entry Is external) OrIf (Pub.type_entry Is unused)
Then
Pub.type_entry = internal;
Pub.Internal.group = Active_segment.owning_group;
Pub.Internal.lseg = Active_segment.lsegs.first;
Pub.Internal.frame = 0;
Pub.Internal.offset = 0;
Else
linker_error(4, "Could not generate symbol \"_end\" "
"when \"/DOSSEG\" set\n"
"because it was explicitly defined.\n");
EndIf;
EndIf;
EndIf;
return;
EndCode
#undef Lseg
#undef Pub
/*+-------------------------------------------------------------------------+
| |
| get_order_token |
| |
+-------------------------------------------------------------------------+*/
void get_order_token()
BeginDeclarations
EndDeclarations
BeginCode
While token_break_char Is ' '
BeginWhile
order_token_get_char();
EndWhile;
copy_string(token, null_string);
If IsIdentifier(token_break_char)
Then
While IsIdentifier(token_break_char)
BeginWhile
concat_char_to_string(token, token_break_char);
order_token_get_char();
EndWhile;
lowercase_string(token);
Else
If token_break_char Is '['
Then
While token_break_char IsNot ']'
BeginWhile
concat_char_to_string(token, token_break_char);
order_token_get_char();
EndWhile;
order_token_get_char();
If case_ignore.val
Then
lowercase_string(token);
EndIf;
Else
concat_char_to_string(token, token_break_char);
order_token_get_char();
EndIf;
EndIf;
return;
EndCode
/*+-------------------------------------------------------------------------+
| |
| order_and_align_segments |
| |
+-------------------------------------------------------------------------+*/
void order_and_align_segments()
BeginDeclarations
byte_ptr start_of_expression;
EndDeclarations
BeginCode
order_start_time = Now;
/*+-------------------------------------------------------------------------+
| |
| Before we can start ordering segments, we have to get some housekeeping |
| done first. |
| |
+-------------------------------------------------------------------------+*/
order_prologue();
/*+-------------------------------------------------------------------------+
| |
| OK, lets get to ordering and aligning segments. |
| |
+-------------------------------------------------------------------------+*/
First(segments_ordered_list) =
Last(segments_ordered_list) = Null;
highest_uninitialized_byte = 0L;
start_of_expression = String(ordering.val);
start_of_expression++;
While *start_of_expression IsNot '\000'
BeginWhile
ExitIf(segment_list.first IsNull);
First(segments_unordered_list) =
Last(segments_unordered_list) = Null;
While segment_list.first IsNotNull
BeginWhile
Pop segment_list InTo active_segment EndPop;
order_expression_char_ptr = start_of_expression;
token_break_char = ' ';
If codeview_information_present AndIf
(((Active_segment.segment_name Is codeview_segment_TYPES) AndIf
(Active_segment.class_name Is codeview_class_DEBTYP)) OrIf
((Active_segment.segment_name Is codeview_segment_SYMBOLS) AndIf
(Active_segment.class_name Is codeview_class_DEBSYM)))
Then /* Eat the codeview segment */
Else /* Process all non-codeview segments */
If order_expression()
Then
Insert active_segment AtEnd InList segments_ordered_list EndInsert;
align_active_segment();
Else
Insert active_segment AtEnd InList segments_unordered_list EndInsert;
EndIf;
EndIf;
EndWhile;
start_of_expression = order_expression_char_ptr;
start_of_expression--;
segment_list = segments_unordered_list;
EndWhile;
/*+-------------------------------------------------------------------------+
| |
| Make one final pass accepting all remaining segments. |
| |
+-------------------------------------------------------------------------+*/
While segment_list.first IsNotNull
BeginWhile
Pop segment_list InTo active_segment EndPop;
Insert active_segment AtEnd InList segments_ordered_list EndInsert;
align_active_segment();
EndWhile;
segment_list = segments_ordered_list;
return;
EndCode
/*+-------------------------------------------------------------------------+
| |
| order_expression |
| |
+-------------------------------------------------------------------------+*/
bit_16 order_expression()
BeginDeclarations
bit_16 left_operand;
EndDeclarations
BeginCode
get_order_token();
left_operand = order_term();
While TokenIs(or_string) OrIf
TokenIs(plus_string) OrIf
TokenIs(bar_string)
BeginWhile
get_order_token();
left_operand |= order_term();
EndWhile;
return(left_operand);
EndCode
/*+-------------------------------------------------------------------------+
| |
| order_factor |
| |
+-------------------------------------------------------------------------+*/
bit_16 order_factor()
BeginDeclarations
bit_16 unary_not;
EndDeclarations
BeginCode
unary_not = False;
While TokenIs(exclamation_string) OrIf
TokenIs(tilde_string) OrIf
TokenIs(minus_string) OrIf
TokenIs(not_string)
BeginWhile
get_order_token();
unary_not ^= True;
EndWhile;
return(unary_not ^ order_primary());
EndCode
/*+-------------------------------------------------------------------------+
| |
| order_primary |
| |
+-------------------------------------------------------------------------+*/
bit_16 order_primary()
BeginDeclarations
group_entry_ptr group;
#define Group (*group)
bit_16 operand;
EndDeclarations
BeginCode
If TokenIs(true_string)
Then
get_order_token();
return(True);
EndIf;
If TokenIs(false_string)
Then
get_order_token();
return(False);
EndIf;
If TokenIs(open_paren_string)
Then
operand = order_expression();
If TokenIs(close_paren_string)
Then
get_order_token();
return(operand);
Else
linker_error(8, "Expression syntax error:\n"
"\t\"%Fs\"\n",
String(ordering.val));
EndIf;
EndIf;
If TokenStartsWith(segment_string)
Then
get_order_token();
If *String(token) IsNot '['
Then
linker_error(8, "Expression syntax error:\n"
"\t\"%Fs\"\n",
String(ordering.val));
EndIf;
cut_string(token, 0, 1);
operand = match_pattern(token,
string((*Active_segment.segment_name).symbol));
get_order_token();
return(operand);
EndIf;
If TokenStartsWith(group_string)
Then
get_order_token();
If *String(token) IsNot '['
Then
linker_error(8, "Expression syntax error:\n"
"\t\"%Fs\"\n",
String(ordering.val));
EndIf;
cut_string(token, 0, 1);
group = Active_segment.owning_group;
If group IsNull
Then
operand = False;
Else
operand =
match_pattern(token, string((*Group.group_name).symbol));
EndIf;
get_order_token();
return(operand);
EndIf;
If TokenStartsWith(class_string)
Then
get_order_token();
If *String(token) IsNot '['
Then
linker_error(8, "Expression syntax error:\n"
"\t\"%Fs\"\n",
String(ordering.val));
EndIf;
cut_string(token, 0, 1);
operand = match_pattern(token,
string((*Active_segment.class_name).symbol));
get_order_token();
return(operand);
EndIf;
linker_error(8, "Expression syntax error:\n"
"\t\"%Fs\"\n",
String(ordering.val));
return(False);
EndCode
#undef Group
/*+-------------------------------------------------------------------------+
| |
| order_prologue |
| |
+-------------------------------------------------------------------------+*/
void order_prologue()
BeginDeclarations
group_entry_ptr group;
bit_32 length;
lseg_ptr lseg;
#define Lseg (*lseg)
public_entry_ptr next_communal;
bit_16 offset;
public_entry_ptr pub;
#define Pub (*pub)
bit_16 size;
EndDeclarations
BeginCode
/*+-------------------------------------------------------------------------+
| |
| Compute the address base for the executable image. For .COM files this |
| will be 100H, for .EXE and .SYS files, this will be 0. |
| |
+-------------------------------------------------------------------------+*/
If comfile.val IsTrue
Then
address_base = 0x100L;
Else
address_base = 0L;
EndIf;
next_available_address = 0L;
/*+-------------------------------------------------------------------------+
| |
| The ordering expression for the segments must be known. If the |
| "/ORDER:(expression)" switch was specified, then it will be used |
| regardless or whether or not "/DOSSEG" is set. If the "/ORDER" |
| switch was not specified and "/DOSSEG" was, then the appropriate |
| expression is used. Otherwise, the linker will just take the |
| segments in the order they were encountered. |
| |
+-------------------------------------------------------------------------+*/
If ordering.val IsNull
Then
If DOSSEG.val IsTrue
Then
ordering.val = duplicate_string(Addr(static_pool),
string((byte *) ("(seg[*code]|seg[*CODE], "
"!(gr[dgroup]|gr[DGROUP]), "
"cl[begdata]|cl[BEGDATA], "
"cl[*data]|cl[*DATA], "
"!(cl[*bss]|cl[*BSS]|cl[*stack]|cl[*STACK]), "
"cl[*bss]|cl[*BSS], "
"cl[*stack]|cl[*STACK])")));
Else
ordering.val = duplicate_string(Addr(static_pool),
string((byte *) ("(true)")));
EndIf;
EndIf;
/*+-------------------------------------------------------------------------+
| |
| Check to insure a stack segment of appropriate size is present. For |
| .COM and .SYS files, no stack segment is required. For .EXE files, |
| one is required. For .EXE files, we must insure that a stack of at |
| least the size specified in the "/STACK" switch is available. |
| |
+-------------------------------------------------------------------------+*/
If exefile IsFalse
Then
If stack_segment_found IsTrue
Then
linker_error(4, "Stack segment found for a non .EXE file.\n");
EndIf;
Else
If (stack_segment_found IsFalse) AndIf
(stack.set IsFalse)
Then
linker_error(4, "No stack segment for .EXE file.\n");
Else
If (stack.set IsTrue) AndIf
(Bit_16(Largest_stack_seg.length) LessThan stack.val)
Then
obj_generate_segment(generated_lname,
none_lname,
stack_combine,
2, /* word aligned */
none_lname,
exe_file_list.first,
0L, /* not absolute segment */
Bit_32(stack.val));
EndIf;
EndIf;
EndIf;
/*+-------------------------------------------------------------------------+
| |
| Handle near communals as follows: If there is at least one near |
| communal, create the segment "c_common" in group "DGROUP" with |
| class "BSS". Then, for each communal place it in "c_common" in |
| ascending order while changing the dictionary entry from |
| "near_communal" to "internal". |
| |
+-------------------------------------------------------------------------+*/
If near_communals IsNotNull
Then
length = 0L;
For pub=near_communals; pub IsNotNull; pub=Pub.Communal.next_communal
BeginFor
LoopIf(Pub.type_entry IsNot near_communal);
length += Pub.Communal.element_size;
EndFor;
If length Exceeds 65536L
Then
linker_error(8, "Near communal size exceeds 64K by %lu bytes.\n",
length-65536L);
EndIf;
lseg = obj_generate_segment(c_common_lname,
BSS_lname,
blank_common_combine,
3, /* paragraph aligned */
none_lname,
exe_file_list.first,
0L, /* not absolute segment */
length);
Lseg.highest_uninitialized_byte = length;
group = lookup_group(DGROUP_lname);
(*Lseg.segment).owning_group = group;
offset = 0;
For pub=near_communals; pub IsNotNull; pub=next_communal
BeginFor
next_communal = Pub.Communal.next_communal;
LoopIf(Pub.type_entry IsNot near_communal);
size = Bit_16(Pub.Communal.element_size);
Pub.type_entry = internal;
Pub.Internal.group = group;
Pub.Internal.lseg = lseg;
Pub.Internal.offset = offset;
Pub.Internal.frame = 0;
offset += size;
EndFor;
EndIf;
/*+-------------------------------------------------------------------------+
| |
| Handle far communals as follows: Packing as many far communals as |
| will fit (64K), create private segments with the segment and class |
| name of "FAR_BSS". They do NOT go in DRGROUP. |
| |
+-------------------------------------------------------------------------+*/
lseg = Null;
offset = 0;
For pub=far_communals; pub IsNotNull; pub=next_communal
BeginFor
next_communal = Pub.Communal.next_communal;
LoopIf(Pub.type_entry IsNot far_communal);
length = Pub.Communal.element_size * Pub.Communal.element_count;
If length Exceeds 65536L
Then
Pub.Communal.next_communal = huge_communals;
huge_communals = pub;
ContinueLoop;
EndIf;
If (lseg IsNull) OrIf ((length + Bit_32(offset)) Exceeds 65536L)
Then
lseg = obj_generate_segment(FAR_BSS_lname,
FAR_BSS_lname,
blank_common_combine,
3, /* paragraph aligned */
none_lname,
exe_file_list.first,
0L, /* not absolute segment */
0L);
offset = 0;
EndIf;
Pub.type_entry = internal;
Pub.Internal.group = Null;
Pub.Internal.lseg = lseg;
Pub.Internal.offset = offset;
Pub.Internal.frame = 0;
offset += Bit_16(length);
Lseg.highest_uninitialized_byte += length;
Lseg.length += length;
(*Lseg.segment).length += length;
EndFor;
/*+-------------------------------------------------------------------------+
| |
| Handle huge communals as follows: Taking as many segments as |
| required, create private segments with the segment and class |
| name of "HUGE_BSS". They do NOT go in DRGROUP. |
| |
+-------------------------------------------------------------------------+*/
For pub=huge_communals; pub IsNotNull; pub=next_communal
BeginFor
next_communal = Pub.Communal.next_communal;
length = Pub.Communal.element_size * Pub.Communal.element_count;
lseg = obj_generate_segment(HUGE_BSS_lname,
HUGE_BSS_lname,
blank_common_combine,
3, /* paragraph aligned */
none_lname,
exe_file_list.first,
0L, /* not absolute segment */
0L);
If Pub.Communal.element_size Exceeds 65536L
Then
linker_error(4, "Communal \"%Fs\" has element size exceeding 64K.\n",
Pub.symbol);
offset = 0;
Else
offset = Bit_16(65536L Mod Pub.Communal.element_size);
EndIf;
length += Bit_32(offset);
Pub.type_entry = internal;
Pub.Internal.group = Null;
Pub.Internal.lseg = lseg;
Pub.Internal.offset = offset;
Pub.Internal.frame = 0;
Lseg.highest_uninitialized_byte += length;
Lseg.length += length;
(*Lseg.segment).length += length;
EndFor;
return;
EndCode
#undef Pub
#undef Lseg
/*+-------------------------------------------------------------------------+
| |
| order_term |
| |
+-------------------------------------------------------------------------+*/
bit_16 order_term()
BeginDeclarations
bit_16 left_operand;
EndDeclarations
BeginCode
left_operand = order_factor();
While TokenIs(and_string) OrIf
TokenIs(star_string) OrIf
TokenIs(ampersand_string)
BeginWhile
get_order_token();
left_operand &= order_factor();
EndWhile;
return(left_operand);
EndCode
/*+-------------------------------------------------------------------------+
| |
| order_token_get_char |
| |
+-------------------------------------------------------------------------+*/
void order_token_get_char()
BeginDeclarations
EndDeclarations
BeginCode
If token_break_char Is '\000'
Then
linker_error(8, "Expression syntax error:\n"
"\t\"%Fs\"\n",
String(ordering.val));
EndIf;
token_break_char = *order_expression_char_ptr++;
return;
EndCode