PR28176, rl78 complex reloc divide by zero

Message ID YQ5N6TLYmhf76jPj@squeak.grove.modra.org
State New
Headers show
Series
  • PR28176, rl78 complex reloc divide by zero
Related show

Commit Message

Alan Modra via Binutils Aug. 7, 2021, 9:10 a.m.
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.


-- 
Alan Modra
Australia Development Lab, IBM

Patch

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: