-- Loader.mesa -- Last Modified by Levin, September 15, 1978 10:57 AM DIRECTORY AltoDefs: FROM "altodefs" USING [PageCount], BcdDefs: FROM "bcddefs" USING [ ControlLink, EPIndex, EPLimit, EXPHandle, EXPIndex, EXPNull, FTHandle, FTIndex, FTSelf, GFTIndex, IMPHandle, IMPIndex, MTHandle, MTIndex, MTNull, NameRecord, NameString, NullLink, PackedString, UnboundLink, VersionID, VersionStamp], CodeDefs: FROM "codedefs" USING [CodeHandle], ControlDefs: FROM "controldefs" USING [ FrameCodeBase, Free, GFT, GlobalFrameHandle, NullGlobalFrame], FrameDefs: FROM "framedefs" USING [EnterGlobalFrame, EnumerateGlobalFrames], InlineDefs: FROM "inlinedefs" USING [BITAND, COPY], LoaderBcdUtilDefs: FROM "loaderbcdutildefs" USING [ BcdBase, EnumerateExportTable, EnumerateImportTable, EnumerateModuleTable, ReleaseBcdSeg, SetUpBcd], LoaderDefs: FROM "loaderdefs" USING [FileSegmentHandle, LoaderErrorType], LoaderUtilityDefs: FROM "loaderutilitydefs" USING [ AllocateSingleModule, AssignControlModules, Binding, ControlModuleFrame, EnterCodeFileNames, FinalizeUtilities, FindCodeSegment, FindFrameIndex, InitializeUtilities, InitImportBinding, LookupFileTable, RequiredFrameSpace], LoadStateDefs: FROM "loadstatedefs" USING [ BcdHasExports, BcdHasUnresolvedImports, BcdSegFromLoadState, ConfigIndex, EnterGfi, InitializeRelocation, InputLoadState, MapConfigToReal, ReleaseLoadState, ReleaseRelocation, Relocation, SetUnresolvedImports, UpdateLoadState], SDDefs: FROM "sddefs" USING [SD, sNew], SegmentDefs: FROM "segmentdefs" USING [ AddressFromPage, FileHandle, FileSegmentHandle, MoveFileSegment, NewFile, NewFileSegment, OldFileOnly, Read, SwapIn, SwapUp, Unlock], StringDefs: FROM "stringdefs" USING [ AppendSubString, EqualSubStrings, EquivalentSubStrings, SubStringDescriptor], SystemDefs: FROM "systemdefs" USING [ AllocateHeapNode, AllocateHeapString, AllocateResidentSegment, FreeHeapNode, FreeHeapString, FreePages], XMesaDefs: FROM "XMesaDefs" USING [XCOPY, XFileSegmentAddress]; --XM DEFINITIONS FROM SegmentDefs, BcdDefs, LoaderDefs; Loader: PROGRAM IMPORTS FrameDefs, LoaderBcdUtilDefs, LoaderUtilityDefs, LoadStateDefs, CodeDefs, SegmentDefs, StringDefs, SystemDefs, XMesaDefs --XM EXPORTS LoaderDefs = --XM BEGIN SSD: TYPE = StringDefs.SubStringDescriptor; Relocation: TYPE = LoadStateDefs.Relocation; BcdBase: TYPE = LoaderBcdUtilDefs.BcdBase; ConfigIndex: TYPE = LoadStateDefs.ConfigIndex; Binding: TYPE = LoaderUtilityDefs.Binding; GlobalFrameHandle: TYPE = ControlDefs.GlobalFrameHandle; LoaderError: PUBLIC SIGNAL [error: LoaderErrorType] = CODE; InvalidBcd: PUBLIC ERROR [bcdfile: FileHandle] = CODE; InvalidFile: PUBLIC ERROR [name: STRING] = CODE; VersionMismatch: PUBLIC SIGNAL [name: STRING] = CODE; NewNew: PROCEDURE [name: STRING] RETURNS [frame: GlobalFrameHandle] = BEGIN RETURN[New[Load[name], TRUE, FALSE]]; END; Load: PUBLIC PROCEDURE [name: STRING] RETURNS [FileSegmentHandle] = BEGIN RETURN [LoadBcd[SegmentDefs.NewFile[name, Read, OldFileOnly] ! InvalidBcd => ERROR InvalidFile[name]]]; END; LoadBcd: PUBLIC PROCEDURE [bcdfile: FileHandle] RETURNS [bcdseg: FileSegmentHandle] = BEGIN OPEN SegmentDefs; pages: AltoDefs.PageCount; bcd: BcdBase; bcdseg _ NewFileSegment[bcdfile, 1, 1, Read]; bcd _ LoaderBcdUtilDefs.SetUpBcd[bcdseg]; pages _ bcd.nPages; IF pages > 1 THEN BEGIN Unlock[bcdseg]; MoveFileSegment[bcdseg, 1, pages]; bcd _ LoaderBcdUtilDefs.SetUpBcd[bcdseg]; END; BEGIN ENABLE UNWIND => LoaderBcdUtilDefs.ReleaseBcdSeg[bcdseg]; IF bcd.versionident # BcdDefs.VersionID OR bcd.definitions THEN ERROR InvalidBcd[bcdfile]; END; -- OF OPEN Unlock[bcdseg]; END; New: PUBLIC PROCEDURE [bcdseg: FileSegmentHandle, framelinks, alloc: BOOLEAN] RETURNS [frame: GlobalFrameHandle] = BEGIN OPEN SegmentDefs, SystemDefs; NullRel: Relocation = DESCRIPTOR[NIL, 0]; NullBind: Binding = DESCRIPTOR[NIL, 0]; loadee, system: BcdBase _ NIL; LReloc: Relocation _ NullRel; SReloc: Relocation _ NullRel; LBind: Binding _ NullBind; SBind: Binding _ NullBind; frames: POINTER _ NIL; nbcds, i: CARDINAL; systemseg: FileSegmentHandle _ NIL; single, unresolved, sysunres, initial: BOOLEAN; CleanUpNew: PROCEDURE = BEGIN LoadStateDefs.ReleaseLoadState[]; IF loadee # NIL THEN LoaderBcdUtilDefs.ReleaseBcdSeg[bcdseg]; IF LReloc # NullRel THEN SystemDefs.FreeHeapNode[BASE[LReloc]]; IF LBind # NullBind THEN SystemDefs.FreeHeapNode[BASE[LBind]]; LoaderUtilityDefs.FinalizeUtilities[]; END; BEGIN ENABLE UNWIND => BEGIN CleanUpNew[]; IF frames # NIL THEN IF single THEN ControlDefs.Free[frames] ELSE FreePages[frames]; END; loadee _ LoaderBcdUtilDefs.SetUpBcd[bcdseg]; LoaderUtilityDefs.InitializeUtilities[loadee]; LoaderUtilityDefs.EnterCodeFileNames[loadee]; LoaderUtilityDefs.LookupFileTable[]; single _ loadee.nModules = 1; frames _ AllocateFrames[loadee, single, alloc, framelinks]; LReloc _ DESCRIPTOR[AllocateHeapNode[loadee.firstdummy], loadee.firstdummy]; nbcds _ LoadStateDefs.InputLoadState[]; AssignFrameAddresses[frames, loadee, LReloc, nbcds, single, alloc, framelinks]; LBind _ LoaderUtilityDefs.InitImportBinding[loadee.nDummies]; unresolved _ loadee.nImports # 0; initial _ TRUE; IF ~unresolved THEN RelocateOnly[loadee, LReloc]; FOR i DECREASING IN [0..nbcds) DO IF unresolved AND LoadStateDefs.BcdHasExports[i] THEN BEGIN ENABLE UNWIND => IF systemseg # NIL THEN LoaderBcdUtilDefs.ReleaseBcdSeg[systemseg]; systemseg _ LoadStateDefs.BcdSegFromLoadState[i]; system _ LoaderBcdUtilDefs.SetUpBcd[systemseg]; BindImports[loadee, system, LBind]; unresolved _ ProcessControlLinks[loadee, system, LReloc, LBind, i, initial]; initial _ FALSE; END; IF LoadStateDefs.BcdHasUnresolvedImports[i] AND loadee.nExports # 0 THEN BEGIN ENABLE UNWIND => BEGIN IF systemseg # NIL THEN LoaderBcdUtilDefs.ReleaseBcdSeg[systemseg]; IF SReloc # NullRel THEN LoadStateDefs.ReleaseRelocation[SReloc]; IF SBind # NullBind THEN SystemDefs.FreeHeapNode[BASE[SBind]]; END; IF systemseg = NIL THEN BEGIN systemseg _ LoadStateDefs.BcdSegFromLoadState[i]; system _ LoaderBcdUtilDefs.SetUpBcd[systemseg]; END; SReloc _ LoadStateDefs.InitializeRelocation[i]; SBind _ LoaderUtilityDefs.InitImportBinding[system.nDummies]; BindImports[system, loadee, SBind]; sysunres _ ProcessControlLinks[system, loadee, SReloc, SBind, nbcds, FALSE]; LoadStateDefs.SetUnresolvedImports[i, sysunres]; LoadStateDefs.ReleaseRelocation[SReloc]; SReloc _ NullRel; SystemDefs.FreeHeapNode[BASE[SBind]]; SBind _ NullBind; END; IF systemseg # NIL THEN BEGIN LoaderBcdUtilDefs.ReleaseBcdSeg[systemseg]; systemseg _ NIL; END; ENDLOOP; LoadStateDefs.UpdateLoadState[ nbcds, bcdseg, unresolved, (loadee.nExports # 0 OR single)]; frame _ IF single THEN LOOPHOLE[frames] ELSE LoaderUtilityDefs.ControlModuleFrame[loadee, LReloc]; CleanUpNew[]; END; END; AllocateFrames: PROCEDURE [loadee: BcdBase, single, alloc, framelinks: BOOLEAN] RETURNS [POINTER] = BEGIN OPEN SegmentDefs; RETURN[IF single THEN LoaderUtilityDefs.AllocateSingleModule[loadee, framelinks] ELSE SystemDefs.AllocateResidentSegment[ LoaderUtilityDefs.RequiredFrameSpace[loadee, alloc, framelinks]]]; END; AssignFrameAddresses: PROCEDURE [p: POINTER, loadee: BcdBase, Reloc: Relocation, config: ConfigIndex, single, alloc, allframelinks: BOOLEAN] = BEGIN frame: GlobalFrameHandle _ p; ModuleSearch: PROCEDURE [mth: MTHandle, mti: MTIndex] RETURNS [BOOLEAN] = BEGIN seg: SegmentDefs.FileSegmentHandle; gfi: GFTIndex; i: CARDINAL; framelinks: BOOLEAN; framelinks _ allframelinks OR mth.links = frame OR ~mth.code.linkspace; IF ~single AND alloc THEN BEGIN p _ NextMultipleOfFour[p+1]; (p-1)^ _ LoaderUtilityDefs.FindFrameIndex[mth, framelinks]; END; IF ~single AND framelinks THEN p _ p + mth.frame.length; frame _ NextMultipleOfFour[p]; p _ frame + mth.framesize; gfi _ FrameDefs.EnterGlobalFrame[frame, mth.ngfi]; FOR i IN [0..mth.ngfi) DO Reloc[mth.gfi+i] _ gfi + i; LoadStateDefs.EnterGfi[mth.gfi+i, gfi+i, config]; ENDLOOP; seg _ LoaderUtilityDefs.FindCodeSegment[loadee, mth, frame]; seg.class _ code; frame^ _ [gfi: gfi, unused: 0, alloced: alloc OR single, shared: FALSE, copied: FALSE, started: FALSE, trapxfers: FALSE, codelinks: ~framelinks, code: [out[mth.code.offset]], codesegment: seg, global:]; frame.code.swappedout _ TRUE; RETURN[FALSE]; END; FindSharedModules: PROCEDURE [f: GlobalFrameHandle] RETURNS [BOOLEAN] = BEGIN Search: PROCEDURE [mth: MTHandle, mti: MTIndex] RETURNS [BOOLEAN] = BEGIN frame: GlobalFrameHandle _ ControlDefs.GFT[Reloc[mth.gfi]].frame; IF EqualCodeSegments[f, frame] THEN BEGIN f.shared _ TRUE; frame.shared _ TRUE; END; RETURN[FALSE]; END; IF f.shared THEN RETURN[FALSE]; [] _ LoaderBcdUtilDefs.EnumerateModuleTable[loadee, Search]; RETURN[FALSE]; END; gfi: GFTIndex; Reloc[0] _ 0; [] _ LoaderBcdUtilDefs.EnumerateModuleTable[loadee, ModuleSearch]; FOR gfi IN [1..LENGTH[Reloc]) DO LoadStateDefs.EnterGfi[gfi, Reloc[gfi], config]; ENDLOOP; LoaderUtilityDefs.AssignControlModules[loadee, Reloc]; [] _ FrameDefs.EnumerateGlobalFrames[FindSharedModules]; END; NextMultipleOfFour: PROCEDURE [n: POINTER] RETURNS [POINTER] = BEGIN RETURN[n + InlineDefs.BITAND[-LOOPHOLE[n, INTEGER], 3B]]; END; EqualCodeSegments: PROCEDURE [f1, f2: GlobalFrameHandle] RETURNS [BOOLEAN] = BEGIN OPEN SegmentDefs; fcb: ControlDefs.FrameCodeBase; s1, s2: FileSegmentHandle; o1, o2: CARDINAL; s1 _ CodeDefs.CodeHandle[f1]; s2 _ CodeDefs.CodeHandle[f2]; IF s1 = s2 THEN BEGIN IF ~f1.code.swappedout THEN o1 _ f1.code.codebase - AddressFromPage[s1.VMpage] ELSE BEGIN fcb _ f1.code; fcb.swappedout _ FALSE; o1 _ fcb.offset; END; IF ~f2.code.swappedout THEN o2 _ f2.code.codebase - AddressFromPage[s2.VMpage] ELSE BEGIN fcb _ f2.code; fcb.swappedout _ FALSE; o2 _ fcb.offset; END; RETURN[o1 = o2] END; RETURN[FALSE] END; BindImports: PROCEDURE [loadee, system: BcdBase, ImportBinding: Binding] = BEGIN ForEachImport: PROCEDURE [ith: IMPHandle, iti: IMPIndex] RETURNS [BOOLEAN] = BEGIN i: CARDINAL; iname, sysname: SSD; issb, sysssb: POINTER TO BcdDefs.PackedString; module: MTIndex; export: EXPIndex; ExportMatch: PROCEDURE [eth: EXPHandle, eti: EXPIndex] RETURNS [BOOLEAN] = BEGIN OPEN StringDefs; sysname.offset _ eth.name; sysname.length _ sysssb.size[eth.name]; RETURN[eth.port = ith.port AND EqualSubStrings[@iname, @sysname] AND EqualFiles[loadee, system, ith.file, eth.file]] END; ModuleMatch: PROCEDURE [mth: MTHandle, mti: MTIndex] RETURNS [BOOLEAN] = BEGIN OPEN StringDefs; sysname.offset _ mth.name; sysname.length _ sysssb.size[mth.name]; RETURN[EqualSubStrings[@iname, @sysname] AND EqualFiles[loadee, system, ith.file, mth.file]] END; issb _ LOOPHOLE[loadee+loadee.ssOffset]; iname _ SSD[base: @issb.string, offset: ith.name, length: issb.size[ith.name]]; sysssb _ LOOPHOLE[system+system.ssOffset]; sysname.base _ @sysssb.string; export _ LoaderBcdUtilDefs.EnumerateExportTable[system, ExportMatch].eti; IF export # EXPNull THEN FOR i IN [0..ith.ngfi) DO ImportBinding[ith.gfi-loadee.firstdummy+i] _ [whichgfi: i, body: interface[export]]; ENDLOOP ELSE BEGIN module _ LoaderBcdUtilDefs.EnumerateModuleTable[system, ModuleMatch].mti; FOR i IN [0..ith.ngfi) DO IF module = MTNull THEN ImportBinding[ith.gfi-loadee.firstdummy+i] _ [whichgfi: i, body: notbound[]] ELSE ImportBinding[ith.gfi-loadee.firstdummy+i] _ [whichgfi: i, body: module[module]]; ENDLOOP; END; RETURN[FALSE]; END; [] _ LoaderBcdUtilDefs.EnumerateImportTable[loadee, ForEachImport]; END; EqualFiles: PROCEDURE [bcd1, bcd2: BcdBase, file1, file2: FTIndex] RETURNS [BOOLEAN] = BEGIN name1, name2: SSD; v1, v2: POINTER TO BcdDefs.VersionStamp; ps1: BcdDefs.NameString _ LOOPHOLE[bcd1+bcd1.ssOffset]; ps2: BcdDefs.NameString _ LOOPHOLE[bcd2+bcd2.ssOffset]; name1.base _ @ps1.string; name2.base _ @ps2.string; IF file1 = FTSelf THEN BEGIN name: NameRecord = (LOOPHOLE[bcd1+bcd1.mtOffset, CARDINAL] + FIRST[MTIndex]).name; name1.offset _ name; name1.length _ ps1.size[name]; v1 _ @bcd1.version; END ELSE BEGIN file: FTHandle _ LOOPHOLE[bcd1+bcd1.ftOffset, CARDINAL] + file1; name1.offset _ file.name; name1.length _ ps1.size[file.name]; v1 _ @file.version; END; IF file2 = FTSelf THEN BEGIN name: NameRecord = (LOOPHOLE[bcd2+bcd2.mtOffset, CARDINAL] + FIRST[MTIndex]).name; name2.offset _ name; name2.length _ ps2.size[name]; v2 _ @bcd2.version; END ELSE BEGIN file: FTHandle _ LOOPHOLE[bcd2+bcd2.ftOffset, CARDINAL] + file2; name2.offset _ file.name; name2.length _ ps2.size[file.name]; v2 _ @file.version; END; IF StringDefs.EquivalentSubStrings[@name1, @name2] THEN IF EqVer[v1, v2] THEN RETURN[TRUE] ELSE BEGIN OPEN SystemDefs; filename: STRING _ AllocateHeapString[name1.length]; StringDefs.AppendSubString[filename, @name1]; SIGNAL VersionMismatch[filename ! UNWIND => FreeHeapString[filename]]; FreeHeapString[filename]; END; RETURN[FALSE]; END; EqVer: PROCEDURE [v1, v2: POINTER TO BcdDefs.VersionStamp] RETURNS [BOOLEAN] = BEGIN RETURN [v1.zapped OR v2.zapped OR v1^ = v2^] END; ProcessControlLinks: PROCEDURE [loadee, system: BcdBase, Reloc: Relocation, ImportBinding: Binding, config: ConfigIndex, initial: BOOLEAN] RETURNS [BOOLEAN]= BEGIN smtb: CARDINAL = LOOPHOLE[system+system.mtOffset]; setb: CARDINAL = LOOPHOLE[system+system.expOffset]; unresolved: BOOLEAN _ FALSE; MungeControlLink: PROCEDURE [link: ControlLink, addr: LONG POINTER TO ControlLink] RETURNS [changedLink: BOOLEAN] = BEGIN gfi: GFTIndex; ep: EPIndex; acl: ControlLink; --XM XMesaDefs.XCOPY[from: addr, to: LONG[@acl], nwords: SIZE[ControlLink]]; --XM changedLink _ FALSE; --XM SELECT link.tag FROM procedure => IF acl = UnboundLink THEN --XM BEGIN IF link.gfi >= loadee.firstdummy THEN WITH ImportBinding[link.gfi-loadee.firstdummy] SELECT FROM module => SIGNAL LoaderError[Impossible]; -- Shouldn't Happen interface => BEGIN OPEN e: setb+eti; SELECT e.port FROM interface => BEGIN ep _ link.ep+(whichgfi*EPLimit); gfi _ LoadStateDefs.MapConfigToReal[e.links[ep].gfi, config]; IF gfi = 0 THEN unresolved _ TRUE ELSE BEGIN changedLink _ TRUE; SELECT e.links[ep].tag FROM procedure => BEGIN acl.gfi _ gfi; --XM acl.ep _ e.links[ep].ep; --XM acl.tag _ procedure; --XM END; frame => acl _ LOOPHOLE[ControlDefs.GFT[gfi].frame]; --XM ENDCASE; END; END; module => SIGNAL LoaderError[Impossible]; ENDCASE; END; notbound => unresolved _ TRUE; ENDCASE ELSE BEGIN acl _ link; --XM acl.gfi _ Reloc[link.gfi]; --XM changedLink _ TRUE; END; END; frame => IF acl = NullLink THEN --XM BEGIN IF link.gfi >= loadee.firstdummy THEN BEGIN WITH ImportBinding[link.gfi-loadee.firstdummy] SELECT FROM module => gfi _ LoadStateDefs.MapConfigToReal[(smtb+mti).gfi, config]; interface => BEGIN OPEN e: setb+eti; SELECT e.port FROM interface => ep _ link.ep+(whichgfi*EPLimit); module => ep _ 0; ENDCASE; gfi _ LoadStateDefs.MapConfigToReal[e.links[ep].gfi, config]; END; notbound => gfi _ 0; ENDCASE; IF gfi = 0 THEN unresolved _ TRUE ELSE BEGIN changedLink _ TRUE; acl _ LOOPHOLE[ControlDefs.GFT[gfi].frame]; --XM END; END ELSE BEGIN changedLink _ TRUE; acl _ LOOPHOLE[ControlDefs.GFT[Reloc[link.gfi]].frame]; --XM END; END; ENDCASE; IF changedLink THEN XMesaDefs.XCOPY[from: LONG[@acl], to: addr, nwords: SIZE[ControlLink]]; --XM END; ModuleSearch: PROCEDURE [mth: MTHandle, mti: MTIndex] RETURNS [BOOLEAN] = BEGIN n: CARDINAL = 10; --XM imax, j: CARDINAL; --XM linkVec: ARRAY [0..n) OF ControlLink; --XM i: CARDINAL; frame: GlobalFrameHandle _ ControlDefs.GFT[Reloc[mth.gfi]].frame; codesegment: SegmentDefs.FileSegmentHandle; linkbase: LONG POINTER TO ControlLink; changed: BOOLEAN; IF frame = ControlDefs.NullGlobalFrame THEN RETURN[FALSE]; codesegment _ CodeDefs.CodeHandle[frame]; IF frame.codelinks THEN BEGIN SwapIn[codesegment]; linkbase _ LOOPHOLE[XMesaDefs.XFileSegmentAddress[codesegment]+mth.code.offset] --XM END ELSE linkbase _ LOOPHOLE[LONG[frame]]; linkbase _ linkbase - mth.frame.length; IF initial THEN FOR j _ 0, j+n UNTIL j >= mth.frame.length --XM DO --XM imax _ MIN [n, mth.frame.length-j]; --XM InlineDefs.COPY[from: @mth.frame.frag[j], to: @linkVec[0], nwords: imax]; --XM FOR i IN [0..imax) --XM DO --XM SELECT linkVec[i].tag FROM --XM procedure => linkVec[i] _ UnboundLink; --XM frame => linkVec[i] _ NullLink; --XM ENDCASE; --XM ENDLOOP; --XM XMesaDefs.XCOPY[from: LONG[@linkVec[0]], to: linkbase+j, nwords: imax]; --XM ENDLOOP; --XM changed _ FALSE; FOR i IN [0..mth.frame.length) DO changed _ MungeControlLink[mth.frame.frag[i], linkbase+i] OR changed; ENDLOOP; IF frame.codelinks THEN BEGIN --XM codesegment.write _ changed OR initial; --XM KickOutCode[codesegment]; --XM END; --XM RETURN[FALSE]; END; [] _ LoaderBcdUtilDefs.EnumerateModuleTable[loadee, ModuleSearch]; RETURN[unresolved]; END; KickOutCode: PROCEDURE[seg: FileSegmentHandle] = --XM BEGIN Unlock[seg]; IF seg.write THEN BEGIN SwapUp[seg]; seg.write _ FALSE; END END; RelocateOnly: PROCEDURE [loadee: BcdBase, Reloc: Relocation]= BEGIN ModuleSearch: PROCEDURE [mth: MTHandle, mti: MTIndex] RETURNS [BOOLEAN] = BEGIN i: CARDINAL; frame: GlobalFrameHandle _ ControlDefs.GFT[Reloc[mth.gfi]].frame; codesegment: SegmentDefs.FileSegmentHandle; codelinks: BOOLEAN _ frame.codelinks; linkbase: LONG POINTER TO ControlLink; IF mth.frame.length = 0 THEN RETURN[FALSE]; codesegment _ CodeDefs.CodeHandle[frame]; IF frame.codelinks THEN BEGIN SwapIn[codesegment]; linkbase _ LOOPHOLE[XMesaDefs.XFileSegmentAddress[codesegment]+mth.code.offset] --XM END ELSE linkbase _ LOOPHOLE[LONG[frame]]; linkbase _ linkbase - mth.frame.length; FOR i IN [0..mth.frame.length) DO OPEN link: mth.frame.frag[i]; SELECT link.tag FROM procedure => BEGIN (linkbase+i)^ _ link; (linkbase+i).gfi _ Reloc[link.gfi]; END; frame => (linkbase+i)^ _ LOOPHOLE[ControlDefs.GFT[Reloc[link.gfi]].frame]; ENDCASE; ENDLOOP; IF codelinks THEN BEGIN codesegment.write _ TRUE; KickOutCode[codesegment]; --XM END; RETURN[FALSE]; END; [] _ LoaderBcdUtilDefs.EnumerateModuleTable[loadee, ModuleSearch]; RETURN END; SDDefs.SD[SDDefs.sNew] _ NewNew; END...