diff options
author | Alan Modra <amodra@gmail.com> | 2021-08-07 14:13:11 +0930 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2021-08-07 14:56:53 +0930 |
commit | 983cdaecc134a5f9adefd052a97bc72321bf0ca3 (patch) | |
tree | eedafc8128f1c26d1a0dc623f7c7a58eb5342396 /bfd/elf32-rl78.c | |
parent | 0175375faa416282d2587ca8bf599867dca5fc9e (diff) | |
download | binutils-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.c | 283 |
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: |