StaticLinker.Mod 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992
  1. MODULE StaticLinker; (* AUTHOR "negelef"; PURPOSE "Static Object File Linker"; *)
  2. IMPORT Commands, Options, Diagnostics, Files, GenericLinker, ObjectFile, BitSets, Strings, Streams;
  3. TYPE
  4. ExportName = ARRAY 128 OF CHAR;
  5. PatchBlock*= POINTER TO RECORD
  6. baseAdr: LONGINT;
  7. addresses: LONGINT;
  8. address: ARRAY 1024 OF LONGINT;
  9. next: PatchBlock;
  10. END;
  11. RelocationInfo= OBJECT
  12. CONST blockSize=4096;
  13. VAR
  14. patchBlock: PatchBlock;
  15. PROCEDURE & Init;
  16. BEGIN
  17. patchBlock := NIL;
  18. END Init;
  19. PROCEDURE GetPatchBlock(adr: LONGINT): PatchBlock;
  20. VAR p, t: PatchBlock;
  21. BEGIN
  22. t := patchBlock;
  23. IF (patchBlock = NIL) OR (patchBlock.baseAdr > adr) THEN
  24. NEW(p); p.next := patchBlock; patchBlock := p; p.baseAdr := adr;
  25. ELSIF patchBlock.baseAdr = adr THEN p := patchBlock
  26. ELSE
  27. t := patchBlock;
  28. WHILE (t.next # NIL) & (t.next.baseAdr <= adr) DO
  29. t := t.next;
  30. END;
  31. IF t.baseAdr = adr THEN p := t
  32. ELSE
  33. NEW(p); p.next := t.next; t.next := p; p.baseAdr := adr
  34. END;
  35. END;
  36. RETURN p
  37. END GetPatchBlock;
  38. PROCEDURE AddReloc(adr: LONGINT);
  39. VAR aligned: LONGINT; p: PatchBlock;
  40. BEGIN
  41. aligned := adr - adr MOD blockSize;
  42. p := GetPatchBlock(aligned);
  43. p.address[p.addresses] := adr (*- aligned*); INC(p.addresses);
  44. END AddReloc;
  45. END RelocationInfo;
  46. ExportInfo=OBJECT
  47. VAR
  48. exports: LONGINT;
  49. name: ExportName;
  50. symbolNames: POINTER TO ARRAY OF ExportName;
  51. exportNames: POINTER TO ARRAY OF ExportName;
  52. exportAddresses: POINTER TO ARRAY OF GenericLinker.Address;
  53. PROCEDURE &Init;
  54. BEGIN
  55. exports := 0;
  56. END Init;
  57. PROCEDURE Swap(i,j: LONGINT);
  58. VAR name: ExportName; adr: LONGINT;
  59. BEGIN
  60. name := exportNames[i]; exportNames[i] := exportNames[j]; exportNames[j] := name;
  61. name := symbolNames[i]; symbolNames[i] := symbolNames[j]; symbolNames[j] := name;
  62. adr := exportAddresses[i]; exportAddresses[i] := exportAddresses[j]; exportAddresses[j] := adr;
  63. END Swap;
  64. PROCEDURE QuickSort(lo, hi: LONGINT);
  65. VAR
  66. i, j,m: LONGINT;
  67. x, t: ANY;
  68. BEGIN
  69. i := lo; j := hi; m := (lo + hi) DIV 2;
  70. WHILE i <= j DO
  71. WHILE exportNames[i] < exportNames[m] DO INC(i) END;
  72. WHILE exportNames[m] < exportNames[j] DO DEC(j) END;
  73. IF i <= j THEN
  74. IF m = i THEN m := j (* pivot will be moved by Swap *)
  75. ELSIF m = j THEN m := i (* pivot will be moved by Swap *)
  76. END;
  77. Swap(i,j);
  78. INC(i); DEC(j)
  79. END
  80. END;
  81. IF lo < j THEN QuickSort( lo, j) END;
  82. IF i < hi THEN QuickSort(i, hi) END
  83. END QuickSort;
  84. PROCEDURE Sort;
  85. BEGIN
  86. QuickSort(0, exports-1)
  87. END Sort;
  88. END ExportInfo;
  89. Arrangement* = OBJECT (GenericLinker.Arrangement);
  90. VAR
  91. displacement: GenericLinker.Address;
  92. bits: BitSets.BitSet;
  93. maxUnitSize: ObjectFile.Bits;
  94. exportInfo: ExportInfo;
  95. relocInfo: RelocationInfo;
  96. PROCEDURE & InitArrangement* (displacement: GenericLinker.Address);
  97. BEGIN
  98. SELF.displacement := displacement; maxUnitSize := 1; NEW (bits, 0); exportInfo := NIL; NEW(relocInfo);
  99. END InitArrangement;
  100. PROCEDURE Allocate* (CONST section: ObjectFile.Section): GenericLinker.Address;
  101. VAR address, alignment: ObjectFile.Bits; i: LONGINT; name: ObjectFile.SegmentedName;
  102. BEGIN
  103. IF section.unit > maxUnitSize THEN maxUnitSize := section.unit END;
  104. IF section.fixed THEN
  105. address := (section.alignment - displacement) * section.unit;
  106. ELSE
  107. address := bits.GetSize (); alignment := section.alignment * section.unit;
  108. IF alignment = 0 THEN alignment := section.unit; END;
  109. INC (address, (alignment - address MOD alignment) MOD alignment);
  110. END;
  111. IF bits.GetSize () < section.bits.GetSize () + address THEN
  112. bits.Resize (address + section.bits.GetSize ());
  113. END;
  114. (*dest pos is for some reason negative*)
  115. ASSERT(address>=0);
  116. BitSets.CopyBits (section.bits, 0, bits, address, section.bits.GetSize ());
  117. IF exportInfo # NIL THEN
  118. FOR i := 0 TO exportInfo.exports-1 DO
  119. ObjectFile.StringToSegmentedName(exportInfo.symbolNames[i], name);
  120. IF name= section.identifier.name THEN
  121. exportInfo.exportAddresses[i] := address DIV section.unit + displacement;
  122. END;
  123. END
  124. END;
  125. RETURN address DIV section.unit + displacement;
  126. END Allocate;
  127. PROCEDURE SizeInBits*(): LONGINT;
  128. BEGIN RETURN bits.GetSize()
  129. END SizeInBits;
  130. PROCEDURE Patch* (pos, value: GenericLinker.Address; offset, bits, unit: ObjectFile.Bits);
  131. BEGIN SELF.bits.SetBits ((pos - displacement) * unit + offset, bits, value);
  132. END Patch;
  133. PROCEDURE CheckReloc(target: LONGINT; pattern: ObjectFile.Pattern; CONST patch: ObjectFile.Patch);
  134. VAR i: LONGINT;
  135. BEGIN
  136. IF (pattern.mode = ObjectFile.Absolute) & (relocInfo # NIL) THEN
  137. relocInfo.AddReloc(target+patch.offset);
  138. END;
  139. END CheckReloc;
  140. END Arrangement;
  141. TYPE FileFormat = PROCEDURE (linker: GenericLinker.Linker; arrangement: Arrangement; writer: Files.Writer);
  142. PROCEDURE Align(this, to: LONGINT): LONGINT;
  143. BEGIN
  144. this := this + (-this) MOD to;
  145. RETURN this;
  146. END Align;
  147. PROCEDURE ReadObjectFile*(CONST moduleName, path, extension: ARRAY OF CHAR; linker: GenericLinker.Linker);
  148. VAR fileName: Files.FileName; file: Files.File; reader: Files.Reader;
  149. BEGIN
  150. linker.Information (moduleName, "processing");
  151. IF path # "" THEN Files.JoinPath (path, moduleName, fileName); ELSE COPY(moduleName,fileName); END;
  152. file := Files.Old (fileName);
  153. IF file = NIL THEN (* try with extension *)
  154. Files.JoinExtension (fileName, extension, fileName);
  155. file := Files.Old (fileName);
  156. END;
  157. IF file = NIL THEN (* try without extension *)
  158. END;
  159. IF file = NIL THEN linker.Error (fileName, "failed to open file"); RETURN; END;
  160. Files.OpenReader (reader, file, 0);
  161. GenericLinker.Process (reader, linker) ;
  162. IF reader.res # Files.Ok THEN linker.Error (fileName, "failed to parse"); END;
  163. END ReadObjectFile;
  164. PROCEDURE WriteOutputFile* (arrangement: Arrangement; CONST fileName: Files.FileName; linker: GenericLinker.Linker; fileFormat: FileFormat);
  165. VAR file: Files.File; writer: Files.Writer; msg: ARRAY 64 OF CHAR; number: ARRAY 32 OF CHAR;
  166. BEGIN
  167. file := Files.New (fileName);
  168. Files.OpenWriter (writer, file, 0);
  169. fileFormat (linker, arrangement, writer);
  170. writer.Update; Files.Register (file);
  171. msg := "written ";
  172. Strings.IntToStr(arrangement.SizeInBits(), number);
  173. Strings.Append(msg, number);
  174. Strings.Append(msg, " bits (= ");
  175. Strings.IntToStr(arrangement.SizeInBits() DIV arrangement.maxUnitSize, number);
  176. Strings.Append(msg, number);
  177. Strings.Append(msg, " units).");
  178. linker.Information (fileName, msg);
  179. END WriteOutputFile;
  180. PROCEDURE WriteBinaryFile (linker: GenericLinker.Linker; arrangement: Arrangement; writer: Files.Writer);
  181. VAR i: LONGINT;
  182. BEGIN
  183. FOR i := 0 TO arrangement.bits.GetSize () - 1 BY 8 DO
  184. writer.Char (CHR (arrangement.bits.GetBits (i, 8)));
  185. END;
  186. END WriteBinaryFile;
  187. PROCEDURE WriteTRMFile (arrangement: Arrangement; writer: Files.Writer; bitsPerLine, lines:LONGINT);
  188. VAR i,j,size,end,nonZeroInLeadingNibble,leadingzeros: LONGINT;
  189. PROCEDURE GetBits(pos: LONGINT): LONGINT;
  190. BEGIN
  191. IF pos >= size THEN RETURN 0
  192. ELSIF pos+4 > size THEN RETURN arrangement.bits.GetBits(pos,size-pos)
  193. ELSE RETURN arrangement.bits.GetBits(pos,4)
  194. END;
  195. END GetBits;
  196. PROCEDURE GetFirstNibble(pos: LONGINT): LONGINT;
  197. BEGIN
  198. RETURN arrangement.bits.GetBits(pos,nonZeroInLeadingNibble);
  199. END GetFirstNibble;
  200. BEGIN
  201. (*allow line size not divisible by 4 by padding the line to a multiple of 4 bits with leading zeros*)
  202. size := arrangement.bits.GetSize();
  203. end := (size-1) DIV bitsPerLine + 1;
  204. (*
  205. D.String("bits per line: ");D.Int(bitsPerLine,0);
  206. D.String(" number of bits: ");D.Int(size,0);
  207. D.String(" number of words: ");D.Int(end,0);D.Ln;
  208. *)
  209. nonZeroInLeadingNibble:=bitsPerLine MOD 4;
  210. FOR i := 0 TO end-1 DO
  211. (*be aware we are writing msb first here*)
  212. (*padded first nibble*)
  213. IF nonZeroInLeadingNibble > 0 THEN
  214. writer.Char(ObjectFile.NibbleToCharacter(GetFirstNibble(i*bitsPerLine+bitsPerLine-nonZeroInLeadingNibble) ) ) ;
  215. END;
  216. (*rest of the instruction word*)
  217. FOR j := bitsPerLine DIV 4 -1 TO 0 BY -1 DO
  218. writer.Char(ObjectFile.NibbleToCharacter(GetBits(i*bitsPerLine+j*4)));
  219. END;
  220. writer.Ln;
  221. END;
  222. IF end > 0 THEN (* allow at least one block, if size = 0 *)
  223. lines := (((end-1) DIV lines)+1)*lines; (* round up to next multiple of lines *)
  224. END;
  225. FOR i := end TO lines -1 DO
  226. FOR j:=1 TO (bitsPerLine-1) DIV 4 + 1 BY 1 DO
  227. writer.Char('F');
  228. END;
  229. writer.Ln;
  230. END;
  231. END WriteTRMFile;
  232. PROCEDURE WriteTRMCodeFile* (linker: GenericLinker.Linker; arrangement: Arrangement; writer: Files.Writer);
  233. BEGIN
  234. WriteTRMFile (arrangement, writer, arrangement.maxUnitSize,1024);
  235. END WriteTRMCodeFile;
  236. PROCEDURE WriteTRMDataFile* (linker: GenericLinker.Linker; arrangement: Arrangement; writer: Files.Writer);
  237. BEGIN WriteTRMFile (arrangement, writer, 32,512);
  238. END WriteTRMDataFile;
  239. PROCEDURE WritePEFile (linker: GenericLinker.Linker; arrangement: Arrangement; writer: Files.Writer; bitmode, subSystem: INTEGER; isDLL: BOOLEAN);
  240. CONST DOSText = "This program cannot be run in DOS mode.$";
  241. CONST DOSHeaderSize = 64; DOSCodeSize = 14; DOSTextSize = 40; DOSStubSize = ((DOSHeaderSize + DOSCodeSize + DOSTextSize + 15) DIV 16) * 16;
  242. CONST FileAlignment = 200H; SectionAlignment = 1000H; HeaderSize = 24; SectionHeaderSize = 40; DirectoryEntries = 16;
  243. VAR OptionalHeaderSize, CodeSize, AlignedCodeSize, HeadersSize, BaseCodeAddress, BaseAddress: LONGINT; exportInfo: ExportInfo; relocInfo: RelocationInfo;
  244. pos: LONGINT;
  245. PROCEDURE Reserve (size: LONGINT);
  246. BEGIN INC(pos, size); WHILE size # 0 DO writer.Char (0X); DEC (size); END;
  247. END Reserve;
  248. PROCEDURE WriteBYTE (value: LONGINT);
  249. BEGIN writer.Char (CHR (value)); INC(pos);
  250. END WriteBYTE;
  251. PROCEDURE WriteWORD (value: LONGINT);
  252. BEGIN WriteBYTE (value MOD 100H); WriteBYTE (value DIV 100H);
  253. END WriteWORD;
  254. PROCEDURE WriteDWORD (value: LONGINT);
  255. BEGIN WriteWORD (value MOD 10000H); WriteWORD (value DIV 10000H);
  256. END WriteDWORD;
  257. PROCEDURE WritePTR (value: LONGINT);
  258. BEGIN WriteDWORD (value); IF bitmode = 64 THEN WriteDWORD (0) END;
  259. END WritePTR;
  260. PROCEDURE WriteString(s: ARRAY OF CHAR);
  261. BEGIN
  262. writer.String(s); INC(pos, Strings.Length(s));
  263. END WriteString;
  264. PROCEDURE WriteString0(s: ARRAY OF CHAR);
  265. BEGIN
  266. WriteString(s); WriteBYTE(0);
  267. END WriteString0;
  268. PROCEDURE AlignTo(alignment: LONGINT);
  269. BEGIN alignment := Align(pos, alignment); Reserve(alignment - pos);
  270. END AlignTo;
  271. PROCEDURE ReserveTo(p: LONGINT);
  272. BEGIN ASSERT(p >= pos); Reserve(p-pos);
  273. END ReserveTo;
  274. PROCEDURE HasExports(): BOOLEAN;
  275. BEGIN
  276. RETURN (exportInfo # NIL) & (exportInfo.exports # 0)
  277. END HasExports;
  278. PROCEDURE ExportTableSize(): LONGINT;
  279. VAR i,offset: LONGINT;
  280. BEGIN
  281. IF ~HasExports() THEN RETURN 0 END;
  282. offset := 40 + Strings.Length(exportInfo.name)+1;
  283. FOR i := 0 TO exportInfo.exports-1 DO
  284. INC(offset, Strings.Length(exportInfo.exportNames[i])+1);
  285. INC(offset, 10);
  286. END;
  287. RETURN offset
  288. END ExportTableSize;
  289. PROCEDURE AlignedExportTableSize(): LONGINT;
  290. BEGIN
  291. RETURN Align(ExportTableSize(), SectionAlignment);
  292. END AlignedExportTableSize;
  293. PROCEDURE HasRelocs(): BOOLEAN;
  294. BEGIN
  295. RETURN (relocInfo # NIL) & (relocInfo.patchBlock # NIL)
  296. END HasRelocs;
  297. PROCEDURE RelocTableSize(): LONGINT;
  298. VAR p: PatchBlock; size: LONGINT;
  299. BEGIN
  300. IF ~HasRelocs() THEN RETURN 0 END;
  301. size := 0;
  302. p := relocInfo.patchBlock;
  303. WHILE p # NIL DO
  304. INC(size, 8 + p.addresses * 2);
  305. IF ODD(p.addresses) THEN INC(size, 2) END;
  306. p := p.next
  307. END;
  308. RETURN size
  309. END RelocTableSize;
  310. PROCEDURE AlignedRelocTableSize(): LONGINT;
  311. BEGIN RETURN Align(RelocTableSize(), SectionAlignment);
  312. END AlignedRelocTableSize;
  313. PROCEDURE SectionHeaderOffset(): LONGINT;
  314. BEGIN RETURN DOSStubSize + HeaderSize + OptionalHeaderSize
  315. END SectionHeaderOffset;
  316. PROCEDURE WriteDOSStub;
  317. BEGIN
  318. WriteWORD (5A4DH); (* e_magic *)
  319. WriteWORD (DOSStubSize); (* e_cblp *)
  320. WriteWORD (1); (* e_cp *)
  321. WriteWORD (0); (* e_crlc *)
  322. WriteWORD (DOSHeaderSize DIV 16); (* e_cparhdr *)
  323. WriteWORD (0); (* e_minalloc *)
  324. WriteWORD (0); (* e_maxalloc *)
  325. WriteWORD (0); (* e_ss *)
  326. WriteWORD (0); (* e_sp *)
  327. WriteWORD (0); (* e_csum *)
  328. WriteWORD (0); (* e_ip *)
  329. WriteWORD (0); (* e_cs *)
  330. WriteWORD (DOSHeaderSize); (* e_lfarlc *)
  331. WriteWORD (0); (* e_ovno *)
  332. Reserve (32); (* e_res *)
  333. WriteDWORD (DOSStubSize); (* e_lfanew *)
  334. WriteBYTE (00EH); WriteBYTE (01FH); WriteBYTE (0BAH); WriteWORD (DOSCodeSize);
  335. WriteBYTE (0B4H); WriteBYTE (009H); WriteBYTE (0CDH); WriteBYTE (021H); WriteBYTE (0B8H);
  336. WriteBYTE (001H); WriteBYTE (04CH); WriteBYTE (0CDH); WriteBYTE (021H); WriteString (DOSText);
  337. Reserve (DOSStubSize - DOSHeaderSize - DOSCodeSize - DOSTextSize);
  338. END WriteDOSStub;
  339. PROCEDURE WriteHeader;
  340. VAR characteristics, sections: LONGINT;
  341. BEGIN
  342. WriteDWORD (000004550H); (* Signature *)
  343. IF bitmode = 64 THEN
  344. WriteWORD (08664H); (* Machine *)
  345. ELSE
  346. WriteWORD (0014CH); (* Machine *)
  347. END;
  348. sections := 1;
  349. IF HasRelocs() THEN INC(sections) END;
  350. IF HasExports()THEN INC(sections) END;
  351. WriteWORD (sections); (* NumberOfSections *)
  352. WriteDWORD (0); (* TimeDateStamp *)
  353. WriteDWORD (0); (* PointerToSymbolTable *)
  354. WriteDWORD (0); (* NumberOfSymbols *)
  355. WriteWORD (OptionalHeaderSize); (* SizeOfOptionalHeader *)
  356. characteristics := 222H;
  357. IF ~HasRelocs() THEN characteristics := characteristics + 1 END;
  358. IF isDLL THEN characteristics := characteristics + 2000H END;
  359. IF bitmode#64 THEN characteristics := characteristics + 100H END;
  360. WriteWORD(characteristics);
  361. END WriteHeader;
  362. PROCEDURE WriteOptionalHeader;
  363. VAR ImageSize: LONGINT;
  364. BEGIN
  365. ImageSize := Align(BaseCodeAddress+AlignedCodeSize+AlignedExportTableSize()+AlignedRelocTableSize(), SectionAlignment);
  366. (* 0 *) IF bitmode = 64 THEN
  367. WriteWORD (0020BH); (* Magic *)
  368. ELSE
  369. WriteWORD (0010BH); (* Magic *)
  370. END;
  371. (* 2 *) WriteBYTE (0); (* MajorLinkerVersion *)
  372. (* 3 *) WriteBYTE (0); (* MinorLinkerVersion *)
  373. (* 4 *) WriteDWORD (CodeSize); (* SizeOfCode *)
  374. (* 8 *) WriteDWORD (0); (* SizeOfInitializedData *)
  375. (* 12 *) WriteDWORD (0); (* SizeOfUninitializedData *)
  376. (* 16 *) WriteDWORD (BaseCodeAddress); (* AddressOfEntryPoint *)
  377. (* 20 *) WriteDWORD (BaseCodeAddress); (* BaseOfCode *)
  378. (* 24 *) IF bitmode # 64 THEN
  379. WriteDWORD (ImageSize); (* BaseOfData *)
  380. END;
  381. (* 28 / 24 *) WritePTR (arrangement.displacement - BaseCodeAddress); (* ImageBase *)
  382. (* 32 *) WriteDWORD (SectionAlignment); (* SectionAlignment *)
  383. (* 36 *)WriteDWORD (FileAlignment); (* FileAlignment *)
  384. (* 40 *)WriteWORD (4); (* MajorOperatingSystemVersion *)
  385. (* 42 *)WriteWORD (0); (* MinorOperatingSystemVersion *)
  386. (* 44 *)WriteWORD (0); (* MajorImageVersion *)
  387. (* 46 *)WriteWORD (0); (* MinorImageVersion *)
  388. (* 48 *)WriteWORD (4); (* MajorSubsystemVersion *)
  389. (* 50 *)WriteWORD (0); (* MinorSubsystemVersion *)
  390. (* 52 *)WriteDWORD (0); (* Win32VersionValue *)
  391. (* 56 *)WriteDWORD (ImageSize); (* SizeOfImage *)
  392. (* 60 *)WriteDWORD (HeadersSize); (* SizeOfHeaders *)
  393. (* 64 *)WriteDWORD (0); (* CheckSum *)
  394. (* 68 *)WriteWORD (subSystem); (* Subsystem *)
  395. (* 70 *)IF isDLL THEN WriteWORD (40H); (* DllCharacteristics *)
  396. ELSE WriteWORD(0)
  397. END;
  398. (* 72 *)WritePTR (0100000H); (* SizeOfStackReserve *)
  399. (* 76 / 80 *)WritePTR (01000H); (* SizeOfStackCommit *)
  400. (* 80 / 88 *)WritePTR (0100000H); (* SizeOfHeapReserve *)
  401. (* 84 / 96 *)WritePTR (01000H); (* SizeOfHeapCommit *)
  402. (* 88 / 104 *)WriteDWORD (0); (* LoaderFlags *)
  403. (* 92 / 108 *)WriteDWORD (DirectoryEntries); (* NumberOfRvaAndSizes *)
  404. IF HasExports() THEN
  405. (* 96 / 112 *) WriteDWORD(BaseCodeAddress + AlignedCodeSize); WriteDWORD(ExportTableSize()); (* location and size of export table *)
  406. ELSE Reserve(8)
  407. END;
  408. (* 104 / 120 *) WriteDWORD (BaseCodeAddress +8) ; WriteDWORD (40); (* location and size of of idata section *)
  409. Reserve (3 * 8);
  410. IF HasRelocs() THEN
  411. WriteDWORD (BaseCodeAddress + AlignedCodeSize+AlignedExportTableSize()) ; WriteDWORD (RelocTableSize()); (* location and size of of reloc section *)
  412. ELSE Reserve(8)
  413. END;
  414. Reserve ((DirectoryEntries - 6) * 8);
  415. END WriteOptionalHeader;
  416. PROCEDURE WriteSections;
  417. VAR ExportNameTableAddress, i, offset: LONGINT; p: PatchBlock;
  418. BEGIN
  419. (* code section header *)
  420. (* 0 *) WriteString (".text"); Reserve (3); (* Name *)
  421. (* 8 *) WriteDWORD (CodeSize); (* VirtualSize *)
  422. (* 12 *) WriteDWORD (BaseCodeAddress); (* VirtualAddress *)
  423. (* 16 *) WriteDWORD (AlignedCodeSize); (* SizeOfRawData *)
  424. (* 20 *) WriteDWORD (BaseCodeAddress); (* PointerToRawData *)
  425. (* 24 *) WriteDWORD (0); (* PointerToRelocations *)
  426. (* 28 *) WriteDWORD (0); (* PointerToLinenumbers *)
  427. (* 32 *) WriteWORD (0); (* NumberOfRelocations *)
  428. (* 34 *) WriteWORD (0); (* NumberOfLinenumbers *)
  429. (* 36 *) WriteDWORD (LONGINT (0E0000020H)); (* Characteristics *)
  430. IF HasExports() THEN
  431. (* export table header *)
  432. (* 0 *) WriteString(".edata"); Reserve(2); (* name *)
  433. (* 8 *) WriteDWORD(ExportTableSize()); (* virtual size *)
  434. (* 12 *) WriteDWORD(BaseCodeAddress + AlignedCodeSize (* address *));
  435. (* 16 *) WriteDWORD(AlignedExportTableSize()); (* raw data size *)
  436. (* 20 *) WriteDWORD(BaseCodeAddress + AlignedCodeSize); (* raw data pointer *)
  437. (* 24 *) WriteDWORD (0); (* PointerToRelocations *)
  438. (* 28 *) WriteDWORD (0); (* PointerToLinenumbers *)
  439. (* 32 *) WriteWORD (0); (* NumberOfRelocations *)
  440. (* 34 *) WriteWORD (0); (* NumberOfLinenumbers *)
  441. (* 36 *) WriteDWORD (LONGINT (040000000H)); (* Characteristics *)
  442. END;
  443. IF HasRelocs() THEN
  444. (* reloc table header *)
  445. (* 0 *) WriteString(".reloc"); Reserve(2); (* name *)
  446. (* 8 *) WriteDWORD(RelocTableSize()); (* virtual size *)
  447. (* 12 *) WriteDWORD(BaseCodeAddress + AlignedCodeSize + AlignedExportTableSize() (* address *));
  448. (* 16 *) WriteDWORD(AlignedRelocTableSize()); (* raw data size *)
  449. (* 20 *) WriteDWORD(BaseCodeAddress + AlignedCodeSize+ AlignedExportTableSize()); (* raw data pointer *)
  450. (* 24 *) WriteDWORD (0); (* PointerToRelocations *)
  451. (* 28 *) WriteDWORD (0); (* PointerToLinenumbers *)
  452. (* 32 *) WriteWORD (0); (* NumberOfRelocations *)
  453. (* 34 *) WriteWORD (0); (* NumberOfLinenumbers *)
  454. (* 36 *) WriteDWORD (LONGINT (040000000H)); (* Characteristics *)
  455. END;
  456. (* 40 / 80 / 120 *) ReserveTo(BaseCodeAddress);
  457. (**** code section *****)
  458. (* BaseCodeAddress *)
  459. WriteBinaryFile (linker, arrangement, writer); INC(pos, arrangement.bits.GetSize () DIV 8);
  460. (* BaseCodeAddress +CodeSize *)
  461. Reserve (AlignedCodeSize-CodeSize);
  462. (* BaseCodeAddress + AlignedCodeSize *)
  463. IF HasExports() THEN
  464. (***** export section *****)
  465. (* BaseCodeAddress + AlignedCodeSize *)
  466. (* 0 *) WriteDWORD(0); (* reserved *)
  467. (* 4 *) WriteDWORD(0); (* time / date *)
  468. (* 6 *) WriteWORD(0); (* major version *)
  469. (* 8 *) WriteWORD(0); (* minor version *)
  470. (* 12 *) WriteDWORD(BaseCodeAddress+AlignedCodeSize + 40 + 10* exportInfo.exports); (* RVA of DLL name *)
  471. (* 16 *) WriteDWORD(1); (* start ordinal number *)
  472. (* 20 *) WriteDWORD(exportInfo.exports); (* number of entries in export table *)
  473. (* 24 *) WriteDWORD(exportInfo.exports); (* number of entries in name pointer table *)
  474. (* 28 *) WriteDWORD(BaseCodeAddress+AlignedCodeSize + 40 ); (* export address table RVA *)
  475. (* 32 *) WriteDWORD(BaseCodeAddress+AlignedCodeSize + 40 + 4* exportInfo.exports); (* name pointer RVA *)
  476. (* 36 *) WriteDWORD(BaseCodeAddress+AlignedCodeSize + 40 + 8* exportInfo.exports); (* ordinal table RVA *)
  477. (* 40 *)
  478. (* export address table *)
  479. FOR i := 0 TO exportInfo.exports-1 DO
  480. ASSERT(exportInfo.exportAddresses[i] # 0);
  481. WriteDWORD(exportInfo.exportAddresses[i]-BaseAddress+BaseCodeAddress); (* RVA ! *)
  482. END;
  483. (* export name pointer table *)
  484. (* 40 + 4 * Number exports *)
  485. ExportNameTableAddress := BaseCodeAddress + AlignedCodeSize + 40 + 10* exportInfo.exports ;
  486. offset := Strings.Length(exportInfo.name)+1;
  487. FOR i := 0 TO exportInfo.exports-1 DO
  488. WriteDWORD(ExportNameTableAddress + offset);
  489. INC(offset, Strings.Length(exportInfo.exportNames[i])+1);
  490. END;
  491. (* export ordinal table *)
  492. (* 40 + 8* NumberExports *)
  493. FOR i := 0 TO exportInfo.exports-1 DO
  494. WriteWORD(i);
  495. END;
  496. (* 40 + 10* NumberExports *)
  497. (* export name table *)
  498. WriteString0(exportInfo.name);
  499. FOR i := 0 TO exportInfo.exports-1 DO
  500. WriteString0(exportInfo.exportNames[i]); (* 0x terminated *)
  501. END;
  502. Reserve(AlignedExportTableSize() - ExportTableSize());
  503. END;
  504. IF HasRelocs() THEN
  505. p := relocInfo.patchBlock;
  506. WHILE p # NIL DO
  507. WriteDWORD(p.baseAdr -BaseAddress+BaseCodeAddress) (* RVA of block *);
  508. WriteDWORD(8+p.addresses*2+2*(p.addresses MOD 2)); (* number bytes of this block *)
  509. FOR i := 0 TO p.addresses-1 DO
  510. WriteWORD(p.address[i] - p.baseAdr+ 3000H);(* block-relative addresses, highlow *)
  511. END;
  512. AlignTo(4);
  513. p := p.next;
  514. END;
  515. Reserve(AlignedRelocTableSize() - RelocTableSize());
  516. END;
  517. END WriteSections;
  518. BEGIN
  519. pos := 0;
  520. exportInfo := arrangement.exportInfo;
  521. relocInfo := arrangement.relocInfo;
  522. IF HasExports() THEN exportInfo.Sort END;
  523. BaseAddress := arrangement.displacement; (* ASSERT (arrangement.displacement = BaseAddress); *)
  524. OptionalHeaderSize := 96 + DirectoryEntries * 8;
  525. IF bitmode = 64 THEN INC (OptionalHeaderSize, 16); END;
  526. CodeSize := arrangement.bits.GetSize () DIV 8;
  527. AlignedCodeSize := Align(CodeSize, SectionAlignment);
  528. HeadersSize := Align(DOSStubSize + HeaderSize + OptionalHeaderSize + SectionHeaderSize, FileAlignment);
  529. BaseCodeAddress := Align(HeadersSize, SectionAlignment);
  530. WriteDOSStub; WriteHeader; WriteOptionalHeader; WriteSections;
  531. END WritePEFile;
  532. PROCEDURE WriteDLL32File (linker: GenericLinker.Linker; arrangement: Arrangement; writer: Files.Writer);
  533. BEGIN WritePEFile (linker, arrangement, writer, 32, 2, TRUE);
  534. END WriteDLL32File;
  535. PROCEDURE WriteDLL64File (linker: GenericLinker.Linker; arrangement: Arrangement; writer: Files.Writer);
  536. BEGIN WritePEFile (linker, arrangement, writer, 64, 2, TRUE);
  537. END WriteDLL64File;
  538. PROCEDURE WritePE32File (linker: GenericLinker.Linker; arrangement: Arrangement; writer: Files.Writer);
  539. BEGIN WritePEFile (linker, arrangement, writer, 32, 2, FALSE);
  540. END WritePE32File;
  541. PROCEDURE WritePE64File (linker: GenericLinker.Linker; arrangement: Arrangement; writer: Files.Writer);
  542. BEGIN WritePEFile (linker, arrangement, writer, 64, 2, FALSE);
  543. END WritePE64File;
  544. PROCEDURE WritePE32CUIFile (linker: GenericLinker.Linker; arrangement: Arrangement; writer: Files.Writer);
  545. BEGIN WritePEFile (linker, arrangement, writer, 32, 3, FALSE);
  546. END WritePE32CUIFile;
  547. PROCEDURE WritePE64CUIFile (linker: GenericLinker.Linker; arrangement: Arrangement; writer: Files.Writer);
  548. BEGIN WritePEFile (linker, arrangement, writer, 64, 3, FALSE);
  549. END WritePE64CUIFile;
  550. PROCEDURE WriteEFI32File (linker: GenericLinker.Linker; arrangement: Arrangement; writer: Files.Writer);
  551. BEGIN WritePEFile (linker, arrangement, writer, 32, 10, FALSE);
  552. END WriteEFI32File;
  553. PROCEDURE WriteEFI64File (linker: GenericLinker.Linker; arrangement: Arrangement; writer: Files.Writer);
  554. BEGIN WritePEFile (linker, arrangement, writer, 64, 10, FALSE);
  555. END WriteEFI64File;
  556. PROCEDURE WriteELFFile (linker: GenericLinker.Linker; arrangement: Arrangement; writer: Files.Writer);
  557. CONST ELFHeaderSize = 52; ProgramHeaderSize = 32; HeadersSize = ELFHeaderSize + ProgramHeaderSize;
  558. CONST BaseAddress = 08048000H; EntryAddress = BaseAddress + HeadersSize;
  559. PROCEDURE Reserve (size: LONGINT);
  560. BEGIN WHILE size # 0 DO writer.Char (0X); DEC (size); END;
  561. END Reserve;
  562. PROCEDURE WriteByte (value: LONGINT);
  563. BEGIN writer.Char (CHR (value));
  564. END WriteByte;
  565. PROCEDURE WriteHalf (value: LONGINT);
  566. BEGIN WriteByte (value MOD 100H); WriteByte (value DIV 100H);
  567. END WriteHalf;
  568. PROCEDURE WriteWord (value: LONGINT);
  569. BEGIN WriteHalf (value MOD 10000H); WriteHalf (value DIV 10000H);
  570. END WriteWord;
  571. PROCEDURE WriteELFHeader;
  572. BEGIN
  573. WriteByte (7FH); (* e_ident[EI_MAG0] *)
  574. WriteByte (ORD('E')); (* e_ident[EI_MAG1] *)
  575. WriteByte (ORD('L')); (* e_ident[EI_MAG2] *)
  576. WriteByte (ORD('F')); (* e_ident[EI_MAG3] *)
  577. WriteByte (1); (* e_ident[EI_CLASS] *)
  578. WriteByte (1); (* e_ident[EI_DATA] *)
  579. WriteByte (1); (* e_ident[EI_VERSION] *)
  580. WriteByte (0); (* e_ident[EI_PAD] *)
  581. Reserve (8); (* e_ident[EI_NIDENT] *)
  582. WriteHalf (2); (* e_type *)
  583. WriteHalf (3); (* e_machine *)
  584. WriteWord (1); (* e_version *)
  585. WriteWord (EntryAddress); (* e_entry *)
  586. WriteWord (ELFHeaderSize); (* e_phoff *)
  587. WriteWord (0); (* e_phoff *)
  588. WriteWord (0); (* e_flags *)
  589. WriteHalf (ELFHeaderSize); (* e_ehsize *)
  590. WriteHalf (ProgramHeaderSize); (* e_phentsize *)
  591. WriteHalf (1); (* e_phnum *)
  592. WriteHalf (0); (* e_shentsize *)
  593. WriteHalf (0); (* e_shnum *)
  594. WriteHalf (0); (* e_shstrndx *)
  595. END WriteELFHeader;
  596. PROCEDURE WriteProgramHeader;
  597. VAR FileSize: LONGINT;
  598. BEGIN
  599. FileSize := HeadersSize + arrangement.bits.GetSize () DIV 8;
  600. WriteWord (1); (* p_type *)
  601. WriteWord (0); (* p_offset *)
  602. WriteWord (BaseAddress); (* p_vaddr *)
  603. WriteWord (0); (* p_paddr *)
  604. WriteWord (FileSize); (* p_filesz *)
  605. WriteWord (FileSize); (* p_memsz *)
  606. WriteWord (7); (* p_flags *)
  607. WriteWord (1000H); (* p_align *)
  608. END WriteProgramHeader;
  609. BEGIN
  610. ASSERT (arrangement.displacement = BaseAddress);
  611. WriteELFHeader;
  612. WriteProgramHeader;
  613. WriteBinaryFile (linker, arrangement, writer);
  614. END WriteELFFile;
  615. PROCEDURE WriteMachOFile (linker: GenericLinker.Linker; arrangement: Arrangement; writer: Files.Writer);
  616. CONST SegmentName = "__TEXT"; SectionName = "__text";
  617. CONST MachHeaderSize = 28; LoadCommandSize = 124; ThreadCommandSize = 80;
  618. CONST CommandsSize = LoadCommandSize + ThreadCommandSize; Start = MachHeaderSize + CommandsSize;
  619. CONST BaseAddress = 000010E8H;
  620. PROCEDURE Write (value: LONGINT);
  621. BEGIN writer.Char (CHR (value)); writer.Char (CHR (value DIV 100H)); writer.Char (CHR (value DIV 10000H)); writer.Char (CHR (value DIV 1000000H));
  622. END Write;
  623. PROCEDURE WriteName (CONST name: ARRAY OF CHAR);
  624. VAR i: INTEGER;
  625. BEGIN i := 0; WHILE name[i] # 0X DO writer.Char (name[i]); INC (i); END;
  626. WHILE i # 16 DO writer.Char (0X); INC (i); END;
  627. END WriteName;
  628. PROCEDURE WriteMachHeader;
  629. BEGIN
  630. Write (LONGINT (0FEEDFACEH)); (* magic *)
  631. Write (7); (* cputype *)
  632. Write (3); (* cpusubtype *)
  633. Write (2); (* filetype *)
  634. Write (2); (* ncmds *)
  635. Write (CommandsSize); (* sizeofcmds *)
  636. Write (0); (* flags *)
  637. END WriteMachHeader;
  638. PROCEDURE WriteLoadCommand;
  639. VAR FileSize: LONGINT;
  640. BEGIN
  641. FileSize := MachHeaderSize + CommandsSize + arrangement.bits.GetSize () DIV 8;
  642. Write (1); (* cmd *)
  643. Write (LoadCommandSize); (* cmdsize *)
  644. WriteName (SegmentName); (* segname *)
  645. Write (BaseAddress - Start); (* vmaddr *)
  646. Write (FileSize); (* vmsize *)
  647. Write (0); (* fileoff *)
  648. Write (FileSize); (* filesize *)
  649. Write (7); (* maxprot *)
  650. Write (7); (* initprot *)
  651. Write (1); (* nsects *)
  652. Write (0); (* flags *)
  653. WriteName (SectionName); (* sectname *)
  654. WriteName (SegmentName); (* segname *)
  655. Write (BaseAddress); (* addr *)
  656. Write (arrangement.bits.GetSize () DIV 8); (* size *)
  657. Write (Start); (* offset *)
  658. Write (2); (* align *)
  659. Write (0); (* reloff *)
  660. Write (0); (* nreloc *)
  661. Write (0); (* flags *)
  662. Write (0); (* reserved1 *)
  663. Write (0); (* reserved2 *)
  664. END WriteLoadCommand;
  665. PROCEDURE WriteThreadCommand;
  666. BEGIN
  667. Write (5); (* cmd *)
  668. Write (ThreadCommandSize); (* cmdsize *)
  669. Write (1); (* flavor *)
  670. Write (16); (* count *)
  671. Write (0); (* eax *)
  672. Write (0); (* ebx *)
  673. Write (0); (* ecx *)
  674. Write (0); (* edx *)
  675. Write (0); (* edi *)
  676. Write (0); (* esi *)
  677. Write (0); (* ebp *)
  678. Write (0); (* esp *)
  679. Write (0); (* ss *)
  680. Write (0); (* eflags *)
  681. Write (BaseAddress); (* eip *)
  682. Write (0); (* cs *)
  683. Write (0); (* ds *)
  684. Write (0); (* es *)
  685. Write (0); (* fs *)
  686. Write (0); (* gs *)
  687. END WriteThreadCommand;
  688. BEGIN
  689. ASSERT (arrangement.displacement = BaseAddress);
  690. WriteMachHeader;
  691. WriteLoadCommand;
  692. WriteThreadCommand;
  693. WriteBinaryFile (linker, arrangement, writer);
  694. END WriteMachOFile;
  695. PROCEDURE GetFileFormat (options: Options.Options; CONST name: Options.Name; default: FileFormat): FileFormat;
  696. VAR format: ARRAY 10 OF CHAR;
  697. BEGIN
  698. IF ~options.GetString (name, format) THEN RETURN default;
  699. ELSIF format = "TRMCode" THEN RETURN WriteTRMCodeFile;
  700. ELSIF format = "TRMData" THEN RETURN WriteTRMDataFile;
  701. ELSIF format = "PE32" THEN RETURN WritePE32File;
  702. ELSIF format = "PE64" THEN RETURN WritePE64File;
  703. ELSIF format = "PE32CUI" THEN RETURN WritePE32CUIFile;
  704. ELSIF format = "PE64CUI" THEN RETURN WritePE64CUIFile;
  705. ELSIF format = "EFI32" THEN RETURN WriteEFI32File;
  706. ELSIF format = "EFI64" THEN RETURN WriteEFI64File;
  707. ELSIF format = "ELF" THEN RETURN WriteELFFile;
  708. ELSIF format = "MACHO" THEN RETURN WriteMachOFile;
  709. ELSIF format = "DLL32" THEN RETURN WriteDLL32File;
  710. ELSIF format = "DLL64" THEN RETURN WriteDLL64File;
  711. ELSE RETURN default; END;
  712. END GetFileFormat;
  713. PROCEDURE ParseExports(CONST names: ARRAY OF CHAR): ExportInfo;
  714. VAR number: LONGINT; info: ExportInfo; pos: LONGINT; name: ExportName;
  715. PROCEDURE SkipWhitespace;
  716. BEGIN WHILE (names[pos] # 0X) & (names[pos] <= " ") DO INC(pos) END;
  717. END SkipWhitespace;
  718. PROCEDURE ReadName(VAR name: ARRAY OF CHAR): BOOLEAN;
  719. VAR i: LONGINT;
  720. BEGIN
  721. i := 0;
  722. WHILE (names[pos] # 0X) & (names[pos] > " ") & (names[pos] # ",") & (names[pos] # "=") DO name[i] := names[pos]; INC(i); INC(pos) END;
  723. name[i] := 0X;
  724. RETURN i > 0;
  725. END ReadName;
  726. PROCEDURE ParseEntry(VAR symbolName, exportName: ARRAY OF CHAR): BOOLEAN;
  727. BEGIN
  728. SkipWhitespace;
  729. IF ReadName(symbolName) THEN
  730. SkipWhitespace;
  731. IF names[pos] = "=" THEN
  732. INC(pos); SkipWhitespace;
  733. IF ~ReadName(exportName) THEN RETURN FALSE END;
  734. SkipWhitespace;
  735. ELSE COPY(symbolName, exportName);
  736. END;
  737. IF names[pos] = "," THEN INC(pos); SkipWhitespace END;
  738. RETURN TRUE
  739. ELSE RETURN FALSE
  740. END;
  741. END ParseEntry;
  742. BEGIN
  743. pos := 0; number := 0;
  744. WHILE ParseEntry(name, name) DO INC(number) END;
  745. IF (names[pos] # 0X) OR (number = 0) THEN RETURN NIL END;
  746. NEW(info);
  747. NEW(info.symbolNames, number);
  748. NEW(info.exportNames, number);
  749. NEW(info.exportAddresses, number);
  750. info.exports := number;
  751. number := 0; pos := 0;
  752. WHILE (names[pos] # 0X) & ParseEntry(info.symbolNames[number], info.exportNames[number]) DO
  753. INC(number)
  754. END;
  755. RETURN info
  756. END ParseExports;
  757. PROCEDURE CheckExports(info: ExportInfo; error: Streams.Writer): BOOLEAN;
  758. VAR success: BOOLEAN; i: LONGINT;
  759. BEGIN
  760. IF info = NIL THEN RETURN TRUE END;
  761. success := TRUE;
  762. FOR i := 0 TO info.exports-1 DO
  763. IF info.exportAddresses[i] = 0 THEN
  764. error.String("Export symbol not found: "); error.String(info.symbolNames[i]); error.String(" (= ");
  765. error.String(info.exportNames[i]); error.String(")"); error.Ln;
  766. success := FALSE;
  767. END;
  768. END;
  769. RETURN success
  770. END CheckExports;
  771. PROCEDURE Link* (context: Commands.Context);
  772. VAR options: Options.Options;
  773. silent, useAll, strict: BOOLEAN;
  774. codeFileFormat, dataFileFormat: FileFormat;
  775. codeDisplacement, dataDisplacement: GenericLinker.Address;
  776. path, extension, codeFileName, dataFileName, moduleName, logFileName, tempName: Files.FileName;
  777. diagnostics: Diagnostics.StreamDiagnostics; code, data: Arrangement; linker: GenericLinker.Linker;
  778. linkRoot: ARRAY 256 OF CHAR; logFile: Files.File; log: Files.Writer;
  779. use: SET;
  780. exportString: ARRAY 1024 OF CHAR;
  781. error: BOOLEAN;
  782. BEGIN
  783. NEW (options);
  784. options.Add (0X, "silent", Options.Flag);
  785. options.Add ('a', "useAll", Options.Flag);
  786. options.Add ('s', "strict", Options.Flag);
  787. options.Add (0X, "path", Options.String); options.Add (0X, "extension", Options.String);
  788. options.Add (0X, "fileName", Options.String); options.Add (0X, "dataFileName", Options.String);
  789. options.Add (0X, "displacement", Options.Integer); options.Add (0X, "dataDisplacement", Options.Integer);
  790. options.Add (0X, "fileFormat", Options.String); options.Add (0X, "dataFileFormat", Options.String);
  791. options.Add (0X, "logFileName", Options.String);
  792. options.Add(0X,"linkRoot", Options.String);
  793. options.Add(0X,"exports", Options.String);
  794. IF ~options.Parse (context.arg, context.error) THEN context.result := Commands.CommandParseError; RETURN; END;
  795. silent := options.GetFlag ("silent");
  796. useAll := options.GetFlag ("useAll");
  797. strict := options.GetFlag ("strict");
  798. IF ~options.GetString ("path", path) THEN path := ""; END;
  799. IF ~options.GetString ("extension", extension) THEN extension := ObjectFile.DefaultExtension; END;
  800. IF ~options.GetString ("fileName", codeFileName) THEN codeFileName := "linker.bin"; END;
  801. IF ~options.GetString ("dataFileName", dataFileName) THEN dataFileName := codeFileName; END;
  802. IF ~options.GetString ("logFileName", logFileName) THEN
  803. COPY(codeFileName, logFileName); Files.SplitExtension(logFileName,logFileName,tempName); Files.JoinExtension(logFileName,"log",logFileName);
  804. END;
  805. IF ~options.GetInteger ("displacement", codeDisplacement) THEN codeDisplacement := 0; END;
  806. IF ~options.GetInteger ("dataDisplacement", codeDisplacement) THEN dataDisplacement := codeDisplacement; END;
  807. codeFileFormat := GetFileFormat (options, "fileFormat", WriteBinaryFile);
  808. dataFileFormat := GetFileFormat (options, "dataFileFormat", codeFileFormat);
  809. NEW (code, codeDisplacement);
  810. IF options.GetString("exports", exportString) THEN
  811. code.exportInfo := ParseExports(exportString);
  812. IF code.exportInfo = NIL THEN
  813. context.error.String("Syntax error in export list or empty export list."); context.error.Ln;
  814. ELSE
  815. COPY(codeFileName, code.exportInfo.name);
  816. END;
  817. END;
  818. IF codeFileName # dataFileName THEN NEW (data, dataDisplacement); ELSE data := code; END;
  819. NEW (diagnostics, context.error);
  820. logFile := Files.New(logFileName);
  821. IF logFile # NIL THEN NEW(log, logFile,0) ELSE log := NIL END;
  822. IF useAll THEN use := GenericLinker.UseAll ELSE use := GenericLinker.UseInitCode END;
  823. NEW (linker, diagnostics, log, use, code, data);
  824. IF options.GetString("linkRoot",linkRoot) THEN linker.SetLinkRoot(linkRoot) END;
  825. WHILE ~linker.error & context.arg.GetString (moduleName) DO
  826. ReadObjectFile (moduleName, path, extension, linker);
  827. IF strict & ~linker.error THEN linker.Resolve END;
  828. END;
  829. (* do linking after having read in all blocks to account for potential constraints *)
  830. IF ~linker.error THEN linker.Link; END;
  831. error := linker.error;
  832. error := error OR ~CheckExports(code.exportInfo, context.error);
  833. IF ~error THEN
  834. IF (code.displacement # 0) & (linker.log # NIL) THEN linker.log.String("code displacement 0"); linker.log.Hex(code.displacement,-8); linker.log.String("H"); linker.log.Ln END;
  835. WriteOutputFile (code, codeFileName, linker, codeFileFormat);
  836. IF data # code THEN
  837. IF (data.displacement # 0) & (linker.log # NIL) THEN linker.log.String("data displacement 0"); linker.log.Hex(data.displacement,-8); linker.log.String("H"); linker.log.Ln END;
  838. WriteOutputFile (data, dataFileName, linker, dataFileFormat);
  839. END;
  840. IF ~silent THEN
  841. context.out.String("Link successful. Written files: ");
  842. context.out.String(codeFileName);
  843. IF data # code THEN context.out.String(", "); context.out.String(dataFileName) END;
  844. IF logFile # NIL THEN context.out.String(", "); context.out.String(logFileName); END;
  845. context.out.Ln
  846. END;
  847. IF log # NIL THEN
  848. log.Update; Files.Register(logFile);
  849. END;
  850. END;
  851. IF error THEN context.result := Commands.CommandError; END;
  852. END Link;
  853. END StaticLinker.
  854. StaticLinker.Link --fileName=test.exe --fileFormat=PE32 --displacement=401000H Test ~
  855. StaticLinker.Link --fileName=a.out --fileFormat=ELF --displacement=08048000H Test ~
  856. StaticLinker.Link --fileName=a.out --fileFormat=MACHO --displacement=000010E8H Test ~