From e63e801e9cf2dddbdd3d95347137548db630f856 Mon Sep 17 00:00:00 2001 From: AntonioND Date: Tue, 4 Apr 2017 21:21:23 +0100 Subject: [PATCH] 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 --- include/asm/symbol.h | 1 + src/asm/asmy.y | 9 +++++++-- src/asm/symbol.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/include/asm/symbol.h b/include/asm/symbol.h index 727f44c4..d0fc764d 100644 --- a/include/asm/symbol.h +++ b/include/asm/symbol.h @@ -71,5 +71,6 @@ ULONG sym_GetDefinedValue(char *s); ULONG sym_isDefined(char *tzName); void sym_Purge(char *tzName); ULONG sym_isConstDefined(char *tzName); +int sym_IsRelocDiffDefined(char *tzSym1, char *tzSym2); #endif diff --git a/src/asm/asmy.y b/src/asm/asmy.y index 1757012b..62bbbdd0 100644 --- a/src/asm/asmy.y +++ b/src/asm/asmy.y @@ -1040,9 +1040,14 @@ const : T_ID { $$ = sym_GetConstantValue($1); } | 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; } diff --git a/src/asm/symbol.c b/src/asm/symbol.c index 01251b3a..10a76f97 100644 --- a/src/asm/symbol.c +++ b/src/asm/symbol.c @@ -619,6 +619,49 @@ sym_AddReloc(char *tzSym) pScope = findsymbol(tzSym, NULL); } +/* + * 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 */