Browse Source

Added offers / requires sections in object file (modeling import / export of a module) -> Can link with shortened module lists now.

git-svn-id: https://svn.inf.ethz.ch/svn/lecturers/a2/trunk@7006 8c9fc860-2736-0410-a75d-ab315db34111
felixf 8 years ago
parent
commit
8771e0390b

+ 66 - 12
source/FoxGenericObjectFile.Mod

@@ -6,7 +6,7 @@ IMPORT
 	FingerPrinter := FoxFingerPrinter, Files, Options, ObjectFile, Diagnostics, SymbolFileFormat := FoxTextualSymbolFile, Strings, KernelLog, D := Debugging;
 
 CONST
-	Version = 3;
+	Version = 4;
 	Trace = FALSE;
 	TraceAliases = FALSE;
 	WarnDuplicateFingerprints = FALSE;
@@ -258,14 +258,36 @@ TYPE ObjectFileFormat* = OBJECT (Formats.ObjectFileFormat)
 			END MakeStatistics;
 
 			PROCEDURE ExportModule (module: Sections.Module): BOOLEAN;
-			VAR result: BOOLEAN; pos: LONGINT;
+			VAR result: BOOLEAN; pos,i: LONGINT;
+				offers, requires: ObjectFile.NameList;
+				numImports: LONGINT; 
+				name: ObjectFile.SectionName;
+				import: SyntaxTree.Import;
 			BEGIN
 				pos := writer.Pos();
 				IF DetailedStatistics THEN
 					MakeStatistics(module.allSections);
 				END;
 				IF mergeSections & ~MergeSections(module.allSections) THEN RETURN FALSE END;
-				WriteHeader(writer,binary,module.allSections,poolMap, fingerPrinter);
+				NEW (offers, 1); offers[0] := module.moduleName;
+				import := module.module.moduleScope.firstImport;
+				numImports := 0;
+				WHILE import # NIL DO
+					IF import.direct THEN INC(numImports) END;
+					import := import.nextImport;
+				END;
+				NEW(requires, numImports);
+				numImports := 0;
+				import := module.module.moduleScope.firstImport;
+				WHILE import # NIL DO
+					IF import.direct THEN
+						import.module.GetName(name);
+						requires[numImports] := name;
+						INC(numImports);
+					END;
+					import := import.nextImport;
+				END;
+				WriteHeader(writer,binary,module.allSections, poolMap, offers, requires, fingerPrinter);
 				INC(statHeaders); INC(statHeadersSize, writer.Pos()-pos);
 				result := ExportSections (module.allSections);
 				INC(statModules); INC(statModulesSize, writer.Pos()-pos);
@@ -450,8 +472,9 @@ TYPE ObjectFileFormat* = OBJECT (Formats.ObjectFileFormat)
 	BEGIN NEW(objectFileFormat); RETURN objectFileFormat
 	END Get;
 
-	PROCEDURE ReadHeader(reader: Streams.Reader; VAR binary: BOOLEAN; VAR poolMap: ObjectFile.PoolMap);
-	VAR ch: CHAR; version: LONGINT; string: ARRAY 32 OF CHAR; i,j,pos,size: LONGINT; name: ObjectFile.SectionName;
+	PROCEDURE ReadHeader(reader: Streams.Reader; VAR binary: BOOLEAN; VAR poolMap: ObjectFile.PoolMap; VAR offers, requires: ObjectFile.NameList);
+	VAR ch: CHAR; string: ARRAY 32 OF CHAR; i,j,pos,size: LONGINT; name: ObjectFile.SectionName;
+	VAR version: LONGINT
 	BEGIN
 		reader.String(string);
 		binary := string="FoxOFB";
@@ -466,9 +489,22 @@ TYPE ObjectFileFormat* = OBJECT (Formats.ObjectFileFormat)
 			NEW(poolMap,64);
 			poolMap.Read(reader);
 		END;
+		offers := NIL;
+		requires := NIL;
+		IF version >= 4 THEN
+			IF ~binary THEN 
+				reader.String(string); ObjectFile.ReadNameList(reader, offers, binary, poolMap);
+				reader.SkipWhitespace;
+				reader.String(string); ObjectFile.ReadNameList(reader, requires, binary, poolMap);
+				reader.SkipWhitespace;
+			ELSE
+				ObjectFile.ReadNameList(reader, offers, binary, poolMap);
+				ObjectFile.ReadNameList(reader, requires, binary, poolMap);
+			END
+		END;
 	END ReadHeader;
 
-	PROCEDURE WriteHeader(writer: Streams.Writer; binary: BOOLEAN; sections: Sections.SectionList; VAR poolMap: ObjectFile.PoolMap; fingerPrinter:FingerPrinter.FingerPrinter);
+	PROCEDURE WriteHeader(writer: Streams.Writer; binary: BOOLEAN; sections: Sections.SectionList; VAR poolMap: ObjectFile.PoolMap; offers, requires: ObjectFile.NameList; fingerPrinter:FingerPrinter.FingerPrinter);
 	VAR p1,p2, size,i: LONGINT; section: Sections.Section; fixups: LONGINT; fixupList: ObjectFile.Fixups;
 
 		PROCEDURE ProcessSection(section: IntermediateCode.Section);
@@ -495,6 +531,15 @@ TYPE ObjectFileFormat* = OBJECT (Formats.ObjectFileFormat)
 				END;
 			END;
 		END ProcessSection;
+		
+		PROCEDURE NameList(CONST names: ObjectFile.NameList);
+		BEGIN
+			IF names # NIL THEN
+				FOR i := 0 TO LEN(names)-1 DO
+					poolMap.PutSegmentedName(names[i]);
+				END;
+			END;
+		END NameList;
 
 	BEGIN
 		IF binary THEN writer.String("FoxOFB");
@@ -502,7 +547,10 @@ TYPE ObjectFileFormat* = OBJECT (Formats.ObjectFileFormat)
 		END;
 		writer.Char(' ');
 		writer.Char('v'); writer.Int(Version,0); writer.Char(".");
-		IF ~binary THEN writer.Ln
+		IF ~binary THEN 
+				writer.Ln;
+				writer.String("offers "); ObjectFile.WriteNameList(writer, offers, binary, poolMap);
+				writer.String("requires "); ObjectFile.WriteNameList(writer, requires, binary, poolMap);
 		ELSE
 			NEW(poolMap,512);
 			poolMap.BeginWriting(writer);
@@ -510,8 +558,10 @@ TYPE ObjectFileFormat* = OBJECT (Formats.ObjectFileFormat)
 				section := sections.GetSection(i);
 				ProcessSection(section(IntermediateCode.Section));
 			END;
+			NameList(offers); NameList(requires);
 			poolMap.EndWriting;
-
+			ObjectFile.WriteNameList(writer, offers, binary, poolMap);
+			ObjectFile.WriteNameList(writer, requires, binary, poolMap);
 			(*
 			FOR i := 0 TO fixups-1 DO
 				D.String("fingerprint: "); Basic.WriteSegmentedName(D.Log, fixupList[i].identifier.name); D.Ln;
@@ -549,14 +599,15 @@ TYPE ObjectFileFormat* = OBJECT (Formats.ObjectFileFormat)
 	VAR
 		fileName: Files.FileName; file: Files.File; reader: Files.Reader; writer: Streams.Writer;
 		section: ObjectFile.Section; binary: BOOLEAN; poolMap, poolMapDummy: ObjectFile.PoolMap;
+		offers, requires: ObjectFile.NameList;
 	BEGIN
 		IF context.arg.GetString(fileName) THEN
 			file := Files.Old(fileName);
 			IF file # NIL THEN
 				NEW(reader,file,0);
 				writer := Basic.GetWriter(Basic.GetDebugWriter(fileName));
-				ReadHeader(reader, binary, poolMap);
-				WriteHeader(writer, FALSE, NIL, poolMapDummy, NIL);
+				ReadHeader(reader, binary, poolMap, offers, requires);
+				WriteHeader(writer, FALSE, NIL, poolMapDummy, offers, requires, NIL);
 				WHILE reader.Peek () # 0X DO
 					ObjectFile.ReadSection (reader, section,binary, poolMap);
 					ObjectFile.WriteSection(writer, section, FALSE, NIL); (* textual *)
@@ -583,6 +634,8 @@ TYPE ObjectFileFormat* = OBJECT (Formats.ObjectFileFormat)
 		 dest: Files.FileName;
 		 writer: Files.Writer;
 		 name: ObjectFile.SegmentedName;
+		 version: LONGINT;
+		 offers, requires: ObjectFile.NameList;
 	BEGIN
 		NEW(sectionList);
 		IF context.arg.GetString(dest) THEN
@@ -591,7 +644,7 @@ TYPE ObjectFileFormat* = OBJECT (Formats.ObjectFileFormat)
 				file := Files.Old(fileName);
 				IF file # NIL THEN
 					NEW(reader,file,0);
-					ReadHeader(reader, binary, poolMap);
+					ReadHeader(reader, binary, poolMap,offers, requires);
 					WHILE reader.Peek () # 0X DO
 						ObjectFile.InitSection(section);
 						ObjectFile.ReadSection (reader, section, binary, poolMap);
@@ -609,7 +662,8 @@ TYPE ObjectFileFormat* = OBJECT (Formats.ObjectFileFormat)
 			END;
 			file := Files.New(dest);
 			Files.OpenWriter(writer, file, 0);
-			WriteHeader(writer, TRUE, sectionList, poolMapDummy, NIL);
+			WriteHeader(writer, TRUE, sectionList, poolMapDummy, NIL, NIL, NIL);
+			
 			FOR i := 0 TO sectionList.Length()-1 DO
 				is := sectionList.GetSection(i)(IntermediateCode.Section);
 				ObjectFile.WriteSection(writer, is.resolved.os, TRUE, poolMapDummy); (* binary *)

+ 1 - 1
source/FoxIntermediateLinker.Mod

@@ -1284,7 +1284,7 @@ TYPE
 		COPY(instanceName, fileName); Strings.Append(fileName,".log");	logFile := Files.New(fileName);
 		IF logFile # NIL THEN NEW(linkerLog,logFile,0) ELSE logFile := NIL END;
 		NEW (linker, diagnostics, linkerLog, GenericLinker.UseInitCode, code, data);
-		StaticLinker.ReadObjectFile(instanceName, "",objectFile.extension, linker);
+		StaticLinker.ReadObjectFile(instanceName, "",objectFile.extension, linker, NIL);
 
 				(* do linking after having read in all blocks to account for potential constraints *)
 				IF ~linker.error THEN linker.Link; END;

+ 55 - 25
source/GenericLinker.Mod

@@ -1,3 +1,4 @@
+
  MODULE GenericLinker;	(* AUTHOR "negelef"; PURPOSE "Generic Object File Linker"; *)
 
 IMPORT ObjectFile, Streams, Diagnostics, Strings, SYSTEM;
@@ -20,7 +21,7 @@ TYPE
 	END;
 	HashSegmentedNameArray = POINTER TO ARRAY OF HashEntrySegmentedName;
 
-	HashTableSegmentedName = OBJECT
+	HashTableSegmentedName* = OBJECT
 	VAR
 		table: HashSegmentedNameArray;
 		size: LONGINT;
@@ -29,7 +30,7 @@ TYPE
 
 		(* Interface *)
 
-		PROCEDURE & Init (initialSize: LONGINT);
+		PROCEDURE & Init* (initialSize: LONGINT);
 		BEGIN
 			ASSERT(initialSize > 2);
 			NEW(table, initialSize);
@@ -39,7 +40,7 @@ TYPE
 			Clear;
 		END Init;
 
-		PROCEDURE Put(CONST key: ObjectFile.SegmentedName; value: Block);
+		PROCEDURE Put*(CONST key: ObjectFile.SegmentedName; value: Block);
 		VAR hash: LONGINT;
 		BEGIN
 			ASSERT(used < size);
@@ -52,10 +53,15 @@ TYPE
 			IF (used / size) > maxLoadFactor THEN Grow END;
 		END Put;
 
-		PROCEDURE Get(CONST key: ObjectFile.SegmentedName):Block;
+		PROCEDURE Get*(CONST key: ObjectFile.SegmentedName):Block;
 		BEGIN
-			RETURN table[HashValue(key)].value;
+			IF table[HashValue(key)].key = key THEN
+				RETURN table[HashValue(key)].value;
+			ELSE
+				RETURN NIL
+			END;
 		END Get;
+		
 
 		PROCEDURE Clear;
 		VAR i: LONGINT;
@@ -159,6 +165,10 @@ VAR
 	BEGIN diagnostics.Error (source, Diagnostics.Invalid, Diagnostics.Invalid, message); error := TRUE;
 	END Error;
 
+	PROCEDURE Warning* (CONST source, message: ARRAY OF CHAR);
+	BEGIN diagnostics.Warning (source, Diagnostics.Invalid, Diagnostics.Invalid, message);
+	END Warning;
+
 	PROCEDURE ErrorP*(CONST pooledName: ObjectFile.SegmentedName; CONST message: ARRAY OF CHAR);
 	VAR source: ARRAY 256 OF CHAR;
 	BEGIN
@@ -461,29 +471,49 @@ BEGIN
 	HALT(100); (* undefined type *)
 END GetPriority;
 
-PROCEDURE Process* (reader: Streams.Reader; linker: Linker);
-VAR section: ObjectFile.Section; binary: BOOLEAN; poolMap: ObjectFile.PoolMap;
-
-	PROCEDURE Header;
-	VAR ch: CHAR; version: LONGINT; string: ARRAY 32 OF CHAR;
-	BEGIN
-		reader.String(string);
-		binary := string="FoxOFB";
-		IF ~binary THEN ASSERT(string="FoxOFT") END;
-		reader.SkipWhitespace;
-		reader.Char(ch); ASSERT(ch='v');
-		reader.Int(version,FALSE);
-		IF version <2 THEN linker.Error("","old object file version encountered. Recompile sources.") END;
-		reader.Char(ch); ASSERT(ch='.');
-		IF ~binary THEN reader.SkipWhitespace
+PROCEDURE Header(reader: Streams.Reader; linker: Linker; VAR binary: BOOLEAN; VAR poolMap: ObjectFile.PoolMap; VAR offers, requires: ObjectFile.NameList);
+VAR ch: CHAR; version: LONGINT; string: ARRAY 32 OF CHAR;
+BEGIN
+	reader.String(string);
+	binary := string="FoxOFB";
+	IF ~binary THEN ASSERT(string="FoxOFT") END;
+	reader.SkipWhitespace;
+	reader.Char(ch); ASSERT(ch='v');
+	reader.Int(version,FALSE);
+	IF (version <2) & (linker # NIL) THEN linker.Error("","old object file version encountered. Recompile sources.") END;
+	reader.Char(ch); ASSERT(ch='.');
+	IF ~binary THEN reader.SkipWhitespace
+	ELSE
+		NEW(poolMap,64);
+		poolMap.Read(reader);
+	END;
+	
+	offers := NIL;
+	requires := NIL;
+	IF version >= 4 THEN
+		IF ~binary THEN 
+			reader.String(string); ObjectFile.ReadNameList(reader, offers, binary, poolMap);
+			reader.SkipWhitespace;
+			reader.String(string); ObjectFile.ReadNameList(reader, requires, binary, poolMap);
+			reader.SkipWhitespace;
 		ELSE
-			NEW(poolMap,64);
-			poolMap.Read(reader);
-		END;
-	END Header;
+			ObjectFile.ReadNameList(reader, offers, binary, poolMap);
+			ObjectFile.ReadNameList(reader, requires, binary, poolMap);
+		END
+	END;
+
+END Header;
 
+PROCEDURE OffersRequires*(reader: Streams.Reader; VAR offers, requires: ObjectFile.NameList);
+VAR section: ObjectFile.Section; binary: BOOLEAN; poolMap: ObjectFile.PoolMap; 
+BEGIN
+	Header(reader, NIL, binary, poolMap, offers, requires);
+END OffersRequires;
+
+PROCEDURE Process* (reader: Streams.Reader; linker: Linker);
+VAR section: ObjectFile.Section; binary: BOOLEAN; poolMap: ObjectFile.PoolMap; offers, requires: ObjectFile.NameList;
 BEGIN
-	Header;
+	Header(reader, linker, binary, poolMap, offers, requires);
 	WHILE reader.Peek () # 0X DO
 		ObjectFile.ReadSection (reader, section,binary,poolMap);
 		reader.SkipWhitespace;

+ 74 - 0
source/ObjectFile.Mod

@@ -233,6 +233,8 @@ TYPE
 		END EndWriting;
 
 	END PoolMap;
+	
+	NameList*= POINTER TO ARRAY OF SegmentedName;
 
 VAR
 	categories: ARRAY 6 OF ARRAY 10 OF CHAR;
@@ -641,6 +643,78 @@ VAR
 		UNTIL ~ReadSegment()
 	END ReadSectionTextual;
 
+	PROCEDURE ReadNameList*(reader: Streams.Reader; VAR nameList: NameList; binary: BOOLEAN; poolMap: PoolMap);
+	VAR i,len,num: LONGINT; name: ARRAY 256 OF CHAR;
+
+		PROCEDURE ReadIdentifier(VAR name: SegmentedName);
+		(*VAR name: SectionName;*)
+		VAR i,num: LONGINT;
+		BEGIN
+			i := 0;
+			REPEAT
+				reader.RawNum(num);
+				name[i] := poolMap.Get(num);
+				INC(i);
+			UNTIL (i = LEN(name)) OR (num < 0);
+			WHILE i < LEN(name) DO
+				name[i] := -1; INC(i);
+			END;
+		END ReadIdentifier;
+
+	BEGIN
+		IF binary THEN
+			reader.RawNum(len);
+			NEW(nameList, len);
+			FOR i := 0 TO len-1 DO
+				ReadIdentifier(nameList[i]);
+			END;
+		ELSE
+			reader.Int(len,FALSE);
+			NEW(nameList, len);
+			FOR i := 0 TO len-1 DO
+				reader.SkipWhitespace;
+				reader.String(name);
+				nameList[i] := name;
+			END;
+		END;
+	END ReadNameList;
+
+	PROCEDURE WriteNameList*(writer: Streams.Writer; nameList: NameList; binary: BOOLEAN; poolMap: PoolMap);
+	VAR i,len,num: LONGINT; name: ARRAY 256 OF CHAR;
+	CONST Separator = ' ';
+
+		PROCEDURE WriteIdentifier(CONST name: SegmentedName);
+		VAR i,num: LONGINT;
+		BEGIN
+			i := 0;
+			REPEAT
+				num := poolMap.Get(name[i]);
+				writer.RawNum(num);
+				INC(i);
+			UNTIL (i = LEN(name)) OR (num < 0);
+		END WriteIdentifier;
+
+	BEGIN
+		IF nameList = NIL THEN len := 0
+		ELSE len := LEN(nameList);
+		END;
+		IF binary THEN
+			writer.RawNum(len);
+			FOR i := 0 TO len-1 DO
+				WriteIdentifier(nameList[i]);
+			END;
+		ELSE
+			writer.Int(len,0);
+			FOR i := 0 TO len-1 DO
+				name := nameList[i];
+				writer.Char(Separator);
+				writer.String(name);
+			END;
+			writer.Ln;
+		END;
+	END WriteNameList;
+	
+
 	PROCEDURE WriteSectionBinary (writer: Streams.Writer; CONST section: Section; poolMap: PoolMap);
 	VAR pos, i, offset, start, len: LONGINT; size: Bits; bits: LONGINT; name: ARRAY 256 OF CHAR;
 	CONST ByteSize=8;

+ 48 - 5
source/StaticLinker.Mod

@@ -170,7 +170,8 @@ END Arrangement;
 
 TYPE FileFormat = PROCEDURE (linker: GenericLinker.Linker; arrangement: Arrangement; writer: Files.Writer);
 
-VAR defaults: Options.Defaults;
+VAR defaults: Options.Defaults; 
+	processing, finished: GenericLinker.Block;
 
 PROCEDURE Align(this, to: LONGINT): LONGINT;
 BEGIN
@@ -178,10 +179,17 @@ BEGIN
 	RETURN this;
 END Align;
 
-PROCEDURE ReadObjectFile*(CONST moduleName, path, extension: ARRAY OF CHAR; linker: GenericLinker.Linker);
-VAR fileName: Files.FileName; file: Files.File; reader: Files.Reader;
+PROCEDURE ReadObjectFile*(CONST moduleName, path, extension: ARRAY OF CHAR; linker: GenericLinker.Linker; moduleList: GenericLinker.HashTableSegmentedName);
+VAR fileName: Files.FileName; file: Files.File; reader: Files.Reader; i: LONGINT;
+offers, requires: ObjectFile.NameList;name: ARRAY 256 OF CHAR; sn: ObjectFile.SegmentedName;
 BEGIN
 	linker.Information (moduleName, "processing");
+	sn := moduleName;
+	IF (moduleList # NIL) & (moduleList.Get(sn) = finished) THEN
+		linker.Warning(moduleName, "duplicate");
+		RETURN;
+	END;
+	
 	IF path # "" THEN Files.JoinPath (path, moduleName, fileName); ELSE COPY(moduleName,fileName); END;
 	file := Files.Old (fileName);
 	IF file = NIL THEN (* try with extension *)
@@ -193,7 +201,32 @@ BEGIN
 	END;
 	IF file = NIL THEN linker.Error (fileName, "failed to open file"); RETURN; END;
 	Files.OpenReader (reader, file, 0);
-	GenericLinker.Process (reader, linker) ;
+	
+	GenericLinker.OffersRequires(reader, offers, requires);
+	reader.SetPos(0);
+	IF moduleList # NIL THEN
+		moduleList.Put(sn,processing);
+	END;
+	
+	IF (moduleList # NIL) & (requires # NIL) THEN
+		FOR i := 0 TO LEN(requires)-1 DO
+			IF moduleList.Get(requires[i]) = NIL THEN 
+				name := requires[i];
+				TRACE(name);
+				ReadObjectFile(name,path,extension, linker, moduleList);
+				IF linker.error THEN RETURN END;
+			ELSIF moduleList.Get(requires[i]) = processing THEN
+				name := requires[i];
+				Strings.Append(name, moduleName);
+				linker.Error(name, "cyclic import!");
+				RETURN;
+			END;
+		END;
+	END;
+	GenericLinker.Process (reader, linker);
+	IF moduleList # NIL THEN
+		moduleList.Put(sn,finished);
+	END;
 	IF reader.res # Files.Ok THEN linker.Error (fileName, "failed to parse"); END;
 END ReadObjectFile;
 
@@ -908,6 +941,8 @@ VAR options: Options.Options;
 	position: LONGINT;
 	name: ARRAY 32 OF CHAR;
 	reader: Streams.Reader;
+	moduleList: GenericLinker.HashTableSegmentedName;
+	segmentedName: ObjectFile.SegmentedName;
 BEGIN
 	NEW (options);
 	options.Add('p',"platform", Options.String);
@@ -970,8 +1005,14 @@ BEGIN
 
 	IF options.GetString("linkRoot",linkRoot) THEN linker.SetLinkRoot(linkRoot) END;
 
+	NEW(moduleList,32);
+	segmentedName := "SYSTEM";
+	moduleList.Put(segmentedName, finished);
+	segmentedName := "system";
+	moduleList.Put(segmentedName, finished);
+	
 	WHILE ~linker.error & context.arg.GetString (moduleName) DO
-		ReadObjectFile (moduleName, path, extension, linker);
+		ReadObjectFile (moduleName, path, extension, linker, moduleList);
 		IF strict & ~linker.error THEN linker.Resolve END;
 	END;
 	(* do linking after having read in all blocks to account for potential constraints *)
@@ -1009,6 +1050,8 @@ BEGIN
 END ShowDefaults;
 
 BEGIN
+	NEW(processing);
+	NEW(finished);
 	NEW(defaults);
 	defaults.Add("Win32C","--fileFormat=PE32CUI --fileName=oberon.exe --extension=GofW --displacement=401000H");
 	defaults.Add("Linux32G","--fileFormat=Raw --fileName=oberon --extension=.GofU --displacement=08048000H");