From f26a03869a9f27d72948377d2012c482f39c34d6 Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Tue, 23 Oct 2018 20:29:24 -0700 Subject: [PATCH] Finish the underscore handling in the label localizer Correctly handle pre-existing underscores and avoidance of "reserved" labels. Also, add more underscores to 2012-label-localizer to exercise the code. (issue #16) --- SourceGen/AsmGen/GenAndAsm.cs | 2 +- SourceGen/AsmGen/LabelLocalizer.cs | 51 +++++++++++++++++-- SourceGen/RuntimeData/Help/codegen.html | 2 + .../SGTestData/2012-label-localizer.dis65 | 16 +++--- .../Expected/2012-label-localizer_64tass.S | 24 +++++---- .../Expected/2012-label-localizer_Merlin32.S | 24 ++++----- .../Expected/2012-label-localizer_cc65.S | 23 +++++---- 7 files changed, 97 insertions(+), 45 deletions(-) diff --git a/SourceGen/AsmGen/GenAndAsm.cs b/SourceGen/AsmGen/GenAndAsm.cs index 951dec0..cf460e2 100644 --- a/SourceGen/AsmGen/GenAndAsm.cs +++ b/SourceGen/AsmGen/GenAndAsm.cs @@ -211,7 +211,7 @@ namespace SourceGen.AsmGen { /// private void UpdateAssemblerControls() { bool asmConf = IsAssemblerConfigured(); - Debug.WriteLine("ID=" + mSelectedAssemblerId + " asmConf=" + asmConf); + //Debug.WriteLine("ID=" + mSelectedAssemblerId + " asmConf=" + asmConf); configureAsmLinkLabel.Visible = !asmConf; if (mGenerationResults == null || !asmConf) { runAssemblerButton.Enabled = false; diff --git a/SourceGen/AsmGen/LabelLocalizer.cs b/SourceGen/AsmGen/LabelLocalizer.cs index 12162f5..934c53c 100644 --- a/SourceGen/AsmGen/LabelLocalizer.cs +++ b/SourceGen/AsmGen/LabelLocalizer.cs @@ -167,6 +167,8 @@ namespace SourceGen.AsmGen { /// Analyzes labels to identify which ones may be treated as non-global. /// public void Analyze() { + Debug.Assert(LocalPrefix.Length > 0); + mGlobalFlags.SetAll(false); // Currently we only support the "local labels have scope that ends at a global @@ -317,6 +319,8 @@ namespace SourceGen.AsmGen { /// /// This may be called even if label localization is disabled. In that case we just /// create an empty label map and populate as needed. + /// + /// Only call this if underscores are used to indicate local labels. /// public void MaskLeadingUnderscores() { bool allGlobal = false; @@ -325,6 +329,14 @@ namespace SourceGen.AsmGen { LabelMap = new Dictionary(); } + // Throw out the original local label generation. + LabelMap.Clear(); + + // Use this to test for uniqueness. We add all labels here as we go, not just the + // ones being remapped. For each label we either add the original or the localized + // form. + SortedList allLabels = new SortedList(); + for (int i = 0; i < mProject.FileDataLength; i++) { Symbol sym = mProject.GetAnattrib(i).Symbol; if (sym == null) { @@ -332,12 +344,43 @@ namespace SourceGen.AsmGen { continue; } - if (sym.Label.StartsWith("_") && (allGlobal || mGlobalFlags[i])) { - Debug.WriteLine("Adjusting " + sym.Label); - // TODO: uniquify - LabelMap[sym.Label] = "X" + sym.Label; + string newLabel; + if (allGlobal || mGlobalFlags[i]) { + // Global symbol. Don't let it start with '_'. + if (sym.Label.StartsWith("_")) { + // There's an underscore here that was added by the user. Stick some + // other character in front. + newLabel = "X" + sym.Label; + } else { + // No change needed. + newLabel = sym.Label; + } + } else { + // Local symbol. + if (sym.Label.StartsWith("_")) { + // The original starts with one or more underscores. Adding another + // will create a "__" label, which is reserved in 64tass. + newLabel = "_X" + sym.Label; + } else { + newLabel = "_" + sym.Label; + } + } + + // Make sure it's unique. + string uniqueLabel = newLabel; + int uval = 1; + while (allLabels.ContainsKey(uniqueLabel)) { + uniqueLabel = newLabel + uval.ToString(); + } + allLabels.Add(uniqueLabel, uniqueLabel); + + // If it's different, add it to the label map. + if (sym.Label != uniqueLabel) { + LabelMap.Add(sym.Label, uniqueLabel); } } + + Debug.WriteLine("UMAP: allcount=" + allLabels.Count + " mapcount=" + LabelMap.Count); } } } diff --git a/SourceGen/RuntimeData/Help/codegen.html b/SourceGen/RuntimeData/Help/codegen.html index 8c9a65f..913dc21 100644 --- a/SourceGen/RuntimeData/Help/codegen.html +++ b/SourceGen/RuntimeData/Help/codegen.html @@ -139,6 +139,8 @@ code, but also needs to know how to handle the corner cases.

label is local. If you create labels with leading underscores that are not local, the labels must be altered to start with some other character, and made unique. +
  • Labels starting with two underscores are "reserved". Trying to + use them causes an error.
  • By default, 64tass sets the first two bytes of the output file to the load address. The --nostart flag is used to suppress this.
  • diff --git a/SourceGen/SGTestData/2012-label-localizer.dis65 b/SourceGen/SGTestData/2012-label-localizer.dis65 index 3011b6e..f297062 100644 --- a/SourceGen/SGTestData/2012-label-localizer.dis65 +++ b/SourceGen/SGTestData/2012-label-localizer.dis65 @@ -30,7 +30,7 @@ "16":{ "Label":"pastglob","Value":4112,"Source":"User","Type":"LocalOrGlobalAddr"}, "15":{ -"Label":"nextglob","Value":4111,"Source":"User","Type":"GlobalAddr"}, +"Label":"X_start","Value":4111,"Source":"User","Type":"GlobalAddr"}, "20":{ "Label":"nlocal","Value":4116,"Source":"User","Type":"GlobalAddr"}, "22":{ @@ -40,9 +40,9 @@ "30":{ "Label":"reach3G","Value":4126,"Source":"User","Type":"GlobalAddr"}, "31":{ -"Label":"reach4","Value":4127,"Source":"User","Type":"LocalOrGlobalAddr"}, +"Label":"_reach4","Value":4127,"Source":"User","Type":"LocalOrGlobalAddr"}, "1":{ -"Label":"start","Value":4097,"Source":"User","Type":"LocalOrGlobalAddr"}, +"Label":"_start","Value":4097,"Source":"User","Type":"LocalOrGlobalAddr"}, "50":{ "Label":"gtest1","Value":4146,"Source":"User","Type":"GlobalAddr"}, "54":{ @@ -52,7 +52,7 @@ "61":{ "Label":"topglob","Value":4157,"Source":"User","Type":"GlobalAddr"}, "70":{ -"Label":"globalnm","Value":4166,"Source":"User","Type":"LocalOrGlobalAddr"}, +"Label":"globalnm","Value":4166,"Source":"User","Type":"GlobalAddr"}, "76":{ "Label":"nglobal","Value":4172,"Source":"User","Type":"LocalOrGlobalAddr"}, "82":{ @@ -60,7 +60,11 @@ "77":{ "Label":"globlat","Value":4173,"Source":"User","Type":"GlobalAddr"}, "83":{ -"Label":"EXCESSIVELY_LONG_LABEL","Value":4179,"Source":"User","Type":"GlobalAddr"}}, +"Label":"EXCESSIVELY_LONG_LABEL","Value":4179,"Source":"User","Type":"GlobalAddr"}, +"14":{ +"Label":"__nopped","Value":4110,"Source":"User","Type":"LocalOrGlobalAddr"}, +"13":{ +"Label":"start","Value":4109,"Source":"User","Type":"LocalOrGlobalAddr"}}, "OperandFormats":{ "23":{ "Length":3,"Format":"NumericLE","SubFormat":"Symbol","SymbolRef":{ @@ -70,6 +74,6 @@ "Label":"reach2","Part":"Low"}}, "32":{ "Length":3,"Format":"NumericLE","SubFormat":"Symbol","SymbolRef":{ -"Label":"reach4","Part":"Low"}}, +"Label":"_reach4","Part":"Low"}}, "58":{ "Length":3,"Format":"NumericLE","SubFormat":"Hex","SymbolRef":null}}} diff --git a/SourceGen/SGTestData/Expected/2012-label-localizer_64tass.S b/SourceGen/SGTestData/Expected/2012-label-localizer_64tass.S index 9260b50..169d0b6 100644 --- a/SourceGen/SGTestData/Expected/2012-label-localizer_64tass.S +++ b/SourceGen/SGTestData/Expected/2012-label-localizer_64tass.S @@ -5,13 +5,14 @@ REALLYLONGLABELNAME = $8888 ;that's a long name .as .xs nop -start lda _L100D - lda nextglob +X_start lda _start + lda X_start1 lda pastglob - lda _L100E -_L100D nop -_L100E nop -nextglob + lda _X__nopped +_start nop +_X__nopped + nop +X_start1 nop pastglob nop @@ -22,12 +23,13 @@ reach1G nop lda _reach2+2 _reach2 nop reach3G nop -_reach4 nop - lda _reach4-2 +_X_reach4 + nop + lda _X_reach4-2 lda $00 beq _L102D - jsr _reach4 - jsr start + jsr _X_reach4 + jsr X_start _L102D lda #$22 lda gtest2 gtest1 nop @@ -42,7 +44,7 @@ topglob nop nop _L1043 nop lda #$44 -_globalnm +globalnm jsr _L104A nop _L104A nop diff --git a/SourceGen/SGTestData/Expected/2012-label-localizer_Merlin32.S b/SourceGen/SGTestData/Expected/2012-label-localizer_Merlin32.S index 4cfd86e..8db753d 100644 --- a/SourceGen/SGTestData/Expected/2012-label-localizer_Merlin32.S +++ b/SourceGen/SGTestData/Expected/2012-label-localizer_Merlin32.S @@ -2,13 +2,14 @@ REALLYLONGLABELNAME equ $8888 ;that's a long name org $1000 nop -start lda :L100D - lda nextglob +_start lda :start + lda X_start lda pastglob - lda :L100E -:L100D nop -:L100E nop -nextglob nop + lda :__nopped +:start nop +:__nopped + nop +X_start nop pastglob nop lda nlocal nlocal lda #$11 @@ -17,12 +18,12 @@ reach1G nop lda :reach2+2 :reach2 nop reach3G nop -:reach4 nop - lda :reach4-2 +:_reach4 nop + lda :_reach4-2 lda $00 beq :L102D - jsr :reach4 - jsr start + jsr :_reach4 + jsr _start :L102D lda #$22 lda gtest2 gtest1 nop @@ -37,8 +38,7 @@ topglob nop nop :L1043 nop lda #$44 -:globalnm - jsr :L104A +globalnm jsr :L104A nop :L104A nop nop diff --git a/SourceGen/SGTestData/Expected/2012-label-localizer_cc65.S b/SourceGen/SGTestData/Expected/2012-label-localizer_cc65.S index 711d71d..7e01e22 100644 --- a/SourceGen/SGTestData/Expected/2012-label-localizer_cc65.S +++ b/SourceGen/SGTestData/Expected/2012-label-localizer_cc65.S @@ -5,14 +5,14 @@ REALLYLONGLABELNAME = $8888 ;that's a long name .a8 .i8 nop -start: lda @L100D - lda nextglob +_start: lda @start + lda X_start lda pastglob - lda @L100E -@L100D: nop -@L100E: nop -nextglob: + lda @__nopped +@start: nop +@__nopped: nop +X_start: nop pastglob: nop lda nlocal @@ -22,12 +22,13 @@ reach1G: nop lda @reach2+2 @reach2: nop reach3G: nop -@reach4: nop - lda @reach4-2 +@_reach4: + nop + lda @_reach4-2 lda $00 beq @L102D - jsr @reach4 - jsr start + jsr @_reach4 + jsr _start @L102D: lda #$22 lda gtest2 gtest1: nop @@ -42,7 +43,7 @@ topglob: nop nop @L1043: nop lda #$44 -@globalnm: +globalnm: jsr @L104A nop @L104A: nop