Category : C Source Code
Archive   : VAL_LINK.ZIP
Filename : ORDER.C

 
Output of file : ORDER.C contained in archive : VAL_LINK.ZIP
/* 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




  3 Responses to “Category : C Source Code
Archive   : VAL_LINK.ZIP
Filename : ORDER.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/