PR28176, rl78 complex reloc divide by zero
authorAlan Modra <amodra@gmail.com>
Sat, 7 Aug 2021 04:43:11 +0000 (14:13 +0930)
committerAlan Modra <amodra@gmail.com>
Sat, 7 Aug 2021 05:26:53 +0000 (14:56 +0930)
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.

bfd/elf32-rl78.c

index 163966f1d6988e6e004b191368276b770f87f9f4..ccccb76d1bac61222126b3234eaeec68fc49a496 100644 (file)
@@ -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;
 }
 \f
 /* 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: