diff --git a/SourceGen/Tools/Omf/OmfFile.cs b/SourceGen/Tools/Omf/OmfFile.cs
index 2c5ff34..a439ddc 100644
--- a/SourceGen/Tools/Omf/OmfFile.cs
+++ b/SourceGen/Tools/Omf/OmfFile.cs
@@ -92,6 +92,9 @@ namespace SourceGen.Tools.Omf {
OmfFileKind = FileKind.Unknown;
}
+ ///
+ /// Analyzes the contents of an OMF file.
+ ///
public void Analyze(Formatter formatter) {
OmfSegment.ParseResult result = DoAnalyze(formatter, false);
if (result == OmfSegment.ParseResult.IsLibrary ||
@@ -104,8 +107,14 @@ namespace SourceGen.Tools.Omf {
MessageList = firstFail;
}
}
+
+ OmfFileKind = DetermineFileKind();
+ Debug.WriteLine("File kind is " + OmfFileKind);
}
+ ///
+ /// Analyzes the contents of an OMF file as a library or non-library.
+ ///
private OmfSegment.ParseResult DoAnalyze(Formatter formatter, bool parseAsLibrary) {
bool first = true;
int offset = 0;
@@ -156,5 +165,85 @@ namespace SourceGen.Tools.Omf {
Debug.WriteLine("Num segments = " + mSegmentList.Count);
return OmfSegment.ParseResult.Success;
}
+
+ ///
+ /// Analyzes the file to determine the file kind.
+ ///
+ private FileKind DetermineFileKind() {
+ if (mSegmentList.Count == 0) {
+ // Couldn't find a single valid segment, this is not OMF.
+ return FileKind.Foreign;
+ }
+
+ // The rules:
+ // * Load files may contain any kind of segment except LibraryDict. Their
+ // segments must be LCONST/DS followed by relocation records
+ // (INTERSEG, cINTERSEG, RELOC, cRELOC, SUPER).
+ // * Object files have Code and Data segments, and may not contain relocation
+ // records or ENTRY.
+ // * Library files are like Object files, but start with a LibraryDict segment.
+ // * Run-Time Library files have an initial segment with ENTRY records. (These
+ // are not supported because I've never actually seen one... the few files I've
+ // found with the RTL filetype ($B4) did not have any ENTRY records.)
+
+ bool maybeLoad = true;
+ bool maybeObject = true;
+ bool maybeLibrary = true;
+
+ foreach (OmfSegment omfSeg in mSegmentList) {
+ switch (omfSeg.Kind) {
+ case OmfSegment.SegmentKind.Code:
+ case OmfSegment.SegmentKind.Data:
+ // Allowed anywhere.
+ break;
+ case OmfSegment.SegmentKind.JumpTable:
+ case OmfSegment.SegmentKind.PathName:
+ case OmfSegment.SegmentKind.Init:
+ case OmfSegment.SegmentKind.AbsoluteBank:
+ case OmfSegment.SegmentKind.DpStack:
+ maybeObject = maybeLibrary = false;
+ break;
+ case OmfSegment.SegmentKind.LibraryDict:
+ maybeLoad = false;
+ maybeObject = false;
+ break;
+ default:
+ Debug.Assert(false, "Unexpected segment kind " + omfSeg.Kind);
+ break;
+ }
+ }
+
+ //
+ // Initial screening complete. Dig into the segment records to see if they're
+ // compatible.
+ //
+
+ if (maybeLoad) {
+ foreach (OmfSegment omfSeg in mSegmentList) {
+ if (!omfSeg.CheckRecords_LoadFile()) {
+ maybeLoad = false;
+ break;
+ }
+ }
+ if (maybeLoad) {
+ return FileKind.Load;
+ }
+ }
+ if (maybeLibrary || maybeObject) {
+ foreach (OmfSegment omfSeg in mSegmentList) {
+ if (!omfSeg.CheckRecords_ObjectOrLib()) {
+ maybeLibrary = maybeObject = false;
+ break;
+ }
+ }
+ if (maybeObject) {
+ return FileKind.Object;
+ } else {
+ return FileKind.Library;
+ }
+ }
+
+ return FileKind.Indeterminate;
+ }
}
}
diff --git a/SourceGen/Tools/Omf/OmfSegment.cs b/SourceGen/Tools/Omf/OmfSegment.cs
index aa696ec..aa51225 100644
--- a/SourceGen/Tools/Omf/OmfSegment.cs
+++ b/SourceGen/Tools/Omf/OmfSegment.cs
@@ -91,8 +91,14 @@ namespace SourceGen.Tools.Omf {
///
public List RawValues = new List();
+ ///
+ /// All known OMF versions.
+ ///
public enum SegmentVersion { v0_0, v1_0, v2_0, v2_1 }
+ ///
+ /// All known segment kinds.
+ ///
public enum SegmentKind {
Code = 0x00,
Data = 0x01,
@@ -155,6 +161,9 @@ namespace SourceGen.Tools.Omf {
// "The BANKSIZE and align restrictions are enforced by the linker, and violations
// of them are unlikely in a load file."
+ ///
+ /// Record list, from body of segment.
+ ///
public List Records = new List();
@@ -231,11 +240,12 @@ namespace SourceGen.Tools.Omf {
newSeg.LabLen = data[offset + 0x0d];
int numLen = data[offset + 0x0e];
newSeg.BankSize = RawData.GetWord(data, offset + 0x10, 4, false);
- newSeg.Org = RawData.GetWord(data, offset + 0x18, 4, false);
- newSeg.Align = RawData.GetWord(data, offset + 0x1c, 4, false);
- int numSex = data[offset + 0x20];
- int dispName;
+ int numSex, dispName;
if (newSeg.Version == SegmentVersion.v0_0) {
+ newSeg.Org = RawData.GetWord(data, offset + 0x14, 4, false);
+ newSeg.Align = RawData.GetWord(data, offset + 0x18, 4, false);
+ numSex = data[offset + 0x1c];
+ // 7 unused bytes follow
dispName = 0x24;
if (newSeg.LabLen == 0) {
newSeg.DispData = dispName + data[offset + dispName];
@@ -243,7 +253,11 @@ namespace SourceGen.Tools.Omf {
newSeg.DispData = dispName + LOAD_NAME_LEN;
}
} else {
- newSeg.LcBank = data[offset + 0x21];
+ newSeg.BankSize = RawData.GetWord(data, offset + 0x10, 4, false);
+ newSeg.Org = RawData.GetWord(data, offset + 0x18, 4, false);
+ newSeg.Align = RawData.GetWord(data, offset + 0x1c, 4, false);
+ numSex = data[offset + 0x20];
+ newSeg.LcBank = data[offset + 0x21]; // v1.0 only
newSeg.SegNum = RawData.GetWord(data, offset + 0x22, 2, false);
newSeg.Entry = RawData.GetWord(data, offset + 0x24, 4, false);
dispName = RawData.GetWord(data, offset + 0x28, 2, false);
@@ -263,7 +277,9 @@ namespace SourceGen.Tools.Omf {
newSeg.TempOrg = RawData.GetWord(data, offset + 0x2c, 4, false);
}
- // Extract Kind and its attributes.
+ // Extract Kind and its attributes. The Orca/M 2.0 manual refers to the 1-byte
+ // field in v0/v1 as "TYPE" and the 2-byte field as "KIND", but we're generally
+ // following the GS/OS reference nomenclature.
int kindByte, kindWord;
if (newSeg.Version <= SegmentVersion.v1_0) {
kindByte = data[offset + 0x0c];
@@ -457,8 +473,9 @@ namespace SourceGen.Tools.Omf {
newSeg.AddRaw("undefined", RawData.GetWord(data, offset + 0x14, 4, false), 4,
string.Empty);
}
- newSeg.AddRaw("ORG", newSeg.Org, 4, string.Empty);
- newSeg.AddRaw("ALIGN", newSeg.Align, 4, string.Empty);
+ newSeg.AddRaw("ORG", newSeg.Org, 4, (newSeg.Org != 0 ? "" : "relocatable"));
+ newSeg.AddRaw("ALIGN", newSeg.Align, 4,
+ "expecting 0, $0100, or $010000");
newSeg.AddRaw("NUMSEX", numSex, 1, "must be 0");
if (newSeg.Version == SegmentVersion.v1_0) {
newSeg.AddRaw("LCBANK", newSeg.LcBank, 1, string.Empty);
@@ -497,8 +514,9 @@ namespace SourceGen.Tools.Omf {
}
if (omfRec.Op == OmfRecord.Opcode.END) {
- // v0/v1 pad to 512-byte block boundaries, so this is expected there, but v2.x
- // should be snug. Doesn't have to be, but might indicate a parsing error.
+ // v0/v1 pad to 512-byte block boundaries, so some slop is expected there,
+ // but v2.x should be snug. Doesn't have to be, but might indicate a
+ // bug in the parser.
int remaining = (FileOffset + FileLength) - (offset + omfRec.Length);
Debug.Assert(remaining >= 0);
Debug.WriteLine("END record found, remaining space=" + remaining);
@@ -513,6 +531,55 @@ namespace SourceGen.Tools.Omf {
}
}
+ ///
+ /// Tests to see whether the record collection is congruent with a Load file.
+ ///
+ public bool CheckRecords_LoadFile() {
+ bool constSection = true;
+ foreach (OmfRecord omfRec in Records) {
+ switch (omfRec.Op) {
+ case OmfRecord.Opcode.LCONST:
+ case OmfRecord.Opcode.DS:
+ if (!constSection) {
+ Debug.WriteLine("Found LCONST/DS past const section");
+ return false;
+ }
+ break;
+ case OmfRecord.Opcode.RELOC:
+ case OmfRecord.Opcode.cRELOC:
+ case OmfRecord.Opcode.INTERSEG:
+ case OmfRecord.Opcode.cINTERSEG:
+ case OmfRecord.Opcode.SUPER:
+ constSection = false;
+ break;
+ default:
+ // incompatible record
+ return false;
+ }
+ }
+ return true;
+ }
+
+ ///
+ /// Tests to see whether the record collection is congruent with an Object or Library file.
+ ///
+ public bool CheckRecords_ObjectOrLib() {
+ foreach (OmfRecord omfRec in Records) {
+ switch (omfRec.Op) {
+ case OmfRecord.Opcode.RELOC:
+ case OmfRecord.Opcode.cRELOC:
+ case OmfRecord.Opcode.INTERSEG:
+ case OmfRecord.Opcode.cINTERSEG:
+ case OmfRecord.Opcode.SUPER:
+ case OmfRecord.Opcode.ENTRY:
+ return false;
+ default:
+ break;
+ }
+ }
+ return true;
+ }
+
//
// Helper functions.
//
diff --git a/SourceGen/Tools/Omf/WpfGui/OmfSegmentViewer.xaml b/SourceGen/Tools/Omf/WpfGui/OmfSegmentViewer.xaml
index ee59e74..9dcc0d7 100644
--- a/SourceGen/Tools/Omf/WpfGui/OmfSegmentViewer.xaml
+++ b/SourceGen/Tools/Omf/WpfGui/OmfSegmentViewer.xaml
@@ -48,7 +48,7 @@ limitations under the License.
-
-
-
+
+ a ??? file
+ a Load file
+ an Object file
+ a Library file
+ a file of indeterminate type
+
+ This is {0}, with {1} segment
+ This is {0}, with {1} segments
+ This is not an Apple II OMF file
@@ -44,7 +55,7 @@ limitations under the License.
-
+