Linker1.Mod 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909
  1. (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
  2. MODULE Linker1; (* pjm *)
  3. (* BootLinker for A2 - cf. Loader *)
  4. IMPORT
  5. SYSTEM, Streams, Files, Commands, KernelLog := Linker0, Heaps := Linker0, Modules := Linker0, Linker0 ;
  6. CONST
  7. Ok* = 0;
  8. FileNotFound = 1;
  9. TagInvalid = 2;
  10. FileCorrupt = 3;
  11. FileTooShort = 4;
  12. IncompatibleImport = 5;
  13. AddressSize = SIZEOF (ADDRESS);
  14. FileTag = 0BBX; (* see PCM.FileTag *)
  15. NoZeroCompress = 0ADX; (* see PCM.NoZeroCompress *)
  16. FileVersion = 0B1X; (* see PCM.FileVersion *)
  17. FileVersionOC=0B2X; (* preparation for object and symbol file for new Oberon Compiler *)
  18. CurrentVersion=0B4X;
  19. MaxStructs = 1024; (* maximum number of structures in export block *)
  20. (* object model exports *)
  21. EUEnd = 0; EURecord = 1; EUobjScope = 0; EUrecScope = 1; EUerrScope = -1;
  22. EUProcFlagBit = 31;
  23. Sentinel = LONGINT(0FFFFFFFFH);
  24. TYPE
  25. ObjHeader = RECORD (* data from object file header *)
  26. entries, commands, pointers, types, modules, links, dataLinks: LONGINT;
  27. codeSize, dataSize, refSize, constSize, exTableLen, procs, maxPtrs, crc: LONGINT;
  28. staticTdSize: LONGINT;
  29. name: Modules.Name
  30. END;
  31. DataLinkRec = RECORD
  32. mod: LONGINT;
  33. entry: LONGINT;
  34. fixups: LONGINT;
  35. ofs: POINTER TO ARRAY OF SIZE
  36. END;
  37. LinkRec = RECORD
  38. mod: LONGINT;
  39. entry: LONGINT;
  40. link: SIZE
  41. END;
  42. TypeRec = RECORD
  43. init: BOOLEAN;
  44. entry, methods, inhMethods, baseMod: LONGINT;
  45. baseEntry: ADDRESS;
  46. END;
  47. VAR
  48. trace: BOOLEAN;
  49. (* ReadHeader - Read object file header. *)
  50. PROCEDURE ReadHeader(r: Streams.Reader; VAR h: ObjHeader; VAR res: LONGINT);
  51. VAR symSize: LONGINT; flags: SET; ignore: Modules.Module; tag: CHAR;
  52. BEGIN
  53. r.Char(tag);
  54. IF tag = FileTag THEN
  55. r.Char(tag);
  56. IF tag = NoZeroCompress THEN r.Char(tag) END; (* no zero compression in symbol file *)
  57. IF (tag = FileVersion) OR (tag >= FileVersionOC) & (tag <= CurrentVersion) THEN
  58. IF tag = FileVersion THEN
  59. r.RawNum(symSize);
  60. ELSIF tag >= FileVersionOC THEN
  61. r.RawLInt(symSize)
  62. END;
  63. r.RawSet(flags); (* compilation flags *)
  64. r.SkipBytes(symSize-4); (* skip symbols *)
  65. r.RawLInt(h.refSize);
  66. r.RawLInt(h.entries);
  67. r.RawLInt(h.commands);
  68. r.RawLInt(h.pointers);
  69. r.RawLInt(h.types);
  70. r.RawLInt(h.modules);
  71. r.RawLInt(h.dataLinks);
  72. r.RawLInt(h.links);
  73. r.RawLInt(h.dataSize);
  74. r.RawLInt(h.constSize);
  75. r.RawLInt(h.codeSize);
  76. r.RawLInt(h.exTableLen);
  77. r.RawLInt(h.procs);
  78. r.RawLInt(h.maxPtrs);
  79. r.RawLInt(h.staticTdSize); (* ug *)
  80. IF ORD(tag) >= 0B4H THEN r.RawLInt(h.crc) END;
  81. r.RawString(h.name);
  82. IF trace THEN
  83. KernelLog.String(" name: "); KernelLog.String(h.name);
  84. KernelLog.String(" symSize: "); KernelLog.Int(symSize, 1);
  85. KernelLog.String(" refSize: "); KernelLog.Int(h.refSize, 1);
  86. KernelLog.String(" dataSize: "); KernelLog.Int(h.dataSize, 1);
  87. KernelLog.String(" constSize: "); KernelLog.Int(h.constSize, 1);
  88. KernelLog.String(" codeSize: "); KernelLog.Int(h.codeSize, 1); KernelLog.Ln;
  89. KernelLog.String(" entries: "); KernelLog.Int(h.entries, 1);
  90. KernelLog.String(" commands: "); KernelLog.Int(h.commands, 1);
  91. KernelLog.String(" pointers: "); KernelLog.Int(h.pointers, 1);
  92. KernelLog.String(" types: "); KernelLog.Int(h.types, 1);
  93. KernelLog.String(" modules: "); KernelLog.Int(h.modules, 1);
  94. KernelLog.String(" dataLinks: "); KernelLog.Int(h.dataLinks, 1);
  95. KernelLog.String(" links: "); KernelLog.Int(h.links, 1); KernelLog.Ln;
  96. KernelLog.String(" exTableLen: "); KernelLog.Int(h.exTableLen, 1);
  97. KernelLog.String(" procs: "); KernelLog.Int(h.procs, 1);
  98. KernelLog.String(" maxPtrs: "); KernelLog.Int(h.maxPtrs, 1);
  99. KernelLog.String(" staticTdSize: "); KernelLog.Int(h.staticTdSize, 1); KernelLog.Ln;
  100. KernelLog.String(" crc: "); KernelLog.Hex(h.crc,-8); KernelLog.Ln
  101. END;
  102. IF r.res # Streams.Ok THEN res := r.res END
  103. ELSE
  104. res := TagInvalid
  105. END
  106. ELSE
  107. res := TagInvalid
  108. END
  109. END ReadHeader;
  110. (* zero compressed strings don't like UTF-8 encoding *)
  111. PROCEDURE ReadString8(r: Streams.Reader; VAR str: ARRAY OF CHAR);
  112. VAR i: LONGINT; ch: CHAR;
  113. BEGIN
  114. i := 0;
  115. r.Char(ch);
  116. WHILE ch # 0X DO
  117. str[i] := ch; INC(i);
  118. r.Char(ch);
  119. END;
  120. str[i] := 0X;
  121. END ReadString8;
  122. PROCEDURE AllocateModule(m: Modules.Module; h: ObjHeader);
  123. CONST
  124. LenOfs = 3 * AddressSize; (* offset of dimension 0 in array header *)
  125. VAR dataSize: SIZE; any: ANY;
  126. offset: ADDRESS;
  127. PROCEDURE NewSysArray(VAR ptr: ANY; elements, elemSize: SIZE);
  128. VAR adr: ADDRESS;
  129. BEGIN
  130. Heaps.NewSys(ptr, Heaps.ArraySize(elements, elemSize, 1));
  131. adr := SYSTEM.VAL(ADDRESS, ptr);
  132. SYSTEM.PUT(adr + LenOfs, elements); (* dimension *)
  133. END NewSysArray;
  134. PROCEDURE NewPtrArray(VAR ptr: ANY; elements, elemSize: SIZE);
  135. VAR adr: ADDRESS;
  136. BEGIN
  137. IF elements = 0 THEN (* case of empty array is mapped to a SystemBlock *)
  138. NewSysArray(ptr, elements, elemSize)
  139. ELSE
  140. Heaps.NewRealArr(ptr, elements, elemSize, 1);
  141. adr := SYSTEM.VAL(ADDRESS, ptr);
  142. SYSTEM.PUT(adr + LenOfs, elements) (* dimension *)
  143. END
  144. END NewPtrArray;
  145. BEGIN
  146. dataSize := SYSTEM.VAL(SIZE, h.dataSize) + (-h.dataSize) MOD 8; (* round up to 8 to align constant block *)
  147. NewSysArray(SYSTEM.VAL(ANY, m.entry), h.entries, SIZEOF(ADDRESS));
  148. NewSysArray(SYSTEM.VAL(ANY, m.command), h.commands, SIZEOF(Modules.Command));
  149. NewSysArray(SYSTEM.VAL(ANY, m.ptrAdr), h.pointers, SIZEOF(ADDRESS));
  150. NewPtrArray(SYSTEM.VAL(ANY, m.typeInfo), h.types, SIZEOF(Modules.TypeDesc));
  151. NewPtrArray(SYSTEM.VAL(ANY, m.module), h.modules, SIZEOF(Modules.Module));
  152. NewSysArray(SYSTEM.VAL(ANY, m.data), dataSize + h.constSize, 1);
  153. NewSysArray(SYSTEM.VAL(ANY, m.code), h.codeSize, 1);
  154. NewSysArray(SYSTEM.VAL(ANY, m.staticTypeDescs), h.staticTdSize, 1);
  155. NewSysArray(SYSTEM.VAL(ANY, m.refs), h.refSize, 1);
  156. NewSysArray(SYSTEM.VAL(ANY, m.exTable), h.exTableLen, SIZEOF(Modules.ExceptionTableEntry));
  157. (* the following code can be used in order to force a certain heapsize / alignment for debugging kernel issues
  158. IF m.name = "BootConsole" THEN
  159. Heaps.NewSys(any, 0);
  160. offset := SYSTEM.VAL(ADDRESS, any) - SYSTEM.VAL(ADDRESS, Heaps.heap);
  161. offset := offset - 0EBE00H;
  162. offset := 4096 - offset;
  163. TRACE(offset);
  164. Heaps.NewSys(any,offset -32);
  165. END;
  166. *)
  167. m.sb := ADDRESSOF(m.data[0]) + dataSize (* constants positive, data negative *)
  168. END AllocateModule;
  169. (* ReadEntryBlock - Read the entry block. *)
  170. PROCEDURE ReadEntryBlock(r: Streams.Reader; m: Modules.Module): BOOLEAN;
  171. VAR tag: CHAR; i, num: LONGINT;
  172. BEGIN
  173. r.Char( tag);
  174. IF tag = 82X THEN (* entry tag *)
  175. FOR i := 0 TO LEN(m.entry)-1 DO
  176. r.RawNum( num);
  177. m.entry[i] := num + ADDRESSOF(m.code[0])
  178. END;
  179. (*ASSERT((m.entries > 0) & (m.entry[0] = ADDRESSOF(m.code[0])));*) (* entry[0] is beginning of code (cf. OPL.Init) *)
  180. RETURN TRUE
  181. ELSE
  182. RETURN FALSE
  183. END
  184. END ReadEntryBlock;
  185. (* ReadCommandBlock - Read the command block. *)
  186. PROCEDURE ReadCommandBlock(r: Streams.Reader; m: Modules.Module): BOOLEAN;
  187. VAR tag : CHAR; i, num : LONGINT;
  188. BEGIN
  189. r.Char( tag);
  190. IF tag = 83X THEN (* command tag *)
  191. FOR i := 0 TO LEN(m.command)-1 DO
  192. r.RawNum( num); m.command[i].argTdAdr := num;
  193. r.RawNum( num); m.command[i].retTdAdr := num;
  194. r.RawString( m.command[i].name);
  195. r.RawNum( num); m.command[i].entryAdr := num;
  196. (* addresses will be fixed up later in FixupCommands *)
  197. END;
  198. RETURN TRUE
  199. ELSE
  200. RETURN FALSE
  201. END;
  202. END ReadCommandBlock;
  203. (* ReadPointerBlock - Read the pointer block. *)
  204. PROCEDURE ReadPointerBlock(r: Streams.Reader; m: Modules.Module): BOOLEAN;
  205. VAR tag: CHAR; i, p: LONGINT;
  206. BEGIN
  207. r.Char( tag);
  208. IF tag = 84X THEN (* pointer tag *)
  209. FOR i := 0 TO LEN(m.ptrAdr)-1 DO
  210. r.RawNum( p);
  211. ASSERT(p MOD AddressSize = 0); (* no deep copy flag *)
  212. m.ptrAdr[i] := m.sb + p
  213. END;
  214. RETURN TRUE
  215. ELSE
  216. RETURN FALSE
  217. END
  218. END ReadPointerBlock;
  219. (* ReadImportBlock - Read the import block. *)
  220. PROCEDURE ReadImportBlock(r: Streams.Reader; m: Modules.Module; VAR res: LONGINT;
  221. VAR msg: ARRAY OF CHAR): BOOLEAN;
  222. VAR tag: CHAR; i: LONGINT; name: Modules.Name;
  223. BEGIN
  224. r.Char( tag);
  225. IF tag = 85X THEN (* import tag *)
  226. i := 0;
  227. WHILE (i # LEN(m.module)) & (res = Ok) DO
  228. ReadString8(r, name);
  229. m.module[i] := Modules.ThisModule(name, res, msg); (* recursively load the imported module *)
  230. INC(i)
  231. END
  232. ELSE
  233. res := FileCorrupt
  234. END;
  235. RETURN res = Ok
  236. END ReadImportBlock;
  237. (* ReadDataLinkBlock - Read the data links block. *)
  238. PROCEDURE ReadDataLinkBlock(r: Streams.Reader; dataLinks: LONGINT; VAR d: ARRAY OF DataLinkRec): BOOLEAN;
  239. VAR tag: CHAR; i, j, num: LONGINT;
  240. BEGIN
  241. r.Char( tag);
  242. IF tag = 8DX THEN (* data links tag *)
  243. FOR i := 0 TO dataLinks-1 DO
  244. r.Char( tag); d[i].mod := ORD(tag);
  245. r.RawNum( num); d[i].entry := num;
  246. r.RawLInt( num); d[i].fixups := num; (* fixed size *)
  247. IF d[i].fixups > 0 THEN
  248. NEW(d[i].ofs, d[i].fixups);
  249. FOR j := 0 TO d[i].fixups-1 DO
  250. r.RawNum( num); d[i].ofs[j] := num
  251. END
  252. ELSE
  253. d[i].ofs := NIL
  254. END
  255. END;
  256. RETURN TRUE
  257. ELSE
  258. RETURN FALSE
  259. END
  260. END ReadDataLinkBlock;
  261. (* ReadLinkBlock - Read the link block. *)
  262. PROCEDURE ReadLinkBlock(r: Streams.Reader; links, entries: LONGINT; VAR l: ARRAY OF LinkRec; VAR f: ARRAY OF LONGINT; VAR caseTableSize: LONGINT): BOOLEAN;
  263. VAR tag: CHAR; i, num: LONGINT;
  264. BEGIN
  265. r.Char( tag);
  266. IF tag = 86X THEN (* links tag *)
  267. FOR i := 0 TO links-1 DO
  268. r.Char( tag); l[i].mod := ORD(tag);
  269. r.Char( tag); l[i].entry := ORD(tag);
  270. r.RawNum( num); l[i].link := num
  271. END;
  272. FOR i := 0 TO entries-1 DO
  273. r.RawNum( num); f[i] := num
  274. END;
  275. r.RawNum( caseTableSize);
  276. RETURN TRUE
  277. ELSE
  278. RETURN FALSE
  279. END
  280. END ReadLinkBlock;
  281. (* ReadConstBlock - Read the constant block. *)
  282. PROCEDURE ReadConstBlock(r: Streams.Reader; m: Modules.Module; h: ObjHeader): BOOLEAN;
  283. VAR tag: CHAR; i: LONGINT; t: ADDRESS;
  284. BEGIN
  285. r.Char( tag);
  286. IF tag = 87X THEN (* constant tag *)
  287. t := m.sb;
  288. FOR i := 0 TO h.constSize-1 DO
  289. r.Char( tag); SYSTEM.PUT(t, tag); INC(t)
  290. END;
  291. SYSTEM.GET(m.sb, t); ASSERT(t = 0);
  292. SYSTEM.PUT(m.sb, m); (* SELF *)
  293. RETURN TRUE
  294. ELSE
  295. RETURN FALSE
  296. END
  297. END ReadConstBlock;
  298. (* ReadExportBlock - Read the export block. *)
  299. PROCEDURE ReadExportBlock(r: Streams.Reader; m: Modules.Module): BOOLEAN;
  300. TYPE ExportPtr = POINTER TO Modules.ExportDesc; (* this type is introduced to dereference fields of an ExportDesc variable *)
  301. VAR tag: CHAR; structs, i: LONGINT; struct: ARRAY MaxStructs OF ADDRESS;
  302. p {UNTRACED}: ExportPtr; (* this variable must be untraced since it will be casted from a pure address field, it is not a valid heap block *)
  303. PROCEDURE LoadScope(VAR scope: Modules.ExportDesc; level, adr: LONGINT);
  304. VAR no1, no2, fp, off, num: LONGINT;
  305. BEGIN
  306. r.RawLInt( num); scope.exports := num; (* fixed size *)
  307. no1 := 0; no2 := 0;
  308. IF scope.exports # 0 THEN
  309. Linker0.NewExportDesc(scope.dsc, scope.exports);
  310. scope.dsc[0].adr := adr
  311. END;
  312. IF level = EUrecScope THEN
  313. INC(structs); struct[structs] := SYSTEM.VAL(ADDRESS, ADDRESSOF(scope))
  314. END;
  315. r.RawNum( fp);
  316. WHILE fp # EUEnd DO
  317. IF fp = EURecord THEN
  318. r.RawNum( off);
  319. IF off < 0 THEN
  320. p := SYSTEM.VAL(ExportPtr, struct[-off]);
  321. scope.dsc[no2].exports := p.exports;
  322. scope.dsc[no2].dsc := p.dsc (* old type *)
  323. ELSE
  324. LoadScope(scope.dsc[no2], EUrecScope, off)
  325. END
  326. ELSE
  327. IF level = EUobjScope THEN r.RawNum( num); scope.dsc[no1].adr := num END;
  328. scope.dsc[no1].fp := fp; no2 := no1; INC(no1)
  329. END;
  330. r.RawNum( fp)
  331. END
  332. END LoadScope;
  333. BEGIN
  334. r.Char( tag);
  335. IF tag = 88X THEN (* export tag *)
  336. structs := 0;
  337. FOR i := 0 TO MaxStructs - 1 DO struct[i] := Heaps.NilVal END;
  338. LoadScope(m.export, EUobjScope, 0);
  339. RETURN TRUE
  340. ELSE
  341. RETURN FALSE
  342. END
  343. END ReadExportBlock;
  344. (* ReadCodeBlock - Read the code block. *)
  345. PROCEDURE ReadCodeBlock(r: Streams.Reader; m: Modules.Module): BOOLEAN;
  346. VAR tag: CHAR;ignore: LONGINT;
  347. BEGIN
  348. r.Char( tag);
  349. IF tag = 89X THEN (* code tag *)
  350. r.Bytes( m.code^, 0, LEN(m.code), ignore);
  351. RETURN TRUE
  352. ELSE
  353. RETURN FALSE
  354. END
  355. END ReadCodeBlock;
  356. (* ReadUseBlock - Read and check the use block. *)
  357. PROCEDURE ReadUseBlock(r: Streams.Reader; m: Modules.Module; VAR dataLink: ARRAY OF DataLinkRec;
  358. VAR res: LONGINT; VAR msg: ARRAY OF CHAR): BOOLEAN;
  359. VAR tag: CHAR; i: LONGINT; name, prevname: Modules.Name; mod: Modules.Module;
  360. PROCEDURE Err;
  361. BEGIN
  362. IF res = Ok THEN
  363. res := IncompatibleImport;
  364. COPY(m.name, msg); Modules.Append(" incompatible with ", msg); Modules.Append(mod.name, msg);
  365. END
  366. END Err;
  367. PROCEDURE FixupCall(code: ADDRESS; link: SIZE; fixval: ADDRESS);
  368. VAR instr, nextlink: SIZE; opcode: CHAR;
  369. BEGIN
  370. REPEAT
  371. SYSTEM.GET(code + link, instr);
  372. nextlink := instr;
  373. SYSTEM.GET(code + link - 1, opcode); (* backward disassembly safe? *)
  374. IF opcode = 0E8X THEN (* call instruction relative *)
  375. SYSTEM.PUT(code + link, fixval - (code + link + 4)) (* + 4: to next instruction *)
  376. (* relative, no further fixup required *)
  377. ELSE (* move instruction absolute *)
  378. SYSTEM.PUT(code + link, fixval);
  379. Linker0.Relocate(code + link)
  380. END;
  381. link := nextlink
  382. UNTIL link = Sentinel
  383. END FixupCall;
  384. PROCEDURE FixupVar(code: ADDRESS; link: SIZE; fixval: ADDRESS);
  385. VAR i: LONGINT; val, adr: ADDRESS;
  386. BEGIN
  387. ASSERT(dataLink[link].mod # 0); (* this must be non-local module (?) *)
  388. FOR i := 0 TO dataLink[link].fixups-1 DO
  389. adr := code + dataLink[link].ofs[i];
  390. SYSTEM.GET(adr, val); (* non-zero for example with constant index into imported array *)
  391. SYSTEM.PUT(adr, val + fixval);
  392. Linker0.Relocate(adr)
  393. END
  394. END FixupVar;
  395. PROCEDURE CheckScope(scope: Modules.ExportDesc; level: LONGINT);
  396. VAR fp, i, num: LONGINT; link, adr: SIZE; tdadr: ADDRESS; tmpErr: BOOLEAN;
  397. BEGIN
  398. tmpErr := (level = EUerrScope);
  399. i := 0; link := 0;
  400. r.RawNum( fp);
  401. WHILE fp # EUEnd DO
  402. IF fp = EURecord THEN
  403. r.RawNum( num); link := num;
  404. IF tmpErr THEN
  405. CheckScope(scope.dsc[i], EUerrScope)
  406. ELSE
  407. IF scope.dsc[i].dsc # NIL THEN
  408. IF link # 0 THEN
  409. adr := scope.dsc[i].dsc[0].adr;
  410. SYSTEM.GET(mod.sb + adr, tdadr);
  411. SYSTEM.PUT(m.sb-link, tdadr); (* tdadr at tadr[0] *)
  412. Linker0.Relocate(m.sb-link)
  413. END
  414. END;
  415. CheckScope(scope.dsc[i], EUrecScope)
  416. END
  417. ELSE
  418. prevname := name; ReadString8(r, name);
  419. IF level >= EUobjScope THEN
  420. tmpErr := FALSE;
  421. IF level = EUobjScope THEN r.RawNum( num); link := num END;
  422. i := 0; WHILE (i < scope.exports) & (scope.dsc[i].fp # fp) DO INC(i) END;
  423. IF i >= scope.exports THEN
  424. Err; tmpErr := TRUE; Modules.Append("/", msg);
  425. IF name = "@" THEN Modules.Append(prevname, msg)
  426. ELSE Modules.Append(name, msg)
  427. END;
  428. DEC(i)
  429. ELSIF (level = EUobjScope) & (link # 0) THEN
  430. IF ~(EUProcFlagBit IN SYSTEM.VAL(SET, link)) THEN
  431. FixupVar(ADDRESSOF(m.code[0]), link, mod.sb + scope.dsc[i].adr)
  432. ELSE
  433. FixupCall(ADDRESSOF(m.code[0]), SYSTEM.VAL(SIZE, SYSTEM.VAL(SET, link) - {EUProcFlagBit}),
  434. scope.dsc[i].adr + ADDRESSOF(mod.code[0]))
  435. END
  436. END
  437. END
  438. END;
  439. r.RawNum( fp)
  440. END
  441. END CheckScope;
  442. BEGIN
  443. r.Char( tag);
  444. IF tag = 8AX THEN (* use tag *)
  445. i := 0;
  446. ReadString8(r, name);
  447. WHILE (name # "") & (res = Ok) DO
  448. mod := Modules.ThisModule(name, res, msg);
  449. IF res = Ok THEN
  450. CheckScope(mod.export, EUobjScope)
  451. END;
  452. ReadString8(r, name);
  453. END
  454. ELSE
  455. res := FileCorrupt
  456. END;
  457. RETURN res = Ok
  458. END ReadUseBlock;
  459. (* ReadTypeBlock - Read the type block. *)
  460. PROCEDURE ReadTypeBlock(r: Streams.Reader; m: Modules.Module; VAR type: ARRAY OF TypeRec): BOOLEAN;
  461. VAR
  462. tag: CHAR; i, j, newMethods, pointers, method, entry, num: LONGINT;
  463. tdSize: LONGINT; (* ug *)
  464. recSize, ofs, totTdSize (* ug *): SIZE; base: ADDRESS;
  465. name: Modules.Name; flags: SET;
  466. startAddr, tdAdr: ADDRESS;
  467. staticTypeBlock {UNTRACED}: Heaps.StaticTypeBlock;
  468. o: LONGINT;
  469. BEGIN
  470. r.Char( tag);
  471. IF tag = 8BX THEN (* type tag *)
  472. totTdSize := 0;
  473. IF LEN(m.staticTypeDescs) > 0 THEN
  474. startAddr := ADDRESSOF(m.staticTypeDescs[0]);
  475. END;
  476. FOR i := 0 TO LEN(type)-1 DO
  477. type[i].init := FALSE;
  478. r.RawNum(num); recSize := num;
  479. r.RawNum(num); type[i].entry := num;
  480. r.RawNum(num); type[i].baseMod := num;
  481. r.RawNum(num); type[i].baseEntry := num;
  482. r.RawNum(num); type[i].methods := ABS (num);
  483. IF num >= 0 THEN flags := {} (* unprotected type *)
  484. ELSE flags := {Heaps.ProtTypeBit} (* protected type *)
  485. END;
  486. r.RawNum(num); type[i].inhMethods := num;
  487. r.RawNum(newMethods);
  488. r.RawLInt(pointers); (* fixed size *)
  489. r.RawString(name);
  490. r.RawLInt(tdSize); (* ug *)
  491. Heaps.NewTypeDesc(SYSTEM.VAL(ANY, m.typeInfo[i]), Modules.TypeDescRecSize);
  492. Heaps.FillStaticType(tdAdr, startAddr, SYSTEM.VAL(ADDRESS, m.typeInfo[i]), tdSize, recSize, pointers,
  493. Modules.MaxTags + type[i].methods);
  494. m.typeInfo[i].tag := tdAdr; (* relocation done in Linker0.RelocateModule *)
  495. m.typeInfo[i].flags := flags;
  496. m.typeInfo[i].mod := m; (* relocation done in Linker0.RelocateModule *)
  497. m.typeInfo[i].name := name;
  498. base := m.typeInfo[i].tag + Modules.Mth0Ofs; (* read new methods *)
  499. FOR j := 0 TO newMethods - 1 DO
  500. r.RawNum(method);
  501. r.RawNum(entry);
  502. SYSTEM.PUT(base - AddressSize * method, m.entry[entry]);
  503. Linker0.Relocate(base - AddressSize * method)
  504. END;
  505. (* other methods are left NIL *)
  506. staticTypeBlock := SYSTEM.VAL(Heaps.StaticTypeBlock, tdAdr);
  507. ASSERT(LEN(staticTypeBlock.pointerOffsets) = pointers);
  508. FOR j := 0 TO pointers - 1 DO
  509. r.RawNum(o);
  510. ofs := o;
  511. ASSERT(ofs MOD AddressSize = 0); (* no deep copy flag *)
  512. staticTypeBlock.pointerOffsets[j] := ofs;
  513. ASSERT(ADDRESSOF(staticTypeBlock.pointerOffsets[j]) < startAddr + tdSize)
  514. END;
  515. SYSTEM.PUT(m.sb + type[i].entry, m.typeInfo[i].tag); (* patch in constant area *)
  516. Linker0.Relocate(m.sb + type[i].entry);
  517. totTdSize := totTdSize + tdSize;
  518. startAddr := startAddr + tdSize;
  519. END;
  520. (*
  521. ASSERT(totTdSize = m.staticTdSize);
  522. *)
  523. RETURN TRUE
  524. ELSE
  525. RETURN FALSE
  526. END
  527. END ReadTypeBlock;
  528. (* ReadRefBlock - Read the reference block. *)
  529. PROCEDURE ReadRefBlock(r: Streams.Reader; m: Modules.Module): BOOLEAN;
  530. VAR tag: CHAR; ignore: LONGINT;
  531. BEGIN
  532. r.Char( tag);
  533. IF tag = 8CX THEN (* ref tag *)
  534. r.Bytes( m.refs^, 0, LEN(m.refs),ignore);
  535. RETURN TRUE
  536. ELSE
  537. RETURN FALSE
  538. END
  539. END ReadRefBlock;
  540. (* FixupGlobals - Fix up references to global variables. *)
  541. PROCEDURE FixupGlobals(m: Modules.Module; VAR dataLink: ARRAY OF DataLinkRec);
  542. VAR i: LONGINT; t: SIZE; adr: ADDRESS;
  543. BEGIN
  544. IF dataLink[0].mod = 0 THEN (* local module has globals *)
  545. FOR i := 0 TO dataLink[0].fixups-1 DO
  546. adr := ADDRESSOF(m.code[0]) + dataLink[0].ofs[i];
  547. SYSTEM.GET(adr, t); SYSTEM.PUT(adr, t + m.sb);
  548. Linker0.Relocate(adr)
  549. END
  550. END
  551. END FixupGlobals;
  552. (* FixupLinks - Fix up other references. *)
  553. PROCEDURE FixupLinks(m: Modules.Module; VAR link: ARRAY OF LinkRec; VAR fixupCounts: ARRAY OF LONGINT; caseTableSize: LONGINT; VAR res: LONGINT);
  554. VAR i: LONGINT;
  555. PROCEDURE FixRelative(ofs: SIZE; val: ADDRESS);
  556. VAR t: SIZE; adr: ADDRESS;
  557. BEGIN
  558. ASSERT(val # 0);
  559. WHILE ofs # Sentinel DO
  560. adr := ADDRESSOF(m.code[0])+ofs;
  561. SYSTEM.GET(adr, t);
  562. SYSTEM.PUT(adr, val - (adr+AddressSize)); (* relative => no relocation required *)
  563. ofs := t
  564. END
  565. END FixRelative;
  566. PROCEDURE FixEntry(ofs: SIZE; VAR fixupCounts: ARRAY OF LONGINT);
  567. VAR t: SIZE; adr: ADDRESS; i: LONGINT;
  568. BEGIN
  569. i := 0;
  570. WHILE ofs # Sentinel DO
  571. adr := ADDRESSOF(m.code[0])+ofs;
  572. SYSTEM.GET(adr, t);
  573. WHILE fixupCounts[i] = 0 DO INC(i) END;
  574. SYSTEM.PUT(adr, m.entry[i]);
  575. DEC(fixupCounts[i]);
  576. Linker0.Relocate(adr);
  577. ofs := t
  578. END
  579. END FixEntry;
  580. PROCEDURE FixCase(ofs: SIZE; caseTableSize: LONGINT);
  581. VAR i: LONGINT; t: SIZE; adr: ADDRESS;
  582. BEGIN
  583. i := caseTableSize;
  584. WHILE i > 0 DO
  585. adr := m.sb+ofs;
  586. SYSTEM.GET(adr, t);
  587. SYSTEM.PUT(adr, ADDRESSOF(m.code[0]) + t);
  588. Linker0.Relocate(adr);
  589. DEC(i);
  590. ofs := ofs + AddressSize
  591. END
  592. END FixCase;
  593. BEGIN
  594. FOR i := 0 TO LEN(link)-1 DO
  595. ASSERT(link[i].mod = 0); (* only fix local things *)
  596. CASE link[i].entry OF
  597. 243..253: HALT(100); (*FixRelative(link[i].link, Modules.GetKernelProc(m, link[i].entry))*)
  598. |254: FixEntry(link[i].link, fixupCounts) (* local procedure address *)
  599. |255: FixCase(link[i].link, caseTableSize) (* case table *)
  600. ELSE res := 3406; RETURN (* unknown fixup type *)
  601. END
  602. END
  603. END FixupLinks;
  604. (* When loader parsed the command block, the type descriptors have not yet been allocated so we could not fixup
  605. the addresses -> do it now. *)
  606. PROCEDURE FixupCommands(m : Modules.Module);
  607. VAR i : LONGINT;
  608. BEGIN
  609. FOR i := 0 TO LEN(m.command)-1 DO
  610. m.command[i].entryAdr := m.command[i].entryAdr + ADDRESSOF(m.code[0]);
  611. IF (m.command[i].argTdAdr > 1) THEN SYSTEM.GET(m.sb + m.command[i].argTdAdr, m.command[i].argTdAdr); END;
  612. IF (m.command[i].retTdAdr > 1) THEN SYSTEM.GET(m.sb + m.command[i].retTdAdr, m.command[i].retTdAdr); END;
  613. END;
  614. END FixupCommands;
  615. (* InitType - Initialize a type. *)
  616. PROCEDURE InitType(m: Modules.Module; VAR type: ARRAY OF TypeRec; i: LONGINT);
  617. VAR j, baseMod, extLevel: LONGINT; t, root, baseTag, baseMth, baseRoot: ADDRESS; baseM: Modules.Module;
  618. BEGIN
  619. IF ~type[i].init THEN
  620. root := SYSTEM.VAL(ADDRESS, m.typeInfo[i].tag);
  621. baseTag := root + Modules.Tag0Ofs;
  622. baseMth := root + Modules.Mth0Ofs;
  623. baseMod := type[i].baseMod; extLevel := 0;
  624. ASSERT(baseMod >= -1);
  625. IF baseMod # -1 THEN (* extended type *)
  626. IF baseMod = 0 THEN (* base type local *)
  627. j := 0; WHILE type[j].entry # type[i].baseEntry DO INC(j) END; (* find base type *)
  628. InitType(m, type, j); (* and initialize it first *)
  629. baseM := m
  630. ELSE (* base type imported *)
  631. baseM := m.module[baseMod-1];
  632. t := type[i].baseEntry; (* fingerprint *)
  633. j := 0; WHILE baseM.export.dsc[j].fp # t DO INC(j) END; (* find base type *)
  634. type[i].baseEntry := baseM.export.dsc[j].dsc[0].adr
  635. END;
  636. (* copy base tags *)
  637. SYSTEM.GET(baseM.sb + type[i].baseEntry, baseRoot);
  638. SYSTEM.GET(baseRoot + Modules.Tag0Ofs, t);
  639. WHILE t # 0 DO
  640. SYSTEM.PUT(baseTag - AddressSize*extLevel, t);
  641. Linker0.Relocate(baseTag - AddressSize * extLevel);
  642. INC(extLevel);
  643. SYSTEM.GET(baseRoot + Modules.Tag0Ofs - AddressSize*extLevel, t)
  644. END;
  645. (* copy non-overwritten base methods *)
  646. FOR j := 0 TO type[i].inhMethods-1 DO
  647. SYSTEM.GET(baseMth - AddressSize*j, t); (* existing method *)
  648. IF t = 0 THEN
  649. SYSTEM.GET(baseRoot + Modules.Mth0Ofs - AddressSize*j, t); (* base method *)
  650. SYSTEM.PUT(baseMth - AddressSize*j, t);
  651. Linker0.Relocate(baseMth - AddressSize * j)
  652. END
  653. END
  654. END;
  655. m.typeInfo[i].flags := m.typeInfo[i].flags + SYSTEM.VAL(SET, extLevel);
  656. ASSERT(extLevel < Modules.MaxTags);
  657. SYSTEM.PUT(baseTag - AddressSize * extLevel, m.typeInfo[i].tag); (* self *)
  658. Linker0.Relocate(baseTag - AddressSize * extLevel);
  659. type[i].init := TRUE
  660. END
  661. END InitType;
  662. PROCEDURE ReadExTableBlock(r: Streams.Reader; m: Modules.Module): BOOLEAN;
  663. VAR
  664. tag: CHAR;
  665. pcFrom, pcTo, pcHandler, i: LONGINT;
  666. BEGIN
  667. r.Char( tag);
  668. IF tag = 8EX THEN
  669. FOR i:= 0 TO LEN(m.exTable) -1 DO
  670. r.Char( tag);
  671. IF tag = 0FEX THEN
  672. r.RawNum( pcFrom);
  673. r.RawNum( pcTo);
  674. r.RawNum( pcHandler);
  675. m.exTable[i].pcFrom := pcFrom + ADDRESSOF(m.code[0]);
  676. m.exTable[i].pcTo := pcTo + ADDRESSOF(m.code[0]);
  677. m.exTable[i].pcHandler := pcHandler + ADDRESSOF(m.code[0]);
  678. ELSE
  679. RETURN FALSE;
  680. END;
  681. END;
  682. RETURN TRUE
  683. ELSE
  684. RETURN FALSE
  685. END;
  686. END ReadExTableBlock;
  687. PROCEDURE ReadPtrsInProcs(r: Streams.Reader; m: Modules.Module): BOOLEAN;
  688. VAR tag: CHAR; i, j, codeoffset, beginOffset, endOffset, nofptrs, p: LONGINT;
  689. procTable: Modules.ProcTable; ptrTable: Modules.PtrTable;
  690. PROCEDURE Max(i, j : LONGINT) : LONGINT;
  691. BEGIN
  692. IF i > j THEN
  693. RETURN i
  694. ELSE
  695. RETURN j
  696. END
  697. END Max;
  698. PROCEDURE SwapProcTableEntries(p, q : LONGINT);
  699. VAR procentry : Modules.ProcTableEntry;
  700. k, i, basep, baseq: LONGINT; ptr: SIZE;
  701. BEGIN
  702. k := Max(procTable[p].noPtr, procTable[q].noPtr);
  703. IF k > 0 THEN (* swap entries in ptrTable first *)
  704. basep := p * m.maxPtrs; baseq := q * m.maxPtrs;
  705. FOR i := 0 TO k - 1 DO
  706. ptr := ptrTable[basep + i];
  707. ptrTable[basep + i] := ptrTable[baseq + i];
  708. ptrTable[baseq + i] := ptr
  709. END
  710. END;
  711. procentry := procTable[p];
  712. procTable[p] := procTable[q];
  713. procTable[q] := procentry
  714. END SwapProcTableEntries;
  715. PROCEDURE SortProcTable;
  716. VAR i, j, min: LONGINT;
  717. BEGIN
  718. FOR i := 0 TO m.noProcs - 2 DO
  719. min := i;
  720. FOR j := i + 1 TO m.noProcs - 1 DO
  721. IF procTable[j].pcFrom < procTable[min].pcFrom THEN min:= j END
  722. END;
  723. IF min # i THEN SwapProcTableEntries(i, min) END
  724. END
  725. END SortProcTable;
  726. BEGIN
  727. r.Char( tag);
  728. IF tag = 8FX THEN
  729. NEW(procTable, m.noProcs); NEW(ptrTable, m.noProcs * m.maxPtrs); (* m.noProcs > 0 since the empty module contains the module body procedure *)
  730. FOR i := 0 TO m.noProcs-1 DO
  731. r.RawNum( codeoffset);
  732. r.RawNum( beginOffset);
  733. r.RawNum( endOffset);
  734. r.RawLInt( nofptrs); (* fixed size *)
  735. procTable[i].pcFrom := codeoffset + ADDRESSOF(m.code[0]);
  736. procTable[i].pcStatementBegin := beginOffset + ADDRESSOF(m.code[0]);
  737. procTable[i].pcStatementEnd := endOffset + ADDRESSOF(m.code[0]);
  738. procTable[i].noPtr := nofptrs;
  739. FOR j := 0 TO nofptrs - 1 DO
  740. r.RawNum( p);
  741. ptrTable[i * m.maxPtrs + j] := p
  742. END
  743. END;
  744. SortProcTable();
  745. m.firstProc := procTable[0].pcFrom;
  746. FOR i := 0 TO m.noProcs - 2 DO
  747. procTable[i].pcLimit := procTable[i + 1].pcFrom
  748. END;
  749. procTable[m.noProcs - 1].pcLimit := ADDRESSOF(m.code[0]) + LEN(m.code) + 1; (* last element reserved for end of code segment,
  750. allow 1 byte extra, cf. Modules.ThisModuleByAdr *)
  751. (* in the dynamic loader, the following may not be executed while loading the pointers since a module might be loaded
  752. more than one times concurrently before effectively one of the loaded modules is loaded, cf. Modules.ThisModule.
  753. In the linker this can be done here already since we are sure we will publish this module in the list of modules.
  754. *)
  755. Linker0.InsertProcOffsets(procTable, ptrTable, m.maxPtrs);
  756. procTable := NIL; ptrTable := NIL;
  757. m.procTable := NIL; m.ptrTable := NIL;
  758. RETURN TRUE
  759. ELSE
  760. RETURN FALSE
  761. END
  762. END ReadPtrsInProcs;
  763. (** LoadObj - Load an Active Oberon object file. *)
  764. PROCEDURE LoadObj*(name, fileName: ARRAY OF CHAR; VAR res: LONGINT; VAR msg: ARRAY OF CHAR): Modules.Module;
  765. VAR
  766. f: Files.File; r: Files.Reader; h: ObjHeader; m: Modules.Module; i, caseTableSize : LONGINT;
  767. dataLink: POINTER TO ARRAY OF DataLinkRec;
  768. link: POINTER TO ARRAY OF LinkRec;
  769. fixupCounts: POINTER TO ARRAY OF LONGINT;
  770. type: POINTER TO ARRAY OF TypeRec;
  771. BEGIN
  772. f := Files.Old(fileName);
  773. IF f # NIL THEN
  774. IF trace THEN KernelLog.String("Loading "); KernelLog.String(fileName); KernelLog.Ln END;
  775. NEW(r,f,0);
  776. res := Ok; msg[0] := 0X;
  777. ReadHeader(r, h, res);
  778. IF res = Ok THEN
  779. ASSERT(h.name = name);
  780. Linker0.NewModule(m);
  781. i := 0; WHILE h.name[i] # 0X DO m.name[i] := h.name[i]; INC(i) END;
  782. m.name[i] := 0X;
  783. m.noProcs := h.procs;
  784. m.maxPtrs := h.maxPtrs;
  785. m.crc := h.crc;
  786. AllocateModule(m,h);
  787. IF trace THEN
  788. KernelLog.Address(ADDRESSOF(m.code[0])); KernelLog.Char(" ");
  789. KernelLog.String(m.name); KernelLog.Address(m.sb); KernelLog.Ln
  790. END;
  791. NEW(dataLink, h.dataLinks); NEW(link, h.links); NEW(fixupCounts, h.entries); NEW(type, h.types);
  792. IF ReadEntryBlock(r, m) & ReadCommandBlock(r, m) & ReadPointerBlock(r, m) &
  793. ReadImportBlock(r, m, res, msg) & ReadDataLinkBlock(r, h.dataLinks, dataLink^) &
  794. ReadLinkBlock(r, h.links, h.entries, link^, fixupCounts^, caseTableSize) &
  795. ReadConstBlock(r, m,h) & ReadExportBlock(r, m) &
  796. ReadCodeBlock(r, m) & ReadUseBlock(r, m, dataLink^, res, msg) &
  797. ReadTypeBlock(r, m, type^) & ReadExTableBlock(r, m) &
  798. ReadPtrsInProcs(r, m) & ReadRefBlock(r, m) THEN
  799. IF h.dataLinks # 0 THEN FixupGlobals(m, dataLink^) END;
  800. IF h.links # 0 THEN FixupLinks(m, link^, fixupCounts^, caseTableSize, res) END;
  801. IF h.commands # 0 THEN FixupCommands(m); END;
  802. IF res = Ok THEN
  803. FOR i := 0 TO LEN(type^)-1 DO InitType(m, type^, i) END
  804. END
  805. ELSE
  806. IF res = Ok THEN res := FileCorrupt END
  807. END;
  808. dataLink := NIL; link := NIL; type := NIL
  809. END;
  810. IF (res # Ok) & (msg[0] = 0X) THEN COPY(fileName, msg); Modules.Append(" corrupt", msg) END
  811. ELSE
  812. res := FileNotFound; COPY(fileName, msg); Modules.Append(" not found", msg)
  813. END;
  814. ASSERT(res = Ok);
  815. IF res # Ok THEN m := NIL END;
  816. RETURN m
  817. END LoadObj;
  818. BEGIN
  819. Modules.loadObj := LoadObj;
  820. trace := TRUE;
  821. END Linker1.
  822. (*
  823. 20.05.98 pjm Started
  824. *)
  825. SystemTools.FreeDownTo Linker1 Linker0 ~