public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/4] bfd_install_relocation and aarch64-pe changes
@ 2023-01-18  6:26 Alan Modra
  2023-01-18  6:26 ` [PATCH 1/4] howto install_addend Alan Modra
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Alan Modra @ 2023-01-18  6:26 UTC (permalink / raw)
  To: binutils; +Cc: Mark Harmstone

This is where I'm at with some baby steps towards making
bfd_install_relocation sane and fixing a number of problems with the
aarch64-pe target.

Alan Modra (4):
  howto install_addend
  coff-aarch64.c howtos
  Correct coff-aarch64 howtos and delete unnecessary special functions
  The fuzzers have found the reloc special functions in coff-aarch64.c

 bfd/bfd-in2.h      |   9 +-
 bfd/coff-aarch64.c | 467 ++++++++++++++++++++++-----------------------
 bfd/reloc.c        | 289 ++++++----------------------
 3 files changed, 296 insertions(+), 469 deletions(-)


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/4] howto install_addend
  2023-01-18  6:26 [PATCH 0/4] bfd_install_relocation and aarch64-pe changes Alan Modra
@ 2023-01-18  6:26 ` Alan Modra
  2023-01-18  6:26 ` [PATCH 2/4] coff-aarch64.c howtos Alan Modra
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Alan Modra @ 2023-01-18  6:26 UTC (permalink / raw)
  To: binutils; +Cc: Mark Harmstone

This adds a new flag to the reloc howtos that can be used to
incrementally change targets over to simple bfd_install_relocation
that just installs the addend without any weird adjustments.
I've made a few other changes to bfd_install_relocation, removing dead
code and comments that are really only applicable to
bfd_perform_relocation.

There is also a reloc offset bounds check change.  I've moved the
check to where data is accessed, as it seems reasonable to me to not
perform the check unless it is needed.  There is precedence for this;
Relocations against absolute symbols already avoided the check.

I also tried always performing the reloc offset check, and ran into
testsuite failures due to _NONE and _ALIGN relocs at the end of
sections.  These likely would be fixed if all such reloc howtos had
size set to zero, but I would rather not edit lots of files when it
involves checking that target code does not use the size.

	* reloc.c (struct reloc_howto_struct): Add install_addend.
	(HOWTO_INSTALL_ADDEND): Define.
	(HOWTO): Init new field with HOWTO_INSTALL_ADDEND.
	(bfd_install_relocation): Remove comments copied from
	bfd_perform_relocation that aren't applicable here.  Remove
	code dealing with output_offset and output_section.  Just set
	relocation to addend if install_addend.  Move reloc offset
	bounds check to just before section data is accessed, avoiding
	the check when data is not accessed.
	* bfd-in2.h: Regenerate.

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index a20678f7c18..7c5953442aa 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -2063,6 +2063,11 @@ struct reloc_howto_struct
      empty (e.g., ELF); this flag signals the fact.  */
   unsigned int pcrel_offset:1;
 
+  /* Whether bfd_install_relocation should just install the addend,
+     or should follow the practice of some older object formats and
+     install a value including the symbol.  */
+  unsigned int install_addend:1;
+
   /* src_mask selects the part of the instruction (or data) to be used
      in the relocation sum.  If the target relocations don't have an
      addend in the reloc, eg. ELF USE_REL, src_mask will normally equal
@@ -2088,11 +2093,13 @@ struct reloc_howto_struct
   const char *name;
 };
 
+#define HOWTO_INSTALL_ADDEND 0
 #define HOWTO_RSIZE(sz) ((sz) < 0 ? -(sz) : (sz))
 #define HOWTO(type, right, size, bits, pcrel, left, ovf, func, name,   \
               inplace, src_mask, dst_mask, pcrel_off)                  \
   { (unsigned) type, HOWTO_RSIZE (size), bits, right, left, ovf,       \
-    size < 0, pcrel, inplace, pcrel_off, src_mask, dst_mask, func, name }
+    size < 0, pcrel, inplace, pcrel_off, HOWTO_INSTALL_ADDEND,         \
+    src_mask, dst_mask, func, name }
 #define EMPTY_HOWTO(C) \
   HOWTO ((C), 0, 1, 0, false, 0, complain_overflow_dont, NULL, \
          NULL, false, 0, 0, false)
diff --git a/bfd/reloc.c b/bfd/reloc.c
index c543097b4d7..346dd7638db 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -338,6 +338,11 @@ CODE_FRAGMENT
 .     empty (e.g., ELF); this flag signals the fact.  *}
 .  unsigned int pcrel_offset:1;
 .
+.  {* Whether bfd_install_relocation should just install the addend,
+.     or should follow the practice of some older object formats and
+.     install a value including the symbol.  *}
+.  unsigned int install_addend:1;
+.
 .  {* src_mask selects the part of the instruction (or data) to be used
 .     in the relocation sum.  If the target relocations don't have an
 .     addend in the reloc, eg. ELF USE_REL, src_mask will normally equal
@@ -373,11 +378,13 @@ DESCRIPTION
 	The HOWTO macro fills in a reloc_howto_type (a typedef for
 	const struct reloc_howto_struct).
 
+.#define HOWTO_INSTALL_ADDEND 0
 .#define HOWTO_RSIZE(sz) ((sz) < 0 ? -(sz) : (sz))
 .#define HOWTO(type, right, size, bits, pcrel, left, ovf, func, name,	\
 .              inplace, src_mask, dst_mask, pcrel_off)			\
 .  { (unsigned) type, HOWTO_RSIZE (size), bits, right, left, ovf,	\
-.    size < 0, pcrel, inplace, pcrel_off, src_mask, dst_mask, func, name }
+.    size < 0, pcrel, inplace, pcrel_off, HOWTO_INSTALL_ADDEND,		\
+.    src_mask, dst_mask, func, name }
 
 DESCRIPTION
 	This is used to fill in an empty howto entry in an array.
@@ -1019,8 +1026,6 @@ bfd_install_relocation (bfd *abfd,
 	 reloc_entry->address field might actually be valid for the
 	 backend concerned.  It is up to the special_function itself
 	 to call bfd_reloc_offset_in_range if needed.  */
-      /* XXX - The special_function calls haven't been fixed up to deal
-	 with creating new relocations and section contents.  */
       cont = howto->special_function (abfd, reloc_entry, symbol,
 				      /* XXX - Non-portable! */
 				      ((bfd_byte *) data_start
@@ -1030,197 +1035,81 @@ bfd_install_relocation (bfd *abfd,
 	return cont;
     }
 
-  if (bfd_is_abs_section (symbol->section))
-    {
-      reloc_entry->address += input_section->output_offset;
-      return bfd_reloc_ok;
-    }
-
-  /* No need to check for howto != NULL if !bfd_is_abs_section as
-     it will have been checked in `bfd_perform_relocation already'.  */
-
-  /* Is the address of the relocation really within the section?  */
-  octets = reloc_entry->address * bfd_octets_per_byte (abfd, input_section);
-  if (!bfd_reloc_offset_in_range (howto, abfd, input_section, octets))
-    return bfd_reloc_outofrange;
-
-  /* Work out which section the relocation is targeted at and the
-     initial relocation command value.  */
-
-  /* Get symbol value.  (Common symbols are special.)  */
-  if (bfd_is_com_section (symbol->section))
-    relocation = 0;
+  if (howto->install_addend)
+    relocation = reloc_entry->addend;
   else
-    relocation = symbol->value;
-
-  reloc_target_output_section = symbol->section->output_section;
-
-  /* Convert input-section-relative symbol value to absolute.  */
-  if (! howto->partial_inplace)
-    output_base = 0;
-  else
-    output_base = reloc_target_output_section->vma;
-
-  output_base += symbol->section->output_offset;
-
-  /* If symbol addresses are in octets, convert to bytes.  */
-  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
-      && (symbol->section->flags & SEC_ELF_OCTETS))
-    output_base *= bfd_octets_per_byte (abfd, input_section);
+    {
+      if (bfd_is_abs_section (symbol->section))
+	return bfd_reloc_ok;
 
-  relocation += output_base;
+      /* Work out which section the relocation is targeted at and the
+	 initial relocation command value.  */
 
-  /* Add in supplied addend.  */
-  relocation += reloc_entry->addend;
+      /* Get symbol value.  (Common symbols are special.)  */
+      if (bfd_is_com_section (symbol->section))
+	relocation = 0;
+      else
+	relocation = symbol->value;
 
-  /* Here the variable relocation holds the final address of the
-     symbol we are relocating against, plus any addend.  */
+      reloc_target_output_section = symbol->section;
 
-  if (howto->pc_relative)
-    {
-      /* This is a PC relative relocation.  We want to set RELOCATION
-	 to the distance between the address of the symbol and the
-	 location.  RELOCATION is already the address of the symbol.
+      /* Convert input-section-relative symbol value to absolute.  */
+      if (! howto->partial_inplace)
+	output_base = 0;
+      else
+	output_base = reloc_target_output_section->vma;
 
-	 We start by subtracting the address of the section containing
-	 the location.
+      /* If symbol addresses are in octets, convert to bytes.  */
+      if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+	  && (symbol->section->flags & SEC_ELF_OCTETS))
+	output_base *= bfd_octets_per_byte (abfd, input_section);
 
-	 If pcrel_offset is set, we must further subtract the position
-	 of the location within the section.  Some targets arrange for
-	 the addend to be the negative of the position of the location
-	 within the section; for example, i386-aout does this.  For
-	 i386-aout, pcrel_offset is FALSE.  Some other targets do not
-	 include the position of the location; for example, ELF.
-	 For those targets, pcrel_offset is TRUE.
+      relocation += output_base;
 
-	 If we are producing relocatable output, then we must ensure
-	 that this reloc will be correctly computed when the final
-	 relocation is done.  If pcrel_offset is FALSE we want to wind
-	 up with the negative of the location within the section,
-	 which means we must adjust the existing addend by the change
-	 in the location within the section.  If pcrel_offset is TRUE
-	 we do not want to adjust the existing addend at all.
+      /* Add in supplied addend.  */
+      relocation += reloc_entry->addend;
 
-	 FIXME: This seems logical to me, but for the case of
-	 producing relocatable output it is not what the code
-	 actually does.  I don't want to change it, because it seems
-	 far too likely that something will break.  */
+      /* Here the variable relocation holds the final address of the
+	 symbol we are relocating against, plus any addend.  */
 
-      relocation -=
-	input_section->output_section->vma + input_section->output_offset;
+      if (howto->pc_relative)
+	{
+	  relocation -= input_section->vma;
 
-      if (howto->pcrel_offset && howto->partial_inplace)
-	relocation -= reloc_entry->address;
+	  if (howto->pcrel_offset && howto->partial_inplace)
+	    relocation -= reloc_entry->address;
+	}
     }
 
-  if (! howto->partial_inplace)
+  if (!howto->partial_inplace)
     {
-      /* This is a partial relocation, and we want to apply the relocation
-	 to the reloc entry rather than the raw data. Modify the reloc
-	 inplace to reflect what we now know.  */
       reloc_entry->addend = relocation;
-      reloc_entry->address += input_section->output_offset;
       return flag;
     }
-  else
-    {
-      /* This is a partial relocation, but inplace, so modify the
-	 reloc record a bit.
-
-	 If we've relocated with a symbol with a section, change
-	 into a ref to the section belonging to the symbol.  */
-      reloc_entry->address += input_section->output_offset;
-
-      /* WTF?? */
-      if (abfd->xvec->flavour == bfd_target_coff_flavour)
-	{
-
-	  /* For m68k-coff, the addend was being subtracted twice during
-	     relocation with -r.  Removing the line below this comment
-	     fixes that problem; see PR 2953.
-
-However, Ian wrote the following, regarding removing the line below,
-which explains why it is still enabled:  --djm
-
-If you put a patch like that into BFD you need to check all the COFF
-linkers.  I am fairly certain that patch will break coff-i386 (e.g.,
-SCO); see coff_i386_reloc in coff-i386.c where I worked around the
-problem in a different way.  There may very well be a reason that the
-code works as it does.
-
-Hmmm.  The first obvious point is that bfd_install_relocation should
-not have any tests that depend upon the flavour.  It's seem like
-entirely the wrong place for such a thing.  The second obvious point
-is that the current code ignores the reloc addend when producing
-relocatable output for COFF.  That's peculiar.  In fact, I really
-have no idea what the point of the line you want to remove is.
-
-A typical COFF reloc subtracts the old value of the symbol and adds in
-the new value to the location in the object file (if it's a pc
-relative reloc it adds the difference between the symbol value and the
-location).  When relocating we need to preserve that property.
-
-BFD handles this by setting the addend to the negative of the old
-value of the symbol.  Unfortunately it handles common symbols in a
-non-standard way (it doesn't subtract the old value) but that's a
-different story (we can't change it without losing backward
-compatibility with old object files) (coff-i386 does subtract the old
-value, to be compatible with existing coff-i386 targets, like SCO).
-
-So everything works fine when not producing relocatable output.  When
-we are producing relocatable output, logically we should do exactly
-what we do when not producing relocatable output.  Therefore, your
-patch is correct.  In fact, it should probably always just set
-reloc_entry->addend to 0 for all cases, since it is, in fact, going to
-add the value into the object file.  This won't hurt the COFF code,
-which doesn't use the addend; I'm not sure what it will do to other
-formats (the thing to check for would be whether any formats both use
-the addend and set partial_inplace).
 
-When I wanted to make coff-i386 produce relocatable output, I ran
-into the problem that you are running into: I wanted to remove that
-line.  Rather than risk it, I made the coff-i386 relocs use a special
-function; it's coff_i386_reloc in coff-i386.c.  The function
-specifically adds the addend field into the object file, knowing that
-bfd_install_relocation is not going to.  If you remove that line, then
-coff-i386.c will wind up adding the addend field in twice.  It's
-trivial to fix; it just needs to be done.
-
-The problem with removing the line is just that it may break some
-working code.  With BFD it's hard to be sure of anything.  The right
-way to deal with this is simply to build and test at least all the
-supported COFF targets.  It should be straightforward if time and disk
-space consuming.  For each target:
-    1) build the linker
-    2) generate some executable, and link it using -r (I would
-       probably use paranoia.o and link against newlib/libc.a, which
-       for all the supported targets would be available in
-       /usr/cygnus/progressive/H-host/target/lib/libc.a).
-    3) make the change to reloc.c
-    4) rebuild the linker
-    5) repeat step 2
-    6) if the resulting object files are the same, you have at least
-       made it no worse
-    7) if they are different you have to figure out which version is
-       right.  */
-	  relocation -= reloc_entry->addend;
-	  /* FIXME: There should be no target specific code here...  */
-	  if (strcmp (abfd->xvec->name, "coff-z8k") != 0)
-	    reloc_entry->addend = 0;
-	}
-      else
-	{
-	  reloc_entry->addend = relocation;
-	}
+  if (!howto->install_addend
+      && abfd->xvec->flavour == bfd_target_coff_flavour)
+    {
+      /* This is just weird.  We're subtracting out the original
+	 addend, so that for COFF the addend is ignored???  */
+      relocation -= reloc_entry->addend;
+      /* FIXME: There should be no target specific code here...  */
+      if (strcmp (abfd->xvec->name, "coff-z8k") != 0)
+	reloc_entry->addend = 0;
     }
+  else
+    reloc_entry->addend = relocation;
+
+  /* Is the address of the relocation really within the section?  */
+  octets = reloc_entry->address * bfd_octets_per_byte (abfd, input_section);
+  if (!bfd_reloc_offset_in_range (howto, abfd, input_section, octets))
+    return bfd_reloc_outofrange;
 
   /* FIXME: This overflow checking is incomplete, because the value
      might have overflowed before we get here.  For a correct check we
      need to compute the value in a size larger than bitsize, but we
      can't reasonably do that for a reloc the same size as a host
-     machine word.
-     FIXME: We should also do overflow checking on the result after
-     adding in the value contained in the object file.  */
+     machine word.  */
   if (howto->complain_on_overflow != complain_overflow_dont)
     flag = bfd_check_overflow (howto->complain_on_overflow,
 			       howto->bitsize,
@@ -1228,71 +1117,11 @@ space consuming.  For each target:
 			       bfd_arch_bits_per_address (abfd),
 			       relocation);
 
-  /* Either we are relocating all the way, or we don't want to apply
-     the relocation to the reloc entry (probably because there isn't
-     any room in the output format to describe addends to relocs).  */
-
-  /* The cast to bfd_vma avoids a bug in the Alpha OSF/1 C compiler
-     (OSF version 1.3, compiler version 3.11).  It miscompiles the
-     following program:
-
-     struct str
-     {
-       unsigned int i0;
-     } s = { 0 };
-
-     int
-     main ()
-     {
-       unsigned long x;
-
-       x = 0x100000000;
-       x <<= (unsigned long) s.i0;
-       if (x == 0)
-	 printf ("failed\n");
-       else
-	 printf ("succeeded (%lx)\n", x);
-     }
-     */
-
   relocation >>= (bfd_vma) howto->rightshift;
 
   /* Shift everything up to where it's going to be used.  */
   relocation <<= (bfd_vma) howto->bitpos;
 
-  /* Wait for the day when all have the mask in them.  */
-
-  /* What we do:
-     i instruction to be left alone
-     o offset within instruction
-     r relocation offset to apply
-     S src mask
-     D dst mask
-     N ~dst mask
-     A part 1
-     B part 2
-     R result
-
-     Do this:
-     ((	 i i i i i o o o o o  from bfd_get<size>
-     and	   S S S S S) to get the size offset we want
-     +	 r r r r r r r r r r) to get the final value to place
-     and	   D D D D D  to chop to right size
-     -----------------------
-     =		   A A A A A
-     And this:
-     (	 i i i i i o o o o o  from bfd_get<size>
-     and N N N N N	    ) get instruction
-     -----------------------
-     =	 B B B B B
-
-     And then:
-     (	 B B B B B
-     or		   A A A A A)
-     -----------------------
-     =	 R R R R R R R R R R  put into bfd_put<size>
-     */
-
   data = (bfd_byte *) data_start + (octets - data_start_offset);
   apply_reloc (abfd, data, howto, relocation);
   return flag;

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 2/4] coff-aarch64.c howtos
  2023-01-18  6:26 [PATCH 0/4] bfd_install_relocation and aarch64-pe changes Alan Modra
  2023-01-18  6:26 ` [PATCH 1/4] howto install_addend Alan Modra
@ 2023-01-18  6:26 ` Alan Modra
  2023-01-18  6:26 ` [PATCH 3/4] Correct coff-aarch64 howtos and delete unnecessary special functions Alan Modra
  2023-01-18  6:26 ` [PATCH 4/4] The fuzzers have found the reloc special functions in coff-aarch64.c Alan Modra
  3 siblings, 0 replies; 5+ messages in thread
From: Alan Modra @ 2023-01-18  6:26 UTC (permalink / raw)
  To: binutils; +Cc: Mark Harmstone

This is just a patch to fix overlong lines.  Wrapping the HOWTO macro
in a new HOW macro helps in this.  No functional changes here.

	* coff-aarch64.c (HOW): Define and use for reloc howtos.

diff --git a/bfd/coff-aarch64.c b/bfd/coff-aarch64.c
index 8e9081a0e74..1360ae0ba73 100644
--- a/bfd/coff-aarch64.c
+++ b/bfd/coff-aarch64.c
@@ -281,73 +281,62 @@ coff_aarch64_secrel_reloc (bfd *abfd ATTRIBUTE_UNUSED,
   return bfd_reloc_ok;
 }
 
-/* In case we're on a 32-bit machine, construct a 64-bit "-1" value.  */
-#define MINUS_ONE (~ (bfd_vma) 0)
-
-static const reloc_howto_type arm64_reloc_howto_abs = HOWTO(IMAGE_REL_ARM64_ABSOLUTE, 0, 1, 0, false, 0,
-	 complain_overflow_dont,
-	 NULL, "IMAGE_REL_ARM64_ABSOLUTE",
-	 false, 0, 0, false);
-
-static const reloc_howto_type arm64_reloc_howto_64 = HOWTO(IMAGE_REL_ARM64_ADDR64, 0, 8, 64, false, 0,
-	 complain_overflow_bitfield,
-	 coff_aarch64_addr64_reloc, "IMAGE_REL_ARM64_ADDR64",
-	 false, MINUS_ONE, MINUS_ONE, false);
-
-static const reloc_howto_type arm64_reloc_howto_32 = HOWTO (IMAGE_REL_ARM64_ADDR32, 0, 4, 32, false, 0,
-	 complain_overflow_bitfield,
-	 coff_aarch64_addr32_reloc, "IMAGE_REL_ARM64_ADDR32",
-	 false, 0xffffffff, 0xffffffff, false);
-
-static const reloc_howto_type arm64_reloc_howto_32_pcrel = HOWTO (IMAGE_REL_ARM64_REL32, 0, 4, 32, true, 0,
-	 complain_overflow_bitfield,
-	 NULL, "IMAGE_REL_ARM64_REL32",
-	 false, 0xffffffff, 0xffffffff, true);
-
-static const reloc_howto_type arm64_reloc_howto_branch26 = HOWTO (IMAGE_REL_ARM64_BRANCH26, 0, 4, 26, true, 0,
-	 complain_overflow_bitfield,
-	 coff_aarch64_branch26_reloc, "IMAGE_REL_ARM64_BRANCH26",
-	 false, 0x03ffffff, 0x03ffffff, true);
-
-static const reloc_howto_type arm64_reloc_howto_page21 = HOWTO (IMAGE_REL_ARM64_PAGEBASE_REL21, 12, 4, 21, true, 0,
-	 complain_overflow_signed,
-	 coff_aarch64_rel21_reloc, "IMAGE_REL_ARM64_PAGEBASE_REL21",
-	 false, 0x1fffff, 0x1fffff, false);
-
-static const reloc_howto_type arm64_reloc_howto_lo21 = HOWTO (IMAGE_REL_ARM64_REL21, 0, 4, 21, true, 0,
-	 complain_overflow_signed,
-	 coff_aarch64_rel21_reloc, "IMAGE_REL_ARM64_REL21",
-	 false, 0x1fffff, 0x1fffff, true);
-
-static const reloc_howto_type arm64_reloc_howto_pgoff12l = HOWTO (IMAGE_REL_ARM64_PAGEOFFSET_12L, 1, 4, 12, true, 0,
-	 complain_overflow_signed,
-	 coff_aarch64_po12l_reloc, "IMAGE_REL_ARM64_PAGEOFFSET_12L",
-	 false, 0xffe, 0xffe, true);
-
-static const reloc_howto_type arm64_reloc_howto_branch19 = HOWTO (IMAGE_REL_ARM64_BRANCH19, 2, 4, 19, true, 0,
-	 complain_overflow_signed,
-	 coff_aarch64_branch19_reloc, "IMAGE_REL_ARM64_BRANCH19",
-	 false, 0x7ffff, 0x7ffff, true);
-
-static const reloc_howto_type arm64_reloc_howto_branch14 = HOWTO (IMAGE_REL_ARM64_BRANCH14, 2, 4, 14, true, 0,
-	 complain_overflow_signed,
-	 coff_aarch64_branch14_reloc, "IMAGE_REL_ARM64_BRANCH14",
-	 false, 0x3fff, 0x3fff, true);
-
-static const reloc_howto_type arm64_reloc_howto_pgoff12a = HOWTO (IMAGE_REL_ARM64_PAGEOFFSET_12A, 2, 4, 12, true, 10,
-	 complain_overflow_dont,
-	 coff_aarch64_po12a_reloc, "IMAGE_REL_ARM64_PAGEOFFSET_12A",
-	 false, 0x3ffc00, 0x3ffc00, false);
-
-static const reloc_howto_type arm64_reloc_howto_32nb = HOWTO (IMAGE_REL_ARM64_ADDR32NB, 0, 4, 32, false, 0,
-	 complain_overflow_bitfield,
-	 coff_aarch64_addr32nb_reloc, "IMAGE_REL_ARM64_ADDR32NB",
-	 false, 0xffffffff, 0xffffffff, false);
-
-static const reloc_howto_type arm64_reloc_howto_secrel = HOWTO (IMAGE_REL_ARM64_SECREL, 0, 4, 32, false, 0,
-	 complain_overflow_bitfield,
-	 coff_aarch64_secrel_reloc, "IMAGE_REL_ARM64_SECREL",
-	 false, 0xffffffff, 0xffffffff, false);
+#define coff_aarch64_NULL NULL
+#define HOW(type, right, size, bits, pcrel, left, ovf, func, mask, pcrel_off) \
+  HOWTO (type, right, size, bits, pcrel, left, complain_overflow_##ovf, \
+	 coff_aarch64_##func, #type, false, mask, mask, pcrel_off)
+
+static const reloc_howto_type arm64_reloc_howto_abs
+= HOW (IMAGE_REL_ARM64_ABSOLUTE,
+       0, 1, 0, false, 0, dont, NULL, 0, false);
+
+static const reloc_howto_type arm64_reloc_howto_64
+= HOW (IMAGE_REL_ARM64_ADDR64,
+       0, 8, 64, false, 0, bitfield, addr64_reloc, UINT64_C (-1), false);
+
+static const reloc_howto_type arm64_reloc_howto_32
+= HOW (IMAGE_REL_ARM64_ADDR32,
+       0, 4, 32, false, 0, bitfield, addr32_reloc, 0xffffffff, false);
+
+static const reloc_howto_type arm64_reloc_howto_32_pcrel
+= HOW (IMAGE_REL_ARM64_REL32,
+       0, 4, 32, true, 0, bitfield, NULL, 0xffffffff, true);
+
+static const reloc_howto_type arm64_reloc_howto_branch26
+= HOW (IMAGE_REL_ARM64_BRANCH26,
+       0, 4, 26, true, 0, bitfield, branch26_reloc, 0x03ffffff, true);
+
+static const reloc_howto_type arm64_reloc_howto_page21
+= HOW (IMAGE_REL_ARM64_PAGEBASE_REL21,
+       12, 4, 21, true, 0, signed, rel21_reloc, 0x1fffff, false);
+
+static const reloc_howto_type arm64_reloc_howto_lo21
+= HOW (IMAGE_REL_ARM64_REL21,
+       0, 4, 21, true, 0, signed, rel21_reloc, 0x1fffff, true);
+
+static const reloc_howto_type arm64_reloc_howto_pgoff12l
+= HOW (IMAGE_REL_ARM64_PAGEOFFSET_12L,
+       1, 4, 12, true, 0, signed, po12l_reloc, 0xffe, true);
+
+static const reloc_howto_type arm64_reloc_howto_branch19
+= HOW (IMAGE_REL_ARM64_BRANCH19,
+       2, 4, 19, true, 0, signed, branch19_reloc, 0x7ffff, true);
+
+static const reloc_howto_type arm64_reloc_howto_branch14
+= HOW (IMAGE_REL_ARM64_BRANCH14,
+       2, 4, 14, true, 0, signed, branch14_reloc, 0x3fff, true);
+
+static const reloc_howto_type arm64_reloc_howto_pgoff12a
+= HOW (IMAGE_REL_ARM64_PAGEOFFSET_12A,
+       2, 4, 12, true, 10, dont, po12a_reloc, 0x3ffc00, false);
+
+static const reloc_howto_type arm64_reloc_howto_32nb
+= HOW (IMAGE_REL_ARM64_ADDR32NB,
+       0, 4, 32, false, 0, bitfield, addr32nb_reloc, 0xffffffff, false);
+
+static const reloc_howto_type arm64_reloc_howto_secrel
+= HOW (IMAGE_REL_ARM64_SECREL,
+       0, 4, 32, false, 0, bitfield, secrel_reloc, 0xffffffff, false);
 
 static const reloc_howto_type* const arm64_howto_table[] = {
      &arm64_reloc_howto_abs,

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 3/4] Correct coff-aarch64 howtos and delete unnecessary special functions
  2023-01-18  6:26 [PATCH 0/4] bfd_install_relocation and aarch64-pe changes Alan Modra
  2023-01-18  6:26 ` [PATCH 1/4] howto install_addend Alan Modra
  2023-01-18  6:26 ` [PATCH 2/4] coff-aarch64.c howtos Alan Modra
@ 2023-01-18  6:26 ` Alan Modra
  2023-01-18  6:26 ` [PATCH 4/4] The fuzzers have found the reloc special functions in coff-aarch64.c Alan Modra
  3 siblings, 0 replies; 5+ messages in thread
From: Alan Modra @ 2023-01-18  6:26 UTC (permalink / raw)
  To: binutils; +Cc: Mark Harmstone

The remaining special functions are still broken except when called
by gas bfd_install_relocation.

	* coff-aarch64.c (coff_aarch64_addr64_reloc),
	(coff_aarch64_addr32_reloc, coff_aarch64_branch26_reloc),
	(coff_aarch64_branch19_reloc, coff_aarch64_branch14_reloc),
	(coff_aarch64_po12a_reloc): Delete.
	(HOWTO_INSTALL_ADDEND): Define as 1.
	(HOW): Remove pcrel_off.  Correct all the howtos.
	(CALC_ADDEND): Define.
	(coff_aarch64_rtype_to_howto): New function.
	(coff_rtype_to_howto): Define.

diff --git a/bfd/coff-aarch64.c b/bfd/coff-aarch64.c
index 1360ae0ba73..7057396f6dd 100644
--- a/bfd/coff-aarch64.c
+++ b/bfd/coff-aarch64.c
@@ -39,70 +39,6 @@
 
 #include "libcoff.h"
 
-static bfd_reloc_status_type
-coff_aarch64_addr64_reloc (bfd *abfd ATTRIBUTE_UNUSED,
-			   arelent *reloc_entry,
-			   asymbol *symbol ATTRIBUTE_UNUSED,
-			   void *data,
-			   asection *input_section ATTRIBUTE_UNUSED,
-			   bfd *output_bfd ATTRIBUTE_UNUSED,
-			   char **error_message ATTRIBUTE_UNUSED)
-{
-  uint64_t val = reloc_entry->addend;
-
-  bfd_putl64 (val, data + reloc_entry->address);
-
-  return bfd_reloc_ok;
-}
-
-static bfd_reloc_status_type
-coff_aarch64_addr32_reloc (bfd *abfd ATTRIBUTE_UNUSED,
-			   arelent *reloc_entry,
-			   asymbol *symbol ATTRIBUTE_UNUSED,
-			   void *data,
-			   asection *input_section ATTRIBUTE_UNUSED,
-			   bfd *output_bfd ATTRIBUTE_UNUSED,
-			   char **error_message ATTRIBUTE_UNUSED)
-{
-  uint64_t val;
-
-  if ((int64_t) reloc_entry->addend > 0x7fffffff
-      || (int64_t) reloc_entry->addend < -0x7fffffff)
-    return bfd_reloc_overflow;
-
-  val = reloc_entry->addend;
-
-  bfd_putl32 ((uint32_t) val, data + reloc_entry->address);
-
-  return bfd_reloc_ok;
-}
-
-static bfd_reloc_status_type
-coff_aarch64_branch26_reloc (bfd *abfd ATTRIBUTE_UNUSED,
-			     arelent *reloc_entry,
-			     asymbol *symbol ATTRIBUTE_UNUSED,
-			     void *data,
-			     asection *input_section ATTRIBUTE_UNUSED,
-			     bfd *output_bfd ATTRIBUTE_UNUSED,
-			     char **error_message ATTRIBUTE_UNUSED)
-{
-  uint32_t op;
-  int32_t param;
-
-  op = bfd_getl32 (data + reloc_entry->address);
-  param = reloc_entry->addend;
-
-  if (param > 0x7ffffff || param < -0x8000000)
-    return bfd_reloc_overflow;
-
-  op &= 0xfc000000;
-  op |= (param >> 2) & 0x3ffffff;
-
-  bfd_putl32 (op, data + reloc_entry->address);
-
-  return bfd_reloc_ok;
-}
-
 static bfd_reloc_status_type
 coff_aarch64_rel21_reloc (bfd *abfd ATTRIBUTE_UNUSED,
 			  arelent *reloc_entry,
@@ -170,81 +106,6 @@ coff_aarch64_po12l_reloc (bfd *abfd ATTRIBUTE_UNUSED,
   return bfd_reloc_ok;
 }
 
-static bfd_reloc_status_type
-coff_aarch64_branch19_reloc (bfd *abfd ATTRIBUTE_UNUSED,
-			     arelent *reloc_entry,
-			     asymbol *symbol ATTRIBUTE_UNUSED,
-			     void *data,
-			     asection *input_section ATTRIBUTE_UNUSED,
-			     bfd *output_bfd ATTRIBUTE_UNUSED,
-			     char **error_message ATTRIBUTE_UNUSED)
-{
-  uint32_t op;
-  int32_t param;
-
-  op = bfd_getl32 (data + reloc_entry->address);
-  param = reloc_entry->addend;
-
-  if (param > 0xfffff || param < -0x100000)
-    return bfd_reloc_overflow;
-
-  op &= 0xff00001f;
-  op |= ((param >> 2) & 0x7ffff) << 5;
-
-  bfd_putl32 (op, data + reloc_entry->address);
-
-  return bfd_reloc_ok;
-}
-
-static bfd_reloc_status_type
-coff_aarch64_branch14_reloc (bfd *abfd ATTRIBUTE_UNUSED,
-			     arelent *reloc_entry,
-			     asymbol *symbol ATTRIBUTE_UNUSED,
-			     void *data,
-			     asection *input_section ATTRIBUTE_UNUSED,
-			     bfd *output_bfd ATTRIBUTE_UNUSED,
-			     char **error_message ATTRIBUTE_UNUSED)
-{
-  uint32_t op;
-  int32_t param;
-
-  op = bfd_getl32 (data + reloc_entry->address);
-  param = reloc_entry->addend;
-
-  if (param > 0x7fff || param < -0x8000)
-    return bfd_reloc_overflow;
-
-  op &= 0xfff8001f;
-  op |= ((param >> 2) & 0x3fff) << 5;
-
-  bfd_putl32 (op, data + reloc_entry->address);
-
-  return bfd_reloc_ok;
-}
-
-static bfd_reloc_status_type
-coff_aarch64_po12a_reloc (bfd *abfd ATTRIBUTE_UNUSED,
-			  arelent *reloc_entry,
-			  asymbol *symbol ATTRIBUTE_UNUSED,
-			  void *data,
-			  asection *input_section ATTRIBUTE_UNUSED,
-			  bfd *output_bfd ATTRIBUTE_UNUSED,
-			  char **error_message ATTRIBUTE_UNUSED)
-{
-  uint32_t op;
-  int32_t param;
-
-  op = bfd_getl32 (data + reloc_entry->address);
-  param = reloc_entry->addend;
-
-  op &= 0xffc003ff;
-  op |= (param & 0xfff) << 10;
-
-  bfd_putl32 (op, data + reloc_entry->address);
-
-  return bfd_reloc_ok;
-}
-
 static bfd_reloc_status_type
 coff_aarch64_addr32nb_reloc (bfd *abfd ATTRIBUTE_UNUSED,
 			     arelent *reloc_entry,
@@ -282,61 +143,63 @@ coff_aarch64_secrel_reloc (bfd *abfd ATTRIBUTE_UNUSED,
 }
 
 #define coff_aarch64_NULL NULL
-#define HOW(type, right, size, bits, pcrel, left, ovf, func, mask, pcrel_off) \
+#undef HOWTO_INSTALL_ADDEND
+#define HOWTO_INSTALL_ADDEND 1
+#define HOW(type, right, size, bits, pcrel, left, ovf, func, mask) \
   HOWTO (type, right, size, bits, pcrel, left, complain_overflow_##ovf, \
-	 coff_aarch64_##func, #type, false, mask, mask, pcrel_off)
+	 coff_aarch64_##func, #type, true, mask, mask, false)
 
 static const reloc_howto_type arm64_reloc_howto_abs
 = HOW (IMAGE_REL_ARM64_ABSOLUTE,
-       0, 1, 0, false, 0, dont, NULL, 0, false);
+       0, 0, 0, false, 0, dont, NULL, 0);
 
 static const reloc_howto_type arm64_reloc_howto_64
 = HOW (IMAGE_REL_ARM64_ADDR64,
-       0, 8, 64, false, 0, bitfield, addr64_reloc, UINT64_C (-1), false);
+       0, 8, 64, false, 0, dont, NULL, UINT64_C (-1));
 
 static const reloc_howto_type arm64_reloc_howto_32
 = HOW (IMAGE_REL_ARM64_ADDR32,
-       0, 4, 32, false, 0, bitfield, addr32_reloc, 0xffffffff, false);
+       0, 4, 32, false, 0, signed, NULL, 0xffffffff);
 
 static const reloc_howto_type arm64_reloc_howto_32_pcrel
 = HOW (IMAGE_REL_ARM64_REL32,
-       0, 4, 32, true, 0, bitfield, NULL, 0xffffffff, true);
+       0, 4, 32, true, 0, signed, NULL, 0xffffffff);
 
 static const reloc_howto_type arm64_reloc_howto_branch26
 = HOW (IMAGE_REL_ARM64_BRANCH26,
-       0, 4, 26, true, 0, bitfield, branch26_reloc, 0x03ffffff, true);
+       2, 4, 26, true, 0, signed, NULL, 0x3ffffff);
 
 static const reloc_howto_type arm64_reloc_howto_page21
 = HOW (IMAGE_REL_ARM64_PAGEBASE_REL21,
-       12, 4, 21, true, 0, signed, rel21_reloc, 0x1fffff, false);
+       12, 4, 21, true, 0, signed, rel21_reloc, 0x1fffff);
 
 static const reloc_howto_type arm64_reloc_howto_lo21
 = HOW (IMAGE_REL_ARM64_REL21,
-       0, 4, 21, true, 0, signed, rel21_reloc, 0x1fffff, true);
+       0, 4, 21, true, 0, signed, rel21_reloc, 0x1fffff);
 
 static const reloc_howto_type arm64_reloc_howto_pgoff12l
 = HOW (IMAGE_REL_ARM64_PAGEOFFSET_12L,
-       1, 4, 12, true, 0, signed, po12l_reloc, 0xffe, true);
+       0, 4, 12, true, 10, signed, po12l_reloc, 0x3ffc00);
 
 static const reloc_howto_type arm64_reloc_howto_branch19
 = HOW (IMAGE_REL_ARM64_BRANCH19,
-       2, 4, 19, true, 0, signed, branch19_reloc, 0x7ffff, true);
+       2, 4, 19, true, 5, signed, NULL, 0xffffe0);
 
 static const reloc_howto_type arm64_reloc_howto_branch14
 = HOW (IMAGE_REL_ARM64_BRANCH14,
-       2, 4, 14, true, 0, signed, branch14_reloc, 0x3fff, true);
+       2, 4, 14, true, 5, signed, NULL, 0x7ffe0);
 
 static const reloc_howto_type arm64_reloc_howto_pgoff12a
 = HOW (IMAGE_REL_ARM64_PAGEOFFSET_12A,
-       2, 4, 12, true, 10, dont, po12a_reloc, 0x3ffc00, false);
+       0, 4, 12, true, 10, dont, NULL, 0x3ffc00);
 
 static const reloc_howto_type arm64_reloc_howto_32nb
 = HOW (IMAGE_REL_ARM64_ADDR32NB,
-       0, 4, 32, false, 0, bitfield, addr32nb_reloc, 0xffffffff, false);
+       0, 4, 32, false, 0, signed, addr32nb_reloc, 0xffffffff);
 
 static const reloc_howto_type arm64_reloc_howto_secrel
 = HOW (IMAGE_REL_ARM64_SECREL,
-       0, 4, 32, false, 0, bitfield, secrel_reloc, 0xffffffff, false);
+       0, 4, 32, false, 0, dont, secrel_reloc, 0xffffffff);
 
 static const reloc_howto_type* const arm64_howto_table[] = {
      &arm64_reloc_howto_abs,
@@ -354,6 +217,13 @@ static const reloc_howto_type* const arm64_howto_table[] = {
      &arm64_reloc_howto_secrel
 };
 
+/* No adjustment to addends should be needed.  The actual relocation
+   addend is in the section contents.  Unfortunately this means actual
+   addends are not shown by objdump -r, but that's true for most
+   COFF/PE targets where arelent.addend is an adjustment.  */
+#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr)		\
+  cache_ptr->addend = 0;
+
 #ifndef NUM_ELEM
 #define NUM_ELEM(a) ((sizeof (a)) / sizeof ((a)[0]))
 #endif
@@ -455,15 +325,32 @@ coff_aarch64_rtype_lookup (unsigned int code)
     case IMAGE_REL_ARM64_SECREL:
       return &arm64_reloc_howto_secrel;
     default:
-      BFD_FAIL ();
       return NULL;
   }
 
   return NULL;
 }
 
-#define RTYPE2HOWTO(cache_ptr, dst)				\
-  ((cache_ptr)->howto =	coff_aarch64_rtype_lookup((dst)->r_type))
+#define RTYPE2HOWTO(cache_ptr, dst)					\
+  ((cache_ptr)->howto = coff_aarch64_rtype_lookup((dst)->r_type))
+
+static reloc_howto_type *
+coff_aarch64_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
+			     asection *sec ATTRIBUTE_UNUSED,
+			     struct internal_reloc *rel,
+			     struct coff_link_hash_entry *h ATTRIBUTE_UNUSED,
+			     struct internal_syment *sym ATTRIBUTE_UNUSED,
+			     bfd_vma *addendp)
+{
+  reloc_howto_type *howto = coff_aarch64_rtype_lookup (rel->r_type);
+
+  /* Cancel out code in _bfd_coff_generic_relocate_section.  */
+  *addendp = 0;
+
+  return howto;
+}
+
+#define coff_rtype_to_howto coff_aarch64_rtype_to_howto
 
 #define SELECT_RELOC(x,howto) { (x).r_type = (howto)->type; }
 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 4/4] The fuzzers have found the reloc special functions in coff-aarch64.c
  2023-01-18  6:26 [PATCH 0/4] bfd_install_relocation and aarch64-pe changes Alan Modra
                   ` (2 preceding siblings ...)
  2023-01-18  6:26 ` [PATCH 3/4] Correct coff-aarch64 howtos and delete unnecessary special functions Alan Modra
@ 2023-01-18  6:26 ` Alan Modra
  3 siblings, 0 replies; 5+ messages in thread
From: Alan Modra @ 2023-01-18  6:26 UTC (permalink / raw)
  To: binutils; +Cc: Mark Harmstone

All of them need a bfd_reloc_offset_in_range check before accessing
data + reloc_entry->address.  This patch adds the missing checks and
sanity checks reloc offsets in coff_pe_aarch64_relocate_section too.

All of them also need changing to support objdump -W calls to
bfd_simple_get_relocated_section_contents.  At least, secrel_reloc
needs the support, the others might not be present in dwarf debug
sections.

	* coff-aarch64.c (coff_aarch64_rel21_reloc): Range check
	reloc offset.  Support final-linking.
	(coff_aarch64_po12l_reloc): Likewise.
	(coff_aarch64_addr32nb_reloc): Likewise.
	(coff_aarch64_secrel_reloc): Likewise.
	(coff_pe_aarch64_relocate_section): Range check reloc offset.

diff --git a/bfd/coff-aarch64.c b/bfd/coff-aarch64.c
index 7057396f6dd..73fa2442dfe 100644
--- a/bfd/coff-aarch64.c
+++ b/bfd/coff-aarch64.c
@@ -39,48 +39,85 @@
 
 #include "libcoff.h"
 
+/* For these howto special functions,
+   output_bfd == NULL => final link, or objdump -W and other calls to
+   bfd_simple_get_relocated_section_contents
+   output_bfd != NULL && output_bfd != abfd => ld -r
+   output_bfd != NULL && output_bfd == abfd => gas.
+   FIXME: ld -r is punted to bfd_perform_relocation.  This won't be
+   correct for cases where the addend needs to be adjusted, eg. for
+   relocations against section symbols, and the field is split because
+   bfd_perform_relocation can't write addends to split relocation fields.  */
+
 static bfd_reloc_status_type
-coff_aarch64_rel21_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+coff_aarch64_rel21_reloc (bfd *abfd,
 			  arelent *reloc_entry,
-			  asymbol *symbol ATTRIBUTE_UNUSED,
+			  asymbol *symbol,
 			  void *data,
-			  asection *input_section ATTRIBUTE_UNUSED,
-			  bfd *output_bfd ATTRIBUTE_UNUSED,
+			  asection *input_section,
+			  bfd *output_bfd,
 			  char **error_message ATTRIBUTE_UNUSED)
 {
-  uint32_t op;
-  int32_t param;
+  if (output_bfd != NULL && output_bfd != abfd)
+    return bfd_reloc_continue;
 
-  op = bfd_getl32 (data + reloc_entry->address);
-  param = reloc_entry->addend;
+  if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
+				  input_section, reloc_entry->address))
+    return bfd_reloc_outofrange;
 
-  if (param > 0xfffff || param < -0x100000)
-    return bfd_reloc_overflow;
+  uint32_t op = bfd_getl32 (data + reloc_entry->address);
+  bfd_vma relocation = reloc_entry->addend;
+  bfd_reloc_status_type ret = bfd_reloc_ok;
+  if (output_bfd == NULL)
+    {
+      if (bfd_is_und_section (symbol->section))
+	{
+	  if ((symbol->flags & BSF_WEAK) == 0)
+	    ret = bfd_reloc_undefined;
+	}
+      else if (!bfd_is_com_section (symbol->section))
+	relocation += (symbol->value
+		       + symbol->section->output_offset
+		       + symbol->section->output_section->vma);
+      bfd_vma addend = ((op >> 3) & 0x1ffffc) | ((op >> 29) & 0x3);
+      addend = (addend ^ 0x100000) - 0x100000;
+      relocation += addend;
+      relocation -= (reloc_entry->address
+		     + input_section->output_offset
+		     + input_section->output_section->vma);
+      relocation = (bfd_signed_vma) relocation >> reloc_entry->howto->rightshift;
+    }
+  if (relocation + 0x100000 > 0x1fffff)
+    ret = bfd_reloc_overflow;
 
   op &= 0x9f00001f;
-  op |= (param & 0x1ffffc) << 3;
-  op |= (param & 0x3) << 29;
+  op |= (relocation & 0x1ffffc) << 3;
+  op |= (relocation & 0x3) << 29;
 
   bfd_putl32 (op, data + reloc_entry->address);
 
-  return bfd_reloc_ok;
+  return ret;
 }
 
 static bfd_reloc_status_type
-coff_aarch64_po12l_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+coff_aarch64_po12l_reloc (bfd *abfd,
 			  arelent *reloc_entry,
 			  asymbol *symbol ATTRIBUTE_UNUSED,
 			  void *data,
-			  asection *input_section ATTRIBUTE_UNUSED,
-			  bfd *output_bfd ATTRIBUTE_UNUSED,
+			  asection *input_section,
+			  bfd *output_bfd,
 			  char **error_message ATTRIBUTE_UNUSED)
 {
-  uint32_t op;
-  int32_t param;
-  uint8_t shift;
+  if (output_bfd != NULL && output_bfd != abfd)
+    return bfd_reloc_continue;
 
-  op = bfd_getl32 (data + reloc_entry->address);
-  param = reloc_entry->addend & 0xfff;
+  if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
+				  input_section, reloc_entry->address))
+    return bfd_reloc_outofrange;
+
+  uint32_t op = bfd_getl32 (data + reloc_entry->address);
+  bfd_vma relocation = reloc_entry->addend & 0xfff;
+  int shift;
 
   if ((op & 0xff800000) == 0x3d800000)
     {
@@ -93,53 +130,120 @@ coff_aarch64_po12l_reloc (bfd *abfd ATTRIBUTE_UNUSED,
       shift = op >> 30;
     }
 
-  if (param & ((1 << shift) - 1))
-    return bfd_reloc_overflow;
+  bfd_reloc_status_type ret = bfd_reloc_ok;
+  if (output_bfd == NULL)
+    {
+      if (bfd_is_und_section (symbol->section))
+	{
+	  if ((symbol->flags & BSF_WEAK) == 0)
+	    ret = bfd_reloc_undefined;
+	}
+      else if (!bfd_is_com_section (symbol->section))
+	relocation += (symbol->value
+		       + symbol->section->output_offset
+		       + symbol->section->output_section->vma);
+      bfd_vma addend = (op >> 10) & 0xfff;
+      addend <<= shift;
+      relocation += addend;
+    }
 
-  param >>= shift;
+  if (relocation & ((1 << shift) - 1))
+    ret = bfd_reloc_overflow;
 
   op &= 0xffc003ff;
-  op |= param << 10;
+  op |= (relocation >> shift << 10) & 0x3ffc00;
 
   bfd_putl32 (op, data + reloc_entry->address);
 
-  return bfd_reloc_ok;
+  return ret;
 }
 
 static bfd_reloc_status_type
-coff_aarch64_addr32nb_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+coff_aarch64_addr32nb_reloc (bfd *abfd,
 			     arelent *reloc_entry,
 			     asymbol *symbol ATTRIBUTE_UNUSED,
 			     void *data,
-			     asection *input_section ATTRIBUTE_UNUSED,
-			     bfd *output_bfd ATTRIBUTE_UNUSED,
-			     char **error_message ATTRIBUTE_UNUSED)
+			     asection *input_section,
+			     bfd *output_bfd,
+			     char **error_message)
 {
-  uint64_t val;
+  if (output_bfd != NULL && output_bfd != abfd)
+    return bfd_reloc_continue;
 
-  if ((int64_t) reloc_entry->addend > 0x7fffffff
-      || (int64_t) reloc_entry->addend < -0x7fffffff)
-    return bfd_reloc_overflow;
+  if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
+				  input_section, reloc_entry->address))
+    return bfd_reloc_outofrange;
 
-  val = reloc_entry->addend;
+  bfd_vma relocation = reloc_entry->addend;
+  bfd_reloc_status_type ret = bfd_reloc_ok;
+  if (output_bfd == NULL)
+    {
+      if (bfd_is_und_section (symbol->section))
+	{
+	  if ((symbol->flags & BSF_WEAK) == 0)
+	    ret = bfd_reloc_undefined;
+	}
+      else if (!bfd_is_com_section (symbol->section))
+	relocation += (symbol->value
+		       + symbol->section->output_offset
+		       + symbol->section->output_section->vma);
+      bfd_vma addend = bfd_getl_signed_32 (data + reloc_entry->address);
+      relocation += addend;
+      if (bfd_get_flavour (output_bfd) == bfd_target_coff_flavour
+	  && obj_pe (output_bfd))
+	relocation -= pe_data (output_bfd)->pe_opthdr.ImageBase;
+      else
+	{
+	  *error_message = "unsupported";
+	  return bfd_reloc_dangerous;
+	}
+    }
+
+  if (relocation + 0x80000000 > 0xffffffff)
+    ret = bfd_reloc_overflow;
 
-  bfd_putl32 ((uint32_t) val, data + reloc_entry->address);
+  bfd_putl32 (relocation, data + reloc_entry->address);
 
-  return bfd_reloc_ok;
+  return ret;
 }
 
 static bfd_reloc_status_type
-coff_aarch64_secrel_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+coff_aarch64_secrel_reloc (bfd *abfd,
 			   arelent *reloc_entry,
 			   asymbol *symbol ATTRIBUTE_UNUSED,
 			   void *data,
-			   asection *input_section ATTRIBUTE_UNUSED,
-			   bfd *output_bfd ATTRIBUTE_UNUSED,
+			   asection *input_section,
+			   bfd *output_bfd,
 			   char **error_message ATTRIBUTE_UNUSED)
 {
-  bfd_putl32 (reloc_entry->addend, data + reloc_entry->address);
+  if (output_bfd != NULL && output_bfd != abfd)
+    return bfd_reloc_continue;
+
+  if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
+				  input_section, reloc_entry->address))
+    return bfd_reloc_outofrange;
+
+  bfd_vma relocation = reloc_entry->addend;
+  bfd_reloc_status_type ret = bfd_reloc_ok;
+  if (output_bfd == NULL)
+    {
+      if (bfd_is_und_section (symbol->section))
+	{
+	  if ((symbol->flags & BSF_WEAK) == 0)
+	    ret = bfd_reloc_undefined;
+	}
+      else if (!bfd_is_com_section (symbol->section))
+	relocation += (symbol->value
+		       + symbol->section->output_offset);
+      bfd_vma addend = bfd_getl_signed_32 (data + reloc_entry->address);
+      relocation += addend;
+    }
+  if (relocation > 0xffffffff)
+    ret = bfd_reloc_overflow;
+
+  bfd_putl32 (relocation, data + reloc_entry->address);
 
-  return bfd_reloc_ok;
+  return ret;
 }
 
 #define coff_aarch64_NULL NULL
@@ -438,6 +542,17 @@ coff_pe_aarch64_relocate_section (bfd *output_bfd,
 	  || (unsigned long) symndx >= obj_raw_syment_count (input_bfd))
 	continue;
 
+      /* All the relocs handled below operate on 4 bytes.  */
+      if (input_section->size < rel->r_vaddr
+	  || input_section->size - rel->r_vaddr < 4)
+	{
+	  _bfd_error_handler
+	    /* xgettext: c-format */
+	    (_("%pB: bad reloc address %#" PRIx64 " in section `%pA'"),
+	     input_bfd, (uint64_t) rel->r_vaddr, input_section);
+	  continue;
+	}
+
       switch (rel->r_type)
 	{
 	case IMAGE_REL_ARM64_ADDR32NB:

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2023-01-18  6:27 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-18  6:26 [PATCH 0/4] bfd_install_relocation and aarch64-pe changes Alan Modra
2023-01-18  6:26 ` [PATCH 1/4] howto install_addend Alan Modra
2023-01-18  6:26 ` [PATCH 2/4] coff-aarch64.c howtos Alan Modra
2023-01-18  6:26 ` [PATCH 3/4] Correct coff-aarch64 howtos and delete unnecessary special functions Alan Modra
2023-01-18  6:26 ` [PATCH 4/4] The fuzzers have found the reloc special functions in coff-aarch64.c Alan Modra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).