Linker1.Mod 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907
  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. BEGIN
  469. r.Char( tag);
  470. IF tag = 8BX THEN (* type tag *)
  471. totTdSize := 0;
  472. IF LEN(m.staticTypeDescs) > 0 THEN
  473. startAddr := ADDRESSOF(m.staticTypeDescs[0]);
  474. END;
  475. FOR i := 0 TO LEN(type)-1 DO
  476. type[i].init := FALSE;
  477. r.RawNum(num); recSize := num;
  478. r.RawNum(num); type[i].entry := num;
  479. r.RawNum(num); type[i].baseMod := num;
  480. r.RawNum(num); type[i].baseEntry := num;
  481. r.RawNum(num); type[i].methods := ABS (num);
  482. IF num >= 0 THEN flags := {} (* unprotected type *)
  483. ELSE flags := {Heaps.ProtTypeBit} (* protected type *)
  484. END;
  485. r.RawNum(num); type[i].inhMethods := num;
  486. r.RawNum(newMethods);
  487. r.RawLInt(pointers); (* fixed size *)
  488. r.RawString(name);
  489. r.RawLInt(tdSize); (* ug *)
  490. Heaps.NewTypeDesc(SYSTEM.VAL(ANY, m.typeInfo[i]), Modules.TypeDescRecSize);
  491. Heaps.FillStaticType(tdAdr, startAddr, SYSTEM.VAL(ADDRESS, m.typeInfo[i]), tdSize, recSize, pointers,
  492. Modules.MaxTags + type[i].methods);
  493. m.typeInfo[i].tag := tdAdr; (* relocation done in Linker0.RelocateModule *)
  494. m.typeInfo[i].flags := flags;
  495. m.typeInfo[i].mod := m; (* relocation done in Linker0.RelocateModule *)
  496. m.typeInfo[i].name := name;
  497. base := m.typeInfo[i].tag + Modules.Mth0Ofs; (* read new methods *)
  498. FOR j := 0 TO newMethods - 1 DO
  499. r.RawNum(method);
  500. r.RawNum(entry);
  501. SYSTEM.PUT(base - AddressSize * method, m.entry[entry]);
  502. Linker0.Relocate(base - AddressSize * method)
  503. END;
  504. (* other methods are left NIL *)
  505. staticTypeBlock := SYSTEM.VAL(Heaps.StaticTypeBlock, tdAdr);
  506. ASSERT(LEN(staticTypeBlock.pointerOffsets) = pointers);
  507. FOR j := 0 TO pointers - 1 DO
  508. r.RawNum(ofs);
  509. ASSERT(ofs MOD AddressSize = 0); (* no deep copy flag *)
  510. staticTypeBlock.pointerOffsets[j] := ofs;
  511. ASSERT(ADDRESSOF(staticTypeBlock.pointerOffsets[j]) < startAddr + tdSize)
  512. END;
  513. SYSTEM.PUT(m.sb + type[i].entry, m.typeInfo[i].tag); (* patch in constant area *)
  514. Linker0.Relocate(m.sb + type[i].entry);
  515. totTdSize := totTdSize + tdSize;
  516. startAddr := startAddr + tdSize;
  517. END;
  518. (*
  519. ASSERT(totTdSize = m.staticTdSize);
  520. *)
  521. RETURN TRUE
  522. ELSE
  523. RETURN FALSE
  524. END
  525. END ReadTypeBlock;
  526. (* ReadRefBlock - Read the reference block. *)
  527. PROCEDURE ReadRefBlock(r: Streams.Reader; m: Modules.Module): BOOLEAN;
  528. VAR tag: CHAR; ignore: LONGINT;
  529. BEGIN
  530. r.Char( tag);
  531. IF tag = 8CX THEN (* ref tag *)
  532. r.Bytes( m.refs^, 0, LEN(m.refs),ignore);
  533. RETURN TRUE
  534. ELSE
  535. RETURN FALSE
  536. END
  537. END ReadRefBlock;
  538. (* FixupGlobals - Fix up references to global variables. *)
  539. PROCEDURE FixupGlobals(m: Modules.Module; VAR dataLink: ARRAY OF DataLinkRec);
  540. VAR i: LONGINT; t: SIZE; adr: ADDRESS;
  541. BEGIN
  542. IF dataLink[0].mod = 0 THEN (* local module has globals *)
  543. FOR i := 0 TO dataLink[0].fixups-1 DO
  544. adr := ADDRESSOF(m.code[0]) + dataLink[0].ofs[i];
  545. SYSTEM.GET(adr, t); SYSTEM.PUT(adr, t + m.sb);
  546. Linker0.Relocate(adr)
  547. END
  548. END
  549. END FixupGlobals;
  550. (* FixupLinks - Fix up other references. *)
  551. PROCEDURE FixupLinks(m: Modules.Module; VAR link: ARRAY OF LinkRec; VAR fixupCounts: ARRAY OF LONGINT; caseTableSize: LONGINT; VAR res: LONGINT);
  552. VAR i: LONGINT;
  553. PROCEDURE FixRelative(ofs: SIZE; val: ADDRESS);
  554. VAR t: SIZE; adr: ADDRESS;
  555. BEGIN
  556. ASSERT(val # 0);
  557. WHILE ofs # Sentinel DO
  558. adr := ADDRESSOF(m.code[0])+ofs;
  559. SYSTEM.GET(adr, t);
  560. SYSTEM.PUT(adr, val - (adr+AddressSize)); (* relative => no relocation required *)
  561. ofs := t
  562. END
  563. END FixRelative;
  564. PROCEDURE FixEntry(ofs: SIZE; VAR fixupCounts: ARRAY OF LONGINT);
  565. VAR t: SIZE; adr: ADDRESS; i: LONGINT;
  566. BEGIN
  567. i := 0;
  568. WHILE ofs # Sentinel DO
  569. adr := ADDRESSOF(m.code[0])+ofs;
  570. SYSTEM.GET(adr, t);
  571. WHILE fixupCounts[i] = 0 DO INC(i) END;
  572. SYSTEM.PUT(adr, m.entry[i]);
  573. DEC(fixupCounts[i]);
  574. Linker0.Relocate(adr);
  575. ofs := t
  576. END
  577. END FixEntry;
  578. PROCEDURE FixCase(ofs: SIZE; caseTableSize: LONGINT);
  579. VAR i: LONGINT; t: SIZE; adr: ADDRESS;
  580. BEGIN
  581. i := caseTableSize;
  582. WHILE i > 0 DO
  583. adr := m.sb+ofs;
  584. SYSTEM.GET(adr, t);
  585. SYSTEM.PUT(adr, ADDRESSOF(m.code[0]) + t);
  586. Linker0.Relocate(adr);
  587. DEC(i);
  588. ofs := ofs + AddressSize
  589. END
  590. END FixCase;
  591. BEGIN
  592. FOR i := 0 TO LEN(link)-1 DO
  593. ASSERT(link[i].mod = 0); (* only fix local things *)
  594. CASE link[i].entry OF
  595. 243..253: HALT(100); (*FixRelative(link[i].link, Modules.GetKernelProc(m, link[i].entry))*)
  596. |254: FixEntry(link[i].link, fixupCounts) (* local procedure address *)
  597. |255: FixCase(link[i].link, caseTableSize) (* case table *)
  598. ELSE res := 3406; RETURN (* unknown fixup type *)
  599. END
  600. END
  601. END FixupLinks;
  602. (* When loader parsed the command block, the type descriptors have not yet been allocated so we could not fixup
  603. the addresses -> do it now. *)
  604. PROCEDURE FixupCommands(m : Modules.Module);
  605. VAR i : LONGINT;
  606. BEGIN
  607. FOR i := 0 TO LEN(m.command)-1 DO
  608. m.command[i].entryAdr := m.command[i].entryAdr + ADDRESSOF(m.code[0]);
  609. IF (m.command[i].argTdAdr > 1) THEN SYSTEM.GET(m.sb + m.command[i].argTdAdr, m.command[i].argTdAdr); END;
  610. IF (m.command[i].retTdAdr > 1) THEN SYSTEM.GET(m.sb + m.command[i].retTdAdr, m.command[i].retTdAdr); END;
  611. END;
  612. END FixupCommands;
  613. (* InitType - Initialize a type. *)
  614. PROCEDURE InitType(m: Modules.Module; VAR type: ARRAY OF TypeRec; i: LONGINT);
  615. VAR j, baseMod, extLevel: LONGINT; t, root, baseTag, baseMth, baseRoot: ADDRESS; baseM: Modules.Module;
  616. BEGIN
  617. IF ~type[i].init THEN
  618. root := SYSTEM.VAL(ADDRESS, m.typeInfo[i].tag);
  619. baseTag := root + Modules.Tag0Ofs;
  620. baseMth := root + Modules.Mth0Ofs;
  621. baseMod := type[i].baseMod; extLevel := 0;
  622. ASSERT(baseMod >= -1);
  623. IF baseMod # -1 THEN (* extended type *)
  624. IF baseMod = 0 THEN (* base type local *)
  625. j := 0; WHILE type[j].entry # type[i].baseEntry DO INC(j) END; (* find base type *)
  626. InitType(m, type, j); (* and initialize it first *)
  627. baseM := m
  628. ELSE (* base type imported *)
  629. baseM := m.module[baseMod-1];
  630. t := type[i].baseEntry; (* fingerprint *)
  631. j := 0; WHILE baseM.export.dsc[j].fp # t DO INC(j) END; (* find base type *)
  632. type[i].baseEntry := baseM.export.dsc[j].dsc[0].adr
  633. END;
  634. (* copy base tags *)
  635. SYSTEM.GET(baseM.sb + type[i].baseEntry, baseRoot);
  636. SYSTEM.GET(baseRoot + Modules.Tag0Ofs, t);
  637. WHILE t # 0 DO
  638. SYSTEM.PUT(baseTag - AddressSize*extLevel, t);
  639. Linker0.Relocate(baseTag - AddressSize * extLevel);
  640. INC(extLevel);
  641. SYSTEM.GET(baseRoot + Modules.Tag0Ofs - AddressSize*extLevel, t)
  642. END;
  643. (* copy non-overwritten base methods *)
  644. FOR j := 0 TO type[i].inhMethods-1 DO
  645. SYSTEM.GET(baseMth - AddressSize*j, t); (* existing method *)
  646. IF t = 0 THEN
  647. SYSTEM.GET(baseRoot + Modules.Mth0Ofs - AddressSize*j, t); (* base method *)
  648. SYSTEM.PUT(baseMth - AddressSize*j, t);
  649. Linker0.Relocate(baseMth - AddressSize * j)
  650. END
  651. END
  652. END;
  653. m.typeInfo[i].flags := m.typeInfo[i].flags + SYSTEM.VAL(SET, extLevel);
  654. ASSERT(extLevel < Modules.MaxTags);
  655. SYSTEM.PUT(baseTag - AddressSize * extLevel, m.typeInfo[i].tag); (* self *)
  656. Linker0.Relocate(baseTag - AddressSize * extLevel);
  657. type[i].init := TRUE
  658. END
  659. END InitType;
  660. PROCEDURE ReadExTableBlock(r: Streams.Reader; m: Modules.Module): BOOLEAN;
  661. VAR
  662. tag: CHAR;
  663. pcFrom, pcTo, pcHandler, i: LONGINT;
  664. BEGIN
  665. r.Char( tag);
  666. IF tag = 8EX THEN
  667. FOR i:= 0 TO LEN(m.exTable) -1 DO
  668. r.Char( tag);
  669. IF tag = 0FEX THEN
  670. r.RawNum( pcFrom);
  671. r.RawNum( pcTo);
  672. r.RawNum( pcHandler);
  673. m.exTable[i].pcFrom := pcFrom + ADDRESSOF(m.code[0]);
  674. m.exTable[i].pcTo := pcTo + ADDRESSOF(m.code[0]);
  675. m.exTable[i].pcHandler := pcHandler + ADDRESSOF(m.code[0]);
  676. ELSE
  677. RETURN FALSE;
  678. END;
  679. END;
  680. RETURN TRUE
  681. ELSE
  682. RETURN FALSE
  683. END;
  684. END ReadExTableBlock;
  685. PROCEDURE ReadPtrsInProcs(r: Streams.Reader; m: Modules.Module): BOOLEAN;
  686. VAR tag: CHAR; i, j, codeoffset, beginOffset, endOffset, nofptrs, p: LONGINT;
  687. procTable: Modules.ProcTable; ptrTable: Modules.PtrTable;
  688. PROCEDURE Max(i, j : LONGINT) : LONGINT;
  689. BEGIN
  690. IF i > j THEN
  691. RETURN i
  692. ELSE
  693. RETURN j
  694. END
  695. END Max;
  696. PROCEDURE SwapProcTableEntries(p, q : LONGINT);
  697. VAR procentry : Modules.ProcTableEntry;
  698. k, i, basep, baseq: LONGINT; ptr: SIZE;
  699. BEGIN
  700. k := Max(procTable[p].noPtr, procTable[q].noPtr);
  701. IF k > 0 THEN (* swap entries in ptrTable first *)
  702. basep := p * m.maxPtrs; baseq := q * m.maxPtrs;
  703. FOR i := 0 TO k - 1 DO
  704. ptr := ptrTable[basep + i];
  705. ptrTable[basep + i] := ptrTable[baseq + i];
  706. ptrTable[baseq + i] := ptr
  707. END
  708. END;
  709. procentry := procTable[p];
  710. procTable[p] := procTable[q];
  711. procTable[q] := procentry
  712. END SwapProcTableEntries;
  713. PROCEDURE SortProcTable;
  714. VAR i, j, min: LONGINT;
  715. BEGIN
  716. FOR i := 0 TO m.noProcs - 2 DO
  717. min := i;
  718. FOR j := i + 1 TO m.noProcs - 1 DO
  719. IF procTable[j].pcFrom < procTable[min].pcFrom THEN min:= j END
  720. END;
  721. IF min # i THEN SwapProcTableEntries(i, min) END
  722. END
  723. END SortProcTable;
  724. BEGIN
  725. r.Char( tag);
  726. IF tag = 8FX THEN
  727. NEW(procTable, m.noProcs); NEW(ptrTable, m.noProcs * m.maxPtrs); (* m.noProcs > 0 since the empty module contains the module body procedure *)
  728. FOR i := 0 TO m.noProcs-1 DO
  729. r.RawNum( codeoffset);
  730. r.RawNum( beginOffset);
  731. r.RawNum( endOffset);
  732. r.RawLInt( nofptrs); (* fixed size *)
  733. procTable[i].pcFrom := codeoffset + ADDRESSOF(m.code[0]);
  734. procTable[i].pcStatementBegin := beginOffset + ADDRESSOF(m.code[0]);
  735. procTable[i].pcStatementEnd := endOffset + ADDRESSOF(m.code[0]);
  736. procTable[i].noPtr := nofptrs;
  737. FOR j := 0 TO nofptrs - 1 DO
  738. r.RawNum( p);
  739. ptrTable[i * m.maxPtrs + j] := p
  740. END
  741. END;
  742. SortProcTable();
  743. m.firstProc := procTable[0].pcFrom;
  744. FOR i := 0 TO m.noProcs - 2 DO
  745. procTable[i].pcLimit := procTable[i + 1].pcFrom
  746. END;
  747. procTable[m.noProcs - 1].pcLimit := ADDRESSOF(m.code[0]) + LEN(m.code) + 1; (* last element reserved for end of code segment,
  748. allow 1 byte extra, cf. Modules.ThisModuleByAdr *)
  749. (* in the dynamic loader, the following may not be executed while loading the pointers since a module might be loaded
  750. more than one times concurrently before effectively one of the loaded modules is loaded, cf. Modules.ThisModule.
  751. In the linker this can be done here already since we are sure we will publish this module in the list of modules.
  752. *)
  753. Linker0.InsertProcOffsets(procTable, ptrTable, m.maxPtrs);
  754. procTable := NIL; ptrTable := NIL;
  755. m.procTable := NIL; m.ptrTable := NIL;
  756. RETURN TRUE
  757. ELSE
  758. RETURN FALSE
  759. END
  760. END ReadPtrsInProcs;
  761. (** LoadObj - Load an Active Oberon object file. *)
  762. PROCEDURE LoadObj*(name, fileName: ARRAY OF CHAR; VAR res: LONGINT; VAR msg: ARRAY OF CHAR): Modules.Module;
  763. VAR
  764. f: Files.File; r: Files.Reader; h: ObjHeader; m: Modules.Module; i, caseTableSize : LONGINT;
  765. dataLink: POINTER TO ARRAY OF DataLinkRec;
  766. link: POINTER TO ARRAY OF LinkRec;
  767. fixupCounts: POINTER TO ARRAY OF LONGINT;
  768. type: POINTER TO ARRAY OF TypeRec;
  769. BEGIN
  770. f := Files.Old(fileName);
  771. IF f # NIL THEN
  772. IF trace THEN KernelLog.String("Loading "); KernelLog.String(fileName); KernelLog.Ln END;
  773. NEW(r,f,0);
  774. res := Ok; msg[0] := 0X;
  775. ReadHeader(r, h, res);
  776. IF res = Ok THEN
  777. ASSERT(h.name = name);
  778. Linker0.NewModule(m);
  779. i := 0; WHILE h.name[i] # 0X DO m.name[i] := h.name[i]; INC(i) END;
  780. m.name[i] := 0X;
  781. m.noProcs := h.procs;
  782. m.maxPtrs := h.maxPtrs;
  783. m.crc := h.crc;
  784. AllocateModule(m,h);
  785. IF trace THEN
  786. KernelLog.Address(ADDRESSOF(m.code[0])); KernelLog.Char(" ");
  787. KernelLog.String(m.name); KernelLog.Address(m.sb); KernelLog.Ln
  788. END;
  789. NEW(dataLink, h.dataLinks); NEW(link, h.links); NEW(fixupCounts, h.entries); NEW(type, h.types);
  790. IF ReadEntryBlock(r, m) & ReadCommandBlock(r, m) & ReadPointerBlock(r, m) &
  791. ReadImportBlock(r, m, res, msg) & ReadDataLinkBlock(r, h.dataLinks, dataLink^) &
  792. ReadLinkBlock(r, h.links, h.entries, link^, fixupCounts^, caseTableSize) &
  793. ReadConstBlock(r, m,h) & ReadExportBlock(r, m) &
  794. ReadCodeBlock(r, m) & ReadUseBlock(r, m, dataLink^, res, msg) &
  795. ReadTypeBlock(r, m, type^) & ReadExTableBlock(r, m) &
  796. ReadPtrsInProcs(r, m) & ReadRefBlock(r, m) THEN
  797. IF h.dataLinks # 0 THEN FixupGlobals(m, dataLink^) END;
  798. IF h.links # 0 THEN FixupLinks(m, link^, fixupCounts^, caseTableSize, res) END;
  799. IF h.commands # 0 THEN FixupCommands(m); END;
  800. IF res = Ok THEN
  801. FOR i := 0 TO LEN(type^)-1 DO InitType(m, type^, i) END
  802. END
  803. ELSE
  804. IF res = Ok THEN res := FileCorrupt END
  805. END;
  806. dataLink := NIL; link := NIL; type := NIL
  807. END;
  808. IF (res # Ok) & (msg[0] = 0X) THEN COPY(fileName, msg); Modules.Append(" corrupt", msg) END
  809. ELSE
  810. res := FileNotFound; COPY(fileName, msg); Modules.Append(" not found", msg)
  811. END;
  812. ASSERT(res = Ok);
  813. IF res # Ok THEN m := NIL END;
  814. RETURN m
  815. END LoadObj;
  816. BEGIN
  817. Modules.loadObj := LoadObj;
  818. trace := TRUE;
  819. END Linker1.
  820. (*
  821. 20.05.98 pjm Started
  822. *)
  823. SystemTools.FreeDownTo Linker1 Linker0 ~