shithub: rgbds

Download patch

ref: e63e801e9cf2dddbdd3d95347137548db630f856
parent: 2abdc9c59db277aa203f28da343f3b65ec47df8e
author: AntonioND <[email protected]>
date: Tue Apr 4 17:21:23 EDT 2017

Output error message if diff of labels not defined

When calculating the difference of addresses between two labels, for it
to be defined, either:

- Both of them must have their absolute address defined.
- They belong to the same section, so their relative addresses are
  compatible.

This patch adds a check to make sure that any other case is detected so
that the programmer can correct the code.

This applies to rgbasm. The difference of labels can be used, for
example, as argument of DS. The linker can't resize sections, which
means that the final value must be defined when creating the object
file.

Signed-off-by: AntonioND <[email protected]>

--- a/include/asm/symbol.h
+++ b/include/asm/symbol.h
@@ -71,5 +71,6 @@
 ULONG sym_isDefined(char *tzName);
 void sym_Purge(char *tzName);
 ULONG sym_isConstDefined(char *tzName);
+int sym_IsRelocDiffDefined(char *tzSym1, char *tzSym2);
 
 #endif
--- a/src/asm/asmy.y
+++ b/src/asm/asmy.y
@@ -1040,9 +1040,14 @@
 				|	const T_OP_LOGICNE const 		{ $$ = $1 != $3; }
 				|	const T_OP_ADD const			{ $$ = $1 + $3; }
 				|	const T_OP_SUB const			{ $$ = $1 - $3; }
-				|	T_ID  T_OP_SUB T_ID				{ $$ = sym_GetDefinedValue($1) - sym_GetDefinedValue($3); }
+				|	T_ID  T_OP_SUB T_ID
+					{
+						if (sym_IsRelocDiffDefined($1, $3) == 0)
+							fatalerror("'%s - %s' not defined.", $1, $3);
+						$$ = sym_GetDefinedValue($1) - sym_GetDefinedValue($3);
+					}
 				|	const T_OP_XOR const			{ $$ = $1 ^ $3; }
-				|	const T_OP_OR const				{ $$ = $1 | $3; }
+				|	const T_OP_OR const			{ $$ = $1 | $3; }
 				|	const T_OP_AND const			{ $$ = $1 & $3; }
 				|	const T_OP_SHL const			{ $$ = $1 << $3; }
 				|	const T_OP_SHR const			{ $$ = $1 >> $3; }
--- a/src/asm/symbol.c
+++ b/src/asm/symbol.c
@@ -620,6 +620,49 @@
 }
 
 /*
+ * Check if the subtraction of two symbols is defined. That is, either both
+ * symbols are defined and the result is a constant, or both symbols are
+ * relocatable and belong to the same section.
+ *
+ * It returns 1 if the difference is defined, 0 if not.
+ */
+int
+sym_IsRelocDiffDefined(char *tzSym1, char *tzSym2)
+{
+	/* Do nothing the first pass. */
+	if (nPass != 2)
+		return 1;
+
+	struct sSymbol *nsym1, *nsym2;
+
+	/* Do the symbols exist? */
+	if ((nsym1 = sym_FindSymbol(tzSym1)) == NULL)
+		fatalerror("Symbol \"%s\" isn't defined.", tzSym1);
+	if ((nsym2 = sym_FindSymbol(tzSym2)) == NULL)
+		fatalerror("Symbol \"%s\" isn't defined.", tzSym2);
+
+	int s1reloc = (nsym1->nType & SYMF_RELOC) != 0;
+	int s2reloc = (nsym2->nType & SYMF_RELOC) != 0;
+
+	/* Both are non-relocatable */
+	if (!s1reloc && !s2reloc) return 1;
+
+	/* One of them relocatable, the other one not. */
+	if (s1reloc ^ s2reloc) return 0;
+
+	/* Both of them are relocatable. Make sure they are defined (internal
+         * coherency with sym_AddReloc and sym_AddLocalReloc). */
+	if (!(nsym1->nType & SYMF_DEFINED))
+		fatalerror("Relocatable symbol \"%s\" isn't defined.", tzSym1);
+	if (!(nsym2->nType & SYMF_DEFINED))
+		fatalerror("Relocatable symbol \"%s\" isn't defined.", tzSym2);
+
+	/* Both of them must be in the same section for the difference to be
+         * defined. */
+	return nsym1->pSection == nsym2->pSection;
+}
+
+/*
  * Export a symbol
  */
 void