summaryrefslogtreecommitdiff
path: root/bfd/elf32-rl78.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2021-08-07 14:13:11 +0930
committerAlan Modra <amodra@gmail.com>2021-08-07 14:56:53 +0930
commit983cdaecc134a5f9adefd052a97bc72321bf0ca3 (patch)
treeeedafc8128f1c26d1a0dc623f7c7a58eb5342396 /bfd/elf32-rl78.c
parent0175375faa416282d2587ca8bf599867dca5fc9e (diff)
downloadbinutils-gdb-983cdaecc134a5f9adefd052a97bc72321bf0ca3.tar.gz
PR28176, rl78 complex reloc divide by zero
This is a bit more than just preventing the divide by zero. Most of the patch is tidying up error reporting, so that for example, linking an object file with a reloc stack underflow produces a linker error rather than just displaying a message that might be ignored. PR 28176 * elf32-rl78.c (RL78_STACK_PUSH, RL78_STACK_POP): Delete. (rl78_stack_push, rl78_stack_pop): New inline functions. (rl78_compute_complex_reloc): Add status and error message params. Use new inline stack handling functions. Report stack overflow or underflow, and divide by zero. (rl78_special_reloc): Return status and error message from rl78_compute_complex_reloc. (rl78_elf_relocate_section): Similarly. Modernise reloc error reporting. Delete unused bfd_reloc_other case. Don't assume DIR24S_PCREL overflow is due to undefined function. (rl78_offset_for_reloc): Adjust to suit rl78_compute_complex_reloc.
Diffstat (limited to 'bfd/elf32-rl78.c')
-rw-r--r--bfd/elf32-rl78.c283
1 files changed, 154 insertions, 129 deletions
diff --git a/bfd/elf32-rl78.c b/bfd/elf32-rl78.c
index 163966f1d69..ccccb76d1ba 100644
--- a/bfd/elf32-rl78.c
+++ b/bfd/elf32-rl78.c
@@ -363,28 +363,24 @@ get_ramstart (struct bfd_link_info * info,
static int32_t rl78_stack [ NUM_STACK_ENTRIES ];
static unsigned int rl78_stack_top;
-#define RL78_STACK_PUSH(val) \
- do \
- { \
- if (rl78_stack_top < NUM_STACK_ENTRIES) \
- rl78_stack [rl78_stack_top ++] = (val); \
- else \
- _bfd_error_handler (_("internal error: RL78 reloc stack overflow")); \
- } \
- while (0)
-
-#define RL78_STACK_POP(dest) \
- do \
- { \
- if (rl78_stack_top > 0) \
- (dest) = rl78_stack [-- rl78_stack_top];\
- else \
- { \
- _bfd_error_handler (_("internal error: RL78 reloc stack underflow")); \
- (dest) = 0; \
- } \
- } \
- while (0)
+static inline void
+rl78_stack_push (bfd_vma val, bfd_reloc_status_type *r)
+{
+ if (rl78_stack_top < NUM_STACK_ENTRIES)
+ rl78_stack[rl78_stack_top++] = val;
+ else
+ *r = bfd_reloc_dangerous;
+}
+
+static inline bfd_vma
+rl78_stack_pop (bfd_reloc_status_type *r)
+{
+ if (rl78_stack_top > 0)
+ return rl78_stack[-- rl78_stack_top];
+ else
+ *r = bfd_reloc_dangerous;
+ return 0;
+}
/* Special handling for RL78 complex relocs. Returns the
value of the reloc, or 0 for relocs which do not generate
@@ -393,23 +389,27 @@ static unsigned int rl78_stack_top;
static bfd_vma
rl78_compute_complex_reloc (unsigned long r_type,
- bfd_vma symval,
- asection * input_section)
+ bfd_vma symval,
+ asection *input_section,
+ bfd_reloc_status_type *r,
+ char **error_message)
{
int32_t tmp1, tmp2;
- bfd_vma relocation;
+ bfd_vma relocation = 0;
+ bfd_reloc_status_type stat = bfd_reloc_ok;
switch (r_type)
{
default:
- return 0;
+ stat = bfd_reloc_notsupported;
+ break;
case R_RL78_ABS24S_PCREL:
case R_RL78_ABS16S_PCREL:
case R_RL78_ABS8S_PCREL:
- RL78_STACK_POP (relocation);
+ relocation = rl78_stack_pop (&stat);
relocation -= input_section->output_section->vma + input_section->output_offset;
- return relocation;
+ break;
case R_RL78_ABS32:
case R_RL78_ABS32_REV:
@@ -420,122 +420,144 @@ rl78_compute_complex_reloc (unsigned long r_type,
case R_RL78_ABS8:
case R_RL78_ABS8U:
case R_RL78_ABS8S:
- RL78_STACK_POP (relocation);
- return relocation;
+ relocation = rl78_stack_pop (&stat);
+ break;
case R_RL78_ABS16UL:
case R_RL78_ABS8UL:
- RL78_STACK_POP (relocation);
- return relocation >> 2;
+ relocation = rl78_stack_pop (&stat) >> 2;
+ break;;
case R_RL78_ABS16UW:
case R_RL78_ABS8UW:
- RL78_STACK_POP (relocation);
- return relocation >> 1;
+ relocation = rl78_stack_pop (&stat) >> 1;
+ break;
/* The rest of the relocs compute values and then push them onto the stack. */
case R_RL78_OPramtop:
case R_RL78_OPromtop:
case R_RL78_SYM:
- RL78_STACK_PUSH (symval);
- return 0;
+ rl78_stack_push (symval, &stat);
+ break;
case R_RL78_OPneg:
- RL78_STACK_POP (tmp1);
+ tmp1 = rl78_stack_pop (&stat);
tmp1 = - tmp1;
- RL78_STACK_PUSH (tmp1);
- return 0;
+ rl78_stack_push (tmp1, &stat);
+ break;
case R_RL78_OPadd:
- RL78_STACK_POP (tmp2);
- RL78_STACK_POP (tmp1);
+ tmp2 = rl78_stack_pop (&stat);
+ tmp1 = rl78_stack_pop (&stat);
tmp1 += tmp2;
- RL78_STACK_PUSH (tmp1);
- return 0;
+ rl78_stack_push (tmp1, &stat);
+ break;
case R_RL78_OPsub:
/* For the expression "A - B", the assembler pushes A,
then B, then OPSUB. So the first op we pop is B, not A. */
- RL78_STACK_POP (tmp2); /* B */
- RL78_STACK_POP (tmp1); /* A */
+ tmp2 = rl78_stack_pop (&stat); /* B */
+ tmp1 = rl78_stack_pop (&stat); /* A */
tmp1 -= tmp2; /* A - B */
- RL78_STACK_PUSH (tmp1);
- return 0;
+ rl78_stack_push (tmp1, &stat);
+ break;
case R_RL78_OPmul:
- RL78_STACK_POP (tmp2);
- RL78_STACK_POP (tmp1);
+ tmp2 = rl78_stack_pop (&stat);
+ tmp1 = rl78_stack_pop (&stat);
tmp1 *= tmp2;
- RL78_STACK_PUSH (tmp1);
- return 0;
+ rl78_stack_push (tmp1, &stat);
+ break;
case R_RL78_OPdiv:
- RL78_STACK_POP (tmp2);
- RL78_STACK_POP (tmp1);
- tmp1 /= tmp2;
- RL78_STACK_PUSH (tmp1);
- return 0;
+ tmp2 = rl78_stack_pop (&stat);
+ tmp1 = rl78_stack_pop (&stat);
+ if (tmp2 != 0)
+ tmp1 /= tmp2;
+ else
+ {
+ tmp1 = 0;
+ stat = bfd_reloc_overflow;
+ }
+ rl78_stack_push (tmp1, &stat);
+ break;
case R_RL78_OPshla:
- RL78_STACK_POP (tmp2);
- RL78_STACK_POP (tmp1);
+ tmp2 = rl78_stack_pop (&stat);
+ tmp1 = rl78_stack_pop (&stat);
tmp1 <<= tmp2;
- RL78_STACK_PUSH (tmp1);
- return 0;
+ rl78_stack_push (tmp1, &stat);
+ break;
case R_RL78_OPshra:
- RL78_STACK_POP (tmp2);
- RL78_STACK_POP (tmp1);
+ tmp2 = rl78_stack_pop (&stat);
+ tmp1 = rl78_stack_pop (&stat);
tmp1 >>= tmp2;
- RL78_STACK_PUSH (tmp1);
- return 0;
+ rl78_stack_push (tmp1, &stat);
+ break;
case R_RL78_OPsctsize:
- RL78_STACK_PUSH (input_section->size);
- return 0;
+ rl78_stack_push (input_section->size, &stat);
+ break;
case R_RL78_OPscttop:
- RL78_STACK_PUSH (input_section->output_section->vma);
- return 0;
+ rl78_stack_push (input_section->output_section->vma, &stat);
+ break;
case R_RL78_OPand:
- RL78_STACK_POP (tmp2);
- RL78_STACK_POP (tmp1);
+ tmp2 = rl78_stack_pop (&stat);
+ tmp1 = rl78_stack_pop (&stat);
tmp1 &= tmp2;
- RL78_STACK_PUSH (tmp1);
- return 0;
+ rl78_stack_push (tmp1, &stat);
+ break;
case R_RL78_OPor:
- RL78_STACK_POP (tmp2);
- RL78_STACK_POP (tmp1);
+ tmp2 = rl78_stack_pop (&stat);
+ tmp1 = rl78_stack_pop (&stat);
tmp1 |= tmp2;
- RL78_STACK_PUSH (tmp1);
- return 0;
+ rl78_stack_push (tmp1, &stat);
+ break;
case R_RL78_OPxor:
- RL78_STACK_POP (tmp2);
- RL78_STACK_POP (tmp1);
+ tmp2 = rl78_stack_pop (&stat);
+ tmp1 = rl78_stack_pop (&stat);
tmp1 ^= tmp2;
- RL78_STACK_PUSH (tmp1);
- return 0;
+ rl78_stack_push (tmp1, &stat);
+ break;
case R_RL78_OPnot:
- RL78_STACK_POP (tmp1);
+ tmp1 = rl78_stack_pop (&stat);
tmp1 = ~ tmp1;
- RL78_STACK_PUSH (tmp1);
- return 0;
+ rl78_stack_push (tmp1, &stat);
+ break;
case R_RL78_OPmod:
- RL78_STACK_POP (tmp2);
- RL78_STACK_POP (tmp1);
- tmp1 %= tmp2;
- RL78_STACK_PUSH (tmp1);
- return 0;
+ tmp2 = rl78_stack_pop (&stat);
+ tmp1 = rl78_stack_pop (&stat);
+ if (tmp2 != 0)
+ tmp1 %= tmp2;
+ else
+ {
+ tmp1 = 0;
+ stat = bfd_reloc_overflow;
+ }
+ rl78_stack_push (tmp1, &stat);
+ break;
}
-}
-#undef RL78_STACK_PUSH
-#undef RL78_STACK_POP
+ if (r)
+ {
+ if (stat == bfd_reloc_dangerous)
+ *error_message = (_("RL78 reloc stack overflow/underflow"));
+ else if (stat == bfd_reloc_overflow)
+ {
+ stat = bfd_reloc_dangerous;
+ *error_message = (_("RL78 reloc divide by zero"));
+ }
+ *r = stat;
+ }
+ return relocation;
+}
#define OP(i) (contents[reloc->address + (i)])
@@ -546,7 +568,7 @@ rl78_special_reloc (bfd * input_bfd,
void * data,
asection * input_section,
bfd * output_bfd ATTRIBUTE_UNUSED,
- char ** error_message ATTRIBUTE_UNUSED)
+ char ** error_message)
{
bfd_reloc_status_type r = bfd_reloc_ok;
bfd_vma relocation = 0;
@@ -575,7 +597,8 @@ rl78_special_reloc (bfd * input_bfd,
}
/* Get the value of the relocation. */
- relocation = rl78_compute_complex_reloc (r_type, relocation, input_section);
+ relocation = rl78_compute_complex_reloc (r_type, relocation, input_section,
+ &r, error_message);
/* If the relocation alters the contents of the section then apply it now.
Note - since this function is called from
@@ -689,13 +712,14 @@ rl78_elf_relocate_section
Elf_Internal_Rela * rel;
Elf_Internal_Rela * relend;
asection *splt;
+ bool ret;
symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
relend = relocs + input_section->reloc_count;
splt = elf_hash_table (info)->splt;
-
+ ret = true;
for (rel = relocs; rel < relend; rel ++)
{
reloc_howto_type *howto;
@@ -708,6 +732,7 @@ rl78_elf_relocate_section
const char *name = NULL;
bool unresolved_reloc = true;
int r_type;
+ char *error_message;
r_type = ELF32_R_TYPE (rel->r_info);
r_symndx = ELF32_R_SYM (rel->r_info);
@@ -958,7 +983,8 @@ rl78_elf_relocate_section
case R_RL78_OPxor:
case R_RL78_OPnot:
case R_RL78_OPmod:
- relocation = rl78_compute_complex_reloc (r_type, 0, input_section);
+ relocation = rl78_compute_complex_reloc (r_type, 0, input_section,
+ &r, &error_message);
switch (r_type)
{
@@ -1052,17 +1078,20 @@ rl78_elf_relocate_section
_bfd_error_handler
(_("warning: RL78_SYM reloc with an unknown symbol"));
}
- (void) rl78_compute_complex_reloc (r_type, relocation, input_section);
+ (void) rl78_compute_complex_reloc (r_type, relocation, input_section,
+ &r, &error_message);
break;
case R_RL78_OPromtop:
relocation = get_romstart (info, input_bfd, input_section, rel->r_offset);
- (void) rl78_compute_complex_reloc (r_type, relocation, input_section);
+ (void) rl78_compute_complex_reloc (r_type, relocation, input_section,
+ &r, &error_message);
break;
case R_RL78_OPramtop:
relocation = get_ramstart (info, input_bfd, input_section, rel->r_offset);
- (void) rl78_compute_complex_reloc (r_type, relocation, input_section);
+ (void) rl78_compute_complex_reloc (r_type, relocation, input_section,
+ &r, &error_message);
break;
default:
@@ -1072,20 +1101,12 @@ rl78_elf_relocate_section
if (r != bfd_reloc_ok)
{
- const char * msg = NULL;
-
switch (r)
{
case bfd_reloc_overflow:
- /* Catch the case of a missing function declaration
- and emit a more helpful error message. */
- if (r_type == R_RL78_DIR24S_PCREL)
- /* xgettext:c-format */
- msg = _("%pB(%pA): error: call to undefined function '%s'");
- else
- (*info->callbacks->reloc_overflow)
- (info, (h ? &h->root : NULL), name, howto->name, (bfd_vma) 0,
- input_bfd, input_section, rel->r_offset);
+ (*info->callbacks->reloc_overflow)
+ (info, (h ? &h->root : NULL), name, howto->name, (bfd_vma) 0,
+ input_bfd, input_section, rel->r_offset);
break;
case bfd_reloc_undefined:
@@ -1093,38 +1114,37 @@ rl78_elf_relocate_section
(info, name, input_bfd, input_section, rel->r_offset, true);
break;
- case bfd_reloc_other:
- /* xgettext:c-format */
- msg = _("%pB(%pA): warning: unaligned access to symbol '%s' in the small data area");
- break;
-
case bfd_reloc_outofrange:
- /* xgettext:c-format */
- msg = _("%pB(%pA): internal error: out of range error");
+ /* xgettext:c-format */
+ (*info->callbacks->einfo)
+ (_("%H: %s out of range\n"),
+ input_bfd, input_section, rel->r_offset, howto->name);
break;
case bfd_reloc_notsupported:
/* xgettext:c-format */
- msg = _("%pB(%pA): internal error: unsupported relocation error");
+ (*info->callbacks->einfo)
+ (_("%H: relocation type %u is not supported\n"),
+ input_bfd, input_section, rel->r_offset, r_type);
break;
case bfd_reloc_dangerous:
- /* xgettext:c-format */
- msg = _("%pB(%pA): internal error: dangerous relocation");
+ (*info->callbacks->reloc_dangerous)
+ (info, error_message, input_bfd, input_section, rel->r_offset);
break;
default:
/* xgettext:c-format */
- msg = _("%pB(%pA): internal error: unknown error");
+ (*info->callbacks->einfo)
+ (_("%H: relocation %s returns an unrecognized value %x\n"),
+ input_bfd, input_section, rel->r_offset, howto->name, r);
break;
}
-
- if (msg)
- _bfd_error_handler (msg, input_bfd, input_section, name);
+ ret = false;
}
}
- return true;
+ return ret;
}
/* Function to set the ELF flag bits. */
@@ -1917,17 +1937,20 @@ rl78_offset_for_reloc (bfd * abfd,
switch (r_type)
{
case R_RL78_SYM:
- (void) rl78_compute_complex_reloc (r_type, symval, input_section);
+ (void) rl78_compute_complex_reloc (r_type, symval, input_section,
+ NULL, NULL);
break;
case R_RL78_OPromtop:
symval = get_romstart (info, input_bfd, input_section, rel->r_offset);
- (void) rl78_compute_complex_reloc (r_type, symval, input_section);
+ (void) rl78_compute_complex_reloc (r_type, symval, input_section,
+ NULL, NULL);
break;
case R_RL78_OPramtop:
symval = get_ramstart (info, input_bfd, input_section, rel->r_offset);
- (void) rl78_compute_complex_reloc (r_type, symval, input_section);
+ (void) rl78_compute_complex_reloc (r_type, symval, input_section,
+ NULL, NULL);
break;
case R_RL78_OPneg:
@@ -1944,7 +1967,8 @@ rl78_offset_for_reloc (bfd * abfd,
case R_RL78_OPxor:
case R_RL78_OPnot:
case R_RL78_OPmod:
- (void) rl78_compute_complex_reloc (r_type, 0, input_section);
+ (void) rl78_compute_complex_reloc (r_type, 0, input_section,
+ NULL, NULL);
break;
case R_RL78_DIR16UL:
@@ -1963,7 +1987,8 @@ rl78_offset_for_reloc (bfd * abfd,
default:
reloc_computes_value:
- symval = rl78_compute_complex_reloc (r_type, symval, input_section);
+ symval = rl78_compute_complex_reloc (r_type, symval, input_section,
+ NULL, NULL);
/* Fall through. */
case R_RL78_DIR32:
case R_RL78_DIR24S: