diff --git a/SourceGen/SourceGen.csproj b/SourceGen/SourceGen.csproj
index adf408f..0d668b6 100644
--- a/SourceGen/SourceGen.csproj
+++ b/SourceGen/SourceGen.csproj
@@ -87,6 +87,7 @@
+
OmfSegmentViewer.xaml
diff --git a/SourceGen/Tools/Omf/OmfFile.cs b/SourceGen/Tools/Omf/OmfFile.cs
index a439ddc..afe3b0e 100644
--- a/SourceGen/Tools/Omf/OmfFile.cs
+++ b/SourceGen/Tools/Omf/OmfFile.cs
@@ -13,11 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-using Asm65;
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using Asm65;
+
namespace SourceGen.Tools.Omf {
///
/// Apple IIgs OMF file.
@@ -70,14 +71,19 @@ namespace SourceGen.Tools.Omf {
}
public FileKind OmfFileKind { get; private set; }
+ ///
+ /// File data. Files must be loaded completely into memory.
+ ///
private byte[] mFileData;
- private bool mIsDamaged;
- private List mSegmentList = new List();
- public List SegmentList {
- get { return mSegmentList; }
- }
+ ///
+ /// List of segments.
+ ///
+ public List SegmentList { get; private set; } = new List();
+ ///
+ /// List of strings to show in the message window.
+ ///
public List MessageList { get; private set; } = new List();
@@ -110,6 +116,10 @@ namespace SourceGen.Tools.Omf {
OmfFileKind = DetermineFileKind();
Debug.WriteLine("File kind is " + OmfFileKind);
+
+ if (OmfFileKind == FileKind.Load) {
+ GenerateRelocDicts();
+ }
}
///
@@ -156,13 +166,13 @@ namespace SourceGen.Tools.Omf {
Debug.Assert(seg.FileLength > 0);
- mSegmentList.Add(seg);
+ SegmentList.Add(seg);
offset += seg.FileLength;
len -= seg.FileLength;
Debug.Assert(len >= 0);
}
- Debug.WriteLine("Num segments = " + mSegmentList.Count);
+ Debug.WriteLine("Num segments = " + SegmentList.Count);
return OmfSegment.ParseResult.Success;
}
@@ -170,7 +180,7 @@ namespace SourceGen.Tools.Omf {
/// Analyzes the file to determine the file kind.
///
private FileKind DetermineFileKind() {
- if (mSegmentList.Count == 0) {
+ if (SegmentList.Count == 0) {
// Couldn't find a single valid segment, this is not OMF.
return FileKind.Foreign;
}
@@ -179,8 +189,8 @@ namespace SourceGen.Tools.Omf {
// * 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.
+ // * Object files have Code, Data, and DP/Stack 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
@@ -190,17 +200,18 @@ namespace SourceGen.Tools.Omf {
bool maybeObject = true;
bool maybeLibrary = true;
- foreach (OmfSegment omfSeg in mSegmentList) {
+ foreach (OmfSegment omfSeg in SegmentList) {
switch (omfSeg.Kind) {
case OmfSegment.SegmentKind.Code:
case OmfSegment.SegmentKind.Data:
+ case OmfSegment.SegmentKind.DpStack:
// Allowed anywhere.
break;
case OmfSegment.SegmentKind.JumpTable:
case OmfSegment.SegmentKind.PathName:
case OmfSegment.SegmentKind.Init:
case OmfSegment.SegmentKind.AbsoluteBank:
- case OmfSegment.SegmentKind.DpStack:
+ // Only allowed in Load.
maybeObject = maybeLibrary = false;
break;
case OmfSegment.SegmentKind.LibraryDict:
@@ -219,7 +230,7 @@ namespace SourceGen.Tools.Omf {
//
if (maybeLoad) {
- foreach (OmfSegment omfSeg in mSegmentList) {
+ foreach (OmfSegment omfSeg in SegmentList) {
if (!omfSeg.CheckRecords_LoadFile()) {
maybeLoad = false;
break;
@@ -230,7 +241,7 @@ namespace SourceGen.Tools.Omf {
}
}
if (maybeLibrary || maybeObject) {
- foreach (OmfSegment omfSeg in mSegmentList) {
+ foreach (OmfSegment omfSeg in SegmentList) {
if (!omfSeg.CheckRecords_ObjectOrLib()) {
maybeLibrary = maybeObject = false;
break;
@@ -245,5 +256,20 @@ namespace SourceGen.Tools.Omf {
return FileKind.Indeterminate;
}
+
+ ///
+ /// Generates relocation dictionaries for all code/data/init segments.
+ ///
+ private void GenerateRelocDicts() {
+ Debug.Assert(OmfFileKind == FileKind.Load);
+
+ foreach (OmfSegment omfSeg in SegmentList) {
+ if (omfSeg.Kind == OmfSegment.SegmentKind.Code ||
+ omfSeg.Kind == OmfSegment.SegmentKind.Data ||
+ omfSeg.Kind == OmfSegment.SegmentKind.Init) {
+ omfSeg.GenerateRelocDict();
+ }
+ }
+ }
}
}
diff --git a/SourceGen/Tools/Omf/OmfRecord.cs b/SourceGen/Tools/Omf/OmfRecord.cs
index f66f98a..6d74495 100644
--- a/SourceGen/Tools/Omf/OmfRecord.cs
+++ b/SourceGen/Tools/Omf/OmfRecord.cs
@@ -16,8 +16,8 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
-using System.Security.Cryptography;
using System.Text;
+
using Asm65;
using CommonUtil;
@@ -28,6 +28,11 @@ namespace SourceGen.Tools.Omf {
public class OmfRecord {
private const int NUMLEN = 4; // defined by NUMLEN field in header; always 4 for IIgs
+ ///
+ /// Offset of record start within file.
+ ///
+ public int FileOffset { get; private set; }
+
///
/// Total length, in bytes, of this record.
///
@@ -114,6 +119,7 @@ namespace SourceGen.Tools.Omf {
OmfSegment.SegmentVersion version, int labLen, Formatter formatter,
List msgs, out OmfRecord omfRec) {
omfRec = new OmfRecord();
+ omfRec.FileOffset = offset;
try {
return omfRec.DoParseRecord(data, offset, version, labLen, formatter, msgs);
} catch (IndexOutOfRangeException ioore) {
@@ -299,9 +305,16 @@ namespace SourceGen.Tools.Omf {
break;
case Opcode.SUPER: {
int count = GetNum(data, ref offset, ref len);
- len += count;
+ int type = data[offset];
+ len += count; // count includes type byte
Value = (count - 1) + " bytes, type=" +
- formatter.FormatHexValue(data[offset + NUMLEN], 2);
+ formatter.FormatHexValue(type, 2);
+
+ if (type > 37) {
+ OmfSegment.AddErrorMsg(msgs, offset,
+ "found SUPER record with bogus type=$" + type.ToString("x2"));
+ // the length field allows us to skip it, so keep going
+ }
}
break;
case Opcode.General:
diff --git a/SourceGen/Tools/Omf/OmfReloc.cs b/SourceGen/Tools/Omf/OmfReloc.cs
new file mode 100644
index 0000000..112de28
--- /dev/null
+++ b/SourceGen/Tools/Omf/OmfReloc.cs
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2020 faddenSoft
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+using CommonUtil;
+
+namespace SourceGen.Tools.Omf {
+ ///
+ /// Apple IIgs OMF relocation entry. These are generated from OMF relocation records.
+ /// Note that SUPER records may generate multiple instances of these.
+ ///
+ public class OmfReloc {
+ ///
+ /// Number of bytes to be relocated.
+ ///
+ public int Width { get; private set; }
+
+ ///
+ /// Number of bits to shift the result before storing. Positive values shift left,
+ /// negative values shift right (unsigned).
+ ///
+ public int Shift { get; private set; }
+
+ ///
+ /// Offset within segment of bytes to rewrite.
+ ///
+ public int Offset { get; private set; }
+
+ ///
+ /// Relative offset of the thing being referenced. The segment's address in memory
+ /// is added to this to yield the final value.
+ ///
+ public int RelOffset { get; private set; }
+
+ ///
+ /// File number of target segment. Normally 1. Will be -1 for intra-segment relocs.
+ ///
+ public int FileNum { get; private set; }
+
+ ///
+ /// Segment number of target segment. Will be -1 for intra-segment relocs.
+ ///
+ public int SegNum { get; private set; }
+
+ ///
+ /// Set to the SUPER type, or -1 if this record was not from a SUPER.
+ ///
+ public int SuperType { get; private set; }
+
+
+ ///
+ /// Constructor for RELOC/cRELOC.
+ ///
+ /// Width in bytes of relocation.
+ /// Bit-shift amount.
+ /// Offset within segment of relocation.
+ /// Relative offset of relocation reference.
+ /// True if generated from SUPER.
+ private OmfReloc(int width, int shift, int offset, int relOffset, int superType) {
+ FileNum = SegNum = -1;
+ Width = width;
+ Shift = shift;
+ Offset = offset;
+ RelOffset = relOffset;
+ SuperType = superType;
+ }
+
+ ///
+ /// Constructor for INTERSEG/cINTERSEG.
+ ///
+ /// Width in bytes of relocation.
+ /// Bit-shift amount.
+ /// Offset within segment of relocation.
+ /// Relative offset of relocation reference.
+ /// File number.
+ /// Segment number.
+ /// True if generated from SUPER.
+ private OmfReloc(int width, int shift, int offset, int relOffset, int fileNum,
+ int segNum, int superType) {
+ Width = width;
+ Shift = shift;
+ Offset = offset;
+ RelOffset = relOffset;
+ FileNum = fileNum;
+ SegNum = segNum;
+ SuperType = superType;
+ }
+
+ ///
+ /// Adds one or more OmfReloc instances to the list to represent the provided record.
+ ///
+ /// Segment that contains the record.
+ /// Record to add.
+ /// File data.
+ /// List of relocations. New entries will be appended.
+ /// True on success.
+ public static bool GenerateRelocs(OmfSegment omfSeg, OmfRecord omfRec, byte[] data,
+ List relocs) {
+ try {
+ return DoGenerateRelocs(omfSeg, omfRec, data, relocs);
+ } catch (IndexOutOfRangeException ioore) {
+ Debug.WriteLine("Caught IOORE during reloc gen (" + omfRec.Op + "): " +
+ ioore.Message);
+ return false;
+ }
+ }
+
+ ///
+ /// Adds one or more OmfReloc instances to the list to represent the provided record.
+ ///
+ private static bool DoGenerateRelocs(OmfSegment omfSeg, OmfRecord omfRec, byte[] data,
+ List relocs) {
+ int offset = omfRec.FileOffset;
+ Debug.Assert(data[offset] == (int)omfRec.Op);
+ switch (omfRec.Op) {
+ case OmfRecord.Opcode.RELOC: {
+ byte width = data[offset + 1];
+ sbyte shift = (sbyte)data[offset + 2];
+ int off = RawData.GetWord(data, offset + 3, 4, false);
+ int relOff = RawData.GetWord(data, offset + 7, 4, false);
+ relocs.Add(new OmfReloc(width, shift, off, relOff, -1));
+ }
+ break;
+ case OmfRecord.Opcode.cRELOC: {
+ byte width = data[offset + 1];
+ sbyte shift = (sbyte)data[offset + 2];
+ int off = RawData.GetWord(data, offset + 3, 2, false);
+ int relOff = RawData.GetWord(data, offset + 5, 2, false);
+ relocs.Add(new OmfReloc(width, shift, off, relOff, -1));
+ }
+ break;
+ case OmfRecord.Opcode.INTERSEG: {
+ byte width = data[offset + 1];
+ sbyte shift = (sbyte)data[offset + 2];
+ int off = RawData.GetWord(data, offset + 3, 4, false);
+ int fileNum = RawData.GetWord(data, offset + 7, 2, false);
+ int segNum = RawData.GetWord(data, offset + 9, 2, false);
+ int relOff = RawData.GetWord(data, offset + 11, 4, false);
+ relocs.Add(new OmfReloc(width, shift, off, relOff, fileNum, segNum, -1));
+ }
+ break;
+ case OmfRecord.Opcode.cINTERSEG: {
+ byte width = data[offset + 1];
+ sbyte shift = (sbyte)data[offset + 2];
+ int off = RawData.GetWord(data, offset + 3, 2, false);
+ int fileNum = 1;
+ int segNum = data[offset + 5];
+ int relOff = RawData.GetWord(data, offset + 6, 2, false);
+ relocs.Add(new OmfReloc(width, shift, off, relOff, fileNum, segNum, -1));
+ }
+ break;
+ case OmfRecord.Opcode.SUPER:
+ if (!GenerateRelocForSuper(omfSeg, omfRec, data, relocs)) {
+ return false;
+ }
+ break;
+ default:
+ Debug.Assert(false);
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Generates a series of relocation items for a SUPER record.
+ ///
+ private static bool GenerateRelocForSuper(OmfSegment omfSeg, OmfRecord omfRec, byte[] data,
+ List relocs) {
+ int offset = omfRec.FileOffset;
+ int remaining = RawData.GetWord(data, offset + 1, 4, false);
+ int type = data[offset + 5];
+ offset += 6; // we've consumed 6 bytes
+ remaining--; // ...but only 1 counts against the SUPER length
+
+ int width, shift, fileNum, segNum;
+ bool needSegNum = false;
+
+ if (type == 0) {
+ // SUPER RELOC2
+ width = 2;
+ shift = 0;
+ fileNum = segNum = -1;
+ } else if (type == 1) {
+ // SUPER RELOC3
+ width = 3;
+ shift = 0;
+ fileNum = segNum = -1;
+ } else if (type >= 2 && type <= 13) {
+ // SUPER INTERSEG1 - SUPER INTERSEG12
+ width = 3;
+ shift = 0;
+ fileNum = type - 1;
+ segNum = -100;
+ needSegNum = true;
+ } else if (type >= 14 && type <= 25) {
+ // SUPER INTERSEG13 - SUPER INTERSEG24
+ width = 2;
+ shift = 0;
+ fileNum = 1;
+ segNum = type - 13;
+ } else if (type >= 26 && type <= 37) {
+ // SUPER INTERSEG25 - SUPER INTERSEG36
+ width = 2;
+ shift = -16; // right shift
+ fileNum = 1;
+ segNum = type - 25;
+ } else {
+ return false;
+ }
+
+ int page = 0;
+ while (remaining > 0) {
+ int patchCount = data[offset++];
+ remaining--;
+
+ if ((patchCount & 0x80) != 0) {
+ // high bit set, this is a skip-count
+ page += (patchCount & 0x7f);
+ continue;
+ }
+ patchCount++; // zero means one patch
+ while (patchCount-- != 0) {
+ int patchOff = data[offset++];
+ remaining--;
+
+ int relocOff = page * 256 + patchOff;
+
+ byte[] constData = omfSeg.GetConstData();
+ int relocRelOff = RawData.GetWord(constData, relocOff, 2, false);
+ if (needSegNum) {
+ segNum = constData[relocOff + 2];
+ }
+
+ relocs.Add(new OmfReloc(width, shift, relocOff, relocRelOff,
+ fileNum, segNum, type));
+ }
+
+ page++;
+ }
+
+ if (remaining < 0) {
+ Debug.WriteLine("Ran off end of SUPER record");
+ Debug.Assert(false);
+ return false;
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/SourceGen/Tools/Omf/OmfSegment.cs b/SourceGen/Tools/Omf/OmfSegment.cs
index aa51225..b2576df 100644
--- a/SourceGen/Tools/Omf/OmfSegment.cs
+++ b/SourceGen/Tools/Omf/OmfSegment.cs
@@ -72,6 +72,8 @@ namespace SourceGen.Tools.Omf {
// Length of LOADNAME field.
private const int LOAD_NAME_LEN = 10;
+ private const int DISK_BLOCK_SIZE = 512;
+
public class NameValueNote {
public string Name { get; private set; }
public object Value { get; private set; }
@@ -132,7 +134,8 @@ namespace SourceGen.Tools.Omf {
//
public int FileOffset { get; private set; }
- public int FileLength { get; private set; } // from BLKCNT or BYTECNT
+ public int RawFileLength { get; private set; } // from BLKCNT or BYTECNT
+ public int FileLength { get; private set; } // last block may be short
public int ResSpc { get; private set; }
public int Length { get; private set; }
@@ -166,6 +169,11 @@ namespace SourceGen.Tools.Omf {
///
public List Records = new List();
+ ///
+ /// Relocation list, for segments in Load files.
+ ///
+ public List Relocs = new List();
+
// Constructor is private; use ParseHeader() to create an instance.
private OmfSegment() { }
@@ -321,9 +329,11 @@ namespace SourceGen.Tools.Omf {
// We've got the basic pieces. Handle the block-vs-byte debacle.
int segLen;
+ bool asBlocks = false;
if (newSeg.Version == SegmentVersion.v0_0) {
// Always block count.
- segLen = blkByteCnt * 512;
+ segLen = blkByteCnt * DISK_BLOCK_SIZE;
+ asBlocks = true;
} else if (newSeg.Version >= SegmentVersion.v2_0) {
// Always byte count.
segLen = blkByteCnt;
@@ -332,17 +342,14 @@ namespace SourceGen.Tools.Omf {
// files by checking for a nonzero SegNum field, but there's no reliable way
// to tell the difference between Object and Library while looking at a segment
// in isolation.
- //
- // I have found a couple of examples (e.g. BRIDGE.S16 in Davex v1.23, SYSTEM:START
- // on an old Paintworks GS disk) where the file's length is shy of a multiple
- // of 512, so we ought to handle that.
if (parseAsLibrary) {
segLen = blkByteCnt;
} else {
- segLen = blkByteCnt * 512;
+ segLen = blkByteCnt * DISK_BLOCK_SIZE;
+ asBlocks = true;
}
}
- newSeg.FileLength = segLen;
+ newSeg.RawFileLength = newSeg.FileLength = segLen;
//
// Perform validity checks. If any of these fail, we're probably reading something
@@ -359,11 +366,21 @@ namespace SourceGen.Tools.Omf {
return ParseResult.Failure;
}
if (offset + segLen > data.Length) {
- // Segment is longer than the file. (This can happen easily in a static lib if
- // we're not parsing it as such.)
- AddErrorMsg(msgs, offset, "segment file length exceeds EOF (segLen=" + segLen +
- ", remaining=" + (data.Length - offset) + ")");
- return ParseResult.Failure;
+ if (asBlocks && offset + segLen - data.Length < DISK_BLOCK_SIZE) {
+ // I have found a few examples (e.g. BRIDGE.S16 in Davex v1.23, SYSTEM:START
+ // on an old Paintworks GS disk) where the file's length doesn't fill out
+ // the last block in the file. If we continue, and the segment actually
+ // does pass EOF, we'll fail while reading the records.
+ AddInfoMsg(msgs, offset,
+ "file EOF is not a multiple of 512; last segment may be truncated");
+ newSeg.FileLength = data.Length - offset;
+ } else {
+ // Segment is longer than the file. (This can happen easily in a static lib if
+ // we're not parsing it as such.)
+ AddErrorMsg(msgs, offset, "segment file length exceeds EOF (segLen=" + segLen +
+ ", remaining=" + (data.Length - offset) + ")");
+ return ParseResult.Failure;
+ }
}
if (dispName < expectedDispName || dispName > (segLen - LOAD_NAME_LEN)) {
AddErrorMsg(msgs, offset, "invalid DISPNAME " + dispName + " (expected " +
@@ -456,7 +473,8 @@ namespace SourceGen.Tools.Omf {
} else {
newSeg.AddRaw("undefined", data[offset + 0x0c], 1, string.Empty);
}
- newSeg.AddRaw("LABLEN", newSeg.LabLen, 1, string.Empty);
+ newSeg.AddRaw("LABLEN", newSeg.LabLen, 1,
+ (newSeg.LabLen == 0 ? "variable length" : "fixed length"));
newSeg.AddRaw("NUMLEN", numLen, 1, "must be 4");
newSeg.AddRaw("VERSION", data[offset + 0x0f], 1, VersionToString(newSeg.Version));
newSeg.AddRaw("BANKSIZE", newSeg.BankSize, 4, string.Empty);
@@ -474,8 +492,16 @@ namespace SourceGen.Tools.Omf {
string.Empty);
}
newSeg.AddRaw("ORG", newSeg.Org, 4, (newSeg.Org != 0 ? "" : "relocatable"));
- newSeg.AddRaw("ALIGN", newSeg.Align, 4,
- "expecting 0, $0100, or $010000");
+ // alignment is rounded up to page/bank
+ string alignStr;
+ if (newSeg.Align == 0) {
+ alignStr = "no alignment";
+ } else if (newSeg.Align <= 0x0100) {
+ alignStr = "align to page";
+ } else {
+ alignStr = "align to bank";
+ }
+ newSeg.AddRaw("ALIGN", newSeg.Align, 4, alignStr);
newSeg.AddRaw("NUMSEX", numSex, 1, "must be 0");
if (newSeg.Version == SegmentVersion.v1_0) {
newSeg.AddRaw("LCBANK", newSeg.LcBank, 1, string.Empty);
@@ -507,7 +533,7 @@ namespace SourceGen.Tools.Omf {
// Parsing failure. Bail out.
return false;
}
- if (offset + omfRec.Length > FileOffset + FileLength) {
+ if (offset + omfRec.Length > FileOffset + RawFileLength) {
// Overrun.
AddErrorMsg(msgs, offset, "record ran off end of file (" + omfRec + ")");
return false;
@@ -520,7 +546,8 @@ namespace SourceGen.Tools.Omf {
int remaining = (FileOffset + FileLength) - (offset + omfRec.Length);
Debug.Assert(remaining >= 0);
Debug.WriteLine("END record found, remaining space=" + remaining);
- if (remaining >= 512 || (Version >= SegmentVersion.v2_0 && remaining != 0)) {
+ if (remaining >= DISK_BLOCK_SIZE ||
+ (Version >= SegmentVersion.v2_0 && remaining != 0)) {
AddInfoMsg(msgs, offset, "found " + remaining + " bytes past END record");
}
return true;
@@ -580,6 +607,67 @@ namespace SourceGen.Tools.Omf {
return true;
}
+ public void GenerateRelocDict() {
+ Debug.Assert(CheckRecords_LoadFile());
+
+ 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:
+ OmfReloc.GenerateRelocs(this, omfRec, mFileData, Relocs);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private byte[] mConstData;
+
+ ///
+ /// Returns a reference to the unpacked constant data from the body of a Load segment
+ /// (i.e. the LCONST/DS part).
+ ///
+ public byte[] GetConstData() {
+ if (mConstData != null) {
+ return mConstData;
+ }
+
+ // We haven't generated this yet; do it now. Start by determining the length.
+ int totalLen = 0;
+ foreach (OmfRecord omfRec in Records) {
+ if (omfRec.Op != OmfRecord.Opcode.LCONST && omfRec.Op != OmfRecord.Opcode.DS) {
+ break;
+ }
+ // safe to assume NUMLEN=4, NUMSEX=0
+ totalLen += RawData.GetWord(mFileData, omfRec.FileOffset + 1, 4, false);
+ }
+
+ byte[] data = new byte[totalLen];
+
+ int bufOffset = 0;
+ foreach (OmfRecord omfRec in Records) {
+ if (omfRec.Op == OmfRecord.Opcode.DS) {
+ int len = RawData.GetWord(mFileData, omfRec.FileOffset + 1, 4, false);
+ bufOffset += len; // new buffers are zero-filled
+ } else if (omfRec.Op == OmfRecord.Opcode.LCONST) {
+ int len = RawData.GetWord(mFileData, omfRec.FileOffset + 1, 4, false);
+ Array.Copy(mFileData, omfRec.FileOffset + 5, data, bufOffset, len);
+ bufOffset += len;
+ } else {
+ break;
+ }
+ }
+
+ Debug.Assert(bufOffset == totalLen);
+ Debug.WriteLine("Generated " + totalLen + " bytes of LCONST/DS data for " + this);
+ mConstData = data;
+ return data;
+ }
+
//
// Helper functions.
//
diff --git a/SourceGen/Tools/Omf/WpfGui/OmfSegmentViewer.xaml b/SourceGen/Tools/Omf/WpfGui/OmfSegmentViewer.xaml
index 9dcc0d7..e876528 100644
--- a/SourceGen/Tools/Omf/WpfGui/OmfSegmentViewer.xaml
+++ b/SourceGen/Tools/Omf/WpfGui/OmfSegmentViewer.xaml
@@ -101,8 +101,10 @@ limitations under the License.
-
+
-
-
-
-
+
+
+
+
+
+
+
diff --git a/SourceGen/Tools/Omf/WpfGui/OmfSegmentViewer.xaml.cs b/SourceGen/Tools/Omf/WpfGui/OmfSegmentViewer.xaml.cs
index c541e92..d4e9186 100644
--- a/SourceGen/Tools/Omf/WpfGui/OmfSegmentViewer.xaml.cs
+++ b/SourceGen/Tools/Omf/WpfGui/OmfSegmentViewer.xaml.cs
@@ -63,13 +63,46 @@ namespace SourceGen.Tools.Omf.WpfGui {
public List RecordItems { get; private set; }
+ ///
+ /// Formatted version of OmfReloc object.
+ ///
public class RelocItem {
- public string Offset { get; private set; }
- public string Reference { get; private set; }
public string Width { get; private set; }
public string Shift { get; private set; }
+ public string Offset { get; private set; }
+ public string RelOffset { get; private set; }
+ public string FileNum { get; private set; }
+ public string SegNum { get; private set; }
+ public string SuperType { get; private set; }
+
+ public OmfReloc RelocRef { get; private set; }
+
+ public RelocItem(OmfReloc reloc, Formatter formatter) {
+ RelocRef = reloc;
+
+ Width = reloc.Width.ToString();
+ if (reloc.Shift == 0) {
+ Shift = string.Empty;
+ } else if (reloc.Shift < 0) {
+ Shift = ">> " + -reloc.Shift;
+ } else {
+ Shift = "<< " + reloc.Shift;
+ }
+ Offset = formatter.FormatHexValue(reloc.Offset, 4);
+ RelOffset = formatter.FormatHexValue(reloc.RelOffset, 4);
+ FileNum = reloc.FileNum < 0 ? string.Empty : reloc.FileNum.ToString();
+ SegNum = reloc.SegNum < 0 ? string.Empty : reloc.SegNum.ToString();
+ if (reloc.SuperType < 0) {
+ SuperType = string.Empty;
+ } else if (reloc.SuperType <= 1) {
+ SuperType = "RELOC" + (reloc.SuperType + 2);
+ } else {
+ SuperType = "INTERSEG" + (reloc.SuperType - 1);
+ }
+ }
}
- public List RelocItems { get; private set; } = new List();
+ public List RelocItems { get; private set; }
+ public bool HasRelocs { get { return RelocItems.Count != 0; } }
///
@@ -98,6 +131,13 @@ namespace SourceGen.Tools.Omf.WpfGui {
GenerateHeaderItems();
RecordItems = omfSeg.Records;
+ RelocItems = new List(omfSeg.Relocs.Count);
+ foreach (OmfReloc omfRel in omfSeg.Relocs) {
+ RelocItems.Add(new RelocItem(omfRel, formatter));
+ }
+ RelocItems.Sort(delegate (RelocItem a, RelocItem b) {
+ return a.RelocRef.Offset - b.RelocRef.Offset;
+ });
fmt = (string)FindResource("str_RecordHeaderFmt");
RecordHeaderStr = string.Format(fmt, RecordItems.Count);
diff --git a/SourceGen/Tools/Omf/WpfGui/OmfViewer.xaml.cs b/SourceGen/Tools/Omf/WpfGui/OmfViewer.xaml.cs
index 509be14..6bc983f 100644
--- a/SourceGen/Tools/Omf/WpfGui/OmfViewer.xaml.cs
+++ b/SourceGen/Tools/Omf/WpfGui/OmfViewer.xaml.cs
@@ -29,7 +29,6 @@ namespace SourceGen.Tools.Omf.WpfGui {
/// Apple IIgs OMF file viewer.
///
public partial class OmfViewer : Window, INotifyPropertyChanged {
- private byte[] mFileData;
private OmfFile mOmfFile;
private Formatter mFormatter;
@@ -63,7 +62,7 @@ namespace SourceGen.Tools.Omf.WpfGui {
get { return OmfSeg.Length; }
}
public int FileLength {
- get { return OmfSeg.FileLength; }
+ get { return OmfSeg.RawFileLength; }
}
public SegmentListItem(OmfSegment omfSeg) {
@@ -101,13 +100,13 @@ namespace SourceGen.Tools.Omf.WpfGui {
/// Parent window.
/// Path to file on disk. Only used for display.
/// File contents.
+ /// Text formatter.
public OmfViewer(Window owner, string pathName, byte[] data, Formatter formatter) {
InitializeComponent();
Owner = owner;
DataContext = this;
PathName = pathName;
- mFileData = data;
mFormatter = formatter;
mOmfFile = new OmfFile(data);