From 0fa77cba756e29bca574ff3c4f7ee57f046e175d Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Fri, 3 Jul 2020 22:03:50 -0700 Subject: [PATCH] Apply relocation data to unformatted data Works well for things like jump tables. Seeing a bunch of these scattered in a chunk of data is a decent signal that it's actually code. In a bold move, we now exclude PEA operands from auto-label gen when they don't have relocation data. This is very useful for things like Int2Hex for which constants are typically pushed with PEA. Reworked the "use reloc data" setting so it defaults to false and is explicitly set to true when converting OMF. This provides a minor optimization since we now check the boolean and skip doing a lookup in an empty table. --- SourceGen/DataAnalysis.cs | 67 +++++++++++++++++++++++++++------- SourceGen/ProjectProperties.cs | 2 +- SourceGen/Res/Strings.xaml | 2 +- SourceGen/Tools/Omf/Loader.cs | 15 ++++++-- 4 files changed, 67 insertions(+), 19 deletions(-) diff --git a/SourceGen/DataAnalysis.cs b/SourceGen/DataAnalysis.cs index 4049394..7853a80 100644 --- a/SourceGen/DataAnalysis.cs +++ b/SourceGen/DataAnalysis.cs @@ -163,10 +163,11 @@ namespace SourceGen { } // Check for a relocation. It'll be at offset+1 because it's on the operand, - // not the opcode byte. - if (mAnalysisParams.UseRelocData && mProject.RelocList.TryGetValue(offset + 1, - out DisasmProject.RelocData reloc)) { - if (reloc.Value != attr.OperandAddress) { + // not the opcode byte. (Make sure to check the length, or an RTS followed + // by relocated data will freak out.) + if (mAnalysisParams.UseRelocData) { + if (attr.Length > 1 && mProject.RelocList.TryGetValue(offset + 1, + out DisasmProject.RelocData reloc)) { // The relocation address differs from what the analyzer came up // with. This may be because of incorrect assumptions about the // bank (assuming B==K) or because the partial address refers to @@ -174,28 +175,33 @@ namespace SourceGen { // address is different, attr.OperandOffset will also be different. int relOperandOffset = mProject.AddrMap.AddressToOffset(offset, reloc.Value); - if (relOperandOffset >= 0 && relOperandOffset != attr.OperandOffset) { + if (relOperandOffset >= 0) { // Determined a different offset. Use that instead. //Debug.WriteLine("REL +" + offset.ToString("x6") + " " + // reloc.Value.ToString("x6") + " vs. " + // attr.OperandAddress.ToString("x6")); - WeakSymbolRef.Part part = WeakSymbolRef.Part.Low; - if (reloc.Shift == -8) { - part = WeakSymbolRef.Part.High; - } else if (reloc.Shift == -16) { - part = WeakSymbolRef.Part.Bank; - } + WeakSymbolRef.Part part = ShiftToPart(reloc.Shift); SetDataTarget(offset, attr.Length, relOperandOffset, part); continue; } } + + // No reloc for this instruction. If it's a relative branch we need + // to do the usual stuff, but if it's a PEA we want to treat it like + // an immediate value. The safest thing to do is blacklist PEA and + // let everything else proceed like it does without reloc data enabled. + OpDef op = mProject.CpuDef.GetOpDef(mProject.FileData[offset]); + if (op == OpDef.OpPEA_StackAbs) { + //Debug.WriteLine("NoPEA +" + offset.ToString("x6")); + continue; + } } int operandOffset = attr.OperandOffset; if (operandOffset >= 0) { - // This is an offset reference: a branch or data access instruction whose - // target is inside the file. Create a FormatDescriptor for it, and - // generate a label at the target if one is not already present. + // This is an offset reference: a branch or data access instruction + // whose target is inside the file. Create a FormatDescriptor for it, + // and generate a label at the target if one is not already present. SetDataTarget(offset, attr.Length, operandOffset, WeakSymbolRef.Part.Low); } @@ -237,10 +243,43 @@ namespace SourceGen { // There shouldn't be any data items inside other data items, so we // can just skip forward. offset += mAnattribs[offset].DataDescriptor.Length - 1; + } else if (mAnalysisParams.UseRelocData && + !attr.IsInstruction && !attr.IsData && !attr.IsInlineData && + mProject.RelocList.TryGetValue(offset, + out DisasmProject.RelocData reloc)) { + // Byte is unformatted, but there's relocation data here. If the full + // range of bytes is unformatted, create a symbolic reference. + bool allClear = true; + for (int i = 1; i < reloc.Width; i++) { + if (mAnattribs[offset + i].DataDescriptor != null) { + allClear = false; + break; + } + } + if (allClear) { + int operandOffset = mProject.AddrMap.AddressToOffset(offset, reloc.Value); + if (operandOffset >= 0) { + //Debug.WriteLine("DREL +" + offset.ToString("x6") + " val=" + + // reloc.Value.ToString("x6") + + // " opOff=" + operandOffset.ToString("x6")); + SetDataTarget(offset, reloc.Width, operandOffset, + ShiftToPart(reloc.Shift)); + } + } } } } + private static WeakSymbolRef.Part ShiftToPart(int shift) { + if (shift == -16) { + return WeakSymbolRef.Part.Bank; + } else if (shift == -8) { + return WeakSymbolRef.Part.High; + } else { + return WeakSymbolRef.Part.Low; + } + } + /// /// Extracts the operand offset from a data item. Only useful for numeric/Address /// and numeric/Symbol. diff --git a/SourceGen/ProjectProperties.cs b/SourceGen/ProjectProperties.cs index 9bc4737..d188621 100644 --- a/SourceGen/ProjectProperties.cs +++ b/SourceGen/ProjectProperties.cs @@ -61,7 +61,7 @@ namespace SourceGen { DefaultTextScanMode = TextScanMode.LowHighAscii; MinCharsForString = DataAnalysis.DEFAULT_MIN_STRING_LENGTH; SeekNearbyTargets = true; - UseRelocData = true; + UseRelocData = false; SmartPlpHandling = true; } public AnalysisParameters(AnalysisParameters src) { diff --git a/SourceGen/Res/Strings.xaml b/SourceGen/Res/Strings.xaml index fd4b84c..ff3a8b8 100644 --- a/SourceGen/Res/Strings.xaml +++ b/SourceGen/Res/Strings.xaml @@ -131,7 +131,7 @@ limitations under the License. no files available No exported symbols found. Segment {0:D2}: Kind={1}, Attrs={2}, Name='{3}' - Segment {0:D2}: {3} {1,-9} Name='{2}' + Segment {0:D2}: {3} {1,-9} Name='{2}', Length={4} Seg{0:D2}: {1} '{2}' The file doesn't exist. File is empty diff --git a/SourceGen/Tools/Omf/Loader.cs b/SourceGen/Tools/Omf/Loader.cs index 5ba5814..b1b01a7 100644 --- a/SourceGen/Tools/Omf/Loader.cs +++ b/SourceGen/Tools/Omf/Loader.cs @@ -299,6 +299,7 @@ namespace SourceGen.Tools.Omf { ChangeSet cs = new ChangeSet(mSegmentMap.Count * 2); AddHeaderComment(proj, cs); + UndoableChange uc; // Load the segments, and add entries to the project. int bufOffset = 0; @@ -327,7 +328,7 @@ namespace SourceGen.Tools.Omf { // Add a comment identifying the segment and its attributes. string segCmt = string.Format(Res.Strings.OMF_SEG_COMMENT_FMT, ent.Segment.SegNum, ent.Segment.Kind, ent.Segment.Attrs, ent.Segment.SegName); - UndoableChange uc = UndoableChange.CreateLongCommentChange(bufOffset, null, + uc = UndoableChange.CreateLongCommentChange(bufOffset, null, new MultiLineComment(segCmt)); cs.Add(uc); @@ -343,11 +344,19 @@ namespace SourceGen.Tools.Omf { } proj.PrepForNew(data, "new_proj"); - proj.ApplyChanges(cs, false, out _); foreach (KeyValuePair kvp in mRelocData) { proj.RelocList.Add(kvp.Key, kvp.Value); } + // Enable "use reloc" in the analysis parameters. + ProjectProperties newProps = new ProjectProperties(proj.ProjectProps); + newProps.AnalysisParams.UseRelocData = true; + uc = UndoableChange.CreateProjectPropertiesChange(proj.ProjectProps, newProps); + cs.Add(uc); + + Debug.WriteLine("Applying " + cs.Count + " changes"); + proj.ApplyChanges(cs, false, out _); + mLoadedData = data; mNewProject = proj; return true; @@ -365,7 +374,7 @@ namespace SourceGen.Tools.Omf { } string segCmt = string.Format(Res.Strings.OMF_SEG_HDR_COMMENT_FMT, ent.Segment.SegNum, ent.Segment.Kind, ent.Segment.SegName, - mFormatter.FormatAddress(ent.Address, true)); + mFormatter.FormatAddress(ent.Address, true), ent.Segment.Length); sb.AppendLine(segCmt); }