aboutsummaryrefslogtreecommitdiff
path: root/gas/config
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2021-04-29 11:45:10 +0200
committerJan Beulich <jbeulich@suse.com>2021-04-29 11:45:10 +0200
commit3abbafc2aacc6706fea3e3e326e2f08d107c3672 (patch)
tree8762f858f41c93ef736b2fef06a8b5afc07d83de /gas/config
parent44f871628ccfcfd931f4619c60554f3bd6b57b8d (diff)
downloadgdb-3abbafc2aacc6706fea3e3e326e2f08d107c3672.zip
gdb-3abbafc2aacc6706fea3e3e326e2f08d107c3672.tar.gz
gdb-3abbafc2aacc6706fea3e3e326e2f08d107c3672.tar.bz2
x86: relax when/how @size can be used
Allow a few more expression forms when the entire expression can be resolved at assembly time. For this, i386_validate_fix() needs to arrange for all processing of the relocation to be deferred to tc_gen_reloc().
Diffstat (limited to 'gas/config')
-rw-r--r--gas/config/tc-i386.c50
-rw-r--r--gas/config/tc-i386.h6
2 files changed, 47 insertions, 9 deletions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 9c544ee..8bd725a 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -14173,9 +14173,17 @@ i386_cons_align (int ignore ATTRIBUTE_UNUSED)
}
}
-void
+int
i386_validate_fix (fixS *fixp)
{
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+ if (fixp->fx_r_type == BFD_RELOC_SIZE32
+ || fixp->fx_r_type == BFD_RELOC_SIZE64)
+ return IS_ELF && fixp->fx_addsy
+ && (!S_IS_DEFINED (fixp->fx_addsy)
+ || S_IS_EXTERNAL (fixp->fx_addsy));
+#endif
+
if (fixp->fx_subsy)
{
if (fixp->fx_subsy == GOT_symbol)
@@ -14222,6 +14230,8 @@ i386_validate_fix (fixS *fixp)
}
}
#endif
+
+ return 1;
}
arelent *
@@ -14233,18 +14243,38 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
switch (fixp->fx_r_type)
{
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+ symbolS *sym;
+
case BFD_RELOC_SIZE32:
case BFD_RELOC_SIZE64:
- if (IS_ELF
- && S_IS_DEFINED (fixp->fx_addsy)
- && !S_IS_EXTERNAL (fixp->fx_addsy))
+ if (fixp->fx_addsy
+ && !bfd_is_abs_section (S_GET_SEGMENT (fixp->fx_addsy))
+ && (!fixp->fx_subsy
+ || bfd_is_abs_section (S_GET_SEGMENT (fixp->fx_subsy))))
+ sym = fixp->fx_addsy;
+ else if (fixp->fx_subsy
+ && !bfd_is_abs_section (S_GET_SEGMENT (fixp->fx_subsy))
+ && (!fixp->fx_addsy
+ || bfd_is_abs_section (S_GET_SEGMENT (fixp->fx_addsy))))
+ sym = fixp->fx_subsy;
+ else
+ sym = NULL;
+ if (IS_ELF && sym && S_IS_DEFINED (sym) && !S_IS_EXTERNAL (sym))
{
/* Resolve size relocation against local symbol to size of
the symbol plus addend. */
- valueT value = S_GET_SIZE (fixp->fx_addsy);
+ valueT value = S_GET_SIZE (sym);
- if (symbol_get_bfdsym (fixp->fx_addsy)->flags & BSF_SECTION_SYM)
- value = bfd_section_size (S_GET_SEGMENT (fixp->fx_addsy));
+ if (symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM)
+ value = bfd_section_size (S_GET_SEGMENT (sym));
+ if (sym == fixp->fx_subsy)
+ {
+ value = -value;
+ if (fixp->fx_addsy)
+ value += S_GET_VALUE (fixp->fx_addsy);
+ }
+ else if (fixp->fx_subsy)
+ value -= S_GET_VALUE (fixp->fx_subsy);
value += fixp->fx_offset;
if (fixp->fx_r_type == BFD_RELOC_SIZE32
&& object_64bit
@@ -14256,6 +14286,12 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
md_apply_fix (fixp, (valueT *) &value, NULL);
return NULL;
}
+ if (!fixp->fx_addsy || fixp->fx_subsy)
+ {
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ "unsupported expression involving @size");
+ return NULL;
+ }
#endif
/* Fall through. */
diff --git a/gas/config/tc-i386.h b/gas/config/tc-i386.h
index 39d7c27..5516a16 100644
--- a/gas/config/tc-i386.h
+++ b/gas/config/tc-i386.h
@@ -143,8 +143,10 @@ extern int x86_address_bytes (void);
#define NO_RELOC BFD_RELOC_NONE
-void i386_validate_fix (struct fix *);
-#define TC_VALIDATE_FIX(FIX,SEGTYPE,SKIP) i386_validate_fix(FIX)
+int i386_validate_fix (struct fix *);
+#define TC_VALIDATE_FIX(FIX,SEGTYPE,SKIP) do { \
+ if (!i386_validate_fix(FIX)) goto SKIP; \
+ } while (0)
#define tc_fix_adjustable(X) tc_i386_fix_adjustable(X)
extern int tc_i386_fix_adjustable (struct fix *);