/* TMODULE.C */ /* Object modules are parsed via recursive descent as defined below: obj_t_module:: obj_THEADR obj_seg_grp {obj_component} obj_modtail obj_seg_grp:: {obj_LNAMES | obj_SEGDEF | obj_EXTDEF} {obj_TYPDEF | obj_EXTDEF | obj_GRPDEF} obj_component:: obj_data | obj_debug_record obj_data:: obj_content_def | obj_thread_def | obj_COMDEF | obj_TYPDEF | obj_PUBDEF | obj_EXTDEF | obj_FORREF | obj_MODPUB | obj_MODEXT obj_debug_record:: obj_LINNUM obj_content_def:: obj_data_record {obj_FIXUPP} obj_thread_def:: obj_FIXUPP (containing only thread fields) obj_data_record:: obj_LIDATA | obj_LEDATA obj_modtail:: obj_MODEND */ /*+-------------------------------------------------------------------------+ | | | obj_COMDEF | | | +-------------------------------------------------------------------------+*/ bit_16 obj_COMDEF() BeginDeclarations bit_32 element_count; bit_32 element_size; bit_8 element_type; bit_8 expected_type; bit_16 len; public_entry_ptr pub; #define Pub (*pub) EndDeclarations BeginCode If Current_record_header.rec_typ IsNot COMDEF_record Then return(False); EndIf; While obj_ptr.b8 IsNot end_of_record.b8 BeginWhile If n_externals NotLessThan max_externals.val Then linker_error(12, "Internal limit exceeded:\n" "\tModule: \"%Fs\"\n" "\t File: \"%Fs\"\n" "\tOffset: %lu\n" "\t Error: Too many externals. Max of %u exceeded.\n" "\t Retry with larger \"/maxexternals:n\" " "switch.\n", (*tmodule_name).symbol, (*infile.file_info).filename, current_record_offset, max_externals.val); EndIf; len = obj_name_length(); If case_ignore.val Then far_to_lower(BytePtr(obj_ptr.b8), len); EndIf; pub = lookup_public(len, obj_ptr.b8, 0); obj_ptr.b8 += len; obj_name_length(); /* Eat the type index. */ externals[++n_externals] = pub; element_type = *obj_ptr.b8++; Using element_type BeginCase When 0x61: expected_type = far_communal; element_count = obj_leaf_descriptor(); element_size = obj_leaf_descriptor(); break; When 0x62: expected_type = near_communal; element_size = obj_leaf_descriptor(); element_count = 1L; break; Otherwise: linker_error(12, "Translator error:\n" "\tModule: \"%Fs\"\n" "\t File: \"%Fs\"\n" "\tOffset: %lu\n" "\t Error: Communal type of \"%02X\" is illegal.\n", (*tmodule_name).symbol, (*infile.file_info).filename, current_record_offset, element_type); EndCase; If Pub.type_entry Is unused Then Insert pub AtEnd InList external_list EndInsert; Pub.type_entry = expected_type; Pub.Communal.element_size = element_size; Pub.Communal.element_count = element_count; Using element_type BeginCase When 0x61: Pub.Communal.next_communal = far_communals; far_communals = pub; break; When 0x62: Pub.Communal.next_communal = near_communals; near_communals = pub; break; EndCase; Else If Pub.type_entry Is expected_type Then If (element_size * element_count) Exceeds (Pub.Communal.element_size * Pub.Communal.element_count) Then /* We need the largest common */ Pub.Communal.element_size = element_size; Pub.Communal.element_count = element_count; EndIf; Else If (Pub.type_entry Is near_communal) OrIf (Pub.type_entry Is far_communal) Then linker_error(4, "Translator error:\n" "\tModule: \"%Fs\"\n" "\t File: \"%Fs\"\n" "\tOffset: %lu\n" "\t Error: Communal \"%Fs\" is declared both near " "and far.\n", (*tmodule_name).symbol, (*infile.file_info).filename, current_record_offset, Pub.symbol); EndIf; EndIf; EndIf; EndWhile; obj_next_record(); return(True); EndCode #undef Pub /*+-------------------------------------------------------------------------+ | | | obj_COMENT | | | +-------------------------------------------------------------------------+*/ bit_16 obj_COMENT() BeginDeclarations bit_8 comment_class; EndDeclarations BeginCode If Current_record_header.rec_typ IsNot COMENT_record Then return(False); EndIf; obj_ptr.b8++; comment_class = *obj_ptr.b8++; Using comment_class BeginCase When 158: DOSSEG.val = True; break; When 161: codeview_information_present = True; break; Otherwise: break; EndCase; return(True); EndCode /*+-------------------------------------------------------------------------+ | | | obj_component | | | +-------------------------------------------------------------------------+*/ /* obj_component:: obj_data | obj_debug_record */ bit_16 obj_component() BeginDeclarations EndDeclarations BeginCode If obj_data() OrIf obj_debug_record() Then return(True); EndIf; return(False); EndCode /*+-------------------------------------------------------------------------+ | | | obj_content_def | | | +-------------------------------------------------------------------------+*/ /* obj_content_def:: obj_data_record {obj_FIXUPP} */ bit_16 obj_content_def() BeginDeclarations EndDeclarations BeginCode If Not obj_data_record() Then return(False); EndIf; While obj_FIXUPP() BeginWhile EndWhile; return(True); EndCode /*+-------------------------------------------------------------------------+ | | | obj_data | | | +-------------------------------------------------------------------------+*/ /* obj_data:: obj_content_def | obj_thread_def | obj_TYPDEF | obj_PUBDEF | obj_EXTDEF */ bit_16 obj_data() BeginDeclarations EndDeclarations BeginCode If obj_content_def() OrIf obj_thread_def() OrIf obj_TYPDEF() OrIf obj_PUBDEF() OrIf obj_EXTDEF() OrIf obj_FORREF() OrIf obj_COMDEF() OrIf obj_MODEXT() OrIf obj_MODPUB() Then return(True); EndIf; return(False); EndCode /*+-------------------------------------------------------------------------+ | | | obj_data_record | | | +-------------------------------------------------------------------------+*/ /* obj_data_record:: obj_LIDATA | obj_LEDATA */ bit_16 obj_data_record() BeginDeclarations EndDeclarations BeginCode If obj_LIDATA() OrIf obj_LEDATA() Then return(True); EndIf; return(False); EndCode /*+-------------------------------------------------------------------------+ | | | obj_debug_record | | | +-------------------------------------------------------------------------+*/ /* obj_debug_record:: obj_LINNUM */ bit_16 obj_debug_record() BeginDeclarations EndDeclarations BeginCode If obj_LINNUM() Then return(True); EndIf; return(False); EndCode /*+-------------------------------------------------------------------------+ | | | obj_EXTDEF | | | +-------------------------------------------------------------------------+*/ bit_16 obj_EXTDEF() BeginDeclarations bit_16 len; public_entry_ptr pub; #define Pub (*pub) EndDeclarations BeginCode If Current_record_header.rec_typ IsNot EXTDEF_record Then return(False); EndIf; While obj_ptr.b8 IsNot end_of_record.b8 BeginWhile If n_externals NotLessThan max_externals.val Then linker_error(12, "Internal limit exceeded:\n" "\tModule: \"%Fs\"\n" "\t File: \"%Fs\"\n" "\tOffset: %lu\n" "\t Error: Too many externals. Max of %u exceeded.\n" "\t Retry with larger \"/maxexternals:n\" " "switch.\n", (*tmodule_name).symbol, (*infile.file_info).filename, current_record_offset, max_externals.val); EndIf; len = obj_name_length(); If case_ignore.val Then far_to_lower(BytePtr(obj_ptr.b8), len); EndIf; pub = lookup_public(len, obj_ptr.b8, 0); obj_ptr.b8 += len; obj_name_length(); /* Eat the type index. */ externals[++n_externals] = pub; If Pub.type_entry Is unused Then Insert pub AtEnd InList external_list EndInsert; Pub.type_entry = external; Else If (Pub.type_entry Is public_in_library) AndIf (Not Pub.Library.requested) Then library_request_count++; (*Pub.Library.lib_file).request_count++; Pub.Library.requested = True; EndIf; EndIf; EndWhile; obj_next_record(); return(True); EndCode #undef Pub /*+-------------------------------------------------------------------------+ | | | obj_FIXUPP | | | +-------------------------------------------------------------------------+*/ bit_16 obj_FIXUPP() BeginDeclarations EndDeclarations BeginCode If Current_record_header.rec_typ IsNot FIXUPP_record Then return(False); EndIf; FIXUPP_contains_only_threads = True; While obj_ptr.b8 IsNot end_of_record.b8 BeginWhile If (*obj_ptr.TRD_DAT).type_fixupp_record IsZero Then obj_FIXUPP_thread(); Else FIXUPP_contains_only_threads = False; obj_FIXUPP_fixup(); EndIf; EndWhile; obj_next_record(); return(True); EndCode /*+-------------------------------------------------------------------------+ | | | obj_FIXUPP_fixup | | | +-------------------------------------------------------------------------+*/ void obj_FIXUPP_fixup() BeginDeclarations FIX_DAT_type FIX_DAT; bit_16 frame_method; LOCAT_type LOCAT; bit_16 target_method; bit_8 temp; bit_16 thread_number; EndDeclarations BeginCode /*+-------------------------------------------------------------------------+ | | | The LOCAT field in a FIXUPP record has its low and high bytes swapped | | because the high order bit must be 0 for threads and 1 for fixups. | | Since that bit could not be placed in the offset, the bytes were | | swapped instead. | | | +-------------------------------------------------------------------------+*/ temp = obj_ptr.b8[0]; obj_ptr.b8[0] = obj_ptr.b8[1]; obj_ptr.b8[1] = temp; /*+-------------------------------------------------------------------------+ | | | Pick up the two required fields (LOCAT and FIX_DAT) | | | +-------------------------------------------------------------------------+*/ LOCAT = *obj_ptr.LOCAT++; FIX_DAT = *obj_ptr.FIX_DAT++; /*+-------------------------------------------------------------------------+ | | | A fixup consists of a location, mode, frame and target. | | Process the location part. | | | +-------------------------------------------------------------------------+*/ fixup_index = LOCAT.data_record_offset; fixup.location_type = LOCAT.loc; /*+-------------------------------------------------------------------------+ | | | Process the mode part. | | | +-------------------------------------------------------------------------+*/ fixup.mode = LOCAT.m; /*+-------------------------------------------------------------------------+ | | | Process the frame part. | | | +-------------------------------------------------------------------------+*/ If FIX_DAT.f IsZero Then /* Frame is specified explicitly */ frame_method = FIX_DAT.frame; fixup.frame_method = frame_method; Using frame_method BeginCase When 0: fixup.frame_referent = (void far *) snames[obj_index_segment()]; break; When 1: fixup.frame_referent = (void far *) gnames[obj_index_group()]; break; When 2: fixup.frame_referent = (void far *) externals[obj_index_external()]; break; When 3: fixup.frame_referent = (void far *) (Bit_32(*obj_ptr.b16++) ShiftedLeft 4); Otherwise: fixup.frame_referent = Null; break; EndCase; Else /* Frame is specified by a thread */ thread_number = FIX_DAT.frame; If Not frame_thread[thread_number].thread_defined Then linker_error(12, "Translator error:\n" "\tModule: \"%Fs\"\n" "\t File: \"%Fs\"\n" "\tOffset: %lu\n" "\t Error: Reference to frame thread %u which has " "been defined.n", (*tmodule_name).symbol, (*infile.file_info).filename, current_record_offset, thread_number); EndIf; fixup.frame_referent = frame_thread[thread_number].referent; fixup.frame_method = frame_thread[thread_number].method; EndIf; /*+-------------------------------------------------------------------------+ | | | Process the target part. | | | +-------------------------------------------------------------------------+*/ If FIX_DAT.t IsZero Then /* Target is specified explicitly */ target_method = FIX_DAT.targt; fixup.target_method = target_method; Using target_method BeginCase When 0: /* Target is the segment referenced by the index */ fixup.target_referent = (void far *) snames[obj_index_segment()]; break; When 1: /* Target is the lowest seg in the group referenced by the index */ fixup.target_referent = (void far *) gnames[obj_index_group()]; break; When 2: fixup.target_referent = (void far *) externals[obj_index_external()]; break; When 3: fixup.target_referent = (void far *) (Bit_32(*obj_ptr.b16++) ShiftedLeft 4); break; EndCase; Else /* Target is specified by a thread */ thread_number = FIX_DAT.targt; If Not target_thread[thread_number].thread_defined Then linker_error(12, "Translator error:\n" "\tModule: \"%Fs\"\n" "\t File: \"%Fs\"\n" "\tOffset: %lu\n" "\t Error: Reference to target thread %u which has " "been defined.n", (*tmodule_name).symbol, (*infile.file_info).filename, current_record_offset, thread_number); EndIf; fixup.target_referent = target_thread[thread_number].referent; fixup.target_method = target_thread[thread_number].method; EndIf; If FIX_DAT.p IsZero Then /* There is a target displacement */ fixup.target_offset = *obj_ptr.b16++; Else /* The target displacement is zero */ fixup.target_offset = 0; EndIf; fixup.external_error_detected = False; If (fixup.mode IsZero) AndIf ((fixup.location_type Is base_location) OrIf (fixup.location_type Is pointer_location) OrIf (fixup.location_type Is hibyte_location)) Then /* Undefined fixup action */ linker_error(4, "Possible translator error:\n" "\tModule: \"%Fs\"\n" "\t File: \"%Fs\"\n" "\tOffset: %lu\n" "\t Error: Base, pointer or hibyte self-relative fixups\n" "\t are undefined.\n", (*tmodule_name).symbol, (*infile.file_info).filename, current_record_offset); EndIf; If last_LxDATA_record_type Is LEDATA_record Then If ((fixup.location_type Is base_location) OrIf (fixup.location_type Is pointer_location)) AndIf (exefile IsTrue) Then /* Base and pointer locations will require a relocation item in the EXE header */ n_relocation_items++; EndIf; write_temp_file(Current_record_header.rec_typ, last_LxDATA_lseg, last_LxDATA_offset + fixup_index, BytePtr(Addr(fixup)), sizeof(fixup)); Else If fixup.mode IsZero Then linker_error(4, "Translator warning:\n" "\tModule: \"%Fs\"\n" "\t File: \"%Fs\"\n" "\tOffset: %lu\n" "\t Error: Self-relative fixup not permitted for " "LIDATA.\n", (*tmodule_name).symbol, (*infile.file_info).filename, current_record_offset); Else obj_fixup_LIDATA(); EndIf; EndIf; return; EndCode /*+-------------------------------------------------------------------------+ | | | obj_fixup_LIDATA | | | +-------------------------------------------------------------------------+*/ void obj_fixup_LIDATA() BeginDeclarations obj_ptr_type old_obj_ptr; EndDeclarations BeginCode LIDATA_index = 0; LIDATA_offset = last_LxDATA_offset; old_obj_ptr = obj_ptr; obj_ptr.b8 = Last_LIDATA_record_header.variant_part; end_of_last_LIDATA_record.b8 = (byte *) Addr(Last_LIDATA_record_header.variant_part [Last_LIDATA_record_header.rec_len-1]); obj_index_segment(); obj_ptr.b16++; While obj_ptr.b8 IsNot end_of_last_LIDATA_record.b8 BeginWhile obj_fixup_LIDATA_IDB(); EndWhile; obj_ptr = old_obj_ptr; return; EndCode /*+-------------------------------------------------------------------------+ | | | obj_fixup_LIDATA_IDB | | | +-------------------------------------------------------------------------+*/ void obj_fixup_LIDATA_IDB() BeginDeclarations bit_16 block_count; bit_8 *content; bit_16 i; bit_16 j; bit_16 len; bit_16 old_index; bit_16 repeat_count; EndDeclarations BeginCode repeat_count = *obj_ptr.b16++; LIDATA_index += sizeof(bit_16); block_count = *obj_ptr.b16++; LIDATA_index += sizeof(bit_16); content = obj_ptr.b8; old_index = LIDATA_index; If block_count IsNotZero Then /* Handle recursive case: Content is iterated data block */ For i=0; i