home *** CD-ROM | disk | FTP | other *** search
- /* 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
-
-