DEADSOFTWARE

* -> old; Trurl-based -> new
[bbcp.git] / new / Dev0 / Mod / ElfLinker16.txt
1 MODULE Dev0ElfLinker;
3 (* THIS IS TEXT COPY OF ElfLinker16.odc *)
4 (* DO NOT EDIT *)
6 (**
7 project = "BlackBox"
8 organization = "www.oberon.ch"
9 contributors = "Oberon microsystems"
10 version = "System/Rsrc/AboutBB"
11 copyright = "System/Rsrc/AboutBB"
12 license = "Docu/BB-License"
13 changes = ""
14 issues = ""
16 **)
18 (*
19 DevElfLinker version compatible with BlackBox Component Builder release 1.6.
20 This module will replace DevElfLinker, once the final version of BlackBox 1.6 will be released.
21 *)
23 (*
24 A. V. Shiryaev, 2012.09
26 Based on DevElfLinker16; modified to not depend on TextModels (TextModels -> Console)
27 *)
29 IMPORT
30 Strings,
31 Kernel, Files, (* Dialog, TextMappers, StdLog, DevCommanders *) Console;
33 CONST
34 NewRecFP = 4E27A847H;
35 NewArrFP = 76068C78H;
37 OFdir = "Code";
38 SYSdir = "System";
40 (* meta interface consts *)
41 mConst = 1; mTyp = 2; mVar = 3; mProc = 4;
42 mInternal = 1; mExported = 4;
44 (* mod desc fields *)
45 modOpts = 4; modRefcnt = 8; modTerm = 40; modNames = 84; modImports = 92; modExports = 96;
47 (* .dynsym entries *)
48 stbLocal = 0; stbGlobal = 1;
49 sttNotype = 0; sttObject = 1; sttFunc = 2; sttSection = 3;
50 shnUnd = 0; shnAbs = 0FFF1H;
52 fixup = 0;
53 noSymbol = MIN(INTEGER);
54 noAddr = MIN(INTEGER);
55 firstDllSymbolVal = 12;
57 (* distinguished section header indexes. *)
58 textIndexVal = 1; (* index of the .text section header in the section header table *)
59 rodataIndexVal = 3; (* index of the .rodata section header in the section header table *)
60 dynsymIndexVal = 5; (* index of the .dynsym section header in the section header table *)
61 dynstrIndexVal = 6; (* index of the .dynstr section header in the section header table *)
63 (* fixed elements dimensions *)
64 elfHeaderSizeVal = 52; (* size of the ELF file header *)
65 shEntrySizeVal = 40; (* size of an entry in the section header table *)
66 dynsymEntrySizeVal = 16; (* size of a symbol table entry *)
67 dynamicEntrySizeVal = 8; (* size of an entry in the dynamic section *)
68 gotEntrySizeVal = 4; (* size of an entry in the got section *)
69 relEntrySizeVal = 8; (* size of an entry in a relocation section *)
70 phEntrySizeVal = 32; (* size of an entry in the program header *)
72 shNumVal = 12; (* number of entries in the section header table. See WriteSectionHeaderTable *)
73 shStrndxVal = shNumVal - 1; (* index of the string table for section names. See WriteSectionHeaderTable *)
74 phNumVal = 3; (* number of entries in the program header table *)
76 (* sections alignments (in bytes) *)
77 textAlign = 4H;
78 dynsymAlign = 4H;
79 dynstrAlign = 1H;
80 hashAlign = 4H;
81 gotAlign = 4H;
82 dynamicAlign = 4H;
83 shstrtabAlign = 1H;
84 bssAlign = 4H;
85 rodataAlign = 8H;
86 relAlign = 4H;
88 pageSize = 1000H; (* I386 page size *)
90 r38632 = 1; r386pc32 = 2; r386Relative = 8; (* ELF relocation types *)
93 (* A. V. Shiryaev: Scanner *)
94 TMChar = 0; TMString = 1; TMEOT = 2;
96 TYPE
97 Name = ARRAY 40 OF SHORTCHAR;
99 Export = POINTER TO RECORD
100 next: Export;
101 name: Name;
102 adr: INTEGER
103 END;
105 Module = POINTER TO RECORD
106 next: Module;
107 name: Name;
108 fileName: Files.Name;
109 file: Files.File;
110 hs, ms, ds, cs, vs, ni, ma, ca, va: INTEGER;
111 dll, intf: BOOLEAN;
112 exp: Export;
113 imp: POINTER TO ARRAY OF Module;
114 data: POINTER TO ARRAY OF BYTE
115 END;
117 Strtab = RECORD
118 tab: ARRAY 4096 OF SHORTCHAR;
119 cur: INTEGER
120 END;
122 Relocation = RECORD
123 offset, type: INTEGER
124 END;
126 RelTab = RECORD
127 tab: ARRAY 65536 OF Relocation;
128 cur: INTEGER
129 END;
131 Section = RECORD
132 fileOffset,
133 memOffset,
134 size: INTEGER
135 END;
137 (* A. V. Shiryaev: Scanner *)
138 ScanRider = RECORD
139 s: POINTER TO ARRAY OF CHAR;
140 i: INTEGER
141 END;
142 Scanner = RECORD
143 rider: ScanRider;
144 start, type: INTEGER;
146 string: ARRAY 100 OF CHAR;
147 char: CHAR
148 END;
150 VAR
151 Out: Files.File;
152 R: Files.Reader;
153 Ro: Files.Writer;
154 error, isDll, isStatic: BOOLEAN;
155 modList, kernel, main, last, impg, impd: Module;
156 numMod, lastTerm: INTEGER;
157 firstExp, lastExp: Export;
158 CodeSize, DataSize, ConSize: INTEGER;
159 maxCode, numExp: INTEGER;
160 newRec, newArr: Name;
161 code: POINTER TO ARRAY OF BYTE;
163 (* fixup positions *)
164 entryPos,
165 expPos,
166 shstrtabPos,
167 finiPos: INTEGER;
169 (* sections *)
170 text, reltext, relrodata, rodata, dynstr, shstrtab, hash, got, dynsym, dynamic, bss: Section;
172 (* distinguished file and memory offsets *)
173 shOffsetVal, (* section header table file offset *)
174 phOffsetVal, (* program header table file offset *)
175 finiMemOffsetVal: INTEGER; (* memory offset (aka virtual address) of the finalization code (CLOSE sections) *)
177 dynsymInfoVal, (* value of the info field for the .dynsym section *)
178 sonameStrIndexVal: INTEGER; (* string table index of the name of hte library *)
180 (* segment dimensions *)
181 textSegmentSizeVal,
182 dataSegmentSizeVal,
183 dynamicSegmentSizeVal: INTEGER;
185 headerstrtab, dynstrtab: Strtab;
186 hashtab: ARRAY 256 OF Name;
188 neededIdx: ARRAY 256 OF INTEGER;
190 relTextTab, relRodataTab: RelTab;
192 soName: Name;
194 doWrite: BOOLEAN;
196 PROCEDURE (VAR t: Strtab) AddName (IN s: ARRAY OF SHORTCHAR; OUT idx: INTEGER), NEW;
197 VAR i: INTEGER;
198 BEGIN
199 ASSERT((t.cur + LEN(s$)) <= LEN(t.tab), 20); (* table buffer not large enough: TODO enlarge? *)
200 idx := t.cur;
201 i := 0;
202 WHILE s[i] # 0X DO
203 t.tab[t.cur] := s[i];
204 INC(i); INC(t.cur)
205 END;
206 t.tab[t.cur] := s[i]; (* copy the 0X *)
207 INC(t.cur)
208 END AddName;
210 PROCEDURE (VAR t: RelTab) Add (offset, type: INTEGER), NEW;
211 BEGIN
212 ASSERT(t.cur < LEN(t.tab), 20); (* table buffer not large enough: TODO enlarge? *)
213 t.tab[t.cur].offset := offset;
214 t.tab[t.cur].type := type;
215 INC(t.cur)
216 END Add;
218 PROCEDURE AddNeededIdx (idx: INTEGER);
219 VAR i, len: INTEGER;
220 BEGIN
221 ASSERT(idx > 0, 20); (* index must be positive *)
222 len := LEN(neededIdx);
223 i := 0;
224 WHILE (i # len) & (neededIdx[i] # 0) DO INC(i) END;
225 IF i # len THEN
226 neededIdx[i] := idx
227 ELSE
228 HALT(21) (* no more space for indexes *)
229 END
230 END AddNeededIdx;
232 (* A. V. Shiryaev: Console *)
234 PROCEDURE WriteString (s: ARRAY OF CHAR);
235 BEGIN
236 Console.WriteStr(s)
237 END WriteString;
239 PROCEDURE WriteChar (c: CHAR);
240 VAR s: ARRAY 2 OF CHAR;
241 BEGIN
242 s[0] := c; s[1] := 0X;
243 Console.WriteStr(s)
244 END WriteChar;
246 PROCEDURE WriteSString (ss: ARRAY OF SHORTCHAR);
247 BEGIN
248 Console.WriteStr(ss$)
249 END WriteSString;
251 PROCEDURE WriteInt (x: INTEGER);
252 VAR s: ARRAY 16 OF CHAR;
253 BEGIN
254 Strings.IntToString(x, s);
255 Console.WriteStr(s)
256 END WriteInt;
258 PROCEDURE WriteLn;
259 BEGIN
260 Console.WriteLn
261 END WriteLn;
263 PROCEDURE FlushW;
264 BEGIN
265 END FlushW;
267 PROCEDURE ThisFile (modname: ARRAY OF CHAR): Files.File;
268 VAR dir, name: Files.Name; loc: Files.Locator; f: Files.File;
269 BEGIN
270 Kernel.SplitName(modname, dir, name);
271 Kernel.MakeFileName(name, Kernel.objType);
272 loc := Files.dir.This(dir); loc := loc.This(OFdir);
273 f := Files.dir.Old(loc, name, TRUE);
274 IF (f = NIL) & (dir = "") THEN
275 loc := Files.dir.This(SYSdir); loc := loc.This(OFdir);
276 f := Files.dir.Old(loc, name, TRUE)
277 END;
278 RETURN f
279 END ThisFile;
281 PROCEDURE Read4 (VAR x: INTEGER);
282 VAR b: BYTE;
283 BEGIN
284 R.ReadByte(b); x := b MOD 256;
285 R.ReadByte(b); x := x + 100H * (b MOD 256);
286 R.ReadByte(b); x := x + 10000H * (b MOD 256);
287 R.ReadByte(b); x := x + 1000000H * b
288 END Read4;
290 PROCEDURE ReadName (VAR name: ARRAY OF SHORTCHAR);
291 VAR i: INTEGER; b: BYTE;
292 BEGIN i := 0;
293 REPEAT
294 R.ReadByte(b); name[i] := SHORT(CHR(b)); INC(i)
295 UNTIL b = 0
296 END ReadName;
298 PROCEDURE RNum (VAR i: INTEGER);
299 VAR b: BYTE; s, y: INTEGER;
300 BEGIN
301 s := 0; y := 0; R.ReadByte(b);
302 WHILE b < 0 DO INC(y, ASH(b + 128, s)); INC(s, 7); R.ReadByte(b) END;
303 i := ASH((b + 64) MOD 128 - 64, s) + y
304 END RNum;
306 PROCEDURE WriteCh (ch: SHORTCHAR);
307 BEGIN
308 IF doWrite THEN
309 Ro.WriteByte(SHORT(ORD(ch)))
310 END
311 END WriteCh;
313 PROCEDURE Write2 (x: INTEGER);
314 BEGIN
315 IF doWrite THEN
316 Ro.WriteByte(SHORT(SHORT(x MOD 256))); x := x DIV 256;
317 Ro.WriteByte(SHORT(SHORT(x MOD 256)))
318 END
319 END Write2;
321 PROCEDURE Write4 (x: INTEGER);
322 BEGIN
323 IF doWrite THEN
324 Ro.WriteByte(SHORT(SHORT(x MOD 256))); x := x DIV 256;
325 Ro.WriteByte(SHORT(SHORT(x MOD 256))); x := x DIV 256;
326 Ro.WriteByte(SHORT(SHORT(x MOD 256))); x := x DIV 256;
327 Ro.WriteByte(SHORT(SHORT(x MOD 256)))
328 END
329 END Write4;
331 PROCEDURE WriteBytes (IN x: ARRAY OF BYTE; beg, len: INTEGER);
332 BEGIN
333 IF doWrite THEN
334 Ro.WriteBytes(x, beg, len)
335 END
336 END WriteBytes;
338 PROCEDURE Align (alignment: INTEGER);
339 BEGIN
340 WHILE Ro.Pos() MOD alignment # 0 DO WriteCh(0X) END
341 END Align;
343 PROCEDURE Aligned (pos, alignment: INTEGER): INTEGER;
344 BEGIN
345 RETURN (pos + (alignment - 1)) DIV alignment * alignment
346 END Aligned;
348 PROCEDURE Put (mod: Module; a, x: INTEGER);
349 BEGIN
350 ASSERT((mod.data # NIL) & ((a >= 0) & (a <= LEN(mod.data))), 20);
351 mod.data[a] := SHORT(SHORT(x)); INC(a); x := x DIV 256;
352 mod.data[a] := SHORT(SHORT(x)); INC(a); x := x DIV 256;
353 mod.data[a] := SHORT(SHORT(x)); INC(a); x := x DIV 256;
354 mod.data[a] := SHORT(SHORT(x))
355 END Put;
357 PROCEDURE Get (mod: Module; a: INTEGER; VAR x: INTEGER);
358 BEGIN
359 ASSERT((mod.data # NIL) & ((a >= 0) & (a + 3 <= LEN(mod.data))), 20);
360 x := ((mod.data[a + 3] * 256 +
361 (mod.data[a + 2] MOD 256)) * 256 +
362 (mod.data[a + 1] MOD 256)) * 256 +
363 (mod.data[a] MOD 256)
364 END Get;
366 PROCEDURE CheckDllImports (mod: Module);
367 VAR i, x, y: INTEGER; name: Name; imp: Module; exp: Export;
369 PROCEDURE SkipLink;
370 VAR a: INTEGER;
371 BEGIN
372 RNum(a);
373 WHILE a # 0 DO RNum(a); RNum(a) END
374 END SkipLink;
376 BEGIN
377 R := mod.file.NewReader(R);
378 R.SetPos(mod.hs + mod.ms + mod.ds + mod.cs);
379 SkipLink; SkipLink; SkipLink; SkipLink; SkipLink; SkipLink;
380 i := 0;
381 WHILE i < mod.ni DO
382 imp := mod.imp[i];
383 IF imp # NIL THEN
384 RNum(x);
385 WHILE x # 0 DO
386 ReadName(name); RNum(y);
387 IF x = mVar THEN
388 SkipLink;
389 IF imp.dll THEN
390 exp := imp.exp;
391 WHILE (exp # NIL) & (exp.name # name) DO exp := exp.next END;
392 IF exp = NIL THEN
393 NEW(exp); exp.name := name$;
394 exp.next := imp.exp; imp.exp := exp
395 END
396 END
397 ELSIF x = mTyp THEN RNum(y);
398 IF imp.dll THEN
399 RNum(y);
400 IF y # 0 THEN
401 WriteString("type descriptor (");
402 WriteString(imp.name$); WriteChar(".");
403 WriteSString(name);
404 WriteString(") imported from DLL in ");
405 WriteString(mod.name$);
406 WriteLn; FlushW; error := TRUE;
407 RETURN
408 END
409 ELSE SkipLink
410 END
411 ELSIF x = mProc THEN
412 IF imp.dll THEN
413 SkipLink;
414 exp := imp.exp;
415 WHILE (exp # NIL) & (exp.name # name) DO exp := exp.next END;
416 IF exp = NIL THEN
417 NEW(exp); exp.name := name$;
418 exp.next := imp.exp; imp.exp := exp
419 END
420 END
421 END;
422 RNum(x)
423 END
424 END;
425 INC(i)
426 END
427 END CheckDllImports;
429 PROCEDURE ReadHeaders;
430 VAR mod, im, t: Module; x, i, pos: INTEGER; impdll: BOOLEAN; name: Name;
431 BEGIN
432 ASSERT(isDll, 126);
433 mod := modList; modList := NIL; numMod := 0;
434 WHILE mod # NIL DO (* reverse mod list & count modules *)
435 IF ~mod.dll THEN INC(numMod) END;
436 t := mod; mod := t.next; t.next := modList; modList := t
437 END;
438 IF isStatic THEN
439 CodeSize :=
440 6 + 5 * numMod + 2 (* _init() *)
441 + 1 + 5 * numMod + 2 (* _fini() *)
442 ELSE
443 CodeSize :=
444 6 + 5 + 2 (* _init() *)
445 + 1 + 5 + 2 (* _fini() *)
446 END;
447 DataSize := 0; ConSize := 0;
448 maxCode := 0; numExp := 0;
449 mod := modList;
450 WHILE mod # NIL DO
451 IF ~mod.dll THEN
452 mod.file := ThisFile(mod.fileName);
453 IF mod.file # NIL THEN
454 R := mod.file.NewReader(R); R.SetPos(0);
455 Read4(x);
456 IF x = 6F4F4346H THEN
457 Read4(x);
458 Read4(mod.hs); Read4(mod.ms); Read4(mod.ds); Read4(mod.cs);
459 Read4(mod.vs); RNum(mod.ni); ReadName(mod.name); impdll := FALSE;
460 IF mod.ni > 0 THEN
461 NEW(mod.imp, mod.ni);
462 x := 0;
463 WHILE x < mod.ni DO
464 ReadName(name);
465 IF name = "$$" THEN
466 IF (mod # kernel) & (kernel # NIL) THEN
467 mod.imp[x] := kernel
468 ELSE
469 WriteSString("no kernel"); WriteLn;
470 FlushW; error := TRUE
471 END
472 ELSIF name[0] = "$" THEN
473 (* StdLog.String(name$); *)
474 Console.WriteStr(name$);
475 i := 1;
476 WHILE name[i] # 0X DO name[i-1] := name[i]; INC(i) END;
477 name[i-1] := 0X;
478 IF i # 1 THEN
479 Strings.Find(name$, ".so", 0, pos);
480 IF pos = -1 THEN
481 name[i - 1] := "."; name[i] := "s"; name[i + 1] := "o"; name[i + 2] := 0X
482 END
483 END;
484 (* StdLog.String(" "); StdLog.String(name$); StdLog.Ln; *)
485 Console.WriteStr(" "); Console.WriteStr(name$); Console.WriteLn;
486 impdll := TRUE; im := modList;
487 WHILE (im # mod) & (im.name # name) DO im := im.next END;
488 IF (im = NIL) OR ~im.dll THEN
489 NEW(im); im.next := modList; modList := im;
490 im.dll := TRUE;
491 im.name := name$;
492 dynstrtab.AddName(name, i);
493 AddNeededIdx(i)
494 END;
495 mod.imp[x] := im
496 ELSE
497 im := modList;
498 WHILE (im # mod) & (im.name # name) DO im := im.next END;
499 IF im # mod THEN
500 mod.imp[x] := im
501 ELSE
502 WriteSString(name);
503 WriteString(" not present (imported in ");
504 WriteString(mod.name$); WriteChar(")");
505 WriteLn; FlushW; error := TRUE
506 END
507 END;
508 INC(x)
509 END
510 END;
511 IF impdll & ~error THEN CheckDllImports(mod) END;
512 mod.ma := ConSize; INC(ConSize, mod.ms + mod.ds);
513 mod.va := DataSize; INC(DataSize, mod.vs);
514 mod.ca := CodeSize; INC(CodeSize, mod.cs);
515 IF mod.cs > maxCode THEN maxCode := mod.cs END
516 ELSE
517 WriteString(mod.name$); WriteString(": wrong file type");
518 WriteLn; FlushW; error := TRUE
519 END;
520 mod.file.Close; mod.file := NIL
521 ELSE
522 WriteString(mod.fileName$ (* A. V. Shiryaev *)); WriteString(" not found");
523 WriteLn; FlushW; error := TRUE
524 END;
525 last := mod
526 END;
527 mod := mod.next
528 END;
529 IF ~isStatic & (main = NIL) THEN
530 WriteSString("no main module specified"); WriteLn;
531 FlushW; error := TRUE
532 END;
533 IF DataSize = 0 THEN DataSize := 1 END
534 END ReadHeaders;
536 PROCEDURE WriteElfHeader;
537 BEGIN
538 ASSERT(Ro.Pos() = 0, 100);
539 dynstrtab.AddName(soName$, sonameStrIndexVal);
540 Write4(464C457FH); Write4(00010101H); Write4(0); Write4(0); (* Magic *)
541 Write2(3); (* ET_DYN e_type Object file type *)
542 Write2(3); (* EM_386 e_machine Architecture *)
543 Write4(1); (* EV_CURRENT e_version Object file version *)
544 Write4(text.memOffset); (* e_entry Entry point virtual address *)
545 entryPos := Ro.Pos();
546 Write4(fixup); (* e_phoff Program header table file offset *)
547 Write4(fixup); (* e_shoff: Section header table file offset *)
548 Write4(0); (* e_flags Processor-specific flags *)
549 Write2(elfHeaderSizeVal); (* e_ehsize ELF header size in bytes *)
550 Write2(phEntrySizeVal); (* e_phentsize Program header table entry size *)
551 Write2(phNumVal); (* e_phnum Program header table entry count *)
552 Write2(shEntrySizeVal); (* e_shentsize Section header table entry size *)
553 Write2(shNumVal); (* e_shnum Section header table entry count *)
554 Write2(shStrndxVal); (* e_shstrndx Section header string table index *)
555 ASSERT(Ro.Pos() = elfHeaderSizeVal, 101)
556 END WriteElfHeader;
558 PROCEDURE FixupElfHeader;
559 BEGIN
560 Ro.SetPos(entryPos);
561 Write4(phOffsetVal);
562 Write4(shOffsetVal)
563 END FixupElfHeader;
565 PROCEDURE WriteNullSectionHeader;
566 BEGIN
567 Write4(0); (* sh_name Section name (string tbl index) *)
568 Write4(0); (* SHT_NULL sh_type Section type *)
569 Write4(0); (* sh_flags Section flags *)
570 Write4(0); (* ELF header + program header table; sh_addr Section virtual addr at execution *)
571 Write4(0); (* sh_offset Section file offset *)
572 Write4(0); (* sh_size Section size in bytes *)
573 Write4(0); (* SHN_UNDEF sh_link Link to another section *)
574 Write4(0); (* sh_info Additional section information *)
575 Write4(0); (* sh_addralign Section alignment *)
576 Write4(0) (* sh_entsize Entry size if section holds table *)
577 END WriteNullSectionHeader;
579 PROCEDURE WriteTextSectionHeader;
580 VAR i: INTEGER;
581 BEGIN
582 headerstrtab.AddName(".text", i);
583 Write4(i); (* sh_name Section name (string tbl index) *)
584 Write4(1); (* SHT_PROGBITS sh_type Section type *)
585 Write4(2H + 4H); (* SHF_ALLOC + SHF_EXECINSTR sh_flags Section flags *)
586 Write4(text.memOffset); (* sh_addr Section virtual addr at execution *)
587 Write4(text.fileOffset); (* sh_offset Section file offset *)
588 Write4(text.size); (* sh_size Section size in bytes *)
589 Write4(0); (* SHN_UNDEF sh_link Link to another section *)
590 Write4(0); (* sh_info Additional section information *)
591 Write4(textAlign); (* sh_addralign Section alignment *)
592 Write4(0) (* sh_entsize Entry size if section holds table *)
593 END WriteTextSectionHeader;
595 PROCEDURE WriteRelTextSectionHeader;
596 VAR i: INTEGER;
597 BEGIN
598 headerstrtab.AddName(".rel.text", i);
599 Write4(i); (* sh_name Section name (string tbl index) *)
600 Write4(9); (* SHT_REL sh_type Section type *)
601 Write4(2H); (* SHF_ALLOC sh_flags Section flags *)
602 Write4(reltext.memOffset); (* sh_addr Section virtual addr at execution *)
603 Write4(reltext.fileOffset); (* sh_offset Section file offset *)
604 Write4(reltext.size); (* sh_size Section size in bytes *)
605 Write4(dynsymIndexVal); (* sh_link Link to another section -> index of the associated symbol table *)
606 Write4(textIndexVal); (* sh_info Additional section information -> index of the relocated section *)
607 Write4(relAlign); (* sh_addralign Section alignment *)
608 Write4(relEntrySizeVal) (* sh_entsize Entry size if section holds table *)
609 END WriteRelTextSectionHeader;
611 PROCEDURE WriteRelRodataSectionHeader;
612 VAR i: INTEGER;
613 BEGIN
614 headerstrtab.AddName(".rel.rodata", i);
615 Write4(i); (* sh_name Section name (string tbl index) *)
616 Write4(9); (* SHT_REL sh_type Section type *)
617 Write4(2H); (* SHF_ALLOC sh_flags Section flags *)
618 Write4(relrodata.memOffset); (* sh_addr Section virtual addr at execution *)
619 Write4(relrodata.fileOffset); (* sh_offset Section file offset *)
620 Write4(relrodata.size); (* sh_size Section size in bytes *)
621 Write4(dynsymIndexVal); (* sh_link Link to another section -> index of the associated symbol table *)
622 Write4(rodataIndexVal); (* sh_info Additional section information -> index of the relocated section *)
623 Write4(relAlign); (* sh_addralign Section alignment *)
624 Write4(relEntrySizeVal) (* sh_entsize Entry size if section holds table *)
625 END WriteRelRodataSectionHeader;
627 PROCEDURE WriteRodataSectionHeader;
628 VAR i: INTEGER;
629 BEGIN
630 headerstrtab.AddName(".rodata", i);
631 Write4(i); (* sh_name Section name (string tbl index) *)
632 Write4(1); (* SHT_PROGBITS sh_type Section type *)
633 Write4(2H); (* SHF_ALLOC sh_flags Section flags *)
634 Write4(rodata.memOffset); (* sh_addr Section virtual addr at execution *)
635 Write4(rodata.fileOffset); (* sh_offset Section file offset *)
636 Write4(rodata.size); (* sh_size Section size in bytes *)
637 Write4(0); (* sh_link Link to another section *)
638 Write4(0); (* sh_info Additional section information *)
639 Write4(rodataAlign); (* sh_addralign Section alignment *)
640 Write4(0) (* sh_entsize Entry size if section holds table *)
641 END WriteRodataSectionHeader;
643 PROCEDURE WriteDynsymSectionHeader;
644 VAR i: INTEGER;
645 BEGIN
646 headerstrtab.AddName(".dynsym", i);
647 Write4(i); (* sh_name Section name (string tbl index) *)
648 Write4(11); (* SHT_DYNSYM sh_type Section type *)
649 Write4(2H); (* SHF_ALLOC sh_flags Section flags *)
650 Write4(dynsym.memOffset); (* sh_addr Section virtual addr at execution *)
651 Write4(dynsym.fileOffset); (* sh_offset Section file offset *)
652 Write4(dynsym.size); (* sh_size Section size in bytes *)
653 Write4(dynstrIndexVal); (* sh_link Link to another section -> index of the associated string table *)
654 expPos := Ro.Pos();
655 Write4(fixup); (* sh_info Additional section information -> see docu 4-17 *)
656 Write4(dynsymAlign); (* sh_addralign Section alignment *)
657 Write4(dynsymEntrySizeVal) (* sh_entsize Entry size if section holds table *)
658 END WriteDynsymSectionHeader;
660 PROCEDURE FixupDynsymSectionHeader;
661 BEGIN
662 Ro.SetPos(expPos);
663 Write4(dynsymInfoVal)
664 END FixupDynsymSectionHeader;
666 PROCEDURE WriteDynstrSectionHeader;
667 VAR i: INTEGER;
668 BEGIN
669 headerstrtab.AddName(".dynstr", i);
670 Write4(i); (* sh_name Section name (string tbl index) *)
671 Write4(3); (* SHT_STRTAB sh_type Section type *)
672 Write4(2H); (* SHF_ALLOC sh_flags Section flags *)
673 Write4(dynstr.memOffset); (* sh_addr Section virtual addr at execution *)
674 Write4(dynstr.fileOffset); (* sh_offset Section file offset *)
675 Write4(dynstr.size); (* sh_size Section size in bytes *)
676 Write4(0); (* SHN_UNDEF sh_link Link to another section *)
677 Write4(0); (* sh_info Additional section information *)
678 Write4(dynstrAlign); (* sh_addralign Section alignment *)
679 Write4(0) (* sh_entsize Entry size if section holds table *)
680 END WriteDynstrSectionHeader;
682 PROCEDURE WriteHashSectionHeader;
683 VAR i: INTEGER;
684 BEGIN
685 headerstrtab.AddName(".hash", i);
686 Write4(i); (* sh_name Section name (string tbl index) *)
687 Write4(5); (* SHT_HASH sh_type Section type *)
688 Write4(2H); (* SHF_ALLOC sh_flags Section flags *)
689 Write4(hash.memOffset); (* sh_addr Section virtual addr at execution *)
690 Write4(hash.fileOffset); (* sh_offset Section file offset *)
691 Write4(hash.size); (* sh_size Section size in bytes *)
692 Write4(dynsymIndexVal); (* sh_link Link to another section *)
693 Write4(0); (* sh_info Additional section information *)
694 Write4(hashAlign); (* sh_addralign Section alignment *)
695 Write4(4H) (* sh_entsize Entry size if section holds table *)
696 END WriteHashSectionHeader;
698 PROCEDURE WriteGotSectionHeader;
699 VAR i: INTEGER;
700 BEGIN
701 headerstrtab.AddName(".got", i);
702 Write4(i); (* sh_name Section name (string tbl index) *)
703 Write4(1); (* SHT_PROGBITS sh_type Section type *)
704 Write4(2H + 1H); (* SHF_ALLOC + SHF_WRITE sh_flags Section flags *)
705 Write4(got.memOffset); (* sh_addr Section virtual addr at execution *)
706 Write4(got.fileOffset); (* sh_offset Section file offset *)
707 Write4(got.size); (* sh_size Section size in bytes *)
708 Write4(0); (* SHN_UNDEF sh_link Link to another section *)
709 Write4(0); (* sh_info Additional section information *)
710 Write4(gotAlign); (* sh_addralign Section alignment *)
711 Write4(gotEntrySizeVal) (* sh_entsize Entry size if section holds table *)
712 END WriteGotSectionHeader;
714 PROCEDURE WriteBssSectionHeader;
715 VAR i: INTEGER;
716 BEGIN
717 headerstrtab.AddName(".bss", i);
718 Write4(i); (* sh_name Section name (string tbl index) *)
719 Write4(8); (* SHT_NOBITS sh_type Section type *)
720 Write4(2H + 1H); (* SHF_ALLOC + SHF_WRITE sh_flags Section flags *)
721 Write4(bss.memOffset); (* sh_addr Section virtual addr at execution *)
722 Write4(bss.fileOffset); (* sh_offset Section file offset *)
723 Write4(bss.size); (* sh_size Section size in bytes *)
724 Write4(0); (* SHN_UNDEF sh_link Link to another section *)
725 Write4(0); (* sh_info Additional section information *)
726 Write4(bssAlign); (* sh_addralign Section alignment *)
727 Write4(0) (* sh_entsize Entry size if section holds table *)
728 END WriteBssSectionHeader;
730 PROCEDURE WriteDynamicSectionHeader;
731 VAR i: INTEGER;
732 BEGIN
733 headerstrtab.AddName(".dynamic", i);
734 Write4(i); (* sh_name Section name (string tbl index) *)
735 Write4(6); (* SHT_DYNAMIC sh_type Section type *)
736 Write4(2H); (* SHF_ALLOC sh_flags Section flags *)
737 Write4(dynamic.memOffset); (* sh_addr Section virtual addr at execution *)
738 Write4(dynamic.fileOffset); (* sh_offset Section file offset *)
739 Write4(dynamic.size); (* sh_size Section size in bytes *)
740 Write4(dynstrIndexVal); (* sh_link Link to another section -> index of the associated symbol table *)
741 Write4(0); (* sh_info Additional section information *)
742 Write4(dynamicAlign); (* sh_addralign Section alignment *)
743 Write4(dynamicEntrySizeVal) (* sh_entsize Entry size if section holds table *)
744 END WriteDynamicSectionHeader;
746 PROCEDURE WriteShstrtabSectionHeader;
747 VAR i: INTEGER;
748 BEGIN
749 headerstrtab.AddName(".shstrtab", i);
750 Write4(i); (* sh_name Section name (string tbl index) *)
751 Write4(3); (* SHT_STRTAB sh_type Section type *)
752 Write4(0); (* sh_flags Section flags *)
753 Write4(0); (* sh_addr Section virtual addr at execution *)
754 Write4(shstrtab.fileOffset); (* sh_offset Section file offset *)
755 shstrtabPos := Ro.Pos();
756 Write4(fixup); (* sh_size Section size in bytes *)
757 Write4(0); (* SHN_UNDEF sh_link Link to another section *)
758 Write4(0); (* sh_info Additional section information *)
759 Write4(shstrtabAlign); (* sh_addralign Section alignment *)
760 Write4(0) (* sh_entsize Entry size if section holds table *)
761 END WriteShstrtabSectionHeader;
763 PROCEDURE FixupShstrtabSectionHeader;
764 BEGIN
765 Ro.SetPos(shstrtabPos);
766 Write4(shstrtab.size)
767 END FixupShstrtabSectionHeader;
769 PROCEDURE WriteRelSectionHeaders;
770 BEGIN
771 WriteRelTextSectionHeader;
772 WriteRelRodataSectionHeader
773 END WriteRelSectionHeaders;
775 PROCEDURE WriteSectionHeaderTable;
776 BEGIN
777 shOffsetVal := Ro.Pos();
778 WriteNullSectionHeader;
779 WriteTextSectionHeader;
780 WriteRodataSectionHeader;
781 WriteRelSectionHeaders;
782 WriteDynsymSectionHeader;
783 WriteDynstrSectionHeader;
784 WriteHashSectionHeader;
785 WriteGotSectionHeader;
786 WriteDynamicSectionHeader;
787 WriteBssSectionHeader;
788 WriteShstrtabSectionHeader (* see shStrndxVal *)
789 (* see shNumVal *)
790 END WriteSectionHeaderTable;
792 PROCEDURE FixupSectionHeaderTable;
793 BEGIN
794 FixupDynsymSectionHeader;
795 FixupShstrtabSectionHeader
796 END FixupSectionHeaderTable;
798 PROCEDURE WriteTextSegment;
799 BEGIN
800 Write4(1); (* PT_LOAD *)
801 Write4(0); (* offset *)
802 Write4(0); (* vaddr *)
803 Write4(0); (* paddr *)
804 Write4(textSegmentSizeVal); (* file size *)
805 Write4(textSegmentSizeVal); (* mem size *)
806 Write4(4H + 1H + 2H); (* flags: R+E+W *)
807 Write4(pageSize) (* I386 page size *)
808 END WriteTextSegment;
810 PROCEDURE WriteDataSegment;
811 BEGIN
812 Write4(1); (* PT_LOAD *)
813 Write4(got.fileOffset); (* offset text segment size *)
814 Write4(got.memOffset); (* vaddr: offset + alignment * nof pages of text segment *)
815 Write4(got.memOffset); (* paddr: offset + alignment * nof pages of text segment *)
816 Write4(dataSegmentSizeVal); (* file size *)
817 Write4(dataSegmentSizeVal + bss.size); (* mem size -> dataSegmentSizeVal + NOBITS sections *)
818 Write4(4H + 2H); (* flags: R+W *)
819 Write4(pageSize) (* I386 page size *)
820 END WriteDataSegment;
822 PROCEDURE WriteDynamicSegment;
823 BEGIN
824 Write4(2); (* PT_DYNAMIC *)
825 Write4(dynamic.fileOffset); (* offset text segment size *)
826 Write4(dynamic.memOffset); (* vaddr: offset of .dynamic section *)
827 Write4(dynamic.memOffset); (* paddr: vaddr + alignment * nof pages of text segment *)
828 Write4(dynamicSegmentSizeVal); (* file size *)
829 Write4(dynamicSegmentSizeVal); (* mem size *)
830 Write4(4H + 2H); (* flags: R+W *)
831 Write4(dynamicAlign) (* dynamic section alignement*)
832 END WriteDynamicSegment;
834 PROCEDURE WriteProgramHeaderTable;
835 BEGIN
836 phOffsetVal := Ro.Pos();
837 WriteTextSegment; (* .text .rel.text .rodata .dynsym .dynstr .hash *)
838 WriteDataSegment; (* .got .dynamic .bss *)
839 WriteDynamicSegment (* .dynamic *)
840 END WriteProgramHeaderTable;
842 PROCEDURE SearchObj (mod: Module; VAR name: ARRAY OF SHORTCHAR; m, fp, opt: INTEGER; VAR adr: INTEGER);
843 VAR dir, len, ntab, f, id, l, r, p, n, i, j: INTEGER; nch, och: SHORTCHAR;
844 BEGIN
845 Get(mod, mod.ms + modExports, dir); DEC(dir, rodata.memOffset + mod.ma); Get(mod, dir, len); INC(dir, 4);
846 Get(mod, mod.ms + modNames, ntab); DEC(ntab, rodata.memOffset + mod.ma);
847 IF name # "" THEN
848 l := 0; r := len;
849 WHILE l < r DO (* binary search *)
850 n := (l + r) DIV 2; p := dir + n * 16;
851 Get(mod, p + 8, id);
852 i := 0; j := ntab + id DIV 256; nch := name[0]; och := SHORT(CHR(mod.data[j]));
853 WHILE (nch = och) & (nch # 0X) DO INC(i); INC(j); nch := name[i]; och := SHORT(CHR(mod.data[j])) END;
854 IF och = nch THEN
855 IF id MOD 16 = m THEN
856 Get(mod, p, f);
857 IF m = mTyp THEN
858 IF ODD(opt) THEN Get(mod, p + 4, f) END;
859 IF (opt > 1) & (id DIV 16 MOD 16 # mExported) THEN
860 WriteString(mod.name$); WriteChar("."); WriteSString(name);
861 WriteString(" imported from "); WriteString(impg.name$);
862 WriteString(" has wrong visibility"); WriteLn; error := TRUE
863 END;
864 Get(mod, p + 12, adr)
865 ELSIF m = mVar THEN
866 Get(mod, p + 4, adr); INC(adr, bss.memOffset + mod.va)
867 ELSIF m = mProc THEN
868 Get(mod, p + 4, adr); INC(adr, text.memOffset + mod.ca)
869 END;
870 IF f # fp THEN
871 WriteString(mod.name$); WriteChar("."); WriteSString(name);
872 WriteString(" imported from "); WriteString(impg.name$);
873 WriteString(" has wrong fprint"); WriteLn; error := TRUE
874 END
875 ELSE
876 WriteString(mod.name$); WriteChar("."); WriteSString(name);
877 WriteString(" imported from "); WriteString(impg.name$);
878 WriteString(" has wrong class"); WriteLn; error := TRUE
879 END;
880 RETURN
881 END;
882 IF och < nch THEN l := n + 1 ELSE r := n END
883 END;
884 WriteString(mod.name$); WriteChar("."); WriteSString(name);
885 WriteString(" not found (imported from "); WriteString(impg.name$);
886 WriteChar(")"); WriteLn; error := TRUE
887 ELSE (* anonymous type *)
888 WHILE len > 0 DO
889 Get(mod, dir + 4, f); Get(mod, dir + 8, id);
890 IF (f = fp) & (id MOD 16 = mTyp) & (id DIV 256 = 0) THEN
891 Get(mod, dir + 12, adr); RETURN
892 END;
893 DEC(len); INC(dir, 16)
894 END;
895 WriteString("anonymous type in "); WriteString(mod.name$);
896 WriteString(" not found"); WriteLn; error := TRUE
897 END
898 END SearchObj;
900 PROCEDURE CollectExports (mod: Module);
901 VAR dir, len, ntab, id, i, j, n: INTEGER; e, exp: Export;
902 BEGIN
903 ASSERT(mod.intf & ~mod.dll, 20);
904 Get(mod, mod.ms + modExports, dir);
905 DEC(dir, rodata.memOffset + mod.ma); Get(mod, dir, len); INC(dir, 4);
906 Get(mod, mod.ms + modNames, ntab); DEC(ntab, rodata.memOffset + mod.ma); n := 0;
907 WHILE n < len DO
908 Get(mod, dir + 8, id);
909 IF (id DIV 16 MOD 16 # mInternal) & (id MOD 16 = mProc) THEN (* exported procedure *)
910 NEW(exp);
911 i := 0; j := ntab + id DIV 256;
912 WHILE mod.data[j] # 0 DO exp.name[i] := SHORT(CHR(mod.data[j])); INC(i); INC(j) END;
913 exp.name[i] := 0X;
914 Get(mod, dir + 4, exp.adr);
915 IF id MOD 16 = mProc THEN
916 INC(exp.adr, text.memOffset + mod.ca)
917 ELSE
918 HALT(126);
919 ASSERT(id MOD 16 = mVar); INC(exp.adr, bss.memOffset + mod.va)
920 END;
921 IF (firstExp = NIL) OR (exp.name < firstExp.name) THEN
922 exp.next := firstExp; firstExp := exp;
923 IF lastExp = NIL THEN lastExp := exp END
924 ELSE
925 e := firstExp;
926 WHILE (e.next # NIL) & (exp.name > e.next.name) DO e := e.next END;
927 exp.next := e.next; e.next := exp;
928 IF lastExp = e THEN lastExp := exp END
929 END;
930 INC(numExp)
931 END;
932 INC(n); INC(dir, 16)
933 END
934 END CollectExports;
936 PROCEDURE Relocate0 (link, adr, sym: INTEGER);
937 CONST
938 absolute = 100; relative = 101; copy = 102; table = 103; tableend = 104; (* BB fixup types *)
939 noElfType = MIN(INTEGER);
940 VAR
941 offset, linkadr, bbType, elfType, n, x: INTEGER; relText: BOOLEAN;
942 BEGIN
943 WHILE link # 0 DO
944 RNum(offset);
945 WHILE link # 0 DO
946 IF link > 0 THEN
947 n := (code[link] MOD 256) + (code[link+1] MOD 256) * 256 + code[link+2] * 65536;
948 bbType := code[link+3];
949 linkadr := text.memOffset + impg.ca + link
950 ELSE
951 n := (impg.data[-link] MOD 256) + (impg.data[-link+1] MOD 256) * 256 + impg.data[-link+2] * 65536;
952 bbType := impg.data[-link+3];
953 linkadr := rodata.memOffset + impg.ma - link
954 END;
955 elfType := noElfType;
956 IF bbType = absolute THEN
957 IF sym = noSymbol THEN
958 x := adr + offset;
959 elfType := r386Relative
960 ELSE
961 x := 0H;
962 elfType := r38632 + sym * 256
963 END
964 ELSIF bbType = relative THEN
965 IF sym = noSymbol THEN
966 x := adr + offset - linkadr - 4
967 ELSE
968 x := 0FFFFFFFCH;
969 elfType := r386pc32 + sym * 256
970 END
971 ELSIF bbType = copy THEN
972 Get(impd, adr + offset - rodata.memOffset - impd.ma, x);
973 IF x # 0 THEN elfType := r386Relative END
974 ELSIF bbType = table THEN
975 x := adr + n; n := link + 4;
976 elfType := r386Relative
977 ELSIF bbType = tableend THEN
978 x := adr + n; n := 0;
979 elfType := r386Relative
980 ELSE HALT(99)
981 END;
982 relText := link > 0;
983 IF link > 0 THEN
984 code[link] := SHORT(SHORT(x));
985 code[link+1] := SHORT(SHORT(x DIV 100H));
986 code[link+2] := SHORT(SHORT(x DIV 10000H));
987 code[link+3] := SHORT(SHORT(x DIV 1000000H))
988 ELSE
989 link := -link;
990 impg.data[link] := SHORT(SHORT(x));
991 impg.data[link+1] := SHORT(SHORT(x DIV 100H));
992 impg.data[link+2] := SHORT(SHORT(x DIV 10000H));
993 impg.data[link+3] := SHORT(SHORT(x DIV 1000000H))
994 END;
995 IF elfType # noElfType THEN
996 IF relText THEN
997 relTextTab.Add(linkadr, elfType)
998 ELSE
999 relRodataTab.Add(linkadr, elfType)
1000 END
1001 END;
1002 link := n
1003 END;
1004 RNum(link)
1005 END
1006 END Relocate0;
1008 PROCEDURE Relocate (adr: INTEGER);
1009 VAR link: INTEGER;
1010 BEGIN
1011 RNum(link); Relocate0(link, adr, noSymbol)
1012 END Relocate;
1014 PROCEDURE RelocateSymbol (adr, sym: INTEGER);
1015 VAR link: INTEGER;
1016 BEGIN
1017 RNum(link); Relocate0(link, adr, sym)
1018 END RelocateSymbol;
1020 PROCEDURE SymbolIndex (IN name: Name): INTEGER;
1021 VAR n: INTEGER; exp: Export; m: Module;
1022 BEGIN
1023 n := 0; exp := NIL;
1024 m := modList;
1025 WHILE (m # NIL) & (exp = NIL) DO
1026 IF m.dll THEN
1027 exp := m.exp;
1028 WHILE (exp # NIL) & (exp.name$ # name$) DO
1029 INC(n);
1030 exp := exp.next
1031 END
1032 END;
1033 m := m.next
1034 END;
1035 ASSERT((exp # NIL) & (exp.name$ = name$), 60);
1036 RETURN firstDllSymbolVal + n
1037 END SymbolIndex;
1039 PROCEDURE WriteTextSection;
1040 VAR mod, m: Module; i, x, a, sym, fp, opt: INTEGER; exp: Export; name: Name;
1041 BEGIN
1042 ASSERT(isDll, 126);
1043 ASSERT(~doWrite OR (Ro.Pos() = text.fileOffset), 100);
1044 WriteCh(053X); (* push ebx *) (* _init() *)
1045 a := 1;
1046 WriteCh(0BBX); Write4(rodata.memOffset + last.ma + last.ms); (* mov bx, modlist *)
1047 relTextTab.Add(text.memOffset + a + 1, r386Relative);
1048 INC(a, 5);
1049 IF isStatic THEN
1050 m := modList;
1051 WHILE m # NIL DO
1052 IF ~m.dll THEN
1053 WriteCh(0E8X); INC(a, 5); Write4(m.ca - a) (* call body *)
1054 END;
1055 m := m.next
1056 END
1057 ELSE
1058 WriteCh(0E8X); INC(a, 5); Write4(main.ca - a) (* call main *)
1059 END;
1060 WriteCh(05BX); (* pop ebx *)
1061 WriteCh(0C3X); (* ret *)
1062 INC(a, 2);
1063 finiMemOffsetVal := text.memOffset + a;
1064 WriteCh(053X); (* push ebx *) (* _fini() *)
1065 INC(a);
1066 finiPos := text.memOffset + a;
1067 IF isStatic THEN
1068 i := 0;
1069 WHILE i < numMod DO (* nop for call terminator *)
1070 WriteCh(02DX); Write4(0); (* sub EAX, 0 *)
1071 INC(i); INC(a, 5)
1072 END
1073 ELSE
1074 WriteCh(02DX); Write4(0); (* sub EAX, 0 *)
1075 INC(a, 5)
1076 END;
1077 lastTerm := a;
1078 WriteCh(05BX); (* pop ebx *)
1079 WriteCh(0C3X); (* ret *)
1080 IF ~doWrite THEN NEW(code, maxCode) END;
1081 mod := modList;
1082 WHILE mod # NIL DO
1083 impg := mod;
1084 impd := mod;
1085 IF ~mod.dll THEN
1086 mod.file := ThisFile(mod.fileName);
1087 R := mod.file.NewReader(R);
1088 R.SetPos(mod.hs);
1089 IF ~doWrite THEN NEW(mod.data, mod.ms + mod.ds) END;
1090 R.ReadBytes(mod.data^, 0, mod.ms + mod.ds);
1091 R.ReadBytes(code^, 0, mod.cs);
1092 RNum(x);
1093 IF x # 0 THEN
1094 IF (mod # kernel) & (kernel # NIL) THEN
1095 SearchObj(kernel, newRec, mProc, NewRecFP, 0, a);
1096 IF error THEN RETURN END;
1097 Relocate0(x, a, noSymbol)
1098 ELSE
1099 WriteSString("no kernel"); WriteLn;
1100 FlushW;
1101 error := TRUE;
1102 RETURN
1103 END
1104 END;
1105 RNum(x);
1106 IF x # 0 THEN
1107 IF (mod # kernel) & (kernel # NIL) THEN
1108 SearchObj(kernel, newArr, mProc, NewArrFP, 0, a);
1109 IF error THEN RETURN END;
1110 Relocate0(x, a, noSymbol)
1111 ELSE
1112 WriteSString("no kernel"); WriteLn;
1113 FlushW; error := TRUE;
1114 RETURN
1115 END
1116 END;
1117 Relocate(rodata.memOffset + mod.ma); (* metalink *)
1118 Relocate(rodata.memOffset + mod.ma + mod.ms); (* desclink *)
1119 Relocate(text.memOffset + mod.ca); (* codelink *)
1120 Relocate(bss.memOffset + mod.va); (* datalink *)
1121 i := 0;
1122 WHILE i < mod.ni DO
1123 m := mod.imp[i]; impd := m; RNum(x);
1124 WHILE x # 0 DO
1125 ReadName(name); RNum(fp); opt := 0;
1126 IF x = mTyp THEN RNum(opt) END;
1127 sym := noSymbol;
1128 IF m.dll THEN
1129 IF (x = mProc) OR (x = mVar) THEN
1130 exp := m.exp;
1131 WHILE exp.name # name DO exp := exp.next END;
1132 a := noAddr;
1133 sym := SymbolIndex(name)
1134 END
1135 ELSE
1136 SearchObj(m, name, x, fp, opt, a);
1137 IF error THEN RETURN END
1138 END;
1139 IF x # mConst THEN
1140 RelocateSymbol(a, sym)
1141 END;
1142 RNum(x)
1143 END;
1144 IF ~m.dll THEN
1145 Get(mod, mod.ms + modImports, x); DEC(x, rodata.memOffset + mod.ma); INC(x, 4 * i);
1146 Put(mod, x, rodata.memOffset + m.ma + m.ms); (* imp ref *)
1147 relRodataTab.Add(rodata.memOffset + mod.ma + x, r386Relative);
1148 Get(m, m.ms + modRefcnt, x); Put(m, m.ms + modRefcnt, x + 1) (* inc ref count *)
1149 END;
1150 INC(i)
1151 END;
1152 WriteBytes(code^, 0, mod.cs);
1153 IF mod.intf THEN CollectExports(mod) END;
1154 mod.file.Close; mod.file := NIL
1155 END;
1156 mod := mod.next
1157 END;
1158 ASSERT(~doWrite OR (text.size = Ro.Pos() - text.fileOffset), 101)
1159 END WriteTextSection;
1161 PROCEDURE WriteTermCode (m: Module; i: INTEGER);
1162 VAR x: INTEGER;
1163 BEGIN
1164 IF m # NIL THEN
1165 IF m.dll THEN WriteTermCode(m.next, i)
1166 ELSE
1167 IF isStatic THEN WriteTermCode(m.next, i + 1) END;
1168 Get(m, m.ms + modTerm, x); (* terminator address in mod desc*)
1169 IF x = 0 THEN
1170 WriteCh(005X); Write4(0) (* add EAX, 0 (nop) *)
1171 ELSE
1172 WriteCh(0E8X); Write4(x - lastTerm + 5 * i - text.memOffset) (* call term *)
1173 END
1174 END
1175 END
1176 END WriteTermCode;
1178 PROCEDURE FixupTextSection;
1179 BEGIN
1180 ASSERT(isDll, 126);
1181 Ro.SetPos(finiPos);
1182 IF isStatic THEN
1183 WriteTermCode(modList, 0)
1184 ELSE
1185 WriteTermCode(main, 0)
1186 END
1187 END FixupTextSection;
1189 PROCEDURE WriteRelSection (IN s: Section; IN t: RelTab);
1190 VAR i: INTEGER;
1191 BEGIN
1192 ASSERT(s.fileOffset = Ro.Pos(), 100);
1193 i := 0;
1194 WHILE i # t.cur DO
1195 Write4(t.tab[i].offset);
1196 Write4(t.tab[i].type);
1197 INC(i)
1198 END;
1199 ASSERT(s.size = Ro.Pos() - s.fileOffset, 101)
1200 END WriteRelSection;
1202 PROCEDURE WriteRelSections;
1203 BEGIN
1204 WriteRelSection(reltext, relTextTab);
1205 WriteRelSection(relrodata, relRodataTab)
1206 END WriteRelSections;
1208 PROCEDURE WriteRodataSection;
1209 VAR mod, lastMod: Module; x: INTEGER;
1210 BEGIN
1211 ASSERT(~doWrite OR (rodata.fileOffset = Ro.Pos()), 100);
1212 mod := modList; lastMod := NIL;
1213 WHILE mod # NIL DO
1214 IF ~mod.dll THEN
1215 IF lastMod # NIL THEN
1216 Put(mod, mod.ms, rodata.memOffset + lastMod.ma + lastMod.ms); (* mod list *)
1217 relRodataTab.Add(rodata.memOffset + mod.ma + mod.ms, r386Relative)
1218 END;
1219 Get(mod, mod.ms + modOpts, x);
1220 IF isStatic THEN INC(x, 10000H) END; (* set init bit (16) *)
1221 IF isDll THEN INC(x, 1000000H) END; (* set dll bit (24) *)
1222 Put(mod, mod.ms + modOpts, x);
1223 WriteBytes(mod.data^, 0, mod.ms + mod.ds);
1224 lastMod := mod
1225 END;
1226 mod := mod.next
1227 END;
1228 ASSERT(~doWrite OR (rodata.size = Ro.Pos() - rodata.fileOffset), 101)
1229 END WriteRodataSection;
1231 PROCEDURE WriteSymbolTableEntry (IN name: ARRAY OF SHORTCHAR; val, size: INTEGER; bind, type: BYTE; shndx: INTEGER);
1232 VAR i: INTEGER; info: SHORTCHAR;
1233 BEGIN
1234 IF name # "" THEN dynstrtab.AddName(name, i)
1235 ELSE i := 0
1236 END;
1237 Write4(i);
1238 Write4(val);
1239 Write4(size);
1240 info := SHORT(CHR(bind * 16 + type));
1241 WriteCh(info);
1242 WriteCh(0X); (* Symbol visibility *)
1243 Write2(shndx)
1244 END WriteSymbolTableEntry;
1246 PROCEDURE FixupSymbolTableEntry (val, size: INTEGER; bind, type: BYTE; shndx: INTEGER);
1247 VAR info: SHORTCHAR;
1248 BEGIN
1249 Ro.SetPos(Ro.Pos() + 4); (* skip name *)
1250 Write4(val);
1251 Write4(size);
1252 info := SHORT(CHR(bind * 16 + type));
1253 WriteCh(info);
1254 WriteCh(0X); (* Symbol visibility *)
1255 Write2(shndx)
1256 END FixupSymbolTableEntry;
1258 PROCEDURE WriteDynsymSection;
1259 VAR e: Export; m: Module; i: INTEGER;
1260 BEGIN
1261 ASSERT(Ro.Pos() = dynsym.fileOffset, 100);
1262 WriteSymbolTableEntry("", 0, 0, 0, 0, 0);
1263 WriteSymbolTableEntry("", text.memOffset, 0, stbLocal, sttSection, 1); (* .text section *)
1264 WriteSymbolTableEntry("", rodata.memOffset, 0, stbLocal, sttSection, 2); (* .rodata section *)
1265 WriteSymbolTableEntry("", reltext.memOffset, 0, stbLocal, sttSection, 3); (* .rel.text.section *)
1266 WriteSymbolTableEntry("", relrodata.memOffset, 0, stbLocal, sttSection, 4); (* .rel.rodata section *)
1267 WriteSymbolTableEntry("", dynsym.memOffset, 0, stbLocal, sttSection, 5); (* .dynsym section *)
1268 WriteSymbolTableEntry("", dynstr.memOffset, 0, stbLocal, sttSection, 6); (* .dynstr section *)
1269 WriteSymbolTableEntry("", hash.memOffset, 0, stbLocal, sttSection, 7); (* .hash section *)
1270 WriteSymbolTableEntry("", got.memOffset, 0, stbLocal, sttSection, 8); (* .got section *)
1271 WriteSymbolTableEntry("", dynamic.memOffset, 0, stbLocal, sttSection, 9); (* .dynamic section *)
1272 WriteSymbolTableEntry("", bss.memOffset, 0, stbLocal, sttSection, 10); (* .bss section *)
1273 dynsymInfoVal := 11;
1274 i := dynsymInfoVal;
1275 WriteSymbolTableEntry("_DYNAMIC", dynamic.memOffset, 0, stbGlobal, sttObject, shnAbs);
1276 hashtab[i] := "_DYNAMIC";
1277 INC(i);
1278 ASSERT(i = firstDllSymbolVal);
1279 m := modList;
1280 WHILE m # NIL DO
1281 IF m.dll THEN
1282 e := m.exp;
1283 WHILE e # NIL DO
1284 WriteSymbolTableEntry(e.name, 0, 0, stbGlobal, sttNotype, shnUnd);
1285 hashtab[i] := e.name$;
1286 INC(i);
1287 e := e.next
1288 END
1289 END;
1290 m := m.next
1291 END;
1292 e := firstExp;
1293 WHILE e # NIL DO
1294 WriteSymbolTableEntry(e.name, fixup, 0, stbGlobal, sttFunc, textIndexVal);
1295 hashtab[i] := e.name$; INC(i);
1296 e := e.next
1297 END;
1298 WriteSymbolTableEntry("_GLOBAL_OFFSET_TABLE_", got.memOffset, 0, stbGlobal, sttObject, shnAbs);
1299 hashtab[i] := "_GLOBAL_OFFSET_TABLE_";
1300 ASSERT(dynsym.size = Ro.Pos() - dynsym.fileOffset, 101)
1301 END WriteDynsymSection;
1303 PROCEDURE FixupDynsymSection;
1304 VAR e: Export; m: Module;
1305 BEGIN
1306 Ro.SetPos(dynsym.fileOffset + dynsymEntrySizeVal * firstDllSymbolVal);
1307 m := modList;
1308 WHILE m # NIL DO
1309 IF m.dll THEN
1310 e := m.exp;
1311 WHILE e # NIL DO
1312 Ro.SetPos(Ro.Pos() + dynsymEntrySizeVal);
1313 e := e.next
1314 END
1315 END;
1316 m := m.next
1317 END;
1318 Ro.SetPos(Ro.Pos() + 4);
1319 e := firstExp;
1320 WHILE e # NIL DO
1321 Write4(e.adr);
1322 Ro.SetPos(Ro.Pos() + 12);
1323 e := e.next
1324 END
1325 END FixupDynsymSection;
1327 PROCEDURE WriteStringTable (IN t: Strtab);
1328 VAR i: INTEGER;
1329 BEGIN
1330 i := 0;
1331 WHILE i # t.cur DO
1332 WriteCh(t.tab[i]);
1333 INC(i)
1334 END
1335 END WriteStringTable;
1337 PROCEDURE WriteDynstrSection;
1338 BEGIN
1339 ASSERT(Ro.Pos() = dynstr.fileOffset, 100);
1340 WriteStringTable(dynstrtab);
1341 ASSERT(dynstr.size = Ro.Pos() - dynstr.fileOffset, 101)
1342 END WriteDynstrSection;
1344 PROCEDURE Hash (name: ARRAY OF SHORTCHAR): INTEGER;
1345 VAR i, h, g: INTEGER;
1346 BEGIN
1347 h := 0; i := 0;
1348 WHILE name[i] # 0X DO
1349 h := ASH(h, 4) + ORD(name[i]);
1350 g := ORD(BITS(h) * BITS(0F0000000H));
1351 IF g # 0 THEN
1352 h := ORD(BITS(h) / BITS(SHORT((g MOD 100000000L) DIV 1000000H)))
1353 END;
1354 h := ORD(BITS(h) * (-BITS(g)));
1355 INC(i)
1356 END;
1357 RETURN h
1358 END Hash;
1360 PROCEDURE AddToChain (VAR c: ARRAY OF INTEGER; i, idx: INTEGER);
1361 VAR k: INTEGER;
1362 BEGIN
1363 IF c[i] # 0 THEN
1364 k := i;
1365 WHILE c[k] # 0 DO k := c[k] END;
1366 c[k] := idx
1367 ELSE
1368 c[i] := idx
1369 END
1370 END AddToChain;
1372 PROCEDURE WriteHashSection;
1373 VAR n, i, hi: INTEGER; b, c: POINTER TO ARRAY OF INTEGER;
1374 BEGIN
1375 ASSERT(hash.fileOffset = Ro.Pos(), 100);
1376 n := dynsym.size DIV dynsymEntrySizeVal; (* number of enties in the symbol table *)
1377 NEW(b, n);
1378 NEW(c, n);
1379 i := 0;
1380 WHILE i # n DO
1381 c[i] := 0; (* STN_UNDEF *)
1382 IF hashtab[i] # "" THEN
1383 hi := Hash(hashtab[i]) MOD n;
1384 IF b[hi] # 0 THEN (* another word has the same index *)
1385 AddToChain(c, i, b[hi]) (*c[i] := b[hi]*)
1386 END;
1387 b[hi] := i
1388 END;
1389 INC(i)
1390 END;
1391 Write4(n); (* nbucket *)
1392 Write4(n); (* nchain *)
1393 i := 0;
1394 WHILE i # n DO
1395 Write4(b[i]);
1396 INC(i)
1397 END;
1398 i := 0;
1399 WHILE i # n DO
1400 Write4(c[i]);
1401 INC(i)
1402 END;
1403 ASSERT(hash.size = Ro.Pos() - hash.fileOffset, 101)
1404 END WriteHashSection;
1406 PROCEDURE WriteGotSection;
1407 BEGIN
1408 ASSERT(got.fileOffset = Ro.Pos(), 100);
1409 Write4(dynamic.memOffset); (* addr of .dynamic section *)
1410 Write4(0); (* reserved for ? *)
1411 Write4(0); (* reserved for ? *)
1412 ASSERT(got.size = Ro.Pos() - got.fileOffset, 101)
1413 END WriteGotSection;
1415 PROCEDURE WriteDynamicSectionEntry (tag, val: INTEGER);
1416 BEGIN
1417 Write4(tag);
1418 Write4(val)
1419 END WriteDynamicSectionEntry;
1421 PROCEDURE WriteDynamicSection;
1422 CONST dtNull = 0; dtNeeded = 1; dtHash = 4; dtStrtab = 5; dtSymtab = 6;
1423 dtStrsz = 10; dtSyment = 11; dtInit = 12; dtFini = 13; dtSoname = 14; dtRel = 17; dtRelsz = 18; dtRelent = 19;
1424 dtTextrel = 22;
1425 VAR i: INTEGER;
1426 BEGIN
1427 ASSERT(dynamic.fileOffset = Ro.Pos(), 100);
1428 WriteDynamicSectionEntry(dtSoname, fixup);
1429 WriteDynamicSectionEntry(dtFini, fixup);
1430 WriteDynamicSectionEntry(dtInit, text.memOffset);
1431 WriteDynamicSectionEntry(dtHash, hash.memOffset);
1432 WriteDynamicSectionEntry(dtStrtab, dynstr.memOffset);
1433 WriteDynamicSectionEntry(dtSymtab, dynsym.memOffset);
1434 WriteDynamicSectionEntry(dtStrsz, dynstr.size);
1435 WriteDynamicSectionEntry(dtSyment, dynsymEntrySizeVal);
1436 WriteDynamicSectionEntry(dtRel, reltext.memOffset);
1437 WriteDynamicSectionEntry(dtRelsz, reltext.size + relrodata.size);
1438 WriteDynamicSectionEntry(dtRelent, relEntrySizeVal);
1439 i := 0;
1440 WHILE neededIdx[i] # 0 DO
1441 WriteDynamicSectionEntry(dtNeeded, neededIdx[i]);
1442 INC(i)
1443 END;
1444 WriteDynamicSectionEntry(dtTextrel, 0);
1445 WriteDynamicSectionEntry(dtNull, 0); (* DT_NULL: marks the end *)
1446 ASSERT(dynamic.size = Ro.Pos() - dynamic.fileOffset, 101)
1447 END WriteDynamicSection;
1449 PROCEDURE FixupDynamicSection;
1450 VAR i: INTEGER;
1451 BEGIN
1452 Ro.SetPos(dynamic.fileOffset + 4);
1453 Write4(sonameStrIndexVal);
1454 Ro.SetPos(Ro.Pos() + 4);
1455 Write4(finiMemOffsetVal)
1456 END FixupDynamicSection;
1458 PROCEDURE WriteBssSection;
1459 BEGIN
1460 (*
1461 The .bss section does not take space in the file.
1462 This procedure serves consistency-check purposes.
1463 *)
1464 ASSERT(bss.fileOffset = Ro.Pos(), 100)
1465 END WriteBssSection;
1467 PROCEDURE WriteShstrtabSection;
1468 BEGIN
1469 ASSERT(shstrtab.fileOffset = Ro.Pos(), 100);
1470 WriteStringTable(headerstrtab);
1471 shstrtab.size := Ro.Pos() - shstrtab.fileOffset
1472 END WriteShstrtabSection;
1474 PROCEDURE GetImpListSize (OUT len: INTEGER; OUT count: INTEGER);
1475 VAR m: Module; e: Export;
1476 BEGIN
1477 len := 0; count := 0;
1478 m := modList;
1479 WHILE m # NIL DO
1480 IF m.dll THEN
1481 e := m.exp;
1482 WHILE e # NIL DO
1483 INC(len, LEN(e.name$) + 1);
1484 INC(count);
1485 e := e.next
1486 END
1487 END;
1488 m := m.next
1489 END
1490 END GetImpListSize;
1492 PROCEDURE GetExpListSize (OUT len: INTEGER; OUT count: INTEGER);
1493 VAR e: Export;
1494 BEGIN
1495 count := 0; len := 0;
1496 e := firstExp;
1497 WHILE e # NIL DO
1498 INC(len, LEN(e.name$) + 1);
1499 INC(count);
1500 e := e.next
1501 END
1502 END GetExpListSize;
1504 PROCEDURE DynsymSize (init: INTEGER): INTEGER;
1505 VAR size: INTEGER;
1506 BEGIN
1507 size := init;
1508 INC(size, dynsymEntrySizeVal * 11); (* sections entries *)
1509 INC(size, dynsymEntrySizeVal); (* _DYNAMIC symbol *)
1510 INC(size, dynsymEntrySizeVal); (* _GLOBAL_OFFSET_TABLE_ symbol *)
1511 RETURN size
1512 END DynsymSize;
1514 PROCEDURE DynstrSize (init: INTEGER): INTEGER;
1515 VAR size: INTEGER;
1516 BEGIN
1517 size := init + 1;
1518 INC(size, dynstrtab.cur - 1);
1519 INC(size, LEN(soName$) + 1); (* library name *)
1520 INC(size, 9); (* "_DYNAMIC" symbol + 0X *)
1521 INC(size, 21 + 1); (* "_GLOBAL_OFFSET_TABLE_" symbol + trailing 0X *)
1522 RETURN size
1523 END DynstrSize;
1525 PROCEDURE DynamicSize (init: INTEGER): INTEGER;
1526 VAR i, size: INTEGER;
1527 BEGIN
1528 size := init;
1529 i := 0;
1530 WHILE neededIdx[i] # 0 DO
1531 INC(size, dynamicEntrySizeVal);
1532 INC(i)
1533 END;
1534 RETURN size
1535 END DynamicSize;
1537 PROCEDURE CalculateLayout;
1538 VAR headerSize, impCount, expCount, impLen, expLen: INTEGER;
1539 BEGIN
1540 ASSERT(~error, 20);
1541 headerSize := elfHeaderSizeVal + shEntrySizeVal * shNumVal + phEntrySizeVal * phNumVal;
1542 text.fileOffset := Aligned(headerSize, textAlign);
1543 text.memOffset := text.fileOffset;
1544 text.size := CodeSize;
1545 rodata.fileOffset := Aligned(text.fileOffset + text.size, rodataAlign);
1546 rodata.memOffset := rodata.fileOffset;
1547 rodata.size := ConSize;
1548 reltext.fileOffset := Aligned(rodata.fileOffset + rodata.size, relAlign);
1549 reltext.memOffset := reltext.fileOffset;
1550 doWrite := FALSE;
1551 WriteTextSection; (* this only calculates the number of text relocations *)
1552 IF error THEN RETURN END;
1553 reltext.size := relEntrySizeVal * relTextTab.cur;
1554 relrodata.fileOffset := reltext.fileOffset + reltext.size;
1555 relrodata.memOffset := relrodata.fileOffset;
1556 IF ~error THEN
1557 WriteRodataSection (* this only calculates the number of data relocations *)
1558 ELSE
1559 RETURN
1560 END;
1561 relrodata.size := relEntrySizeVal * relRodataTab.cur;
1562 dynsym.fileOffset := Aligned(relrodata.fileOffset + relrodata.size, dynsymAlign);
1563 dynsym.memOffset := dynsym.fileOffset;
1564 GetImpListSize(impLen, impCount);
1565 GetExpListSize(expLen, expCount);
1566 dynsym.size := DynsymSize((impCount + expCount) * dynsymEntrySizeVal);
1567 dynstr.fileOffset := Aligned(dynsym.fileOffset + dynsym.size, dynstrAlign);
1568 dynstr.memOffset := dynstr.fileOffset;
1569 dynstr.size := DynstrSize(impLen + expLen);
1570 hash.fileOffset := Aligned(dynstr.fileOffset + dynstr.size, hashAlign);
1571 hash.memOffset := hash.fileOffset;
1572 hash.size := 8 + dynsym.size DIV dynsymEntrySizeVal * 4 * 2;
1573 got.fileOffset := Aligned(hash.fileOffset + hash.size, gotAlign);
1574 got.memOffset := Aligned(got.fileOffset, pageSize) + got.fileOffset MOD pageSize;
1575 got.size := 3 * gotEntrySizeVal;
1576 dynamic.fileOffset := Aligned(got.fileOffset + got.size, dynamicAlign);
1577 dynamic.memOffset := got.memOffset + dynamic.fileOffset - got.fileOffset;
1578 dynamic.size := DynamicSize(13 * dynamicEntrySizeVal);
1579 bss.fileOffset := Aligned(dynamic.fileOffset + dynamic.size, bssAlign);
1580 bss.memOffset := dynamic.memOffset + bss.fileOffset - dynamic.fileOffset;
1581 bss.size := DataSize;
1582 shstrtab.fileOffset := Aligned(bss.fileOffset, shstrtabAlign);
1583 shstrtab.size := fixup;
1584 textSegmentSizeVal := got.fileOffset;
1585 dataSegmentSizeVal := shstrtab.fileOffset - got.fileOffset;
1586 dynamicSegmentSizeVal := shstrtab.fileOffset - dynamic.fileOffset;
1587 relTextTab.cur := 0;
1588 relRodataTab.cur := 0;
1589 firstExp := NIL; lastExp := NIL;
1590 doWrite := TRUE
1591 END CalculateLayout;
1593 PROCEDURE WriteOut;
1594 VAR res: INTEGER;
1595 BEGIN
1596 ASSERT(~error, 20);
1597 Out := Files.dir.New(Files.dir.This(""), Files.ask);
1598 IF Out # NIL THEN
1599 Ro := Out.NewWriter(Ro); Ro.SetPos(0);
1600 CalculateLayout;
1601 IF ~error THEN WriteElfHeader END;
1602 IF ~error THEN WriteSectionHeaderTable END;
1603 IF ~error THEN WriteProgramHeaderTable END;
1604 IF ~error THEN Align(textAlign); WriteTextSection END;
1605 IF ~error THEN Align(rodataAlign); WriteRodataSection END;
1606 IF ~error THEN Align(relAlign); WriteRelSections END;
1607 IF ~error THEN Align(dynsymAlign); WriteDynsymSection END;
1608 IF ~error THEN Align(dynstrAlign); WriteDynstrSection END;
1609 IF ~error THEN Align(hashAlign); WriteHashSection END;
1610 IF ~error THEN Align(gotAlign); WriteGotSection END;
1611 IF ~error THEN Align(dynamicAlign); WriteDynamicSection END;
1612 IF ~error THEN Align(bssAlign); WriteBssSection END;
1613 IF ~error THEN Align(shstrtabAlign); WriteShstrtabSection END;
1615 IF ~error THEN FixupElfHeader END;
1616 IF ~error THEN FixupSectionHeaderTable END;
1617 IF ~error THEN FixupTextSection END;
1618 IF ~error THEN FixupDynsymSection END;
1619 IF ~error THEN FixupDynamicSection END;
1620 Out.Register(soName$, "so", Files.ask, res);
1621 IF res # 0 THEN error := TRUE END
1622 ELSE
1623 error := TRUE
1624 END
1625 END WriteOut;
1627 PROCEDURE ResetHashtab;
1628 VAR i: INTEGER;
1629 BEGIN
1630 i := 0;
1631 WHILE i # LEN(hashtab) DO
1632 hashtab[i] := "";
1633 INC(i)
1634 END
1635 END ResetHashtab;
1637 PROCEDURE ResetNeededIdx;
1638 VAR i: INTEGER;
1639 BEGIN
1640 i := 0;
1641 WHILE i # LEN(neededIdx) DO
1642 neededIdx[i] := 0;
1643 INC(i)
1644 END
1645 END ResetNeededIdx;
1647 PROCEDURE MakeSoName (VAR name: ARRAY OF CHAR; type: ARRAY OF CHAR);
1648 VAR i, j: INTEGER; ext: Files.Name; ch: CHAR;
1649 BEGIN
1650 ASSERT((type = "") OR (type[0] = "."), 20);
1651 i := 0;
1652 WHILE (name[i] # 0X) & (name[i] # ".") DO INC(i) END;
1653 IF name[i] = "." THEN
1654 IF name[i + 1] = 0X THEN name[i] := 0X END
1655 ELSIF i < LEN(name) - (LEN(type$) + 1) THEN
1656 IF type = "" THEN ext := ".so" ELSE ext := type$ END;
1657 j := 0; ch := ext[0];
1658 WHILE ch # 0X DO
1659 IF (ch >= "A") & (ch <= "Z") THEN
1660 ch := CHR(ORD(ch) + ORD("a") - ORD("A"))
1661 END;
1662 name[i] := ch; INC(i); INC(j); ch := ext[j]
1663 END;
1664 name[i] := 0X
1665 END
1666 END MakeSoName;
1668 (* A. V. Shiryaev: Scanner *)
1670 PROCEDURE (VAR S: Scanner) SetPos (x: INTEGER), NEW;
1671 BEGIN
1672 S.rider.i := x
1673 END SetPos;
1675 PROCEDURE (VAR S: Scanner) ConnectTo (IN src: ARRAY OF CHAR), NEW;
1676 BEGIN
1677 NEW(S.rider.s, LEN(src$) + 1);
1678 S.rider.s^ := src$;
1679 S.rider.i := 0;
1680 S.start := 0;
1681 S.type := TMEOT
1682 END ConnectTo;
1684 PROCEDURE (VAR R: ScanRider) ReadPrevChar (VAR ch: CHAR), NEW;
1685 BEGIN
1686 ch := R.s[R.i]
1687 END ReadPrevChar;
1689 PROCEDURE (VAR R: ScanRider) ReadChar (VAR ch: CHAR), NEW;
1690 BEGIN
1691 ch := R.s[R.i];
1692 INC(R.i)
1693 END ReadChar;
1695 PROCEDURE (VAR R: ScanRider) Pos (): INTEGER, NEW;
1696 BEGIN
1697 RETURN R.i
1698 END Pos;
1700 PROCEDURE (VAR S: Scanner) Scan, NEW;
1701 VAR j: INTEGER;
1703 PROCEDURE IsLetter (c: CHAR): BOOLEAN;
1704 BEGIN
1705 RETURN ((c >= 'A') & (c <= 'Z')) OR ((c >= 'a') & (c <= 'z')) OR (c = '_')
1706 END IsLetter;
1708 PROCEDURE IsDigit (c: CHAR): BOOLEAN;
1709 BEGIN
1710 RETURN (c >= '0') & (c <= '9')
1711 END IsDigit;
1713 BEGIN
1714 WHILE (S.rider.i < LEN(S.rider.s$)) & (S.rider.s[S.rider.i] = ' ') DO
1715 INC(S.rider.i)
1716 END;
1717 IF S.rider.i < LEN(S.rider.s$) THEN
1718 S.start := S.rider.i;
1719 IF IsDigit(S.rider.s[S.rider.i]) THEN
1720 S.type := TMEOT (* XXX *)
1721 ELSIF IsLetter(S.rider.s[S.rider.i]) THEN
1722 S.type := TMString;
1723 j := 0;
1724 WHILE (S.rider.i < LEN(S.rider.s$)) & (IsLetter(S.rider.s[S.rider.i]) OR IsDigit(S.rider.s[S.rider.i])) DO
1725 S.string[j] := S.rider.s[S.rider.i];
1726 INC(j);
1727 INC(S.rider.i)
1728 END;
1729 S.string[j] := 0X
1730 ELSE
1731 S.type := TMChar;
1732 S.char := S.rider.s[S.rider.i];
1733 INC(S.rider.i)
1734 END
1735 ELSE
1736 S.type := TMEOT
1737 END
1738 END Scan;
1740 PROCEDURE ParseExt (IN S: Scanner; OUT ext: Files.Name);
1741 VAR ch: CHAR; i: INTEGER;
1742 BEGIN
1743 ext := "";
1744 S.rider.ReadPrevChar(ch);
1745 IF ch = "." THEN
1746 S.rider.ReadChar(ch);
1747 i := 0;
1748 WHILE (ch # 20X) & (ch # 9X) DO
1749 ext[i] := ch;
1750 INC(i);
1751 S.rider.ReadChar(ch)
1752 END;
1753 ext[i] := 0X
1754 ELSIF (ch # 20X) & (ch # 9X) THEN
1755 WriteSString("Invalid character '");WriteChar(ch); WriteSString("' for file name.");
1756 WriteLn; FlushW; error := TRUE
1757 END;
1758 S.SetPos(S.rider.Pos())
1759 END ParseExt;
1761 PROCEDURE ParseModList (S: Scanner; end: INTEGER);
1762 VAR mod: Module;
1763 BEGIN
1764 WHILE (S.start < end) & (S.type = TMString) DO
1765 NEW(mod); mod.fileName := S.string$;
1766 mod.next := modList; modList := mod;
1767 S.Scan;
1768 WHILE (S.start < end) & (S.type = TMChar) &
1769 ((S.char = "*") OR (S.char = "+") OR (S.char = "$") OR (S.char = "#")) DO
1770 IF S.char = "*" THEN mod.dll := TRUE
1771 ELSIF S.char = "+" THEN kernel := mod
1772 ELSIF S.char = "$" THEN main := mod
1773 ELSE mod.intf := TRUE;
1774 ASSERT(isDll, 126);
1775 IF ~isDll THEN
1776 WriteSString("Exports from Exe not possible. Use LinkDll or LinkDynDll.");
1777 WriteLn; FlushW; error := TRUE
1778 END
1779 END;
1780 S.Scan
1781 END
1782 END
1783 END ParseModList;
1785 PROCEDURE LinkIt (IN txt: ARRAY OF CHAR);
1786 VAR S: Scanner; name, ext: Files.Name; end: INTEGER;
1787 BEGIN
1788 doWrite := TRUE;
1789 headerstrtab.tab[0] := 0X;
1790 headerstrtab.cur := 1;
1791 dynstrtab.tab[0] := 0X;
1792 dynstrtab.cur := 1;
1793 relTextTab.cur := 0;
1794 relRodataTab.cur := 0;
1795 ResetHashtab;
1796 ResetNeededIdx;
1797 modList := NIL; kernel := NIL; main := NIL;
1798 last := NIL; impg := NIL; impd := NIL;
1799 firstExp := NIL; lastExp := NIL;
1800 (* Dialog.ShowStatus("linking"); *)
1801 Console.WriteStr("linking"); Console.WriteLn;
1802 error := FALSE; modList := NIL;
1804 (*
1805 IF DevCommanders.par = NIL THEN RETURN END;
1806 S.ConnectTo(DevCommanders.par.text);
1807 S.SetPos(DevCommanders.par.beg);
1808 end := DevCommanders.par.end;
1809 DevCommanders.par := NIL;
1810 *)
1812 S.ConnectTo(txt);
1813 S.SetPos(0);
1814 end := LEN(txt$);
1816 S.Scan;
1818 IF S.type = TMString THEN
1819 name := S.string$;
1820 ext := "";
1821 ParseExt(S, ext); S.Scan;
1822 IF ~error THEN
1823 MakeSoName(name, ext);
1824 IF (S.type = TMChar) & (S.char = ":") THEN S.Scan;
1825 IF (S.type = TMChar) & (S.char = "=") THEN S.Scan;
1826 ParseModList(S, end);
1827 ReadHeaders;
1828 soName := SHORT(name$);
1829 IF ~error THEN
1830 WriteOut
1831 END;
1832 IF ~error THEN
1833 WriteString("Library " + name + " written: ");
1834 WriteInt(Out.Length()); WriteString(" "); WriteInt(text.size)
1835 END
1836 ELSE
1837 error := TRUE;
1838 WriteString(" := missing")
1839 END
1840 ELSE
1841 error := TRUE;
1842 WriteString(" := missing")
1843 END;
1844 WriteLn; FlushW
1845 END
1846 END;
1847 (* IF error THEN Dialog.ShowStatus("Failed to write library") ELSE Dialog.ShowStatus("Ok") END; *)
1848 IF error THEN Console.WriteStr("Failed to write library"); Console.WriteLn ELSE Console.WriteStr("Ok"); Console.WriteLn END;
1849 S.ConnectTo("");
1850 modList := NIL; kernel := NIL; main := NIL; firstExp := NIL; lastExp := NIL;
1851 last := NIL; impg := NIL; impd := NIL; code := NIL
1852 END LinkIt;
1854 (*
1855 exes are not supported
1857 PROCEDURE Link*;
1858 BEGIN
1859 HALT(126);
1860 isDll := FALSE; isStatic := FALSE;
1861 LinkIt
1862 END Link;
1864 PROCEDURE LinkExe*;
1865 BEGIN
1866 HALT(126);
1867 isDll := FALSE; isStatic := TRUE;
1868 LinkIt
1869 END LinkExe;
1870 *)
1872 PROCEDURE LinkDll* (IN txt: ARRAY OF CHAR);
1873 BEGIN
1874 isDll := TRUE; isStatic := TRUE;
1875 LinkIt(txt)
1876 END LinkDll;
1878 PROCEDURE LinkDynDll* (IN txt: ARRAY OF CHAR);
1879 BEGIN
1880 isDll := TRUE; isStatic := FALSE;
1881 LinkIt(txt)
1882 END LinkDynDll;
1884 BEGIN
1885 newRec := "NewRec"; newArr := "NewArr"
1886 END Dev0ElfLinker.
1888 LinTestSo LinTestSo2 LinKernel
1890 DevElfLinker.LinkDynDll libtestbb.so := LinKernel+$ LinTestSo2 LinTestSo# ~
1891 DevElfLinker.LinkDll libtestbb.so := LinTestSo2 LinTestSo# ~