diff --git a/SourceGen/DisasmProject.cs b/SourceGen/DisasmProject.cs index 2d79ade..1b22267 100644 --- a/SourceGen/DisasmProject.cs +++ b/SourceGen/DisasmProject.cs @@ -119,6 +119,28 @@ namespace SourceGen { /// public ProjectProperties ProjectProps { get; private set; } + /// + /// "Cooked" form of relocation data (e.g. OmfReloc). This does not contain the file + /// offset, as that's expected to be used as the dictionary key. + /// + /// Will be null unless the project was generated from a relocatable source. + /// + [Serializable] + public class RelocData { + public byte Width; // width of area written by relocator + public byte Shift; // amount to shift the value + public int Value; // value used (unshifted, full width) + + public RelocData() { } // for deserialization + + public RelocData(byte width, byte shift, int value) { + Width = width; + Shift = shift; + Value = value; + } + } + public Dictionary RelocList { get; set; } + #endregion // data to save & restore diff --git a/SourceGen/ProjectFile.cs b/SourceGen/ProjectFile.cs index a8a2116..d3c81ee 100644 --- a/SourceGen/ProjectFile.cs +++ b/SourceGen/ProjectFile.cs @@ -53,7 +53,7 @@ namespace SourceGen { // ignore stuff that's in one side but not the other. However, if we're opening a // newer file in an older program, it's worth letting the user know that some stuff // may get lost as soon as they save the file. - public const int CONTENT_VERSION = 3; + public const int CONTENT_VERSION = 4; private static readonly bool ADD_CRLF = true; @@ -417,6 +417,7 @@ namespace SourceGen { public List Visualizations { get; set; } public List VisualizationAnimations { get; set; } public Dictionary VisualizationSets { get; set; } + public Dictionary RelocList { get; set; } /// /// Serializes a DisasmProject into an augmented JSON string. @@ -525,6 +526,15 @@ namespace SourceGen { spf.ProjectProps = new SerProjectProperties(proj.ProjectProps); + if (proj.RelocList != null) { + // The objects can serialize directly, but the Dictionary key can't be an int. + spf.RelocList = + new Dictionary(proj.RelocList.Count); + foreach (KeyValuePair kvp in proj.RelocList) { + spf.RelocList.Add(kvp.Key.ToString(), kvp.Value); + } + } + JavaScriptSerializer ser = new JavaScriptSerializer(); string cereal = ser.Serialize(spf); sb.Append(cereal); @@ -832,6 +842,19 @@ namespace SourceGen { } } + // Deserialize relocation data. This was added in v1.7. + if (spf.RelocList != null) { + proj.RelocList = new Dictionary(); + foreach (KeyValuePair kvp in spf.RelocList) { + if (!ParseValidateKey(kvp.Key, spf.FileDataLength, + Res.Strings.PROJECT_FIELD_RELOC_DATA, report, out int intKey)) { + continue; + } + proj.RelocList.Add(intKey, kvp.Value); + } + } + + return true; } diff --git a/SourceGen/Res/Strings.xaml b/SourceGen/Res/Strings.xaml index cb97889..fd4b84c 100644 --- a/SourceGen/Res/Strings.xaml +++ b/SourceGen/Res/Strings.xaml @@ -155,6 +155,7 @@ limitations under the License. local variable table note operand format + reloc data status flag override type hint user-defined label diff --git a/SourceGen/Res/Strings.xaml.cs b/SourceGen/Res/Strings.xaml.cs index 4b80c0d..cd5da68 100644 --- a/SourceGen/Res/Strings.xaml.cs +++ b/SourceGen/Res/Strings.xaml.cs @@ -291,6 +291,8 @@ namespace SourceGen.Res { (string)Application.Current.FindResource("str_ProjectFieldNote"); public static string PROJECT_FIELD_OPERAND_FORMAT = (string)Application.Current.FindResource("str_ProjectFieldOperandFormat"); + public static string PROJECT_FIELD_RELOC_DATA = + (string)Application.Current.FindResource("str_ProjectFieldRelocData"); public static string PROJECT_FIELD_STATUS_FLAGS = (string)Application.Current.FindResource("str_ProjectFieldStatusFlags"); public static string PROJECT_FIELD_TYPE_HINT = diff --git a/SourceGen/Tools/Omf/Loader.cs b/SourceGen/Tools/Omf/Loader.cs index f2d61b2..5efd9e2 100644 --- a/SourceGen/Tools/Omf/Loader.cs +++ b/SourceGen/Tools/Omf/Loader.cs @@ -48,11 +48,15 @@ namespace SourceGen.Tools.Omf { } private List mSegmentMap; + private Dictionary mRelocData = + new Dictionary(); + /// /// Constructor. /// /// OMF file to load. + /// Text formatter. public Loader(OmfFile omfFile, Formatter formatter) { Debug.Assert(omfFile.OmfFileKind == OmfFile.FileKind.Load); @@ -83,7 +87,7 @@ namespace SourceGen.Tools.Omf { Debug.Assert(i == ent.Segment.SegNum); } - if (!GenerateOutput()) { + if (!GenerateDataAndProject()) { mSegmentMap = null; return false; } @@ -258,7 +262,7 @@ namespace SourceGen.Tools.Omf { return true; } - private bool GenerateOutput() { + private bool GenerateDataAndProject() { // Sum up the segment lengths to get the total project size. int totalLen = 0; foreach (SegmentMapEntry ent in mSegmentMap) { @@ -339,7 +343,8 @@ namespace SourceGen.Tools.Omf { } proj.PrepForNew(data, "new_proj"); - proj.ApplyChanges(cs, false, out RangeSet unused); + proj.ApplyChanges(cs, false, out _); + proj.RelocList = mRelocData; mLoadedData = data; mNewProject = proj; @@ -401,6 +406,10 @@ namespace SourceGen.Tools.Omf { } } + if (omfRel.Shift < -32 || omfRel.Shift > 32) { + Debug.WriteLine("Invalid reloc shift " + omfRel.Shift); + return false; + } if (omfRel.Shift < 0) { relocAddr >>= -omfRel.Shift; } else if (omfRel.Shift > 0) { @@ -430,6 +439,9 @@ namespace SourceGen.Tools.Omf { Debug.WriteLine("Invalid reloc width " + omfRel.Width); return false; } + + mRelocData.Add(bufOffset + omfRel.Offset, + new DisasmProject.RelocData((byte)omfRel.Width, (byte)omfRel.Shift, relocAddr)); } return true; @@ -439,10 +451,17 @@ namespace SourceGen.Tools.Omf { /// Edits the data file, essentially putting the jump table entries into the /// "loaded" state. /// + /// + /// We don't use ent.Segment.Relocs, as that is expected to be empty. + /// private bool RelocJumpTable(SegmentMapEntry ent, byte[] data, int bufOffset, ChangeSet cs) { const int ENTRY_LEN = 14; + if (ent.Segment.Relocs.Count != 0) { + Debug.WriteLine("WEIRD: jump table has reloc data?"); + } + byte[] srcData = ent.Segment.GetConstData(); Array.Copy(srcData, 0, data, bufOffset, srcData.Length); @@ -458,7 +477,7 @@ namespace SourceGen.Tools.Omf { TypedRangeSet undoSet = new TypedRangeSet(); for (int i = 8; i + 4 <= ent.Segment.Length; i += ENTRY_LEN) { - int userId = RawData.GetWord(data, bufOffset + i, 2, false); + //int userId = RawData.GetWord(data, bufOffset + i, 2, false); int fileNum = RawData.GetWord(data, bufOffset + i + 2, 2, false); if (fileNum == 0) { @@ -476,7 +495,7 @@ namespace SourceGen.Tools.Omf { return false; } - // Note: segment ends right after FileNum, so don't try to read further + // Note: segment might end right after FileNum, so don't try to read further // until we've confirmed that FileNum != 0. int segNum = RawData.GetWord(data, bufOffset + i + 4, 2, false); diff --git a/SourceGen/Tools/Omf/WpfGui/OmfSegmentViewer.xaml b/SourceGen/Tools/Omf/WpfGui/OmfSegmentViewer.xaml index e876528..ef31098 100644 --- a/SourceGen/Tools/Omf/WpfGui/OmfSegmentViewer.xaml +++ b/SourceGen/Tools/Omf/WpfGui/OmfSegmentViewer.xaml @@ -31,6 +31,7 @@ limitations under the License. File offset {0}, length {1} ({2}) Records ({0}): + Relocation dictionary ({0}): @@ -59,7 +60,7 @@ limitations under the License. HeadersVisibility="Column" CanUserReorderColumns="False" CanUserSortColumns="False" - SelectionMode="Single"> + SelectionMode="Extended"> + SelectionMode="Extended"> - + SelectionMode="Extended">