[v3,2/9] elf: Extract _bfd_elf_process_reverse_copy

Message ID 20220111140634.2250914-3-hjl.tools@gmail.com
State New
Headers show
Series
  • ld: Implement DT_RELR for x86
Related show

Commit Message

H.J. Lu via Binutils Jan. 11, 2022, 2:06 p.m.
Extract _bfd_elf_process_reverse_copy from elf_link_input_bfd so that
it can be called in check_relocs to set SEC_ELF_REVERSE_COPY before
elf_link_input_bfd is called.

	* elf-bfd.h (_bfd_elf_process_reverse_copy): New prototype.
	* elflink.c (_bfd_elf_process_reverse_copy): New.  Extracted
	from elf_link_input_bfd.
	(elf_link_input_bfd): Call _bfd_elf_process_reverse_copy.
---
 bfd/elf-bfd.h |  2 ++
 bfd/elflink.c | 60 ++++++++++++++++++++++++++++++++-------------------
 2 files changed, 40 insertions(+), 22 deletions(-)

-- 
2.34.1

Comments

H.J. Lu via Binutils Jan. 12, 2022, 2:28 a.m. | #1
On Tue, Jan 11, 2022 at 06:06:27AM -0800, H.J. Lu via Binutils wrote:
> Extract _bfd_elf_process_reverse_copy from elf_link_input_bfd so that

> it can be called in check_relocs to set SEC_ELF_REVERSE_COPY before

> elf_link_input_bfd is called.

> 

> 	* elf-bfd.h (_bfd_elf_process_reverse_copy): New prototype.

> 	* elflink.c (_bfd_elf_process_reverse_copy): New.  Extracted

> 	from elf_link_input_bfd.

> 	(elf_link_input_bfd): Call _bfd_elf_process_reverse_copy.


You are correct that the flag needs to be set earlier so that
_bfd_elf_section_offset gives correct results when used earlier in the
linking process.  However, this is something that should be done once
for all ELF targets rather than in multiple places depending on
target, via a hook.

It must be done during or after map_input_to_output_sections, and
since your DT_RELR patchset makes decisions about relative relocations
in ldemul_before_allocation, during or before that.  But there isn't a
convenient iteration over all sections in ldelf_before_allocation.  So
I'm inclined to set the flag during map_input_to_output_sections, even
though it adds ELF specific code there.

I'll commit the following after running tests over my normal list of
targets.

bfd/
	* elflink.c (elf_link_input_bfd): Don't set SEC_ELF_REVERSE_COPY
	here.  Move sanity checks to reverse copying code.
ld/
	* ldlang.c (lang_add_section): Set SEC_ELF_REVERSE_COPY for
	.ctors/.dtors in .init_array/.fini_array.

diff --git a/bfd/elflink.c b/bfd/elflink.c
index 059461b5725..f5e3fd53c5d 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -11247,31 +11247,6 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
 	      && o->reloc_count > 0)
 	    return false;
 
-	  /* We need to reverse-copy input .ctors/.dtors sections if
-	     they are placed in .init_array/.finit_array for output.  */
-	  if (o->size > address_size
-	      && ((startswith (o->name, ".ctors")
-		   && strcmp (o->output_section->name,
-			      ".init_array") == 0)
-		  || (startswith (o->name, ".dtors")
-		      && strcmp (o->output_section->name,
-				 ".fini_array") == 0))
-	      && (o->name[6] == 0 || o->name[6] == '.'))
-	    {
-	      if (o->size * bed->s->int_rels_per_ext_rel
-		  != o->reloc_count * address_size)
-		{
-		  _bfd_error_handler
-		    /* xgettext:c-format */
-		    (_("error: %pB: size of section %pA is not "
-		       "multiple of address size"),
-		     input_bfd, o);
-		  bfd_set_error (bfd_error_bad_value);
-		  return false;
-		}
-	      o->flags |= SEC_ELF_REVERSE_COPY;
-	    }
-
 	  action_discarded = -1;
 	  if (!elf_section_ignore_discarded_relocs (o))
 	    action_discarded = (*bed->action_discarded) (o);
@@ -11756,9 +11731,24 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
 
 		offset *= bfd_octets_per_byte (output_bfd, o);
 
-		if ((o->flags & SEC_ELF_REVERSE_COPY))
+		if ((o->flags & SEC_ELF_REVERSE_COPY)
+		    && o->size > address_size)
 		  {
 		    /* Reverse-copy input section to output.  */
+
+		    if (o->reloc_count != 0
+			&& (o->size * bed->s->int_rels_per_ext_rel
+			    != o->reloc_count * address_size))
+		      {
+			_bfd_error_handler
+			  /* xgettext:c-format */
+			  (_("error: %pB: size of section %pA is not "
+			     "multiple of address size"),
+			   input_bfd, o);
+			bfd_set_error (bfd_error_bad_value);
+			return false;
+		      }
+
 		    do
 		      {
 			todo -= address_size;
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 9dbc8752f87..0af6c60bce5 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -2701,6 +2701,16 @@ lang_add_section (lang_statement_list_type *ptr,
       output->block_value = 128;
     }
 
+  /* When a .ctors section is placed in .init_array it must be copied
+     in reverse order.  Similarly for .dtors.  Set that up.  */
+  if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour
+      && ((startswith (section->name, ".ctors")
+	   && strcmp (output->bfd_section->name, ".init_array") == 0)
+	  || (startswith (section->name, ".dtors")
+	      && strcmp (output->bfd_section->name, ".fini_array") == 0))
+      && (section->name[6] == 0 || section->name[6] == '.'))
+    section->flags |= SEC_ELF_REVERSE_COPY;
+
   if (section->alignment_power > output->bfd_section->alignment_power)
     output->bfd_section->alignment_power = section->alignment_power;
 


-- 
Alan Modra
Australia Development Lab, IBM

Patch

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 81f8fd47db7..2441b3c0cd7 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -2331,6 +2331,8 @@  extern const struct bfd_elf_special_section *_bfd_elf_get_special_section
   (const char *, const struct bfd_elf_special_section *, unsigned int);
 extern const struct bfd_elf_special_section *_bfd_elf_get_sec_type_attr
   (bfd *, asection *);
+extern bool _bfd_elf_process_reverse_copy (asection *, unsigned int,
+					   unsigned int);
 
 extern bool _bfd_elf_link_hide_sym_by_version
   (struct bfd_link_info *, struct elf_link_hash_entry *);
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 059461b5725..29ef9ddf8b9 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -10851,6 +10851,41 @@  _bfd_elf_check_kept_section (asection *sec, struct bfd_link_info *info)
   return kept;
 }
 
+/* Set SEC_ELF_REVERSE_COPY on section S when we need to reverse-copy
+   input .ctors/.dtors sections if they are placed in .init_array or
+   .finit_array for output.  ADDRESS_SIZE is address in bytes.
+   INT_RELS_PER_EXT_REL is the number of internal relocations to
+   allocate per external relocation entry.  */
+
+bool
+_bfd_elf_process_reverse_copy (asection *s, unsigned int address_size,
+			       unsigned int int_rels_per_ext_rel)
+{
+  if (s->size <= address_size
+      || (s->flags & SEC_ELF_REVERSE_COPY) != 0)
+    return true;
+
+  if (((startswith (s->name, ".ctors")
+	&& strcmp (s->output_section->name, ".init_array") == 0)
+       || (startswith (s->name, ".dtors")
+	   && strcmp (s->output_section->name, ".fini_array") == 0))
+      && (s->name[6] == 0 || s->name[6] == '.'))
+    {
+      if (s->size * int_rels_per_ext_rel
+	  != s->reloc_count * address_size)
+	{
+	  _bfd_error_handler
+	    /* xgettext:c-format */
+	    (_("error: %pB: size of section %pA is not multiple of "
+	       "address size"), s->owner, s);
+	  bfd_set_error (bfd_error_bad_value);
+	  return false;
+	}
+      s->flags |= SEC_ELF_REVERSE_COPY;
+    }
+  return true;
+}
+
 /* Link an input file into the linker output file.  This function
    handles all the sections and relocations of the input file at once.
    This is so that we only have to read the local symbols once, and
@@ -11249,28 +11284,9 @@  elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
 
 	  /* We need to reverse-copy input .ctors/.dtors sections if
 	     they are placed in .init_array/.finit_array for output.  */
-	  if (o->size > address_size
-	      && ((startswith (o->name, ".ctors")
-		   && strcmp (o->output_section->name,
-			      ".init_array") == 0)
-		  || (startswith (o->name, ".dtors")
-		      && strcmp (o->output_section->name,
-				 ".fini_array") == 0))
-	      && (o->name[6] == 0 || o->name[6] == '.'))
-	    {
-	      if (o->size * bed->s->int_rels_per_ext_rel
-		  != o->reloc_count * address_size)
-		{
-		  _bfd_error_handler
-		    /* xgettext:c-format */
-		    (_("error: %pB: size of section %pA is not "
-		       "multiple of address size"),
-		     input_bfd, o);
-		  bfd_set_error (bfd_error_bad_value);
-		  return false;
-		}
-	      o->flags |= SEC_ELF_REVERSE_COPY;
-	    }
+	  if (!_bfd_elf_process_reverse_copy (o, address_size,
+					      bed->s->int_rels_per_ext_rel))
+	    return false;
 
 	  action_discarded = -1;
 	  if (!elf_section_ignore_discarded_relocs (o))