shithub: rgbds

Download patch

ref: 0f3b708dce0226ffcd2a179bc9650e7f86e22f5b
parent: 7eb9101d4353ae6c5509bb0a4e65ca8b73444220
parent: e63e801e9cf2dddbdd3d95347137548db630f856
author: AntonioND <[email protected]>
date: Wed Apr 5 19:08:37 EDT 2017

Merge pull request #157 from AntonioND/an/error-undef-diff

Output error message if diff of labels not defined

--- 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
@@ -1039,9 +1039,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