elf: Cache ".interp" section pointer in elf_link_hash_table

Message ID 20250914215411.4103887-1-hjl.tools@gmail.com
State New
Headers
Series elf: Cache ".interp" section pointer in elf_link_hash_table |

Commit Message

H.J. Lu Sept. 14, 2025, 9:54 p.m. UTC
  If there is no interpreter (no ".interp" sectio), weak undefined symbols
will always be zero at run-time.  Cache ".interp" section pointer in
elf_link_hash_table so that a backend can use it to check if weak
undefined symbols should be resolved to zero at link-time.

	PR ld/33427
	* elf-bfd.h (elf_link_hash_table): Add interp.
	* elflink.c (_bfd_elf_link_create_dynamic_sections): Cache the
	pointer to ".interp" section in interp.
	* elfxx-x86.c (_bfd_x86_elf_link_symbol_references_local): Check
	htab->elf.interp instead of htab->interp.
	(_bfd_x86_elf_link_setup_gnu_properties): Use htab->elf.interp.
	* elfxx-x86.h (elf_x86_link_hash_table): Remove interp.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
 bfd/elf-bfd.h   | 1 +
 bfd/elflink.c   | 1 +
 bfd/elfxx-x86.c | 7 ++-----
 bfd/elfxx-x86.h | 1 -
 4 files changed, 4 insertions(+), 6 deletions(-)
  

Comments

Alan Modra Sept. 18, 2025, 12:04 a.m. UTC | #1
On Sun, Sep 14, 2025 at 02:54:11PM -0700, H.J. Lu wrote:
> If there is no interpreter (no ".interp" sectio), weak undefined symbols
> will always be zero at run-time.  Cache ".interp" section pointer in
> elf_link_hash_table so that a backend can use it to check if weak
> undefined symbols should be resolved to zero at link-time.

Since you are moving this to the main elf_link_hash_table, I assume
you have a followup patch that updates occurrences of
	bfd_get_linker_section (dynobj, ".interp");
If so this patch is OK and I'll preapprove the bfd_get_linker_section
changes.

> 	PR ld/33427
> 	* elf-bfd.h (elf_link_hash_table): Add interp.
> 	* elflink.c (_bfd_elf_link_create_dynamic_sections): Cache the
> 	pointer to ".interp" section in interp.
> 	* elfxx-x86.c (_bfd_x86_elf_link_symbol_references_local): Check
> 	htab->elf.interp instead of htab->interp.
> 	(_bfd_x86_elf_link_setup_gnu_properties): Use htab->elf.interp.
> 	* elfxx-x86.h (elf_x86_link_hash_table): Remove interp.
> 
> Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
> ---
>  bfd/elf-bfd.h   | 1 +
>  bfd/elflink.c   | 1 +
>  bfd/elfxx-x86.c | 7 ++-----
>  bfd/elfxx-x86.h | 1 -
>  4 files changed, 4 insertions(+), 6 deletions(-)
> 
> diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
> index de7cc410a99..51e6ae7bb78 100644
> --- a/bfd/elf-bfd.h
> +++ b/bfd/elf-bfd.h
> @@ -774,6 +774,7 @@ struct elf_link_hash_table
>    asection *dynsym;
>    asection *srelrdyn;
>    asection *dynamic;
> +  asection *interp;
>  };
>  
>  /* Returns TRUE if the hash table is a struct elf_link_hash_table.  */
> diff --git a/bfd/elflink.c b/bfd/elflink.c
> index 53ec792852c..b8ffcab419c 100644
> --- a/bfd/elflink.c
> +++ b/bfd/elflink.c
> @@ -354,6 +354,7 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
>  					      flags | SEC_READONLY);
>        if (s == NULL)
>  	return false;
> +      elf_hash_table (info)->interp = s;
>      }
>  
>    /* Create sections to hold version informations.  These are removed
> diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
> index 06265ee4e15..4ca4c3a3948 100644
> --- a/bfd/elfxx-x86.c
> +++ b/bfd/elfxx-x86.c
> @@ -3665,7 +3665,7 @@ _bfd_x86_elf_link_symbol_references_local (struct bfd_link_info *info,
>        || (h->root.type == bfd_link_hash_undefweak
>  	  && (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
>  	      || (bfd_link_executable (info)
> -		  && htab->interp == NULL)
> +		  && htab->elf.interp == NULL)
>  	      || info->dynamic_undefined_weak == 0))
>        || ((h->def_regular || ELF_COMMON_DEF_P (h))
>  	  && info->version_info != NULL
> @@ -4704,13 +4704,10 @@ _bfd_x86_elf_link_setup_gnu_properties
>  	 section to the interpreter.  */
>        if (bfd_link_executable (info) && !info->nointerp)
>  	{
> -	  asection *s = bfd_get_linker_section (dynobj, ".interp");
> -	  if (s == NULL)
> -	    abort ();
> +	  asection *s = htab->elf.interp;
>  	  s->size = htab->dynamic_interpreter_size;
>  	  s->contents = (unsigned char *) htab->dynamic_interpreter;
>  	  s->alloced = 1;
> -	  htab->interp = s;
>  	}
>  
>        if (normal_target)
> diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
> index 5593203f9ec..1ebc9d2f2e5 100644
> --- a/bfd/elfxx-x86.h
> +++ b/bfd/elfxx-x86.h
> @@ -602,7 +602,6 @@ struct elf_x86_link_hash_table
>    struct elf_link_hash_table elf;
>  
>    /* Short-cuts to get to dynamic linker sections.  */
> -  asection *interp;
>    asection *plt_eh_frame;
>    asection *plt_second;
>    asection *plt_second_eh_frame;
> -- 
> 2.51.0
  
H.J. Lu Sept. 18, 2025, 1:54 a.m. UTC | #2
On Thu, Sep 18, 2025 at 09:34:16AM +0930, Alan Modra wrote:
> On Sun, Sep 14, 2025 at 02:54:11PM -0700, H.J. Lu wrote:
> > If there is no interpreter (no ".interp" sectio), weak undefined symbols
> > will always be zero at run-time.  Cache ".interp" section pointer in
> > elf_link_hash_table so that a backend can use it to check if weak
> > undefined symbols should be resolved to zero at link-time.
> 
> Since you are moving this to the main elf_link_hash_table, I assume
> you have a followup patch that updates occurrences of
> 	bfd_get_linker_section (dynobj, ".interp");
> If so this patch is OK and I'll preapprove the bfd_get_linker_section
> changes.

Here is the combined patch I am checking in.

Thanks.

H.J.
---
Cache ".interp" section pointer in elf_link_hash_table so that a backend
can use it to avoid calling bfd_get_linker_section.

	* elf-bfd.h (elf_link_hash_table): Add interp.
	* elf-m10300.c (_bfd_mn10300_elf_late_size_sections): Use the
	interp field in elf_link_hash_table.
	* elf32-arc.c (elf_arc_late_size_sections): Likewise.
	* elf32-arm.c (elf32_arm_late_size_sections): Likewise.
	* elf32-bfin.c (elf32_bfinfdpic_late_size_sections): Likewise.
	(bfin_late_size_sections): Likewise.
	* elf32-cr16.c (_bfd_cr16_elf_late_size_sections): Likewise.
	* elf32-cris.c (elf_cris_late_size_sections): Likewise.
	* elf32-csky.c (csky_elf_late_size_sections): Likewise.
	* elf32-frv.c (elf32_frvfdpic_late_size_sections): Likewise.
	* elf32-hppa.c (elf32_hppa_late_size_sections): Likewise.
	* elf32-lm32.c (lm32_elf_late_size_sections): Likewise.
	* elf32-m32r.c (m32r_elf_late_size_sections): Likewise.
	* elf32-m68k.c (elf_m68k_late_size_sections): Likewise.
	* elf32-metag.c (elf_metag_late_size_sections): Likewise.
	* elf32-nds32.c (nds32_elf_late_size_sections): Likewise.
	* elf32-or1k.c (or1k_elf_late_size_sections): Likewise.
	* elf32-ppc.c (ppc_elf_late_size_sections): Likewise.
	* elf32-s390.c (elf_s390_late_size_sections): Likewise.
	* elf32-score.c (s3_bfd_score_elf_late_size_sections): Likewise.
	* elf32-score7.c (s7_bfd_score_elf_late_size_sections): Likewise.
	* elf32-sh.c (sh_elf_late_size_sections): Likewise.
	* elf32-tic6x.c (elf32_tic6x_late_size_sections): Likewise.
	* elf32-tilepro.c (tilepro_elf_late_size_sections): Likewise.
	* elf32-vax.c (elf_vax_late_size_sections): Likewise.
	* elf32-xtensa.c (elf_xtensa_late_size_sections): Likewise.
	* elf64-alpha.c (elf64_alpha_late_size_sections): Likewise.
	* elf64-hppa.c (elf64_hppa_late_size_sections): Likewise.
	* elf64-ppc.c (ppc64_elf_late_size_sections): Likewise.
	* elf64-s390.c (elf_s390_late_size_sections): Likewise.
	* elfnn-aarch64.c (elfNN_aarch64_late_size_sections): Likewise.
	* elfnn-ia64.c (elfNN_ia64_late_size_sections): Likewise.
	* elfnn-kvx.c (elfNN_kvx_late_size_sections): Likewise.
	* elfnn-loongarch.c (loongarch_elf_late_size_sections): Likewise.
	* elfnn-riscv.c (riscv_elf_late_size_sections): Likewise.
	* elfxx-mips.c (_bfd_mips_elf_late_size_sections): Likewise.
	* elfxx-tilegx.c (tilegx_elf_late_size_sections): Likewise.
	* elflink.c (_bfd_elf_link_create_dynamic_sections): Cache the
	pointer to ".interp" section in the interp field in
	elf_link_hash_table.
	(bfd_elf_size_dynamic_sections): Use the interp field in
	elf_link_hash_table.
	* elfxx-sparc.c (UNDEFINED_WEAK_RESOLVED_TO_ZERO): Use the
	interp field in elf_link_hash_table.
	(_bfd_sparc_elf_late_size_sections): Likewise.  Don't set
	interp.
	* elfxx-sparc.h (_bfd_sparc_elf_link_hash_table): Remove interp.
	* elfxx-x86.c (_bfd_x86_elf_link_symbol_references_local): Check
	htab->elf.interp instead of htab->interp.
	(_bfd_x86_elf_link_setup_gnu_properties): Use htab->elf.interp.
	* elfxx-x86.h (elf_x86_link_hash_table): Remove interp.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
 bfd/elf-bfd.h         | 1 +
 bfd/elf-m10300.c      | 2 +-
 bfd/elf32-arc.c       | 2 +-
 bfd/elf32-arm.c       | 2 +-
 bfd/elf32-bfin.c      | 4 ++--
 bfd/elf32-cr16.c      | 2 +-
 bfd/elf32-cris.c      | 2 +-
 bfd/elf32-csky.c      | 2 +-
 bfd/elf32-frv.c       | 2 +-
 bfd/elf32-hppa.c      | 2 +-
 bfd/elf32-lm32.c      | 2 +-
 bfd/elf32-m32r.c      | 2 +-
 bfd/elf32-m68k.c      | 2 +-
 bfd/elf32-metag.c     | 2 +-
 bfd/elf32-nds32.c     | 2 +-
 bfd/elf32-or1k.c      | 2 +-
 bfd/elf32-ppc.c       | 2 +-
 bfd/elf32-s390.c      | 2 +-
 bfd/elf32-score.c     | 2 +-
 bfd/elf32-score7.c    | 2 +-
 bfd/elf32-sh.c        | 2 +-
 bfd/elf32-tic6x.c     | 2 +-
 bfd/elf32-tilepro.c   | 2 +-
 bfd/elf32-vax.c       | 2 +-
 bfd/elf32-xtensa.c    | 2 +-
 bfd/elf64-alpha.c     | 2 +-
 bfd/elf64-hppa.c      | 2 +-
 bfd/elf64-ppc.c       | 2 +-
 bfd/elf64-s390.c      | 2 +-
 bfd/elflink.c         | 3 ++-
 bfd/elfnn-aarch64.c   | 2 +-
 bfd/elfnn-ia64.c      | 2 +-
 bfd/elfnn-kvx.c       | 2 +-
 bfd/elfnn-loongarch.c | 2 +-
 bfd/elfnn-riscv.c     | 2 +-
 bfd/elfxx-mips.c      | 2 +-
 bfd/elfxx-sparc.c     | 5 ++---
 bfd/elfxx-sparc.h     | 3 ---
 bfd/elfxx-tilegx.c    | 2 +-
 bfd/elfxx-x86.c       | 9 +++------
 bfd/elfxx-x86.h       | 1 -
 41 files changed, 44 insertions(+), 50 deletions(-)

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index de7cc410a99..51e6ae7bb78 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -762,30 +762,31 @@ struct elf_link_hash_table
   asection *sgotplt;
   asection *srelgot;
   asection *splt;
   asection *srelplt;
   asection *sdynbss;
   asection *srelbss;
   asection *sdynrelro;
   asection *sreldynrelro;
   asection *igotplt;
   asection *iplt;
   asection *irelplt;
   asection *irelifunc;
   asection *dynsym;
   asection *srelrdyn;
   asection *dynamic;
+  asection *interp;
 };
 
 /* Returns TRUE if the hash table is a struct elf_link_hash_table.  */
 
 static inline bool
 is_elf_hash_table (const struct bfd_link_hash_table *htab)
 {
   return htab->type == bfd_link_elf_hash_table;
 }
 
 /* Look up an entry in an ELF linker hash table.  */
 
 static inline struct elf_link_hash_entry *
 elf_link_hash_lookup (struct elf_link_hash_table *table, const char *string,
 		      bool create, bool copy, bool follow)
diff --git a/bfd/elf-m10300.c b/bfd/elf-m10300.c
index ba993869e28..b381bb9037c 100644
--- a/bfd/elf-m10300.c
+++ b/bfd/elf-m10300.c
@@ -5019,31 +5019,31 @@ _bfd_mn10300_elf_late_size_sections (bfd * output_bfd,
 {
   struct elf32_mn10300_link_hash_table *htab = elf32_mn10300_hash_table (info);
   bfd * dynobj;
   asection * s;
   bool relocs;
 
   dynobj = htab->root.dynobj;
   if (dynobj == NULL)
     return true;
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = elf_hash_table (info)->interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
   else
     {
       /* We may have created entries in the .rela.got section.
 	 However, if we are not creating the dynamic sections, we will
 	 not actually use these entries.  Reset the size of .rela.got,
 	 which will cause it to get stripped from the output file
 	 below.  */
       s = htab->root.sgot;
       if (s != NULL)
diff --git a/bfd/elf32-arc.c b/bfd/elf32-arc.c
index a78516dc12f..ebfe4dcc26a 100644
--- a/bfd/elf32-arc.c
+++ b/bfd/elf32-arc.c
@@ -2731,31 +2731,31 @@ elf_arc_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   bool relocs_exist = false;
   struct elf_link_hash_table *htab = elf_hash_table (info);
 
   dynobj = htab->dynobj;
   if (dynobj == NULL)
     return true;
 
   if (htab->dynamic_sections_created)
     {
       struct elf_link_hash_entry *h;
 
       /* Set the contents of the .interp section to the
 	 interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_section_by_name (dynobj, ".interp");
+	  s = htab->interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = sizeof (ELF_DYNAMIC_INTERPRETER);
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
 
       /* Add some entries to the .dynamic section.  We fill in some of
 	 the values later, in elf_bfd_final_link, but we must add the
 	 entries now so that we know the final size of the .dynamic
 	 section.  Checking if the .init section is present.  We also
 	 create DT_INIT and DT_FINI entries if the init_str has been
 	 changed by the user.  */
       ADD_DYNAMIC_SYMBOL (info->init_function, DT_INIT);
       ADD_DYNAMIC_SYMBOL (info->fini_function, DT_FINI);
     }
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index df60430b7c3..ae3dc246be0 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -16681,31 +16681,31 @@ elf32_arm_late_size_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
   htab = elf32_arm_hash_table (info);
   if (htab == NULL)
     return false;
 
   dynobj = elf_hash_table (info)->dynobj;
   if (dynobj == NULL)
     return true;
 
   check_use_blx (htab);
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = elf_hash_table (info)->interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
       struct arm_local_iplt_info **local_iplt_ptr, *local_iplt;
       char *local_tls_type;
diff --git a/bfd/elf32-bfin.c b/bfd/elf32-bfin.c
index 249c6b52af0..7ed1285f4c2 100644
--- a/bfd/elf32-bfin.c
+++ b/bfd/elf32-bfin.c
@@ -4038,31 +4038,31 @@ elf32_bfinfdpic_late_size_sections (bfd *output_bfd,
   struct elf_link_hash_table *htab;
   bfd *dynobj;
   asection *s;
   struct _bfinfdpic_dynamic_got_plt_info gpinfo;
 
   htab = elf_hash_table (info);
   dynobj = htab->dynobj;
   if (dynobj == NULL)
     return true;
 
   if (htab->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = htab->interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   memset (&gpinfo, 0, sizeof (gpinfo));
   gpinfo.g.info = info;
 
   for (;;)
     {
       htab_t relocs = bfinfdpic_relocs_info (info);
 
       htab_traverse (relocs, _bfinfdpic_resolve_final_relocs_info, &relocs);
@@ -5130,31 +5130,31 @@ bfin_late_size_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
 			 struct bfd_link_info *info)
 {
   bfd *dynobj;
   asection *s;
   bool relocs;
 
   dynobj = elf_hash_table (info)->dynobj;
   if (dynobj == NULL)
     return true;
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = elf_hash_table (info)->interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
   else
     {
       /* We may have created entries in the .rela.got section.
 	 However, if we are not creating the dynamic sections, we will
 	 not actually use these entries.  Reset the size of .rela.got,
 	 which will cause it to get stripped from the output file
 	 below.  */
       s = elf_hash_table (info)->srelgot;
       if (s != NULL)
diff --git a/bfd/elf32-cr16.c b/bfd/elf32-cr16.c
index fc2e2d48f27..31d1ba41c17 100644
--- a/bfd/elf32-cr16.c
+++ b/bfd/elf32-cr16.c
@@ -2396,31 +2396,31 @@ _bfd_cr16_elf_late_size_sections (bfd * output_bfd,
 {
   bfd * dynobj;
   asection * s;
   bool relocs;
 
   dynobj = elf_hash_table (info)->dynobj;
   if (dynobj == NULL)
     return true;
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
 #if 0
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = elf_hash_table (info)->interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 #endif
 	}
     }
   else
     {
       /* We may have created entries in the .rela.got section.
 	 However, if we are not creating the dynamic sections, we will
 	 not actually use these entries.  Reset the size of .rela.got,
 	 which will cause it to get stripped from the output file
 	 below.  */
       s = elf_hash_table (info)->srelgot;
diff --git a/bfd/elf32-cris.c b/bfd/elf32-cris.c
index 285c6c794a2..faaebb9ebee 100644
--- a/bfd/elf32-cris.c
+++ b/bfd/elf32-cris.c
@@ -3515,31 +3515,31 @@ elf_cris_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   bool relocs;
 
   htab = elf_cris_hash_table (info);
   if (htab == NULL)
     return false;
 
   dynobj = htab->root.dynobj;
   if (dynobj == NULL)
     return true;
 
   if (htab->root.dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = htab->root.interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
   else
     {
       /* Adjust all expected GOTPLT uses to use a GOT entry instead.  */
       elf_cris_link_hash_traverse (htab, elf_cris_adjust_gotplt_to_got,
 				   info);
 
       /* We may have created entries in the .rela.got section.
 	 However, if we are not creating the dynamic sections, we will
 	 not actually use these entries.  Reset the size of .rela.got,
diff --git a/bfd/elf32-csky.c b/bfd/elf32-csky.c
index 2a08659f06f..40781a0e1bb 100644
--- a/bfd/elf32-csky.c
+++ b/bfd/elf32-csky.c
@@ -1900,31 +1900,31 @@ csky_elf_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   bool relocs;
   bfd *ibfd;
 
   htab = csky_elf_hash_table (info);
   if (htab == NULL)
     return false;
   dynobj = htab->elf.dynobj;
   if (dynobj == NULL)
     return true;
 
   if (htab->elf.dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (!bfd_link_pic (info) && !info->nointerp)
 	{
-	  s = bfd_get_section_by_name (dynobj, ".interp");
+	  s = htab->elf.interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       bfd_signed_vma *local_got_refcounts;
       bfd_signed_vma *end_local_got;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
diff --git a/bfd/elf32-frv.c b/bfd/elf32-frv.c
index 0423540cf98..b7183133ad1 100644
--- a/bfd/elf32-frv.c
+++ b/bfd/elf32-frv.c
@@ -5432,31 +5432,31 @@ elf32_frvfdpic_late_size_sections (bfd *output_bfd,
 				   struct bfd_link_info *info)
 {
   bfd *dynobj;
   asection *s;
   struct _frvfdpic_dynamic_got_plt_info gpinfo;
 
   dynobj = elf_hash_table (info)->dynobj;
   if (dynobj == NULL)
     return true;
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = elf_hash_table (info)->interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   memset (&gpinfo, 0, sizeof (gpinfo));
   gpinfo.g.info = info;
 
   for (;;)
     {
       htab_t relocs = frvfdpic_relocs_info (info);
 
       htab_traverse (relocs, _frvfdpic_resolve_final_relocs_info, &relocs);
diff --git a/bfd/elf32-hppa.c b/bfd/elf32-hppa.c
index 80b89fac38b..2f463e12829 100644
--- a/bfd/elf32-hppa.c
+++ b/bfd/elf32-hppa.c
@@ -2051,31 +2051,31 @@ elf32_hppa_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   bool relocs;
 
   htab = hppa_link_hash_table (info);
   if (htab == NULL)
     return false;
 
   dynobj = htab->etab.dynobj;
   if (dynobj == NULL)
     return true;
 
   if (htab->etab.dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  sec = bfd_get_linker_section (dynobj, ".interp");
+	  sec = htab->etab.interp;
 	  if (sec == NULL)
 	    abort ();
 	  sec->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  sec->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  sec->alloced = 1;
 	}
 
       /* Force millicode symbols local.  */
       elf_link_hash_traverse (&htab->etab,
 			      clobber_millicode_symbols,
 			      info);
     }
 
   /* Set up .got and .plt offsets for local syms, and space for local
      dynamic relocs.  */
diff --git a/bfd/elf32-lm32.c b/bfd/elf32-lm32.c
index b36e92d150a..0ead0df9cf0 100644
--- a/bfd/elf32-lm32.c
+++ b/bfd/elf32-lm32.c
@@ -1914,31 +1914,31 @@ lm32_elf_late_size_sections (bfd *output_bfd,
   bfd *ibfd;
 
   htab = lm32_elf_hash_table (info);
   if (htab == NULL)
     return false;
 
   dynobj = htab->root.dynobj;
   if (dynobj == NULL)
     return true;
 
   if (htab->root.dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = htab->root.interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
diff --git a/bfd/elf32-m32r.c b/bfd/elf32-m32r.c
index 49cc5fc4240..c51133090b4 100644
--- a/bfd/elf32-m32r.c
+++ b/bfd/elf32-m32r.c
@@ -1971,31 +1971,31 @@ m32r_elf_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 #endif
 
   htab = m32r_elf_hash_table (info);
   if (htab == NULL)
     return false;
 
   dynobj = htab->dynobj;
   if (dynobj == NULL)
     return true;
 
   if (htab->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = htab->interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
diff --git a/bfd/elf32-m68k.c b/bfd/elf32-m68k.c
index 84ad64ac0ec..44ef102ea60 100644
--- a/bfd/elf32-m68k.c
+++ b/bfd/elf32-m68k.c
@@ -3110,31 +3110,31 @@ elf_m68k_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 			     struct bfd_link_info *info)
 {
   bfd *dynobj;
   asection *s;
   bool relocs;
 
   dynobj = elf_hash_table (info)->dynobj;
   if (dynobj == NULL)
     return true;
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = elf_hash_table (info)->interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
   else
     {
       /* We may have created entries in the .rela.got section.
 	 However, if we are not creating the dynamic sections, we will
 	 not actually use these entries.  Reset the size of .rela.got,
 	 which will cause it to get stripped from the output file
 	 below.  */
       s = elf_hash_table (info)->srelgot;
       if (s != NULL)
diff --git a/bfd/elf32-metag.c b/bfd/elf32-metag.c
index 0e6cfd885fe..916f3e15c72 100644
--- a/bfd/elf32-metag.c
+++ b/bfd/elf32-metag.c
@@ -2686,31 +2686,31 @@ elf_metag_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   bfd *dynobj;
   bfd *ibfd;
   asection *s;
   bool relocs;
 
   htab = metag_link_hash_table (info);
   dynobj = htab->etab.dynobj;
   if (dynobj == NULL)
     return true;
 
   if (htab->etab.dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = htab->etab.interp;
 	  if (s == NULL)
 	    abort ();
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
       bfd_size_type locsymcount;
diff --git a/bfd/elf32-nds32.c b/bfd/elf32-nds32.c
index bcd7c42e300..e22b58c4ea8 100644
--- a/bfd/elf32-nds32.c
+++ b/bfd/elf32-nds32.c
@@ -4314,31 +4314,31 @@ nds32_elf_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   bfd *ibfd;
 
   htab = nds32_elf_hash_table (info);
   if (htab == NULL)
     return false;
 
   dynobj = elf_hash_table (info)->dynobj;
   if (dynobj == NULL)
     return true;
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_section_by_name (dynobj, ".interp");
+	  s = elf_hash_table (info)->interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
diff --git a/bfd/elf32-or1k.c b/bfd/elf32-or1k.c
index b17a872f123..159308fec74 100644
--- a/bfd/elf32-or1k.c
+++ b/bfd/elf32-or1k.c
@@ -3054,31 +3054,31 @@ or1k_elf_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   bfd *ibfd;
 
   htab = or1k_elf_hash_table (info);
   if (htab == NULL)
     return false;
 
   dynobj = htab->root.dynobj;
   if (dynobj == NULL)
     return true;
 
   if (htab->root.dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_section_by_name (dynobj, ".interp");
+	  s = htab->root.interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index 1ed995bfb00..a3adcf8430e 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -5473,31 +5473,31 @@ ppc_elf_late_size_sections (bfd *output_bfd,
   bfd *ibfd;
 
 #ifdef DEBUG
   fprintf (stderr, "ppc_elf_late_size_sections called\n");
 #endif
 
   htab = ppc_elf_hash_table (info);
   if (htab->elf.dynobj == NULL)
     return true;
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (htab->elf.dynobj, ".interp");
+	  s = elf_hash_table (info)->interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   if (htab->plt_type == PLT_OLD)
     htab->got_header_size = 16;
   else if (htab->plt_type == PLT_NEW)
     htab->got_header_size = 12;
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
diff --git a/bfd/elf32-s390.c b/bfd/elf32-s390.c
index 40fcb53ff3a..56c613dd7d7 100644
--- a/bfd/elf32-s390.c
+++ b/bfd/elf32-s390.c
@@ -1781,31 +1781,31 @@ elf_s390_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   bfd *dynobj;
   asection *s;
   bool relocs;
   bfd *ibfd;
 
   htab = elf_s390_hash_table (info);
   dynobj = htab->elf.dynobj;
   if (dynobj == NULL)
     return true;
 
   if (htab->elf.dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = htab->elf.interp;
 	  if (s == NULL)
 	    abort ();
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
       char *local_tls_type;
diff --git a/bfd/elf32-score.c b/bfd/elf32-score.c
index 57bf04d9366..d91f2dedcf5 100644
--- a/bfd/elf32-score.c
+++ b/bfd/elf32-score.c
@@ -3231,31 +3231,31 @@ static bool
 s3_bfd_score_elf_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
 {
   bfd *dynobj;
   asection *s;
   bool reltext;
 
   dynobj = elf_hash_table (info)->dynobj;
   if (dynobj == NULL)
     return true;
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = elf_hash_table (info)->interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = strlen (ELF_DYNAMIC_INTERPRETER) + 1;
 	  s->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   /* The check_relocs and adjust_dynamic_symbol entry points have
      determined the sizes of the various dynamic sections.  Allocate
      memory for them.  */
   reltext = false;
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
       const char *name;
 
diff --git a/bfd/elf32-score7.c b/bfd/elf32-score7.c
index cbbff13933e..44718f39ccf 100644
--- a/bfd/elf32-score7.c
+++ b/bfd/elf32-score7.c
@@ -3041,31 +3041,31 @@ bool
 s7_bfd_score_elf_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
 {
   bfd *dynobj;
   asection *s;
   bool reltext;
 
   dynobj = elf_hash_table (info)->dynobj;
   if (dynobj == NULL)
     return true;
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = elf_hash_table (info)->interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = strlen (ELF_DYNAMIC_INTERPRETER) + 1;
 	  s->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   /* The check_relocs and adjust_dynamic_symbol entry points have
      determined the sizes of the various dynamic sections.  Allocate
      memory for them.  */
   reltext = false;
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
       const char *name;
 
diff --git a/bfd/elf32-sh.c b/bfd/elf32-sh.c
index d3f3a567589..e078e41b675 100644
--- a/bfd/elf32-sh.c
+++ b/bfd/elf32-sh.c
@@ -2950,31 +2950,31 @@ sh_elf_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   bfd *ibfd;
 
   htab = sh_elf_hash_table (info);
   if (htab == NULL)
     return false;
 
   dynobj = htab->root.dynobj;
   if (dynobj == NULL)
     return true;
 
   if (htab->root.dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = htab->root.interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
       union gotref *local_funcdesc, *end_local_funcdesc;
       char *local_got_type;
diff --git a/bfd/elf32-tic6x.c b/bfd/elf32-tic6x.c
index cc204c2ca08..a31c381531e 100644
--- a/bfd/elf32-tic6x.c
+++ b/bfd/elf32-tic6x.c
@@ -3159,31 +3159,31 @@ elf32_tic6x_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
   bfd *dynobj;
   asection *s;
   bool relocs;
   bfd *ibfd;
 
   htab = elf32_tic6x_hash_table (info);
   dynobj = htab->elf.dynobj;
   if (dynobj == NULL)
     return true;
 
   if (htab->elf.dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = htab->elf.interp;
 	  if (s == NULL)
 	    abort ();
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
       bfd_size_type locsymcount;
diff --git a/bfd/elf32-tilepro.c b/bfd/elf32-tilepro.c
index 3e3a068ac7b..12ff2a9121f 100644
--- a/bfd/elf32-tilepro.c
+++ b/bfd/elf32-tilepro.c
@@ -2187,31 +2187,31 @@ tilepro_elf_late_size_sections (bfd *output_bfd,
   bfd *dynobj;
   asection *s;
   bfd *ibfd;
 
   htab = tilepro_elf_hash_table (info);
   BFD_ASSERT (htab != NULL);
   dynobj = htab->dynobj;
   if (dynobj == NULL)
     return true;
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = elf_hash_table (info)->interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = sizeof ELF32_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF32_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
       char *local_tls_type;
       bfd_size_type locsymcount;
diff --git a/bfd/elf32-vax.c b/bfd/elf32-vax.c
index 4cb69ad3117..a5ced1f6958 100644
--- a/bfd/elf32-vax.c
+++ b/bfd/elf32-vax.c
@@ -1025,31 +1025,31 @@ static bool
 elf_vax_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
 {
   bfd *dynobj;
   asection *s;
   bool relocs;
 
   dynobj = elf_hash_table (info)->dynobj;
   if (dynobj == NULL)
     return true;
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = elf_hash_table (info)->interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   /* If this is a -Bsymbolic shared link, then we need to discard all PC
      relative relocs against symbols defined in a regular object.  We
      allocated space for them in the check_relocs routine, but we will not
      fill them in in the relocate_section routine.  */
   if (bfd_link_pic (info) && info->symbolic)
     elf_vax_link_hash_traverse (elf_hash_table (info),
 				elf_vax_discard_copies,
 				NULL);
diff --git a/bfd/elf32-xtensa.c b/bfd/elf32-xtensa.c
index 6f8a4fa7c21..b21676df36a 100644
--- a/bfd/elf32-xtensa.c
+++ b/bfd/elf32-xtensa.c
@@ -1576,31 +1576,31 @@ elf_xtensa_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
     return true;
   srelgot = htab->elf.srelgot;
   srelplt = htab->elf.srelplt;
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       BFD_ASSERT (htab->elf.srelgot != NULL
 		  && htab->elf.srelplt != NULL
 		  && htab->elf.sgot != NULL
 		  && htab->spltlittbl != NULL
 		  && htab->sgotloc != NULL);
 
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = elf_hash_table (info)->interp;
 	  if (s == NULL)
 	    abort ();
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
 
       /* Allocate room for one word in ".got".  */
       htab->elf.sgot->size = 4;
 
       /* Allocate space in ".rela.got" for literals that reference global
 	 symbols and space in ".rela.plt" for literals that have PLT
 	 entries.  */
       elf_link_hash_traverse (elf_hash_table (info),
 			      elf_xtensa_allocate_dynrelocs,
diff --git a/bfd/elf64-alpha.c b/bfd/elf64-alpha.c
index 55aebca0ee8..b13c99e4958 100644
--- a/bfd/elf64-alpha.c
+++ b/bfd/elf64-alpha.c
@@ -2797,31 +2797,31 @@ elf64_alpha_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   struct alpha_elf_link_hash_table * htab;
 
   htab = alpha_elf_hash_table (info);
   if (htab == NULL)
     return false;
 
   dynobj = elf_hash_table(info)->dynobj;
   if (dynobj == NULL)
     return true;
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = elf_hash_table (info)->interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
 
       /* Now that we've seen all of the input files, we can decide which
 	 symbols need dynamic relocation entries and which don't.  We've
 	 collected information in check_relocs that we can now apply to
 	 size the dynamic relocation sections.  */
       alpha_elf_link_hash_traverse (htab,
 				    elf64_alpha_calc_dynrel_sizes, info);
 
       elf64_alpha_size_rela_got_section (info);
       elf64_alpha_size_plt_section (info);
diff --git a/bfd/elf64-hppa.c b/bfd/elf64-hppa.c
index 7b80603fdaf..57de68c9b07 100644
--- a/bfd/elf64-hppa.c
+++ b/bfd/elf64-hppa.c
@@ -1543,31 +1543,31 @@ elf64_hppa_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
      symbols to -1 and remove them from the string table for .dynstr.
 
      We have to traverse the main linker hash table since we have to
      find functions which may not have been mentioned in any relocs.  */
   elf_link_hash_traverse (&hppa_info->root,
 			  (hppa_info->root.dynamic_sections_created
 			   ? elf64_hppa_mark_milli_and_exported_functions
 			   : elf64_hppa_mark_exported_functions),
 			  info);
 
   if (hppa_info->root.dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  sec = bfd_get_linker_section (dynobj, ".interp");
+	  sec = hppa_info->root.interp;
 	  BFD_ASSERT (sec != NULL);
 	  sec->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  sec->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  sec->alloced = 1;
 	}
     }
   else
     {
       /* We may have created entries in the .rela.got section.
 	 However, if we are not creating the dynamic sections, we will
 	 not actually use these entries.  Reset the size of .rela.dlt,
 	 which will cause it to get stripped from the output file
 	 below.  */
       sec = hppa_info->dlt_rel_sec;
       if (sec != NULL)
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 2cacc9e27a2..fdda9e0bbb3 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -10238,31 +10238,31 @@ ppc64_elf_late_size_sections (bfd *output_bfd,
   struct got_entry *first_tlsld;
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
     return false;
 
   dynobj = htab->elf.dynobj;
   if (dynobj == NULL)
     return true;
 
   if (htab->elf.dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = htab->elf.interp;
 	  if (s == NULL)
 	    abort ();
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       struct got_entry **lgot_ents;
       struct got_entry **end_lgot_ents;
       struct plt_entry **local_plt;
diff --git a/bfd/elf64-s390.c b/bfd/elf64-s390.c
index 6ae62a91112..555395ca5ad 100644
--- a/bfd/elf64-s390.c
+++ b/bfd/elf64-s390.c
@@ -1934,31 +1934,31 @@ elf_s390_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   bfd *ibfd;
 
   htab = elf_s390_hash_table (info);
   if (htab == NULL)
     return false;
 
   dynobj = htab->elf.dynobj;
   if (dynobj == NULL)
     return true;
 
   if (htab->elf.dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = htab->elf.interp;
 	  if (s == NULL)
 	    abort ();
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   if (htab->elf.sgot && s390_gotplt_after_got_p (info))
     {
       /* _bfd_elf_create_got_section adds the got header size always
 	 to .got.plt but we need it in .got if this section comes
 	 first.  */
       htab->elf.sgot->size += 3 * GOT_ENTRY_SIZE;
       htab->elf.sgotplt->size -= 3 * GOT_ENTRY_SIZE;
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 53ec792852c..b04b017747f 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -342,30 +342,31 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
     return false;
 
   abfd = elf_hash_table (info)->dynobj;
   bed = get_elf_backend_data (abfd);
 
   flags = bed->dynamic_sec_flags;
 
   /* A dynamically linked executable has a .interp section, but a
      shared library does not.  */
   if (bfd_link_executable (info) && !info->nointerp)
     {
       s = bfd_make_section_anyway_with_flags (abfd, ".interp",
 					      flags | SEC_READONLY);
       if (s == NULL)
 	return false;
+      elf_hash_table (info)->interp = s;
     }
 
   /* Create sections to hold version informations.  These are removed
      if they are not needed.  */
   s = bfd_make_section_anyway_with_flags (abfd, ".gnu.version_d",
 					  flags | SEC_READONLY);
   if (s == NULL
       || !bfd_set_section_alignment (s, bed->s->log_file_align))
     return false;
 
   s = bfd_make_section_anyway_with_flags (abfd, ".gnu.version",
 					  flags | SEC_READONLY);
   if (s == NULL
       || !bfd_set_section_alignment (s, 1))
     return false;
@@ -7535,31 +7536,31 @@ NOTE: This behaviour is deprecated and will be removed in a future version of th
 	  elf_stack_flags (output_bfd) = PF_R | PF_W | exec;
 	}
 
       if (notesec && exec && bfd_link_relocatable (info)
 	  && notesec->output_section != bfd_abs_section_ptr)
 	notesec->output_section->flags |= SEC_CODE;
     }
 
   if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created)
     {
       struct elf_info_failed eif;
       struct elf_link_hash_entry *h;
       asection *dynstr;
       asection *s;
 
-      *sinterpptr = bfd_get_linker_section (dynobj, ".interp");
+      *sinterpptr = elf_hash_table (info)->interp;
       BFD_ASSERT (*sinterpptr != NULL || !bfd_link_executable (info) || info->nointerp);
 
       if (info->symbolic)
 	{
 	  if (!_bfd_elf_add_dynamic_entry (info, DT_SYMBOLIC, 0))
 	    return false;
 	  info->flags |= DF_SYMBOLIC;
 	}
 
       if (rpath != NULL)
 	{
 	  size_t indx;
 	  bfd_vma tag;
 
 	  indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, rpath,
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 4517567a554..3c3c2899674 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -9474,31 +9474,31 @@ elfNN_aarch64_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   bfd *dynobj;
   asection *s;
   bool relocs;
   bfd *ibfd;
 
   htab = elf_aarch64_hash_table ((info));
   dynobj = htab->root.dynobj;
 
   if (dynobj == NULL)
     return true;
 
   if (htab->root.dynamic_sections_created)
     {
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = htab->root.interp;
 	  if (s == NULL)
 	    abort ();
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       struct elf_aarch64_local_symbol *locals = NULL;
       Elf_Internal_Shdr *symtab_hdr;
       asection *srel;
diff --git a/bfd/elfnn-ia64.c b/bfd/elfnn-ia64.c
index 685a37f4072..528b1dcdcc3 100644
--- a/bfd/elfnn-ia64.c
+++ b/bfd/elfnn-ia64.c
@@ -2995,31 +2995,31 @@ elfNN_ia64_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   bfd *dynobj;
 
   ia64_info = elfNN_ia64_hash_table (info);
   if (ia64_info == NULL)
     return false;
   dynobj = ia64_info->root.dynobj;
   if (dynobj == NULL)
     return true;
   ia64_info->self_dtpmod_offset = (bfd_vma) -1;
   data.info = info;
 
   /* Set the contents of the .interp section to the interpreter.  */
   if (ia64_info->root.dynamic_sections_created
       && bfd_link_executable (info) && !info->nointerp)
     {
-      sec = bfd_get_linker_section (dynobj, ".interp");
+      sec = ia64_info->root.interp;
       BFD_ASSERT (sec != NULL);
       sec->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER;
       sec->alloced = 1;
       sec->size = strlen (ELF_DYNAMIC_INTERPRETER) + 1;
     }
 
   /* Allocate the GOT entries.  */
 
   if (ia64_info->root.sgot)
     {
       data.ofs = 0;
       elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_data_got, &data);
       elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_fptr_got, &data);
       elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_local_got, &data);
       ia64_info->root.sgot->size = data.ofs;
diff --git a/bfd/elfnn-kvx.c b/bfd/elfnn-kvx.c
index 0634ad389d5..3b44db57421 100644
--- a/bfd/elfnn-kvx.c
+++ b/bfd/elfnn-kvx.c
@@ -4034,31 +4034,31 @@ elfNN_kvx_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   struct elf_kvx_link_hash_table *htab;
   bfd *dynobj;
   asection *s;
   bool relocs;
   bfd *ibfd;
 
   htab = elf_kvx_hash_table ((info));
   dynobj = htab->root.dynobj;
   if (dynobj == NULL)
     return true;
 
   if (htab->root.dynamic_sections_created)
     {
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = htab->root.interp;
 	  if (s == NULL)
 	    abort ();
 	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       struct elf_kvx_local_symbol *locals = NULL;
       Elf_Internal_Shdr *symtab_hdr;
       asection *srel;
diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index 8beb3d84079..c7b3711de86 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -2372,31 +2372,31 @@ loongarch_elf_late_size_sections (bfd *output_bfd,
   asection *s;
   bfd *ibfd;
 
   htab = loongarch_elf_hash_table (info);
   BFD_ASSERT (htab != NULL);
   dynobj = htab->elf.dynobj;
   if (dynobj == NULL)
     return true;
 
   if (htab->elf.dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
 	  const char *interpreter;
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = htab->elf.interp;
 	  BFD_ASSERT (s != NULL);
 
 	  if (elf_elfheader (output_bfd)->e_ident[EI_CLASS] == ELFCLASS32)
 	    interpreter = "/lib32/ld.so.1";
 	  else if (elf_elfheader (output_bfd)->e_ident[EI_CLASS] == ELFCLASS64)
 	    interpreter = "/lib64/ld.so.1";
 	  else
 	    interpreter = "/lib/ld.so.1";
 
 	  s->contents = (unsigned char *) interpreter;
 	  s->alloced = 1;
 	  s->size = strlen (interpreter) + 1;
 	}
     }
 
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index aac061fb43d..09cf7076733 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -1699,31 +1699,31 @@ riscv_elf_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
   bfd *dynobj;
   asection *s;
   bfd *ibfd;
 
   htab = riscv_elf_hash_table (info);
   BFD_ASSERT (htab != NULL);
   dynobj = htab->elf.dynobj;
   if (dynobj == NULL)
     return true;
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = elf_hash_table (info)->interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = strlen (ELFNN_DYNAMIC_INTERPRETER) + 1;
 	  s->contents = (unsigned char *) ELFNN_DYNAMIC_INTERPRETER;
 	  s->alloced = 1;
 	}
     }
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
       char *local_tls_type;
       bfd_size_type locsymcount;
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index a171af59bf8..bf3fd7df805 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -10063,31 +10063,31 @@ _bfd_mips_elf_late_size_sections (bfd *output_bfd,
   hti.output_bfd = output_bfd;
   hti.error = false;
   mips_elf_link_hash_traverse (htab, mips_elf_check_symbols, &hti);
   if (hti.error)
     return false;
 
   dynobj = htab->root.dynobj;
   if (dynobj == NULL)
     return true;
 
   if (htab->root.dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = htab->root.interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size
 	    = strlen (ELF_DYNAMIC_INTERPRETER (output_bfd)) + 1;
 	  s->contents
 	    = (bfd_byte *) ELF_DYNAMIC_INTERPRETER (output_bfd);
 	  s->alloced = 1;
 	}
 
       /* Figure out the size of the PLT header if we know that we
 	 are using it.  For the sake of cache alignment always use
 	 a standard header whenever any standard entries are present
 	 even if microMIPS entries are present as well.  This also
 	 lets the microMIPS header rely on the value of $v0 only set
 	 by microMIPS entries, for a small size reduction.
 
diff --git a/bfd/elfxx-sparc.c b/bfd/elfxx-sparc.c
index f0b379555af..bbaa7829132 100644
--- a/bfd/elfxx-sparc.c
+++ b/bfd/elfxx-sparc.c
@@ -667,31 +667,31 @@ _bfd_sparc_elf_info_to_howto (bfd *abfd, arelent *cache_ptr,
 
 /* The nop opcode we use.  */
 #define SPARC_NOP 0x01000000
 
 #define SPARC_INSN_BYTES	4
 
 /* Is an undefined weak symbol resolved to 0 ?
    Reference to an undefined weak symbol is resolved to 0 when
    building an executable if it isn't dynamic and
    1. Has non-GOT/non-PLT relocations in text section.
    Or
    2. Has no GOT/PLT relocation.  */
 #define UNDEFINED_WEAK_RESOLVED_TO_ZERO(INFO, EH)		\
   ((EH)->elf.root.type == bfd_link_hash_undefweak		\
    && bfd_link_executable (INFO)				\
-   && (_bfd_sparc_elf_hash_table (INFO)->interp == NULL		\
+   && (_bfd_sparc_elf_hash_table (INFO)->elf.interp == NULL	\
        || !(INFO)->dynamic_undefined_weak			\
        || (EH)->has_non_got_reloc				\
        || !(EH)->has_got_reloc))
 
 /* SPARC ELF linker hash entry.  */
 
 struct _bfd_sparc_elf_link_hash_entry
 {
   struct elf_link_hash_entry elf;
 
 #define GOT_UNKNOWN     0
 #define GOT_NORMAL      1
 #define GOT_TLS_GD      2
 #define GOT_TLS_IE      3
   unsigned char tls_type;
@@ -2396,36 +2396,35 @@ _bfd_sparc_elf_late_size_sections (bfd *output_bfd,
   bfd *dynobj;
   asection *s;
   bfd *ibfd;
 
   htab = _bfd_sparc_elf_hash_table (info);
   BFD_ASSERT (htab != NULL);
   dynobj = htab->elf.dynobj;
   if (dynobj == NULL)
     return true;
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = elf_hash_table (info)->interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = htab->dynamic_interpreter_size;
 	  s->contents = (unsigned char *) htab->dynamic_interpreter;
 	  s->alloced = 1;
-	  htab->interp = s;
 	}
     }
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
       char *local_tls_type;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
       asection *srel;
 
       if (! is_sparc_elf (ibfd))
diff --git a/bfd/elfxx-sparc.h b/bfd/elfxx-sparc.h
index 633b10e55e9..572c2331112 100644
--- a/bfd/elfxx-sparc.h
+++ b/bfd/elfxx-sparc.h
@@ -34,33 +34,30 @@ struct _bfd_sparc_elf_section_data
 
 struct _bfd_sparc_elf_app_reg
 {
   unsigned char bind;
   unsigned short shndx;
   bfd *abfd;
   char *name;
 };
 
 /* Sparc ELF linker hash table.  */
 
 struct _bfd_sparc_elf_link_hash_table
 {
   struct elf_link_hash_table elf;
 
-  /* Short-cut to get to dynamic linker sections.  */
-  asection *interp;
-
   union
   {
     bfd_signed_vma refcount;
     bfd_vma offset;
   } tls_ldm_got;
 
   /* Used by local STT_GNU_IFUNC symbols.  */
   htab_t loc_hash_table;
   void *loc_hash_memory;
 
   /* The (unloaded but important) .rela.plt.unloaded section, for VxWorks.  */
   asection *srelplt2;
 
   void (*put_word) (bfd *, bfd_vma, void *);
   bfd_vma (*r_info) (Elf_Internal_Rela *, bfd_vma, bfd_vma);
diff --git a/bfd/elfxx-tilegx.c b/bfd/elfxx-tilegx.c
index 1854e693931..79358e6b204 100644
--- a/bfd/elfxx-tilegx.c
+++ b/bfd/elfxx-tilegx.c
@@ -2436,31 +2436,31 @@ tilegx_elf_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   bfd *dynobj;
   asection *s;
   bfd *ibfd;
 
   htab = tilegx_elf_hash_table (info);
   BFD_ASSERT (htab != NULL);
   dynobj = htab->elf.dynobj;
   if (dynobj == NULL)
     return true;
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  s = bfd_get_linker_section (dynobj, ".interp");
+	  s = htab->elf.interp;
 	  BFD_ASSERT (s != NULL);
 	  s->size = strlen (htab->dynamic_interpreter) + 1;
 	  s->contents = (unsigned char *) htab->dynamic_interpreter;
 	  s->alloced = 1;
 	}
     }
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
       char *local_tls_type;
       bfd_size_type locsymcount;
diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
index 06265ee4e15..0d389968c91 100644
--- a/bfd/elfxx-x86.c
+++ b/bfd/elfxx-x86.c
@@ -3653,31 +3653,31 @@ _bfd_x86_elf_link_symbol_references_local (struct bfd_link_info *info,
 
   if (eh->local_ref == 1)
     return false;
 
   /* Unversioned symbols defined in regular objects can be forced local
      by linker version script.  A weak undefined symbol is forced local
      if
      1. It has non-default visibility.  Or
      2. When building executable, there is no dynamic linker.  Or
      3. or "-z nodynamic-undefined-weak" is used.
    */
   if (_bfd_elf_symbol_refs_local_p (h, info, 1)
       || (h->root.type == bfd_link_hash_undefweak
 	  && (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
 	      || (bfd_link_executable (info)
-		  && htab->interp == NULL)
+		  && htab->elf.interp == NULL)
 	      || info->dynamic_undefined_weak == 0))
       || ((h->def_regular || ELF_COMMON_DEF_P (h))
 	  && info->version_info != NULL
 	  && _bfd_elf_link_hide_sym_by_version (info, h)))
     {
       eh->local_ref = 2;
       return true;
     }
 
   eh->local_ref = 1;
   return false;
 }
 
 /* Return the section that should be marked against GC for a given
    relocation.	*/
@@ -4690,39 +4690,36 @@ _bfd_x86_elf_link_setup_gnu_properties
   sec = htab->elf.sgotplt;
   if (!bfd_set_section_alignment (sec, got_align))
     abort ();
 
   /* Create the ifunc sections here so that check_relocs can be
      simplified.  */
   if (!_bfd_elf_create_ifunc_sections (dynobj, info))
     info->callbacks->fatal (_("%P: failed to create ifunc sections\n"));
 
   plt_alignment = bfd_log2 (htab->plt.plt_entry_size);
 
   if (pltsec != NULL)
     {
       /* Whe creating executable, set the contents of the .interp
 	 section to the interpreter.  */
-      if (bfd_link_executable (info) && !info->nointerp)
+      asection *s = htab->elf.interp;
+      if (s != NULL)
 	{
-	  asection *s = bfd_get_linker_section (dynobj, ".interp");
-	  if (s == NULL)
-	    abort ();
 	  s->size = htab->dynamic_interpreter_size;
 	  s->contents = (unsigned char *) htab->dynamic_interpreter;
 	  s->alloced = 1;
-	  htab->interp = s;
 	}
 
       if (normal_target)
 	{
 	  flagword pltflags = (bed->dynamic_sec_flags
 			       | SEC_ALLOC
 			       | SEC_CODE
 			       | SEC_LOAD
 			       | SEC_READONLY);
 	  unsigned int non_lazy_plt_alignment
 	    = bfd_log2 (htab->non_lazy_plt->plt_entry_size);
 
 	  sec = pltsec;
 	  if (!bfd_set_section_alignment (sec, plt_alignment))
 	    abort ();
diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
index 5593203f9ec..1ebc9d2f2e5 100644
--- a/bfd/elfxx-x86.h
+++ b/bfd/elfxx-x86.h
@@ -590,31 +590,30 @@ struct elf_dt_relr_bitmap
     {
       /* 32-bit bitmap.  */
       uint32_t *elf32;
       /* 64-bit bitmap.  */
       uint64_t *elf64;
     } u;
 };
 
 /* x86 ELF linker hash table.  */
 
 struct elf_x86_link_hash_table
 {
   struct elf_link_hash_table elf;
 
   /* Short-cuts to get to dynamic linker sections.  */
-  asection *interp;
   asection *plt_eh_frame;
   asection *plt_second;
   asection *plt_second_eh_frame;
   asection *plt_got;
   asection *plt_got_eh_frame;
 
   sframe_encoder_ctx *plt_cfe_ctx;
   asection *plt_sframe;
   sframe_encoder_ctx *plt_second_cfe_ctx;
   asection *plt_second_sframe;
   sframe_encoder_ctx *plt_got_cfe_ctx;
   asection *plt_got_sframe;
 
   /* Parameters describing PLT generation, lazy or non-lazy.  */
   struct elf_x86_plt_layout plt;
  

Patch

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index de7cc410a99..51e6ae7bb78 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -774,6 +774,7 @@  struct elf_link_hash_table
   asection *dynsym;
   asection *srelrdyn;
   asection *dynamic;
+  asection *interp;
 };
 
 /* Returns TRUE if the hash table is a struct elf_link_hash_table.  */
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 53ec792852c..b8ffcab419c 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -354,6 +354,7 @@  _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
 					      flags | SEC_READONLY);
       if (s == NULL)
 	return false;
+      elf_hash_table (info)->interp = s;
     }
 
   /* Create sections to hold version informations.  These are removed
diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
index 06265ee4e15..4ca4c3a3948 100644
--- a/bfd/elfxx-x86.c
+++ b/bfd/elfxx-x86.c
@@ -3665,7 +3665,7 @@  _bfd_x86_elf_link_symbol_references_local (struct bfd_link_info *info,
       || (h->root.type == bfd_link_hash_undefweak
 	  && (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
 	      || (bfd_link_executable (info)
-		  && htab->interp == NULL)
+		  && htab->elf.interp == NULL)
 	      || info->dynamic_undefined_weak == 0))
       || ((h->def_regular || ELF_COMMON_DEF_P (h))
 	  && info->version_info != NULL
@@ -4704,13 +4704,10 @@  _bfd_x86_elf_link_setup_gnu_properties
 	 section to the interpreter.  */
       if (bfd_link_executable (info) && !info->nointerp)
 	{
-	  asection *s = bfd_get_linker_section (dynobj, ".interp");
-	  if (s == NULL)
-	    abort ();
+	  asection *s = htab->elf.interp;
 	  s->size = htab->dynamic_interpreter_size;
 	  s->contents = (unsigned char *) htab->dynamic_interpreter;
 	  s->alloced = 1;
-	  htab->interp = s;
 	}
 
       if (normal_target)
diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
index 5593203f9ec..1ebc9d2f2e5 100644
--- a/bfd/elfxx-x86.h
+++ b/bfd/elfxx-x86.h
@@ -602,7 +602,6 @@  struct elf_x86_link_hash_table
   struct elf_link_hash_table elf;
 
   /* Short-cuts to get to dynamic linker sections.  */
-  asection *interp;
   asection *plt_eh_frame;
   asection *plt_second;
   asection *plt_second_eh_frame;