Press enter to see results or esc to cancel.

Resolving References

Once the offsets of code blocks, variables and typed constants are known, the compiler can resolve references. This procedure calculates all references (displacements, offsets, near and far pointers) to code or data.

Procedure ResolveReferences (Block: TSymbolTable; DataBlockSegment, ReferencesBlockSegment: Word);
Var CodeConstBlock: PCodeConstBlockRecord;
    CodeConstBlockRec: PtrRec absolute CodeConstBlock;
    ReferenceRecord: PReferencesBlockRecord;
    ReferenceRec: PtrRec absolute ReferenceRecord;
    ReferencedUnitRecord: PReferencedModulesBlockRecord;
    CurrentBlockOffset: Word;

  Procedure ResolveReferencesForUsedBlock;
  Var EndOffset: Word;
      TempUnit: PUnitHeader;
      BlockRecord: Word;
      ReferenceFlags: TReferenceFlagSet;
      ReferencePosition: Word;
      ReferencePointer: PPtrRec;
      ReferencePointerRec: PtrRec absolute ReferencePointer;
      ProcedureRecordPtr: PProceduresBlockRecord;
      Reference: PtrRec;
  begin
    EndOffset := ReferenceRec.Ofs + CodeConstBlock^.ReferencesSize;
    While ReferenceRec.Ofs <> EndOffset do
      begin
        TempUnit := Ptr (CurrentUnitForProcessing, 0);
        ReferencedUnitRecord := Ptr (CurrentUnitForProcessing,
                                     TempUnit^.BlockOffset [stReferencedModules] +
                                     ReferenceRecord^.ReferencedUnitRecord and $0FFF);
        TempUnit := Ptr (ReferencedUnitRecord^.ModuleSegment, 0);
        With ReferenceRecord^ do
          begin
            ReferenceFlags := Flags;
            BlockRecord := ReferencedBlockRecordOffset;
            Reference.Ofs := ReferencedOffset;
            ReferencePosition := PositionOfReference;
          end;
        If rfDataSegment in ReferenceFlags then
          begin
            Case rfConstant in ReferenceFlags of
              True: Inc (BlockRecord, TempUnit^.BlockOffset [stTypedConstantsBlocks]);
              else  Inc (BlockRecord, TempUnit^.BlockOffset [stVariablesBlocks]);
            end;
            Inc (Reference.Ofs, PConstVarBlockRecord (PChar (TempUnit) + BlockRecord)^.Offset);
            Reference.Seg := DataSegment;
          end else begin
                     If rfConstant in ReferenceFlags then
                       begin
                         Inc (BlockRecord, TempUnit^.BlockOffset [stCodeBlocks]);
                         Inc (Reference.Ofs, PProgramCodeBlockRecord (PChar (TempUnit) + BlockRecord)^.Offset);
                         Reference.Seg := TempUnit^.CodeSegment;
                       end else begin
                                  Inc (BlockRecord, TempUnit^.BlockOffset [stProcedures]);
                                  ProcedureRecordPtr := Ptr (Seg (TempUnit^), BlockRecord);
                                  If Lo (ProcedureRecordPtr^.prW2) and $08 <> 0 then
                                    begin
                                      Inc (Reference.Ofs, ProcedureRecordPtr^.SizeOfConstants);
                                      BlockRecord := ProcedureRecordPtr^.ProgramCodeBlockRecordOffset;
                                      Inc (BlockRecord, TempUnit^.BlockOffset [stTypedConstantsBlocks]);
                                      Inc (Reference.Ofs, PWord (PChar (TempUnit) + BlockRecord)^);
                                      Reference.Seg := DataSegment;
                                    end else begin
                                               If (ReferenceFlags * [rfSegment, rfOffset] = []) or
                                                  (UnitPtr^.OverlayedUnitCodeSize = 0) then
                                                 begin
                                                   Inc (Reference.Ofs, ProcedureRecordPtr^.SizeOfConstants);
                                                   BlockRecord := ProcedureRecordPtr^.ProgramCodeBlockRecordOffset;
                                                   Inc (BlockRecord, TempUnit^.BlockOffset [stCodeBlocks]);
                                                   Inc (Reference.Ofs, PWord (PChar (TempUnit) + BlockRecord)^);
                                                   Reference.Seg := TempUnit^.CodeSegment;
                                                 end else begin
                                                            Inc (Reference.Ofs, ProcedureRecordPtr^.OverlayedProcedureOffset);
                                                            Reference.Seg := TempUnit^.CodeSegment;
                                                          end;
                                             end;
                                end;
                   end;
        ReferencePointer := DataBlockPointer.Ptr;
        Inc (ReferencePointerRec.Ofs, ReferencePosition);
        Case rfOffset in ReferenceFlags of
          True: begin
                  ReferencePointer^.Ofs := Reference.Ofs;
                  If rfSegment in ReferenceFlags then ReferencePointer^.Seg := Reference.Seg;
                end;
          else If rfSegment in ReferenceFlags then ReferencePointer^.Word := Reference.Seg
                 else ReferencePointer^.Word := Reference.Ofs - ReferencePosition - UsedBlockOffset - 2;
        end;
        Inc (ReferenceRecord);
      end;
  end;

begin
  CurrentUnitForProcessing := UnitPtrRec.Seg;
  ReferenceRecordsSegment := ReferencesBlockSegment;
  DataBlockPointer.Seg := DataBlockSegment;
  CodeConstBlock := Ptr (UnitPtrRec.Seg, UnitPtr^.BlockOffset [Block]);
  CurrentBlockOffset := 0;
  ReferenceRecord := Ptr (ReferenceRecordsSegment, 0);
  While CodeConstBlockRec.Ofs <> UnitPtr^.BlockOffset [Succ (Block)] do
    begin
      If CodeConstBlock^.Offset <> BlockUnused then
        begin
          UsedBlockOffset := CodeConstBlock^.Offset;
          DataBlockPointer.Ofs := CurrentBlockOffset;
          ResolveReferencesForUsedBlock;
        end else Inc (ReferenceRec.Ofs, CodeConstBlock^.ReferencesSize);
      Inc (CurrentBlockOffset, CodeConstBlock^.Size);
      Inc (CodeConstBlock);
    end;
end;