Browse Source

ConsCompiler added

Alexander Shiryaev 12 years ago
parent
commit
47b261cc8d

BIN
BlackBox/Cons/Mod/Compiler.odc


+ 2 - 2
BlackBox/Interp.txt → BlackBox/Cons/Mod/Interp.txt

@@ -1,4 +1,4 @@
-MODULE Interp;
+MODULE ConsInterp;
 
 	(*
 		A. V. Shiryaev, 2012.09
@@ -100,4 +100,4 @@ MODULE Interp;
 		END
 	END Run;
 
-END Interp.
+END ConsInterp.

+ 0 - 1740
BlackBox/Dev/Mod/ElfLinker16.txt

@@ -1,1740 +0,0 @@
-MODULE DevElfLinker;
-
-	(* THIS IS TEXT COPY OF OpenBUGS Dev/Mod/ElfLinker16.odc *)
-	(* DO NOT EDIT *)
-
-(*
-	DevElfLinker version compatible with BlackBox Component Builder release 1.6.
-	This module will replace DevElfLinker, once the final version of BlackBox 1.6 will be released.
-*)
-
-	IMPORT
-		Strings,
-		Kernel, Files, Dialog,
-		TextMappers,
-		StdLog, DevCommanders;
-
-	CONST
-		NewRecFP = 4E27A847H;
-		NewArrFP = 76068C78H;
-
-		OFdir = "Code";
-		SYSdir = "System";
-
-		(* meta interface consts *)
-		mConst = 1; mTyp = 2; mVar = 3; mProc = 4;
-		mInternal = 1; mExported = 4;
-
-		(* mod desc fields *)
-		modOpts = 4; modRefcnt = 8; modTerm = 40; modNames = 84; modImports = 92; modExports = 96;
-
-		(* .dynsym entries *)
-		stbLocal = 0; stbGlobal = 1;
-		sttNotype = 0; sttObject = 1; sttFunc = 2; sttSection = 3;
-		shnUnd = 0; shnAbs = 0FFF1H;
-
-		fixup = 0;
-		noSymbol = MIN(INTEGER);
-		noAddr = MIN(INTEGER);
-		firstDllSymbolVal = 12;
-
-		(* distinguished section header indexes. *)
-		textIndexVal = 1;	(* index of the .text section header in the section header table *)
-		rodataIndexVal = 3;	(* index of the .rodata section header in the section header table *)
-		dynsymIndexVal = 5;	(* index of the .dynsym section header in the section header table *)
-		dynstrIndexVal = 6;	(* index of the .dynstr section header in the section header table *)
-
-		(* fixed elements dimensions *)
-		elfHeaderSizeVal = 52;	(* size of the ELF file header *)
-		shEntrySizeVal = 40;	(* size of an entry in the section header table *)
-		dynsymEntrySizeVal = 16; (* size of a symbol table entry *)
-		dynamicEntrySizeVal = 8; (* size of an entry in the dynamic section *)
-		gotEntrySizeVal = 4; (* size of an entry in the got section *)
-		relEntrySizeVal = 8; (* size of an entry in a relocation section *)
-		phEntrySizeVal = 32; (* size of an entry in the program header *)
-
-		shNumVal = 12; (* number of entries in the section header table. See WriteSectionHeaderTable *)
-		shStrndxVal = shNumVal - 1; (* index of the string table for section names. See WriteSectionHeaderTable *)
-		phNumVal = 3; (* number of entries in the program header table *)
-
-		(* sections alignments (in bytes) *)
-		textAlign = 4H;
-		dynsymAlign = 4H;
-		dynstrAlign = 1H;
-		hashAlign = 4H;
-		gotAlign = 4H;
-		dynamicAlign = 4H;
-		shstrtabAlign = 1H;
-		bssAlign = 4H;
-		rodataAlign = 8H;
-		relAlign = 4H;
-
-		pageSize = 1000H; (* I386 page size *)
-
-		r38632 = 1; r386pc32 = 2; r386Relative = 8; (* ELF relocation types *)
-
-	TYPE
-		Name = ARRAY 40 OF SHORTCHAR;
-
-		Export = POINTER TO RECORD
-			next: Export;
-			name: Name;
-			adr: INTEGER
-		END;
-
-		Module = POINTER TO RECORD
-			next: Module;
-			name: Name;
-			fileName: Files.Name;
-			file: Files.File;
-			hs, ms, ds, cs, vs, ni, ma, ca, va: INTEGER;
-			dll, intf: BOOLEAN;
-			exp: Export;
-			imp: POINTER TO ARRAY OF Module;
-			data: POINTER TO ARRAY OF BYTE
-		END;
-
-		Strtab = RECORD
-			tab: ARRAY 4096 OF SHORTCHAR;
-			cur: INTEGER
-		END;
-
-		Relocation = RECORD
-			offset, type: INTEGER
-		END;
-
-		RelTab = RECORD
-			tab: ARRAY 65536 OF Relocation;
-			cur: INTEGER
-		END;
-
-		Section = RECORD
-			fileOffset,
-			memOffset,
-			size: INTEGER
-		END;
-
-	VAR
-		W: TextMappers.Formatter;
-		Out: Files.File;
-		R: Files.Reader;
-		Ro: Files.Writer;
-		error, isDll, isStatic: BOOLEAN;
-		modList, kernel, main, last, impg, impd: Module;
-		numMod, lastTerm: INTEGER;
-		firstExp, lastExp: Export;
-		CodeSize, DataSize, ConSize: INTEGER;
-		maxCode, numExp: INTEGER;
-		newRec, newArr: Name;
-		code: POINTER TO ARRAY OF BYTE;
-
-		(* fixup positions *)
-		entryPos,
-		expPos,
-		shstrtabPos,
-		finiPos: INTEGER;
-
-		(* sections *)
-		text, reltext, relrodata, rodata, dynstr, shstrtab, hash, got, dynsym, dynamic, bss: Section;
-
-		(* distinguished file and memory offsets *)
-		shOffsetVal,	(* section header table file offset *)
-		phOffsetVal,	(* program header table file offset *)
-		finiMemOffsetVal: INTEGER;	(* memory offset (aka virtual address) of the finalization code (CLOSE sections) *)
-
-		dynsymInfoVal,	(* value of the info field for the .dynsym section *)
-		sonameStrIndexVal: INTEGER;	(* string table index of the name of hte library *)
-
-		(* segment dimensions *)
-		textSegmentSizeVal,
-		dataSegmentSizeVal,
-		dynamicSegmentSizeVal: INTEGER;
-
-		headerstrtab, dynstrtab: Strtab;
-		hashtab: ARRAY 256 OF Name;
-
-		neededIdx: ARRAY 256 OF INTEGER;
-
-		relTextTab, relRodataTab: RelTab;
-
-		soName: Name;
-
-		doWrite: BOOLEAN;
-
-	PROCEDURE (VAR t: Strtab) AddName (IN s: ARRAY OF SHORTCHAR; OUT idx: INTEGER), NEW;
-		VAR i: INTEGER;
-	BEGIN
-		ASSERT((t.cur + LEN(s$)) <= LEN(t.tab), 20); (* table buffer not large enough: TODO enlarge? *)
-		idx := t.cur;
-		i := 0;
-		WHILE s[i] # 0X DO
-			t.tab[t.cur] := s[i];
-			INC(i); INC(t.cur)
-		END;
-		t.tab[t.cur] := s[i]; (* copy the 0X *)
-		INC(t.cur)
-	END AddName;
-
-	PROCEDURE (VAR t: RelTab) Add (offset, type: INTEGER), NEW;
-	BEGIN
-		ASSERT(t.cur < LEN(t.tab), 20); (* table buffer not large enough: TODO enlarge? *)
-		t.tab[t.cur].offset := offset;		
-		t.tab[t.cur].type := type;
-		INC(t.cur)
-	END Add;
-
-	PROCEDURE AddNeededIdx (idx: INTEGER);
-		VAR i, len: INTEGER;
-	BEGIN
-		ASSERT(idx > 0, 20);	(* index must be positive *)
-		len := LEN(neededIdx);
-		i := 0;
-		WHILE (i # len) & (neededIdx[i] # 0) DO INC(i) END;
-		IF i # len THEN
-			neededIdx[i] := idx
-		ELSE
-			HALT(21)	(* no more space for indexes *)
-		END
-	END AddNeededIdx;
-
-	PROCEDURE ThisFile (modname: ARRAY OF CHAR): Files.File;
-		VAR dir, name: Files.Name; loc: Files.Locator; f: Files.File;
-	BEGIN
-		Kernel.SplitName(modname, dir, name);
-		Kernel.MakeFileName(name, Kernel.objType);
-		loc := Files.dir.This(dir); loc := loc.This(OFdir);
-		f := Files.dir.Old(loc, name, TRUE);
-		IF (f = NIL) & (dir = "") THEN
-			loc := Files.dir.This(SYSdir); loc := loc.This(OFdir);
-			f := Files.dir.Old(loc, name, TRUE)
-		END;
-		RETURN f
-	END ThisFile;
-
-	PROCEDURE Read4 (VAR x: INTEGER);
-		VAR b: BYTE;
-	BEGIN
-		R.ReadByte(b); x := b MOD 256;
-		R.ReadByte(b); x := x + 100H * (b MOD 256);
-		R.ReadByte(b); x := x + 10000H * (b MOD 256);
-		R.ReadByte(b); x := x + 1000000H * b
-	END Read4;
-
-	PROCEDURE ReadName (VAR name: ARRAY OF SHORTCHAR);
-		VAR i: INTEGER; b: BYTE;
-	BEGIN i := 0;
-		REPEAT
-			R.ReadByte(b); name[i] := SHORT(CHR(b)); INC(i)
-		UNTIL b = 0
-	END ReadName;
-
-	PROCEDURE RNum (VAR i: INTEGER);
-		VAR b: BYTE; s, y: INTEGER;
-	BEGIN
-		s := 0; y := 0; R.ReadByte(b);
-		WHILE b < 0 DO INC(y, ASH(b + 128, s)); INC(s, 7); R.ReadByte(b) END;
-		i := ASH((b + 64) MOD 128 - 64, s) + y
-	END RNum;
-
-	PROCEDURE WriteCh (ch: SHORTCHAR);
-	BEGIN
-		IF doWrite THEN
-		Ro.WriteByte(SHORT(ORD(ch)))
-		END
-	END WriteCh;
-
-	PROCEDURE Write2 (x: INTEGER);
-	BEGIN
-		IF doWrite THEN
-			Ro.WriteByte(SHORT(SHORT(x MOD 256))); x := x DIV 256;
-			Ro.WriteByte(SHORT(SHORT(x MOD 256)))
-		END
-	END Write2;
-
-	PROCEDURE Write4 (x: INTEGER);
-	BEGIN
-		IF doWrite THEN
-			Ro.WriteByte(SHORT(SHORT(x MOD 256))); x := x DIV 256;
-			Ro.WriteByte(SHORT(SHORT(x MOD 256))); x := x DIV 256;
-			Ro.WriteByte(SHORT(SHORT(x MOD 256))); x := x DIV 256;
-			Ro.WriteByte(SHORT(SHORT(x MOD 256)))
-		END
-	END Write4;
-
-	PROCEDURE WriteBytes (IN x: ARRAY OF BYTE; beg, len: INTEGER);
-	BEGIN
-		IF doWrite THEN
-			Ro.WriteBytes(x, beg, len)
-		END
-	END WriteBytes;
-
-	PROCEDURE Align (alignment: INTEGER);
-	BEGIN
-		WHILE Ro.Pos() MOD alignment # 0 DO WriteCh(0X) END
-	END Align;
-	
-	PROCEDURE Aligned (pos, alignment: INTEGER): INTEGER;
-	BEGIN
-		RETURN (pos + (alignment - 1)) DIV alignment * alignment
-	END Aligned;
-	
-	PROCEDURE Put (mod: Module; a, x: INTEGER);
-	BEGIN
-		ASSERT((mod.data # NIL) & ((a >= 0) & (a <= LEN(mod.data))), 20);
-		mod.data[a] := SHORT(SHORT(x)); INC(a); x := x DIV 256;
-		mod.data[a] := SHORT(SHORT(x)); INC(a); x := x DIV 256;
-		mod.data[a] := SHORT(SHORT(x)); INC(a); x := x DIV 256;
-		mod.data[a] := SHORT(SHORT(x))
-	END Put;
-
-	PROCEDURE Get (mod: Module; a: INTEGER; VAR x: INTEGER);
-	BEGIN
-		ASSERT((mod.data # NIL) & ((a >= 0) & (a + 3 <= LEN(mod.data))), 20);
-		x := ((mod.data[a + 3] * 256 +
-			(mod.data[a + 2] MOD 256)) * 256 +
-			(mod.data[a + 1] MOD 256)) * 256 +
-			(mod.data[a] MOD 256)
-	END Get;
-
-	PROCEDURE CheckDllImports (mod: Module);
-		VAR i, x, y: INTEGER; name: Name; imp: Module; exp: Export;
-
-		PROCEDURE SkipLink;
-			VAR a: INTEGER;
-		BEGIN
-			RNum(a);
-			WHILE a # 0 DO RNum(a); RNum(a) END
-		END SkipLink;
-
-	BEGIN
-		R := mod.file.NewReader(R);
-		R.SetPos(mod.hs + mod.ms + mod.ds + mod.cs);
-		SkipLink; SkipLink; SkipLink; SkipLink; SkipLink; SkipLink;
-		i := 0;
-		WHILE i < mod.ni DO
-			imp := mod.imp[i];
-			IF imp # NIL THEN
-				RNum(x);
-				WHILE x # 0 DO
-					ReadName(name); RNum(y);
-					IF x = mVar THEN
-						SkipLink;
-						IF imp.dll THEN
-							exp := imp.exp;
-							WHILE (exp # NIL) & (exp.name # name) DO exp := exp.next END;
-							IF exp = NIL THEN
-								NEW(exp); exp.name := name$;
-								exp.next := imp.exp; imp.exp := exp
-							 END
-						END
-					ELSIF x = mTyp THEN RNum(y);
-						IF imp.dll THEN
-							RNum(y);
-							IF y # 0 THEN
-								W.WriteString("type descriptor (");
-								W.WriteString(imp.name$); W.WriteChar(".");
-								W.WriteSString(name);
-								W.WriteString(") imported from DLL in ");
-								W.WriteString(mod.name$);
-								W.WriteLn; StdLog.text.Append(StdLog.buf); error := TRUE;
-								RETURN
-							END
-						ELSE SkipLink
-						END
-					ELSIF x = mProc THEN
-						IF imp.dll THEN
-							SkipLink;
-							exp := imp.exp;
-							WHILE (exp # NIL) & (exp.name # name) DO exp := exp.next END;
-							IF exp = NIL THEN
-								NEW(exp); exp.name := name$;
-								exp.next := imp.exp; imp.exp := exp
-							 END
-						END
-					END;
-					RNum(x)
-				END
-			END;
-			INC(i)
-		END
-	END CheckDllImports;
-
-	PROCEDURE ReadHeaders;
-		VAR mod, im, t: Module; x, i, pos: INTEGER; impdll: BOOLEAN; name: Name;
-	BEGIN
-		ASSERT(isDll, 126);
-		mod := modList; modList := NIL; numMod := 0;
-		WHILE mod # NIL DO	(* reverse mod list & count modules *)
-			IF ~mod.dll THEN INC(numMod) END;
-			t := mod; mod := t.next; t.next := modList; modList := t
-		END;
-		IF isStatic THEN
-			CodeSize :=
-				6 + 5 * numMod + 2	(* _init() *)
-				+ 1 + 5 * numMod + 2	(* _fini() *)
-		ELSE
-			CodeSize :=
-				6 + 5 + 2	(* _init() *)
-				+ 1 + 5 + 2	(* _fini() *)
-		END;
-		DataSize := 0; ConSize := 0;
-		maxCode := 0; numExp := 0;
-		mod := modList;
-		WHILE mod # NIL DO
-			IF ~mod.dll THEN
-				mod.file := ThisFile(mod.fileName);
-				IF mod.file # NIL THEN
-					R := mod.file.NewReader(R); R.SetPos(0);
-					Read4(x);
-					IF x = 6F4F4346H THEN
-						Read4(x);
-						Read4(mod.hs); Read4(mod.ms); Read4(mod.ds); Read4(mod.cs);
-						Read4(mod.vs); RNum(mod.ni); ReadName(mod.name); impdll := FALSE;
-						IF mod.ni > 0 THEN
-							NEW(mod.imp, mod.ni);
-							x := 0;
-							WHILE x < mod.ni DO
-								ReadName(name);
-								IF name = "$$" THEN
-									IF (mod # kernel) & (kernel # NIL) THEN
-										mod.imp[x] := kernel
-									ELSE
-										W.WriteSString("no kernel"); W.WriteLn;
-										StdLog.text.Append(StdLog.buf); error := TRUE
-									END
-								ELSIF name[0] = "$" THEN
-									StdLog.String(name$); 
-									i := 1;
-									WHILE name[i] # 0X DO name[i-1] := name[i]; INC(i) END;
-									name[i-1] := 0X; 
-									IF i # 1 THEN
-										Strings.Find(name$, ".so", 0, pos);
-										IF pos = -1 THEN
-											name[i - 1] := "."; name[i] := "s"; name[i + 1] := "o"; name[i + 2] := 0X
-										END
-									END;
-									StdLog.String("  "); StdLog.String(name$); StdLog.Ln;
-									impdll := TRUE; im := modList;
-									WHILE (im # mod) & (im.name # name) DO im := im.next END;
-									IF (im = NIL) OR ~im.dll THEN
-										NEW(im); im.next := modList; modList := im;
-										im.dll := TRUE;
-										im.name := name$; 
-										dynstrtab.AddName(name, i);
-										AddNeededIdx(i)
-									END;
-									mod.imp[x] := im
-								ELSE
-									im := modList;
-									WHILE (im # mod) & (im.name # name) DO im := im.next END;
-									IF im # mod THEN
-										mod.imp[x] := im
-									ELSE
-										W.WriteSString(name);
-										W.WriteString(" not present (imported in ");
-										W.WriteString(mod.name$); W.WriteChar(")");
-										W.WriteLn; StdLog.text.Append(StdLog.buf); error := TRUE
-									END
-								END;
-								INC(x)
-							END
-						END;
-						IF impdll & ~error THEN CheckDllImports(mod) END;
-						mod.ma := ConSize; INC(ConSize, mod.ms + mod.ds);
-						mod.va := DataSize; INC(DataSize, mod.vs);
-						mod.ca := CodeSize; INC(CodeSize, mod.cs);
-						IF mod.cs > maxCode THEN maxCode := mod.cs END
-					ELSE
-						W.WriteString(mod.name$); W.WriteString(": wrong file type"); 
-						W.WriteLn; StdLog.text.Append(StdLog.buf); error := TRUE
-					END;
-					mod.file.Close; mod.file := NIL
-				ELSE
-					W.WriteString(mod.name$); W.WriteString(" not found"); 
-					W.WriteLn; StdLog.text.Append(StdLog.buf); error := TRUE
-				END;
-				last := mod
-			END;
-			mod := mod.next
-		END;
-		IF ~isStatic & (main = NIL) THEN
-			W.WriteSString("no main module specified"); W.WriteLn;
-			StdLog.text.Append(StdLog.buf); error := TRUE
-		END;
-		IF DataSize = 0 THEN DataSize := 1 END
-	END ReadHeaders;
-
-	PROCEDURE WriteElfHeader;
-	BEGIN
-		ASSERT(Ro.Pos() = 0, 100);
-		dynstrtab.AddName(soName$, sonameStrIndexVal);
-		Write4(464C457FH); Write4(00010101H); Write4(0); Write4(0); (* Magic *)
-		Write2(3); (* ET_DYN e_type Object file type *)
-		Write2(3); (* EM_386 e_machine Architecture *)
-		Write4(1); (* EV_CURRENT e_version Object file version *)
-		Write4(text.memOffset); (* e_entry Entry point virtual address *)
-		entryPos := Ro.Pos();
-		Write4(fixup); (* e_phoff Program header table file offset *)
-		Write4(fixup); (* e_shoff: Section header table file offset *)
-		Write4(0); (* e_flags Processor-specific flags *)
-		Write2(elfHeaderSizeVal); (* e_ehsize ELF header size in bytes *)
-		Write2(phEntrySizeVal); (* e_phentsize Program header table entry size *)
-		Write2(phNumVal); (* e_phnum Program header table entry count *)
-		Write2(shEntrySizeVal); (* e_shentsize Section header table entry size *)
-		Write2(shNumVal); (* e_shnum Section header table entry count *)
-		Write2(shStrndxVal); (* e_shstrndx Section header string table index *)
-		ASSERT(Ro.Pos() = elfHeaderSizeVal, 101)
-	END WriteElfHeader;
-
-	PROCEDURE FixupElfHeader;
-	BEGIN
-		Ro.SetPos(entryPos);
-		Write4(phOffsetVal);
-		Write4(shOffsetVal)
-	END FixupElfHeader;
-
-	PROCEDURE WriteNullSectionHeader;
-	BEGIN
-		Write4(0); (* sh_name Section name (string tbl index) *)
-		Write4(0); (* SHT_NULL sh_type Section type *)
-		Write4(0); (* sh_flags Section flags *)
-		Write4(0); (* ELF header + program header table; sh_addr Section virtual addr at execution *)
-		Write4(0); (* sh_offset Section file offset *)
-		Write4(0); (* sh_size Section size in bytes *)
-		Write4(0); (* SHN_UNDEF sh_link Link to another section *)
-		Write4(0); (* sh_info Additional section information *)
-		Write4(0); (* sh_addralign Section alignment *)
-		Write4(0) (* sh_entsize Entry size if section holds table *)
-	END WriteNullSectionHeader;
-
-	PROCEDURE WriteTextSectionHeader;
-		VAR i: INTEGER;
-	BEGIN
-		headerstrtab.AddName(".text", i);
-		Write4(i); (* sh_name Section name (string tbl index) *)
-		Write4(1); (* SHT_PROGBITS sh_type Section type *)
-		Write4(2H + 4H); (* SHF_ALLOC + SHF_EXECINSTR sh_flags Section flags *)
-		Write4(text.memOffset); (* sh_addr Section virtual addr at execution *)
-		Write4(text.fileOffset); (* sh_offset Section file offset *)
-		Write4(text.size); (* sh_size Section size in bytes *)
-		Write4(0); (* SHN_UNDEF sh_link Link to another section *)
-		Write4(0); (* sh_info Additional section information *)
-		Write4(textAlign); (* sh_addralign Section alignment *)
-		Write4(0) (* sh_entsize Entry size if section holds table *)
-	END WriteTextSectionHeader;
-
-	PROCEDURE WriteRelTextSectionHeader;
-		VAR i: INTEGER;
-	BEGIN
-		headerstrtab.AddName(".rel.text", i);
-		Write4(i); (* sh_name Section name (string tbl index) *)
-		Write4(9); (* SHT_REL sh_type Section type *)
-		Write4(2H); (* SHF_ALLOC sh_flags Section flags *)
-		Write4(reltext.memOffset); (* sh_addr Section virtual addr at execution *)
-		Write4(reltext.fileOffset); (* sh_offset Section file offset *)
-		Write4(reltext.size); (* sh_size Section size in bytes *)
-		Write4(dynsymIndexVal); (* sh_link Link to another section -> index of the associated symbol table *)
-		Write4(textIndexVal); (* sh_info Additional section information -> index of the relocated section *)
-		Write4(relAlign); (* sh_addralign Section alignment *)
-		Write4(relEntrySizeVal) (* sh_entsize Entry size if section holds table *)
-	END WriteRelTextSectionHeader;
-
-	PROCEDURE WriteRelRodataSectionHeader;
-		VAR i: INTEGER;
-	BEGIN
-		headerstrtab.AddName(".rel.rodata", i);
-		Write4(i); (* sh_name Section name (string tbl index) *)
-		Write4(9); (* SHT_REL sh_type Section type *)
-		Write4(2H); (* SHF_ALLOC sh_flags Section flags *)
-		Write4(relrodata.memOffset); (* sh_addr Section virtual addr at execution *)
-		Write4(relrodata.fileOffset); (* sh_offset Section file offset *)
-		Write4(relrodata.size); (* sh_size Section size in bytes *)
-		Write4(dynsymIndexVal); (* sh_link Link to another section -> index of the associated symbol table *)
-		Write4(rodataIndexVal); (* sh_info Additional section information -> index of the relocated section *)
-		Write4(relAlign); (* sh_addralign Section alignment *)
-		Write4(relEntrySizeVal) (* sh_entsize Entry size if section holds table *)
-	END WriteRelRodataSectionHeader;
-
-	PROCEDURE WriteRodataSectionHeader;
-		VAR i: INTEGER;
-	BEGIN
-		headerstrtab.AddName(".rodata", i);
-		Write4(i); (* sh_name Section name (string tbl index) *)
-		Write4(1); (* SHT_PROGBITS sh_type Section type *)
-		Write4(2H); (* SHF_ALLOC sh_flags Section flags *)
-		Write4(rodata.memOffset); (* sh_addr Section virtual addr at execution *)
-		Write4(rodata.fileOffset); (* sh_offset Section file offset *)
-		Write4(rodata.size); (* sh_size Section size in bytes *)
-		Write4(0); (* sh_link Link to another section *)
-		Write4(0); (* sh_info Additional section information *)
-		Write4(rodataAlign); (* sh_addralign Section alignment *)
-		Write4(0) (* sh_entsize Entry size if section holds table *)
-	END WriteRodataSectionHeader;
-
-	PROCEDURE WriteDynsymSectionHeader;
-		VAR i: INTEGER;
-	BEGIN
-		headerstrtab.AddName(".dynsym", i);
-		Write4(i); (* sh_name Section name (string tbl index) *)
-		Write4(11); (* SHT_DYNSYM sh_type Section type *)
-		Write4(2H); (* SHF_ALLOC sh_flags Section flags *)
-		Write4(dynsym.memOffset); (* sh_addr Section virtual addr at execution *)
-		Write4(dynsym.fileOffset); (* sh_offset Section file offset *)
-		Write4(dynsym.size); (* sh_size Section size in bytes *)
-		Write4(dynstrIndexVal); (* sh_link Link to another section -> index of the associated string table *)
-		expPos := Ro.Pos();
-		Write4(fixup); (* sh_info Additional section information -> see docu 4-17 *)
-		Write4(dynsymAlign); (* sh_addralign Section alignment *)
-		Write4(dynsymEntrySizeVal) (* sh_entsize Entry size if section holds table *)
-	END WriteDynsymSectionHeader;
-
-	PROCEDURE FixupDynsymSectionHeader;
-	BEGIN
-		Ro.SetPos(expPos);
-		Write4(dynsymInfoVal)
-	END FixupDynsymSectionHeader;
-	
-	PROCEDURE WriteDynstrSectionHeader;
-		VAR i: INTEGER;
-	BEGIN
-		headerstrtab.AddName(".dynstr", i);
-		Write4(i); (* sh_name Section name (string tbl index) *)
-		Write4(3); (* SHT_STRTAB sh_type Section type *)
-		Write4(2H); (* SHF_ALLOC sh_flags Section flags *)
-		Write4(dynstr.memOffset); (* sh_addr Section virtual addr at execution *)
-		Write4(dynstr.fileOffset); (* sh_offset Section file offset *)
-		Write4(dynstr.size); (* sh_size Section size in bytes *)
-		Write4(0); (* SHN_UNDEF sh_link Link to another section *)
-		Write4(0); (* sh_info Additional section information *)
-		Write4(dynstrAlign); (* sh_addralign Section alignment *)
-		Write4(0) (* sh_entsize Entry size if section holds table *)
-	END WriteDynstrSectionHeader;
-	
-	PROCEDURE WriteHashSectionHeader;
-		VAR i: INTEGER;
-	BEGIN
-		headerstrtab.AddName(".hash", i);
-		Write4(i); (* sh_name Section name (string tbl index) *)
-		Write4(5); (* SHT_HASH sh_type Section type *)
-		Write4(2H); (* SHF_ALLOC sh_flags Section flags *)
-		Write4(hash.memOffset); (* sh_addr Section virtual addr at execution *)
-		Write4(hash.fileOffset); (* sh_offset Section file offset *)
-		Write4(hash.size); (* sh_size Section size in bytes *)
-		Write4(dynsymIndexVal); (* sh_link Link to another section *)
-		Write4(0); (* sh_info Additional section information *)
-		Write4(hashAlign); (* sh_addralign Section alignment *)
-		Write4(4H) (* sh_entsize Entry size if section holds table *)
-	END WriteHashSectionHeader;
-
-	PROCEDURE WriteGotSectionHeader;
-		VAR i: INTEGER;
-	BEGIN
-		headerstrtab.AddName(".got", i);
-		Write4(i); (* sh_name Section name (string tbl index) *)
-		Write4(1); (* SHT_PROGBITS sh_type Section type *)
-		Write4(2H + 1H); (* SHF_ALLOC + SHF_WRITE sh_flags Section flags *)
-		Write4(got.memOffset); (* sh_addr Section virtual addr at execution *)
-		Write4(got.fileOffset); (* sh_offset Section file offset *)
-		Write4(got.size); (* sh_size Section size in bytes *)
-		Write4(0); (* SHN_UNDEF sh_link Link to another section *)
-		Write4(0); (* sh_info Additional section information *)
-		Write4(gotAlign); (* sh_addralign Section alignment *)
-		Write4(gotEntrySizeVal) (* sh_entsize Entry size if section holds table *)
-	END WriteGotSectionHeader;
-	
-	PROCEDURE WriteBssSectionHeader;
-		VAR i: INTEGER;
-	BEGIN
-		headerstrtab.AddName(".bss", i);
-		Write4(i); (* sh_name Section name (string tbl index) *)
-		Write4(8); (* SHT_NOBITS sh_type Section type *)
-		Write4(2H + 1H); (* SHF_ALLOC + SHF_WRITE sh_flags Section flags *)
-		Write4(bss.memOffset); (* sh_addr Section virtual addr at execution *)
-		Write4(bss.fileOffset); (* sh_offset Section file offset *)
-		Write4(bss.size); (* sh_size Section size in bytes *)
-		Write4(0); (* SHN_UNDEF sh_link Link to another section *)
-		Write4(0); (* sh_info Additional section information *)
-		Write4(bssAlign); (* sh_addralign Section alignment *)
-		Write4(0) (* sh_entsize Entry size if section holds table *)
-	END WriteBssSectionHeader;
-	
-	PROCEDURE WriteDynamicSectionHeader;
-		VAR i: INTEGER;
-	BEGIN
-		headerstrtab.AddName(".dynamic", i);
-		Write4(i); (* sh_name Section name (string tbl index) *)
-		Write4(6); (* SHT_DYNAMIC sh_type Section type *)
-		Write4(2H); (* SHF_ALLOC sh_flags Section flags *)
-		Write4(dynamic.memOffset); (* sh_addr Section virtual addr at execution *)
-		Write4(dynamic.fileOffset); (* sh_offset Section file offset *)
-		Write4(dynamic.size); (* sh_size Section size in bytes *)
-		Write4(dynstrIndexVal); (* sh_link Link to another section -> index of the associated symbol table *)
-		Write4(0); (* sh_info Additional section information *)
-		Write4(dynamicAlign); (* sh_addralign Section alignment *)
-		Write4(dynamicEntrySizeVal) (* sh_entsize Entry size if section holds table *)
-	END WriteDynamicSectionHeader;
-	
-	PROCEDURE WriteShstrtabSectionHeader;
-		VAR i: INTEGER;
-	BEGIN
-		headerstrtab.AddName(".shstrtab", i);
-		Write4(i); (* sh_name Section name (string tbl index) *)
-		Write4(3); (* SHT_STRTAB sh_type Section type *)
-		Write4(0); (* sh_flags Section flags *)
-		Write4(0); (* sh_addr Section virtual addr at execution *)
-		Write4(shstrtab.fileOffset); (* sh_offset Section file offset *)
-		shstrtabPos := Ro.Pos();
-		Write4(fixup); (* sh_size Section size in bytes *)
-		Write4(0); (* SHN_UNDEF sh_link Link to another section *)
-		Write4(0); (* sh_info Additional section information *)
-		Write4(shstrtabAlign); (* sh_addralign Section alignment *)
-		Write4(0) (* sh_entsize Entry size if section holds table *)
-	END WriteShstrtabSectionHeader;
-	
-	PROCEDURE FixupShstrtabSectionHeader;
-	BEGIN
-		Ro.SetPos(shstrtabPos);
-		Write4(shstrtab.size)
-	END FixupShstrtabSectionHeader;
-
-	PROCEDURE WriteRelSectionHeaders;
-	BEGIN
-		WriteRelTextSectionHeader;
-		WriteRelRodataSectionHeader
-	END WriteRelSectionHeaders;
-	
-	PROCEDURE WriteSectionHeaderTable;
-	BEGIN
-		shOffsetVal := Ro.Pos();
-		WriteNullSectionHeader;
-		WriteTextSectionHeader;
-		WriteRodataSectionHeader;
-		WriteRelSectionHeaders;
-		WriteDynsymSectionHeader;
-		WriteDynstrSectionHeader;
-		WriteHashSectionHeader;
-		WriteGotSectionHeader;
-		WriteDynamicSectionHeader;
-		WriteBssSectionHeader;
-		WriteShstrtabSectionHeader	(* see shStrndxVal *)
-		(* see shNumVal *)
-	END WriteSectionHeaderTable;
-
-	PROCEDURE FixupSectionHeaderTable;
-	BEGIN
-		FixupDynsymSectionHeader;
-		FixupShstrtabSectionHeader
-	END FixupSectionHeaderTable;
-
-	PROCEDURE WriteTextSegment;
-	BEGIN
-		Write4(1); (* PT_LOAD *)
-		Write4(0); (* offset *)
-		Write4(0); (* vaddr *)
-		Write4(0); (* paddr *)
-		Write4(textSegmentSizeVal); (* file size *)
-		Write4(textSegmentSizeVal); (* mem size *)
-		Write4(4H + 1H + 2H); (* flags: R+E+W *)
-		Write4(pageSize) (* I386 page size *)
-	END WriteTextSegment;
-	
-	PROCEDURE WriteDataSegment;
-	BEGIN
-		Write4(1); (* PT_LOAD *)
-		Write4(got.fileOffset); (* offset text segment size *)
-		Write4(got.memOffset); (* vaddr: offset + alignment * nof pages of text segment *)
-		Write4(got.memOffset); (* paddr: offset + alignment * nof pages of text segment *)
-		Write4(dataSegmentSizeVal); (* file size *)
-		Write4(dataSegmentSizeVal + bss.size); (* mem size -> dataSegmentSizeVal + NOBITS sections *)
-		Write4(4H + 2H); (* flags: R+W *)
-		Write4(pageSize) (* I386 page size *)
-	END WriteDataSegment;
-	
-	PROCEDURE WriteDynamicSegment;
-	BEGIN
-		Write4(2); (* PT_DYNAMIC *)
-		Write4(dynamic.fileOffset); (* offset text segment size *)
-		Write4(dynamic.memOffset); (* vaddr: offset of .dynamic section *)
-		Write4(dynamic.memOffset); (* paddr: vaddr + alignment * nof pages of text segment *)
-		Write4(dynamicSegmentSizeVal); (* file size *)
-		Write4(dynamicSegmentSizeVal); (* mem size *)
-		Write4(4H + 2H); (* flags: R+W *)
-		Write4(dynamicAlign) (* dynamic section alignement*)
-	END WriteDynamicSegment;
-	
-	PROCEDURE WriteProgramHeaderTable;
-	BEGIN
-		phOffsetVal := Ro.Pos();
-		WriteTextSegment; (* .text .rel.text .rodata .dynsym .dynstr .hash *)
-		WriteDataSegment; (* .got .dynamic .bss *)
-		WriteDynamicSegment (* .dynamic *)
-	END WriteProgramHeaderTable;
-	
-	PROCEDURE SearchObj (mod: Module; VAR name: ARRAY OF SHORTCHAR; m, fp, opt: INTEGER; VAR adr: INTEGER);
-		VAR dir, len, ntab, f, id, l, r, p, n, i, j: INTEGER; nch, och: SHORTCHAR;
-	BEGIN
-		Get(mod, mod.ms + modExports, dir); DEC(dir, rodata.memOffset + mod.ma); Get(mod, dir, len); INC(dir, 4);
-		Get(mod, mod.ms + modNames, ntab); DEC(ntab, rodata.memOffset + mod.ma);
-		IF name # "" THEN
-			l := 0; r := len;
-			WHILE l < r DO	(* binary search *)
-				n := (l + r) DIV 2; p := dir + n * 16;
-				Get(mod, p + 8, id);
-				i := 0; j := ntab + id DIV 256; nch := name[0]; och := SHORT(CHR(mod.data[j]));
-				WHILE (nch = och) & (nch # 0X) DO INC(i); INC(j); nch := name[i]; och := SHORT(CHR(mod.data[j])) END;
-				IF och = nch THEN
-					IF id MOD 16 = m THEN
-						Get(mod, p, f);
-						IF m = mTyp THEN
-							IF ODD(opt) THEN Get(mod, p + 4, f) END;
-							IF (opt > 1) & (id DIV 16 MOD 16 # mExported) THEN
-								W.WriteString(mod.name$); W.WriteChar("."); W.WriteSString(name);
-								W.WriteString(" imported from "); W.WriteString(impg.name$);
-								W.WriteString(" has wrong visibility"); W.WriteLn; error := TRUE
-							END;
-							Get(mod, p + 12, adr)
-						ELSIF m = mVar THEN
-							Get(mod, p + 4, adr); INC(adr, bss.memOffset + mod.va)
-						ELSIF m = mProc THEN
-							Get(mod, p + 4, adr); INC(adr, text.memOffset + mod.ca)
-						END;
-						IF f # fp THEN
-							W.WriteString(mod.name$); W.WriteChar("."); W.WriteSString(name);
-							W.WriteString(" imported from "); W.WriteString(impg.name$);
-							W.WriteString(" has wrong fprint"); W.WriteLn; error := TRUE
-						END
-					ELSE
-						W.WriteString(mod.name$); W.WriteChar("."); W.WriteSString(name);
-						W.WriteString(" imported from "); W.WriteString(impg.name$);
-						W.WriteString(" has wrong class"); W.WriteLn; error := TRUE
-					END;
-					RETURN
-				END;
-				IF och < nch THEN l := n + 1 ELSE r := n END
-			END;
-			W.WriteString(mod.name$); W.WriteChar("."); W.WriteSString(name);
-			W.WriteString(" not found (imported from "); W.WriteString(impg.name$);
-			W.WriteChar(")"); W.WriteLn; error := TRUE
-		ELSE (* anonymous type *)
-			WHILE len > 0 DO
-				Get(mod, dir + 4, f); Get(mod, dir + 8, id);
-				IF (f = fp) & (id MOD 16 = mTyp) & (id DIV 256 = 0) THEN
-					Get(mod, dir + 12, adr); RETURN
-				END;
-				DEC(len); INC(dir, 16)
-			END;
-			W.WriteString("anonymous type in "); W.WriteString(mod.name$);
-			W.WriteString(" not found"); W.WriteLn; error := TRUE
-		END
-	END SearchObj;
-	
-	PROCEDURE CollectExports (mod: Module);
-		VAR dir, len, ntab, id, i, j, n: INTEGER; e, exp: Export;
-	BEGIN
-		ASSERT(mod.intf & ~mod.dll, 20);
-		Get(mod, mod.ms + modExports, dir);
-		DEC(dir, rodata.memOffset + mod.ma); Get(mod, dir, len); INC(dir, 4);
-		Get(mod, mod.ms + modNames, ntab); DEC(ntab, rodata.memOffset + mod.ma); n := 0;
-		WHILE n < len DO
-			Get(mod, dir + 8, id);
-			IF (id DIV 16 MOD 16 # mInternal) & (id MOD 16 = mProc) THEN	(* exported procedure *)
-				NEW(exp);
-				i := 0; j := ntab + id DIV 256;
-				WHILE mod.data[j] # 0 DO exp.name[i] := SHORT(CHR(mod.data[j])); INC(i); INC(j) END;
-				exp.name[i] := 0X;
-				Get(mod, dir + 4, exp.adr);
-				IF id MOD 16 = mProc THEN
-					INC(exp.adr, text.memOffset + mod.ca)
-				ELSE
-					HALT(126);
-					ASSERT(id MOD 16 = mVar); INC(exp.adr, bss.memOffset + mod.va)
-				END;
-				IF (firstExp = NIL) OR (exp.name < firstExp.name) THEN
-					exp.next := firstExp; firstExp := exp;
-					IF lastExp = NIL THEN lastExp := exp END
-				ELSE
-					e := firstExp;
-					WHILE (e.next # NIL) & (exp.name > e.next.name) DO e := e.next END;
-					exp.next := e.next; e.next := exp;
-					IF lastExp = e THEN lastExp := exp END
-				END;
-				INC(numExp)
-			END;
-			INC(n); INC(dir, 16)
-		END
-	END CollectExports;
-
-	PROCEDURE Relocate0 (link, adr, sym: INTEGER);
-		CONST
-			absolute = 100; relative = 101; copy = 102; table = 103; tableend = 104; (* BB fixup types *)
-			noElfType = MIN(INTEGER);
-		VAR
-			offset, linkadr, bbType, elfType, n, x: INTEGER; relText: BOOLEAN;
-	BEGIN
-		WHILE link # 0 DO
-			RNum(offset);
-			WHILE link # 0 DO
-				IF link > 0 THEN
-					n := (code[link] MOD 256) + (code[link+1] MOD 256) * 256 + code[link+2] * 65536;
-					bbType := code[link+3];
-					linkadr := text.memOffset + impg.ca + link
-				ELSE
-					n := (impg.data[-link] MOD 256) + (impg.data[-link+1] MOD 256) * 256 + impg.data[-link+2] * 65536;
-					bbType := impg.data[-link+3];
-					linkadr := rodata.memOffset + impg.ma - link
-				END;
-				elfType := noElfType;
-				IF bbType = absolute THEN
-					IF sym = noSymbol THEN
-						x := adr + offset;
-						elfType := r386Relative
-					ELSE
-						x := 0H;
-						elfType := r38632 + sym * 256
-					END
-				ELSIF bbType = relative THEN
-					IF sym = noSymbol THEN
-						x := adr + offset - linkadr - 4
-					ELSE
-						x := 0FFFFFFFCH;
-						elfType := r386pc32 + sym * 256
-					END
-				ELSIF bbType = copy THEN
-					Get(impd, adr + offset - rodata.memOffset - impd.ma, x);
-					IF x # 0 THEN elfType := r386Relative END
-				ELSIF bbType = table THEN
-					x := adr + n; n := link + 4;
-					elfType := r386Relative
-				ELSIF bbType = tableend THEN
-					x := adr + n; n := 0;
-					elfType := r386Relative
-				ELSE HALT(99)
-				END;
-				relText := link > 0; 
-				IF link > 0 THEN
-					code[link] := SHORT(SHORT(x));
-					code[link+1] := SHORT(SHORT(x DIV 100H));
-					code[link+2] := SHORT(SHORT(x DIV 10000H));
-					code[link+3] := SHORT(SHORT(x DIV 1000000H))
-				ELSE
-					link := -link;
-					impg.data[link] := SHORT(SHORT(x));
-					impg.data[link+1] := SHORT(SHORT(x DIV 100H));
-					impg.data[link+2] := SHORT(SHORT(x DIV 10000H));
-					impg.data[link+3] := SHORT(SHORT(x DIV 1000000H))
-				END;
-				IF elfType # noElfType THEN
-					IF relText THEN
-						relTextTab.Add(linkadr, elfType)
-					ELSE
-						relRodataTab.Add(linkadr, elfType)
-					END
-				END;
-				link := n
-			END;
-			RNum(link)
-		END
-	END Relocate0;
-	
-	PROCEDURE Relocate (adr: INTEGER);
-		VAR link: INTEGER;
-	BEGIN
-		RNum(link); Relocate0(link, adr, noSymbol)
-	END Relocate;
-
-	PROCEDURE RelocateSymbol (adr, sym: INTEGER);
-		VAR link: INTEGER;
-	BEGIN
-		RNum(link); Relocate0(link, adr, sym)
-	END RelocateSymbol;
-	
-	PROCEDURE SymbolIndex (IN name: Name): INTEGER;
-		VAR n: INTEGER; exp: Export; m: Module;
-	BEGIN
-		n := 0; exp := NIL;
-		m := modList;
-		WHILE (m # NIL) & (exp = NIL) DO
-			IF m.dll THEN
-				exp := m.exp;
-				WHILE (exp # NIL) & (exp.name$ # name$) DO
-					INC(n);
-					exp := exp.next
-				END
-			END;
-			m := m.next
-		END;
-		ASSERT((exp # NIL) & (exp.name$ = name$), 60);
-		RETURN firstDllSymbolVal + n
-	END SymbolIndex;
-
-	PROCEDURE WriteTextSection;
-		VAR mod, m: Module; i, x, a, sym, fp, opt: INTEGER; exp: Export; name: Name;
-	BEGIN
-		ASSERT(isDll, 126);
-		ASSERT(~doWrite OR (Ro.Pos() = text.fileOffset), 100);
-		WriteCh(053X);	(* push ebx *)	(* _init() *)
-		a := 1;
-		WriteCh(0BBX); Write4(rodata.memOffset  + last.ma + last.ms);	(* mov bx, modlist *)
-		relTextTab.Add(text.memOffset + a + 1, r386Relative);
-		INC(a, 5);
-		IF isStatic THEN
-			m := modList;
-			WHILE m # NIL DO
-				IF ~m.dll THEN
-					WriteCh(0E8X); INC(a, 5); Write4(m.ca - a)	(* call body *)
-				END;
-				m := m.next
-			END
-		ELSE
-			WriteCh(0E8X); INC(a, 5); Write4(main.ca - a)	(* call main *)
-		END;
-		WriteCh(05BX); 	(* pop ebx *)
-		WriteCh(0C3X);	(* ret *)
-		INC(a, 2);
-		finiMemOffsetVal := text.memOffset + a;
-		WriteCh(053X);	(* push ebx *)	(* _fini() *)
-		INC(a);
-		finiPos := text.memOffset + a;
-		IF isStatic THEN
-			i := 0;
-			WHILE i < numMod DO	(* nop for call terminator *)
-				WriteCh(02DX); Write4(0);	(* sub EAX, 0 *)
-				INC(i); INC(a, 5)
-			END
-		ELSE
-			WriteCh(02DX); Write4(0);	(* sub EAX, 0 *)
-			INC(a, 5)
-		END;
-		lastTerm := a;
-		WriteCh(05BX); 	(* pop ebx *)
-		WriteCh(0C3X);	(* ret *)	
-		IF ~doWrite THEN NEW(code, maxCode) END;
-		mod := modList;
-		WHILE mod # NIL DO
-			impg := mod;
-			impd := mod;
-			IF ~mod.dll THEN
-				mod.file := ThisFile(mod.fileName);
-				R := mod.file.NewReader(R);
-				R.SetPos(mod.hs);
-				IF ~doWrite THEN NEW(mod.data, mod.ms + mod.ds) END;
-				R.ReadBytes(mod.data^, 0, mod.ms + mod.ds);
-				R.ReadBytes(code^, 0, mod.cs);
-				RNum(x);
-				IF x # 0 THEN
-					IF (mod # kernel) & (kernel # NIL) THEN
-						SearchObj(kernel, newRec, mProc, NewRecFP, 0, a);
-						IF error THEN RETURN END;
-						Relocate0(x, a, noSymbol)
-					ELSE
-						W.WriteSString("no kernel"); W.WriteLn;
-						StdLog.text.Append(StdLog.buf);
-						error := TRUE;
-						RETURN
-					END
-				END;
-				RNum(x);
-				IF x # 0 THEN
-					IF (mod # kernel) & (kernel # NIL) THEN
-						SearchObj(kernel, newArr, mProc, NewArrFP, 0, a);
-						IF error THEN RETURN END;
-						Relocate0(x, a, noSymbol)
-					ELSE
-						W.WriteSString("no kernel"); W.WriteLn;
-						StdLog.text.Append(StdLog.buf); error := TRUE;
-						RETURN
-					END
-				END;
-				Relocate(rodata.memOffset + mod.ma); (* metalink *)
-				Relocate(rodata.memOffset + mod.ma + mod.ms); (* desclink *)
-				Relocate(text.memOffset + mod.ca); (* codelink *)
-				Relocate(bss.memOffset + mod.va); (* datalink *)
-				i := 0;
-				WHILE i < mod.ni DO
-					m := mod.imp[i]; impd := m; RNum(x);
-					WHILE x # 0 DO
-						ReadName(name); RNum(fp); opt := 0;
-						IF x = mTyp THEN RNum(opt) END;
-						sym := noSymbol;
-						IF m.dll THEN
-							IF (x = mProc) OR (x = mVar) THEN
-								exp := m.exp;
-								WHILE exp.name # name DO exp := exp.next END;
-								a := noAddr;
-								sym := SymbolIndex(name)
-							END
-						ELSE
-							SearchObj(m, name, x, fp, opt, a);
-							IF error THEN RETURN END
-						END;
-						IF x # mConst THEN
-							RelocateSymbol(a, sym)
-						END;
-						RNum(x)
-					END;
-					IF ~m.dll THEN
-						Get(mod, mod.ms + modImports, x); DEC(x, rodata.memOffset + mod.ma); INC(x, 4 * i);
-						Put(mod, x, rodata.memOffset + m.ma + m.ms);	(* imp ref *)
-						relRodataTab.Add(rodata.memOffset + mod.ma + x, r386Relative);
-						Get(m, m.ms + modRefcnt, x); Put(m, m.ms + modRefcnt, x + 1)	(* inc ref count *)
-					END;
-					INC(i)
-				END;
-				WriteBytes(code^, 0, mod.cs);
-				IF mod.intf THEN CollectExports(mod) END;
-				mod.file.Close; mod.file := NIL
-			END;
-			mod := mod.next
-		END;
-		ASSERT(~doWrite OR (text.size = Ro.Pos() - text.fileOffset), 101)
-	END WriteTextSection;
-
-	PROCEDURE WriteTermCode (m: Module; i: INTEGER);
-		VAR x: INTEGER;
-	BEGIN
-		IF m # NIL THEN
-			IF m.dll THEN WriteTermCode(m.next, i)
-			ELSE
-				IF isStatic THEN WriteTermCode(m.next, i + 1) END;
-				Get(m, m.ms + modTerm, x);	(* terminator address in mod desc*)
-				IF x = 0 THEN
-					WriteCh(005X); Write4(0)	(* add EAX, 0 (nop) *)
-				ELSE
-					WriteCh(0E8X); Write4(x - lastTerm + 5 * i - text.memOffset)	(* call term *)
-				END
-			END
-		END
-	END WriteTermCode;
-
-	PROCEDURE FixupTextSection;
-	BEGIN
-		ASSERT(isDll, 126);
-		Ro.SetPos(finiPos);
-		IF isStatic THEN
-			WriteTermCode(modList, 0)
-		ELSE
-			WriteTermCode(main, 0)
-		END
-	END FixupTextSection;
-
-	PROCEDURE WriteRelSection (IN s: Section; IN t: RelTab);
-		VAR i: INTEGER;
-	BEGIN
-		ASSERT(s.fileOffset = Ro.Pos(), 100);
-		i := 0;
-		WHILE i # t.cur DO
-			Write4(t.tab[i].offset);
-			Write4(t.tab[i].type);
-			INC(i)
-		END;
-		ASSERT(s.size = Ro.Pos() - s.fileOffset, 101)
-	END WriteRelSection;
-
-	PROCEDURE WriteRelSections;
-	BEGIN
-		WriteRelSection(reltext, relTextTab);
-		WriteRelSection(relrodata, relRodataTab)
-	END WriteRelSections;
-	
-	PROCEDURE WriteRodataSection;
-		VAR mod, lastMod: Module; x: INTEGER;
-	BEGIN
-		ASSERT(~doWrite OR (rodata.fileOffset = Ro.Pos()), 100);
-		mod := modList; lastMod := NIL;
-		WHILE mod # NIL DO
-			IF ~mod.dll THEN
-				IF lastMod # NIL THEN
-					Put(mod, mod.ms, rodata.memOffset + lastMod.ma + lastMod.ms);	(* mod list *)
-					relRodataTab.Add(rodata.memOffset + mod.ma + mod.ms, r386Relative)
-				END;
-				Get(mod, mod.ms + modOpts, x);
-				IF isStatic THEN INC(x, 10000H) END;	(* set init bit (16) *)
-				IF isDll THEN INC(x, 1000000H) END;	(* set dll bit (24) *)
-				Put(mod, mod.ms + modOpts, x);
-				WriteBytes(mod.data^, 0, mod.ms + mod.ds);
-				lastMod := mod
-			END;
-			mod := mod.next
-		END;		
-		ASSERT(~doWrite OR (rodata.size = Ro.Pos() - rodata.fileOffset), 101)
-	END WriteRodataSection;
-		
-	PROCEDURE WriteSymbolTableEntry (IN name: ARRAY OF SHORTCHAR; val, size: INTEGER; bind, type: BYTE; shndx: INTEGER);
-		VAR i: INTEGER; info: SHORTCHAR;
-	BEGIN
-		IF name # "" THEN dynstrtab.AddName(name, i)
-		ELSE i := 0
-		END;
-		Write4(i);
-		Write4(val);
-		Write4(size);
-		info := SHORT(CHR(bind * 16 + type));
-		WriteCh(info);
-		WriteCh(0X); (* Symbol visibility *)
-		Write2(shndx)
-	END WriteSymbolTableEntry;
-	
-	PROCEDURE FixupSymbolTableEntry (val, size: INTEGER; bind, type: BYTE; shndx: INTEGER);
-		VAR info: SHORTCHAR;
-	BEGIN
-		Ro.SetPos(Ro.Pos() + 4); (* skip name *)
-		Write4(val);
-		Write4(size);
-		info := SHORT(CHR(bind * 16 + type));
-		WriteCh(info);
-		WriteCh(0X); (* Symbol visibility *)
-		Write2(shndx)
-	END FixupSymbolTableEntry;
-	
-	PROCEDURE WriteDynsymSection;
-		VAR e: Export; m: Module; i: INTEGER;
-	BEGIN
-		ASSERT(Ro.Pos() = dynsym.fileOffset, 100);
-		WriteSymbolTableEntry("", 0, 0, 0, 0, 0);
-		WriteSymbolTableEntry("", text.memOffset, 0, stbLocal, sttSection, 1); (* .text section *)
-		WriteSymbolTableEntry("", rodata.memOffset, 0, stbLocal, sttSection, 2); (* .rodata section *)
-		WriteSymbolTableEntry("", reltext.memOffset, 0, stbLocal, sttSection, 3); (* .rel.text.section *)
-		WriteSymbolTableEntry("", relrodata.memOffset, 0, stbLocal, sttSection, 4); (* .rel.rodata section *)
-		WriteSymbolTableEntry("", dynsym.memOffset, 0, stbLocal, sttSection, 5); (* .dynsym section *)
-		WriteSymbolTableEntry("", dynstr.memOffset, 0, stbLocal, sttSection, 6); (* .dynstr section *)
-		WriteSymbolTableEntry("", hash.memOffset, 0, stbLocal, sttSection, 7); (* .hash section *)
-		WriteSymbolTableEntry("", got.memOffset, 0, stbLocal, sttSection, 8); (* .got section *)
-		WriteSymbolTableEntry("", dynamic.memOffset, 0, stbLocal, sttSection, 9); (* .dynamic section *)
-		WriteSymbolTableEntry("", bss.memOffset, 0, stbLocal, sttSection, 10); (* .bss section *)
-		dynsymInfoVal := 11;
-		i := dynsymInfoVal;
-		WriteSymbolTableEntry("_DYNAMIC", dynamic.memOffset, 0, stbGlobal, sttObject, shnAbs);
-		hashtab[i] := "_DYNAMIC";
-		INC(i);
-		ASSERT(i = firstDllSymbolVal);
-		m := modList;
-		WHILE m # NIL DO
-			IF m.dll THEN
-				e := m.exp;
-				WHILE e # NIL DO
-					WriteSymbolTableEntry(e.name, 0, 0, stbGlobal, sttNotype, shnUnd);
-					hashtab[i] := e.name$;
-					INC(i);
-					e := e.next
-				END
-			END;
-			m := m.next
-		END;
-		e := firstExp;
-		WHILE e # NIL DO
-			WriteSymbolTableEntry(e.name, fixup, 0, stbGlobal, sttFunc, textIndexVal);
-			hashtab[i] := e.name$; INC(i);
-			e := e.next
-		END;
-		WriteSymbolTableEntry("_GLOBAL_OFFSET_TABLE_", got.memOffset, 0, stbGlobal, sttObject, shnAbs);
-		hashtab[i] := "_GLOBAL_OFFSET_TABLE_";
-		ASSERT(dynsym.size = Ro.Pos() - dynsym.fileOffset, 101)
-	END WriteDynsymSection;
-	
-	PROCEDURE FixupDynsymSection;
-		VAR e: Export; m: Module;
-	BEGIN
-		Ro.SetPos(dynsym.fileOffset + dynsymEntrySizeVal * firstDllSymbolVal);
-		m := modList;
-		WHILE m # NIL DO
-			IF m.dll THEN
-				e := m.exp;
-				WHILE e # NIL DO
-					Ro.SetPos(Ro.Pos() + dynsymEntrySizeVal);
-					e := e.next
-				END
-			END;
-			m := m.next
-		END;
-		Ro.SetPos(Ro.Pos() + 4);
-		e := firstExp;
-		WHILE e # NIL DO
-			Write4(e.adr);
-			Ro.SetPos(Ro.Pos() + 12);
-			e := e.next
-		END
-	END FixupDynsymSection;
-
-	PROCEDURE WriteStringTable (IN t: Strtab);
-		VAR i: INTEGER;
-	BEGIN
-		i := 0;
-		WHILE i # t.cur DO
-			WriteCh(t.tab[i]);
-			INC(i)
-		END
-	END WriteStringTable;
-
-	PROCEDURE WriteDynstrSection;
-	BEGIN
-		ASSERT(Ro.Pos() = dynstr.fileOffset, 100);
-		WriteStringTable(dynstrtab);
-		ASSERT(dynstr.size = Ro.Pos() - dynstr.fileOffset, 101)
-	END WriteDynstrSection;
-
-	PROCEDURE Hash (name: ARRAY OF SHORTCHAR): INTEGER;
-		VAR i, h, g: INTEGER;
-	BEGIN
-		h := 0; i := 0;
-		WHILE name[i] # 0X DO
-			h := ASH(h, 4) + ORD(name[i]);
-			g := ORD(BITS(h) * BITS(0F0000000H));
-			IF g # 0 THEN
-				h := ORD(BITS(h) / BITS(SHORT((g MOD 100000000L) DIV 1000000H)))
-			END;
-			h := ORD(BITS(h) * (-BITS(g)));
-			INC(i)
-		END;
-		RETURN h
-	END Hash;
-
-	PROCEDURE AddToChain (VAR c: ARRAY OF INTEGER; i, idx: INTEGER);
-		VAR k: INTEGER;
-	BEGIN
-		IF c[i] # 0 THEN
-			k := i;
-			WHILE c[k] # 0 DO k := c[k] END;
-			c[k] := idx
-		ELSE
-			c[i] := idx
-		END
-	END AddToChain;
-
-	PROCEDURE WriteHashSection;
-		VAR n, i, hi: INTEGER; b, c: POINTER TO ARRAY OF INTEGER;
-	BEGIN
-		ASSERT(hash.fileOffset = Ro.Pos(), 100);
-		n := dynsym.size DIV dynsymEntrySizeVal; (* number of enties in the symbol table *)
-		NEW(b, n);
-		NEW(c, n);
-		i := 0;
-		WHILE i # n DO
-			c[i] := 0; (* STN_UNDEF *)
-			IF hashtab[i] # "" THEN
-				hi := Hash(hashtab[i]) MOD n;
-				IF b[hi] # 0 THEN (* another word has the same index *)
-					AddToChain(c, i, b[hi])  (*c[i] := b[hi]*)
-				END;
-				b[hi] := i
-			END;
-			INC(i)
-		END;
-		Write4(n); (* nbucket *)
-		Write4(n); (* nchain *)
-		i := 0;
-		WHILE i # n DO
-			Write4(b[i]);
-			INC(i)
-		END;
-		i := 0;
-		WHILE i # n DO
-			Write4(c[i]);
-			INC(i)
-		END;
-		ASSERT(hash.size = Ro.Pos() - hash.fileOffset, 101)
-	END WriteHashSection;
-	
-	PROCEDURE WriteGotSection;
-	BEGIN
-		ASSERT(got.fileOffset = Ro.Pos(), 100);
-		Write4(dynamic.memOffset); (* addr of .dynamic section *)
-		Write4(0); (* reserved for ? *)
-		Write4(0); (* reserved for ? *)
-		ASSERT(got.size = Ro.Pos() - got.fileOffset, 101)
-	END WriteGotSection;
-	
-	PROCEDURE WriteDynamicSectionEntry (tag, val: INTEGER);
-	BEGIN
-		Write4(tag);
-		Write4(val)
-	END WriteDynamicSectionEntry;
-	
-	PROCEDURE WriteDynamicSection;
-		CONST dtNull = 0; dtNeeded = 1; dtHash = 4; dtStrtab = 5; dtSymtab = 6;
-			dtStrsz = 10; dtSyment = 11; dtInit = 12; dtFini = 13; dtSoname = 14; dtRel = 17; dtRelsz = 18; dtRelent = 19;
-			dtTextrel = 22;
-		VAR i: INTEGER;
-	BEGIN
-		ASSERT(dynamic.fileOffset = Ro.Pos(), 100);
-		WriteDynamicSectionEntry(dtSoname, fixup);
-		WriteDynamicSectionEntry(dtFini, fixup);
-		WriteDynamicSectionEntry(dtInit, text.memOffset);
-		WriteDynamicSectionEntry(dtHash, hash.memOffset);
-		WriteDynamicSectionEntry(dtStrtab, dynstr.memOffset);
-		WriteDynamicSectionEntry(dtSymtab, dynsym.memOffset);
-		WriteDynamicSectionEntry(dtStrsz, dynstr.size);
-		WriteDynamicSectionEntry(dtSyment, dynsymEntrySizeVal);
-		WriteDynamicSectionEntry(dtRel, reltext.memOffset);
-		WriteDynamicSectionEntry(dtRelsz, reltext.size + relrodata.size);
-		WriteDynamicSectionEntry(dtRelent, relEntrySizeVal);
-		i := 0;
-		WHILE neededIdx[i] # 0 DO
-			WriteDynamicSectionEntry(dtNeeded, neededIdx[i]);
-			INC(i)
-		END;
-		WriteDynamicSectionEntry(dtTextrel, 0);
-		WriteDynamicSectionEntry(dtNull, 0); (* DT_NULL: marks the end *)
-		ASSERT(dynamic.size = Ro.Pos() - dynamic.fileOffset, 101)
-	END WriteDynamicSection;
-	
-	PROCEDURE FixupDynamicSection;
-		VAR i: INTEGER;
-	BEGIN
-		Ro.SetPos(dynamic.fileOffset + 4);
-		Write4(sonameStrIndexVal);
-		Ro.SetPos(Ro.Pos() + 4);
-		Write4(finiMemOffsetVal)
-	END FixupDynamicSection;
-	
-	PROCEDURE WriteBssSection;
-	BEGIN
-(*
-		The .bss section does not take space in the file.
-		This procedure serves consistency-check purposes.
-*)
-		ASSERT(bss.fileOffset = Ro.Pos(), 100)
-	END WriteBssSection;
-
-	PROCEDURE WriteShstrtabSection;
-	BEGIN
-		ASSERT(shstrtab.fileOffset = Ro.Pos(), 100);
-		WriteStringTable(headerstrtab);
-		shstrtab.size := Ro.Pos() - shstrtab.fileOffset
-	END WriteShstrtabSection;
-
-	PROCEDURE GetImpListSize (OUT len: INTEGER; OUT count: INTEGER);
-		VAR m: Module; e: Export;
-	BEGIN
-		len := 0; count := 0;
-		m := modList;
-		WHILE m # NIL DO
-			IF m.dll THEN
-				e := m.exp;
-				WHILE e # NIL DO
-					INC(len, LEN(e.name$) + 1);
-					INC(count);
-					e := e.next
-				END
-			END;
-			m := m.next
-		END
-	END GetImpListSize;
-	
-	PROCEDURE GetExpListSize (OUT len: INTEGER; OUT count: INTEGER);
-		VAR e: Export;
-	BEGIN
-		count := 0; len := 0;
-		e := firstExp;
-		WHILE e # NIL DO
-			INC(len, LEN(e.name$) + 1);
-			INC(count);
-			e := e.next
-		END
-	END GetExpListSize;
-	
-	PROCEDURE DynsymSize (init: INTEGER): INTEGER;
-		VAR size: INTEGER;
-	BEGIN
-		size := init;
-		INC(size, dynsymEntrySizeVal * 11); (* sections entries *)
-		INC(size, dynsymEntrySizeVal); (* _DYNAMIC symbol *)
-		INC(size, dynsymEntrySizeVal); (* _GLOBAL_OFFSET_TABLE_ symbol *)
-		RETURN size
-	END DynsymSize;
-	
-	PROCEDURE DynstrSize (init: INTEGER): INTEGER;
-		VAR size: INTEGER;
-	BEGIN
-		size := init + 1;
-		INC(size, dynstrtab.cur - 1);
-		INC(size, LEN(soName$) + 1); (* library name *)
-		INC(size, 9); (* "_DYNAMIC" symbol + 0X *)
-		INC(size, 21 + 1); (* "_GLOBAL_OFFSET_TABLE_" symbol + trailing 0X *)
-		RETURN size
-	END DynstrSize;
-	
-	PROCEDURE DynamicSize (init: INTEGER): INTEGER;
-		VAR i, size: INTEGER;
-	BEGIN
-		size := init;
-		i := 0;
-		WHILE neededIdx[i] # 0 DO
-			INC(size, dynamicEntrySizeVal);
-			INC(i)
-		END;
-		RETURN size
-	END DynamicSize;
-	
-	PROCEDURE CalculateLayout;
-		VAR headerSize, impCount, expCount, impLen, expLen: INTEGER;
-	BEGIN
-		ASSERT(~error, 20);
-		headerSize := elfHeaderSizeVal + shEntrySizeVal * shNumVal + phEntrySizeVal * phNumVal;
-		text.fileOffset := Aligned(headerSize, textAlign);
-		text.memOffset := text.fileOffset;
-		text.size := CodeSize;
-		rodata.fileOffset := Aligned(text.fileOffset + text.size, rodataAlign);
-		rodata.memOffset := rodata.fileOffset;
-		rodata.size := ConSize;
-		reltext.fileOffset := Aligned(rodata.fileOffset + rodata.size, relAlign);
-		reltext.memOffset := reltext.fileOffset;
-		doWrite := FALSE;
-		WriteTextSection;	(* this only calculates the number of text relocations *)
-		IF error THEN RETURN END;
-		reltext.size := relEntrySizeVal * relTextTab.cur;
-		relrodata.fileOffset := reltext.fileOffset + reltext.size;
-		relrodata.memOffset := relrodata.fileOffset;
-		IF ~error THEN
-			WriteRodataSection	(* this only calculates the number of data relocations *)
-		ELSE
-			RETURN
-		END;
-		relrodata.size := relEntrySizeVal * relRodataTab.cur;
-		dynsym.fileOffset := Aligned(relrodata.fileOffset + relrodata.size, dynsymAlign);
-		dynsym.memOffset := dynsym.fileOffset;
-		GetImpListSize(impLen, impCount);
-		GetExpListSize(expLen, expCount);
-		dynsym.size := DynsymSize((impCount + expCount) * dynsymEntrySizeVal);
-		dynstr.fileOffset := Aligned(dynsym.fileOffset + dynsym.size, dynstrAlign);
-		dynstr.memOffset := dynstr.fileOffset;
-		dynstr.size := DynstrSize(impLen + expLen);
-		hash.fileOffset := Aligned(dynstr.fileOffset + dynstr.size, hashAlign);
-		hash.memOffset := hash.fileOffset;
-		hash.size := 8 + dynsym.size DIV dynsymEntrySizeVal * 4 * 2;
-		got.fileOffset := Aligned(hash.fileOffset + hash.size, gotAlign);
-		got.memOffset := Aligned(got.fileOffset, pageSize) + got.fileOffset MOD pageSize;
-		got.size := 3 * gotEntrySizeVal;
-		dynamic.fileOffset := Aligned(got.fileOffset + got.size, dynamicAlign);
-		dynamic.memOffset := got.memOffset + dynamic.fileOffset - got.fileOffset;
-		dynamic.size := DynamicSize(13 * dynamicEntrySizeVal);
-		bss.fileOffset := Aligned(dynamic.fileOffset + dynamic.size, bssAlign);
-		bss.memOffset := dynamic.memOffset + bss.fileOffset - dynamic.fileOffset;		
-		bss.size := DataSize;
-		shstrtab.fileOffset := Aligned(bss.fileOffset, shstrtabAlign);
-		shstrtab.size := fixup;
-		textSegmentSizeVal := got.fileOffset;
-		dataSegmentSizeVal := shstrtab.fileOffset - got.fileOffset;
-		dynamicSegmentSizeVal := shstrtab.fileOffset - dynamic.fileOffset;
-		relTextTab.cur := 0;
-		relRodataTab.cur := 0;
-		firstExp := NIL; lastExp := NIL;
-		doWrite := TRUE
-	END CalculateLayout;
-
-	PROCEDURE WriteOut;
-		VAR res: INTEGER;
-	BEGIN
-		ASSERT(~error, 20);
-		Out := Files.dir.New(Files.dir.This(""), Files.ask);
-		IF Out # NIL THEN
-			Ro := Out.NewWriter(Ro); Ro.SetPos(0);
-			CalculateLayout;
-			IF ~error THEN WriteElfHeader END;
-			IF ~error THEN WriteSectionHeaderTable END;
-			IF ~error THEN WriteProgramHeaderTable END;
-			IF ~error THEN Align(textAlign); WriteTextSection END;
-			IF ~error THEN Align(rodataAlign); WriteRodataSection END;
-			IF ~error THEN Align(relAlign); WriteRelSections END;
-			IF ~error THEN Align(dynsymAlign); WriteDynsymSection END;
-			IF ~error THEN Align(dynstrAlign); WriteDynstrSection END;
-			IF ~error THEN Align(hashAlign); WriteHashSection END;
-			IF ~error THEN Align(gotAlign); WriteGotSection END;
-			IF ~error THEN Align(dynamicAlign); WriteDynamicSection END;
-			IF ~error THEN Align(bssAlign); WriteBssSection END;
-			IF ~error THEN Align(shstrtabAlign); WriteShstrtabSection END;
-
-			IF ~error THEN FixupElfHeader END;
-			IF ~error THEN FixupSectionHeaderTable END;
-			IF ~error THEN FixupTextSection END;
-			IF ~error THEN FixupDynsymSection END;
-			IF ~error THEN FixupDynamicSection END;
-			Out.Register(soName$, "so", Files.ask, res);
-			IF res # 0 THEN error := TRUE END
-		ELSE
-			error := TRUE
-		END
-	END WriteOut;
-	
-	PROCEDURE ResetHashtab;
-		VAR i: INTEGER;
-	BEGIN
-		i := 0;
-		WHILE i # LEN(hashtab) DO
-			hashtab[i] := "";
-			INC(i)
-		END
-	END ResetHashtab;
-
-	PROCEDURE ResetNeededIdx;
-		VAR i: INTEGER;
-	BEGIN
-		i := 0;
-		WHILE i # LEN(neededIdx) DO
-			neededIdx[i] := 0;
-			INC(i)
-		END
-	END ResetNeededIdx;
-
-	PROCEDURE MakeSoName (VAR name: ARRAY OF CHAR; type: ARRAY OF CHAR);
-		VAR i, j: INTEGER; ext: Files.Name; ch: CHAR;
-	BEGIN
-		ASSERT((type = "") OR (type[0] = "."), 20);
-		i := 0;
-		WHILE (name[i] # 0X) & (name[i] # ".") DO INC(i) END;
-		IF name[i] = "." THEN
-			IF name[i + 1] = 0X THEN name[i] := 0X END
-		ELSIF i < LEN(name) - (LEN(type$) + 1) THEN
-			IF type = "" THEN ext := ".so" ELSE ext := type$ END;
-			j := 0; ch := ext[0];
-			WHILE ch # 0X DO
-				IF (ch >= "A") & (ch <= "Z") THEN
-					ch := CHR(ORD(ch) + ORD("a") - ORD("A"))
-				END;
-				name[i] := ch; INC(i); INC(j); ch := ext[j]
-			END;
-			name[i] := 0X
-		END
-	END MakeSoName;
-	
-	PROCEDURE ParseExt (IN S: TextMappers.Scanner; OUT ext: Files.Name);
-		VAR ch: CHAR; i: INTEGER;
-	BEGIN
-		ext := "";
-		S.rider.ReadPrevChar(ch);
-		IF ch = "." THEN
-			S.rider.ReadChar(ch);
-			i := 0;
-			WHILE (ch # 20X) & (ch # 9X) DO
-				ext[i] := ch;
-				INC(i);
-				S.rider.ReadChar(ch)
-			END;
-			ext[i] := 0X
-		ELSIF (ch # 20X) & (ch # 9X) THEN
-			W.WriteSString("Invalid character '");W.WriteChar(ch); W.WriteSString("' for file name.");
-			W.WriteLn; StdLog.text.Append(StdLog.buf); error := TRUE
-		END;
-		S.SetPos(S.rider.Pos())
-	END ParseExt;
-
-	PROCEDURE ParseModList (S: TextMappers.Scanner; end: INTEGER);
-		VAR mod: Module;
-	BEGIN
-		WHILE (S.start < end) & (S.type = TextMappers.string) DO
-			NEW(mod); mod.fileName := S.string$;
-			mod.next := modList; modList := mod;
-			S.Scan;
-			WHILE (S.start < end) & (S.type = TextMappers.char) &
-				((S.char = "*") OR (S.char = "+") OR (S.char = "$") OR (S.char = "#")) DO
-				IF S.char = "*" THEN mod.dll := TRUE
-				ELSIF S.char = "+" THEN kernel := mod
-				ELSIF S.char = "$" THEN main := mod
-				ELSE mod.intf := TRUE;
-					ASSERT(isDll, 126);
-					IF ~isDll THEN
-						W.WriteSString("Exports from Exe not possible. Use LinkDll or LinkDynDll.");
-						W.WriteLn; StdLog.text.Append(StdLog.buf); error := TRUE
-					END
-				END;
-				S.Scan
-			END
-		END
-	END ParseModList;
-
-	PROCEDURE LinkIt;
-		VAR S: TextMappers.Scanner; name, ext: Files.Name; end: INTEGER;
-	BEGIN
-		doWrite := TRUE;
-		headerstrtab.tab[0] := 0X;
-		headerstrtab.cur := 1;
-		dynstrtab.tab[0] := 0X;
-		dynstrtab.cur := 1;
-		relTextTab.cur := 0;
-		relRodataTab.cur := 0;
-		ResetHashtab;
-		ResetNeededIdx;
-		modList := NIL; kernel := NIL; main := NIL;
-		last := NIL; impg := NIL; impd := NIL;
-		firstExp := NIL; lastExp := NIL;
-		Dialog.ShowStatus("linking");
-		error := FALSE; modList := NIL;
-		IF DevCommanders.par = NIL THEN RETURN END;
-		S.ConnectTo(DevCommanders.par.text);
-		S.SetPos(DevCommanders.par.beg);
-		end := DevCommanders.par.end;
-		DevCommanders.par := NIL;
-		W.ConnectTo(StdLog.buf); S.Scan;
-		IF S.type = TextMappers.string THEN
-			name := S.string$;
-			ext := "";
-			ParseExt(S, ext); S.Scan;
-			IF ~error THEN
-				MakeSoName(name, ext);
-				IF (S.type = TextMappers.char) & (S.char = ":") THEN S.Scan;
-					IF (S.type = TextMappers.char) & (S.char = "=") THEN S.Scan;
-						ParseModList(S, end);
-						ReadHeaders;
-						soName := SHORT(name$);
-						IF ~error THEN
-							WriteOut
-						END;
-						IF ~error THEN
-							W.WriteString("Library " + name + " written: ");
-							W.WriteInt(Out.Length()); W.WriteString("    "); W.WriteInt(text.size)
-						END
-					ELSE
-						error := TRUE;
-						W.WriteString(" := missing")
-					END
-				ELSE
-					error := TRUE;
-					W.WriteString(" := missing")
-				END;
-				W.WriteLn; StdLog.text.Append(StdLog.buf)
-			END
-		END;
-		IF error THEN Dialog.ShowStatus("Failed to write library") ELSE Dialog.ShowStatus("Ok") END;
-		W.ConnectTo(NIL); S.ConnectTo(NIL);
-		modList := NIL; kernel := NIL; main := NIL; firstExp := NIL; lastExp := NIL;
-		last := NIL; impg := NIL; impd := NIL; code := NIL
-	END LinkIt;
-
-(*
-	exes are not supported
-
-	PROCEDURE Link*;
-	BEGIN
-		HALT(126);
-		isDll := FALSE; isStatic := FALSE;
-		LinkIt
-	END Link;
-	
-	PROCEDURE LinkExe*;
-	BEGIN
-		HALT(126);
-		isDll := FALSE; isStatic := TRUE;
-		LinkIt
-	END LinkExe;
-*)
-	
-	PROCEDURE LinkDll*;
-	BEGIN
-		isDll := TRUE; isStatic := TRUE;
-		LinkIt
-	END LinkDll;
-	
-	PROCEDURE LinkDynDll*;
-	BEGIN
-		isDll := TRUE; isStatic := FALSE;
-		LinkIt
-	END LinkDynDll;
-		
-BEGIN
-	newRec := "NewRec"; newArr := "NewArr"
-END DevElfLinker.
-
-LinTestSo LinTestSo2 LinKernel
-
-(!)DevElfLinker.LinkDynDll libtestbb.so := LinKernel+$ LinTestSo2 LinTestSo# ~
-(!)DevElfLinker.LinkDll libtestbb.so := LinTestSo2 LinTestSo# ~
-

+ 2 - 2
BlackBox/Init-Interp.txt

@@ -16,13 +16,13 @@ MODULE Init;
 
 		TextViews, TextControllers;
 
-	PROCEDURE Init*;
+	PROCEDURE Init;
 		VAR res: INTEGER;
 	BEGIN
 		(* StdLog.Open; *)
 		Converters.Register("Documents.ImportDocument", "Documents.ExportDocument", "", "odc", {});
 		(* Converters.Register("StdETHConv.ImportETHDoc", "", "TextViews.View", "eth", {Converters.importAll}); *)
-		Dialog.Call("Interp.Run", " ", res)
+		Dialog.Call("ConsInterp.Run", " ", res)
 	END Init;
 
 BEGIN

BIN
BlackBox/Obx/Mod/Hello0.odc


+ 0 - 13
BlackBox/Obx/Mod/Hello0.txt

@@ -1,13 +0,0 @@
-MODULE ObxHello0;
-
-	(* THIS IS TEXT COPY OF BlackBox 1.6-rc6 Obx/Mod/Hello0.odc *)
-	(* DO NOT EDIT *)
-
-	IMPORT StdLog;
-
-	PROCEDURE Do*;
-	BEGIN
-		StdLog.String("Hello World"); StdLog.Ln	(* write string and 0DX into log *)
-	END Do;
-
-END ObxHello0.

BIN
BlackBox/Obx/Mod/Pi.odc


+ 0 - 36
BlackBox/Obx/Mod/Pi.txt

@@ -1,36 +0,0 @@
-MODULE ObxPi;
-
-	(* THIS IS TEXT COPY OF BlackBox 1.6-rc6 Obx/Mod/Pi.odc *)
-	(* DO NOT EDIT *)
-
-	IMPORT Int := Integers, StdLog;
-
-	PROCEDURE Pi* (digits: INTEGER): Int.Integer;	(* entier(pi * 10^digits) *)
-		VAR p1, p2, inc, sum: Int.Integer; guard, div: INTEGER;
-	BEGIN
-		(* pi = 16 * atan(1/5) - 4 * atan(1/239) *)
-		(* atan(x) = x - x^3/3 + x^5/5 - x^7/7 + ... *)
-		guard := 8;
-		p1 := Int.Quotient(Int.Product(Int.Power(Int.Long(10), digits + guard), Int.Long(16)), Int.Long(5));
-		p2 := Int.Quotient(Int.Product(Int.Power(Int.Long(10), digits + guard), Int.Long(-4)), Int.Long(239));
-		sum := Int.Sum(p1, p2);
-		div := 1;
-		REPEAT
-			p1 := Int.Quotient(p1, Int.Long(-5 * 5));
-			p2 := Int.Quotient(p2, Int.Long(-239 * 239));
-			INC(div, 2);
-			inc := Int.Quotient(Int.Sum(p1, p2), Int.Long(div));
-			sum := Int.Sum(sum, inc)
-		UNTIL Int.Sign(inc) = 0;
-		RETURN Int.Quotient(sum, Int.Power(Int.Long(10), guard))
-	END Pi;
-
-	PROCEDURE WritePi* (digits: INTEGER);
-		VAR i: Int.Integer; s: ARRAY 10000 OF CHAR;
-	BEGIN
-		i := Pi(digits);
-		Int.ConvertToString(i, s);
-		StdLog.String(s); StdLog.Ln
-	END WritePi;
-
-END ObxPi.

+ 7 - 2
BlackBox/build

@@ -89,7 +89,7 @@ LindevCompiler.Compile('Dev/Mod', 'CPL486.txt')
 LindevCompiler.Compile('Dev/Mod', 'CPC486.txt')
 LindevCompiler.Compile('Dev/Mod', 'CPV486.txt')
 LindevCompiler.Compile('Dev/Mod', 'Compiler.txt')
-LindevCompiler.Compile('Dev/Mod', 'ElfLinker16.txt')
+# LindevCompiler.Compile('Dev/Mod', 'ElfLinker16.txt')
 
 LindevCompiler.Compile('Std/Mod', 'Interpreter.txt')
 
@@ -101,9 +101,14 @@ LindevCompiler.Compile('', 'HostWindows.txt')
 # HostDates:
 LindevCompiler.Compile('Lin/Mod', 'Dates.txt')
 
-LindevCompiler.Compile('', 'Interp.txt')
+LindevCompiler.Compile('Cons/Mod', 'Interp.txt')
 
 LindevCompiler.Compile('', 'Init-Interp.txt')
 
 LindevElfLinker.LinkDll('libBB.so := Kernel+ Files HostFiles StdLoader')
 DATA
+
+./run-BlackBox <<DATA
+DevCompiler.CompileThis DevElfLinker16
+DevCompiler.CompileThis ConsCompiler
+DATA

BIN
BlackBox/libBBInterp.so


+ 0 - 1
BlackBox/run-interp

@@ -1 +0,0 @@
-../c/run-interp

+ 5 - 3
BlackBox/tests

@@ -1,9 +1,11 @@
 #!/bin/sh
 
 ./run-BlackBox <<DATA
-LindevCompiler.Compile('Obx/Mod', 'Hello0.txt')
+DevCompiler.CompileThis ObxHello0
 ObxHello0.Do
-
-LindevCompiler.Compile('Obx/Mod', 'Pi.txt')
+DevCompiler.CompileThis ObxPi
 ObxPi.WritePi(1000)
+
+ConsCompiler.Compile('Obx/Mod', 'Hello0.odc')
+ConsCompiler.Compile('Obx/Mod', 'Pi.odc')
 DATA

+ 8 - 4
README

@@ -11,7 +11,7 @@ How to build:
 
 	compile self:
 
-		cd BlackBox; ./clean; ./build
+		cd BlackBox; ./clean; ./build-lindev; ./build
 
 Files:
 	original:
@@ -60,10 +60,14 @@ Files:
 				modified original BlackBox Dev/Mod/Compiler.odc
 			ElfLinker16.odc:
 				modified OpenBUGS Dev/Mod/ElfLinker16.odc
+		Cons/Mod
+			Compiler.odc:
+				modified original BlackBox Dev/Mod/Compiler.odc
 	new:
-		Interp.odc: simple console interpreter
+		Cons/Mod
+			Interp.odc: console interpreter
 		libBB.so: compiled and linked OpenBSD shared library to run BlackBox
-		libBBInterp.so: compiled and linked OpenBSD shared library to run development interpreter
+		libBB0.so: compiled and linked OpenBSD shared library to run simple development interpreter
 
 		Views.odc: minimal Views implementation required to compile StdInterpreter
 		StdLog.odc: alternative StdLog implementation to not depend on GUI
@@ -71,7 +75,7 @@ Files:
 
 Notes:
 	Lindev:
-		Lindev is temporary solution until TextModels ported?
+		I will not remove Lindev because I can not link .so library based on ConsInerp and Dev
 	Kernel_so_init.SetKernelBaseStack:
 		required only in case of .so shared library dynamic loading
 			(at run-time via dlopen, not on link-time)

+ 3 - 3
TODO

@@ -1,7 +1,7 @@
 By priority:
-	original Dev compiler instead of Lindev:
-		console interface to DevElfLinker16
-		console interface to compiler
+	simplify ConsCompiler?
+		IMPORT DevCompiler;
+		DevCompiler.CompileText
 
 	Services
 

+ 0 - 1
c/libBBInterp.so

@@ -1 +0,0 @@
-../BlackBox/libBBInterp.so