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