This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: dynrelro section for read-only dynamic symbols copied into executable
- From: Christophe Lyon <christophe dot lyon at linaro dot org>
- To: Alan Modra <amodra at gmail dot com>
- Cc: binutils <binutils at sourceware dot org>
- Date: Tue, 3 Jan 2017 11:12:38 +0100
- Subject: Re: dynrelro section for read-only dynamic symbols copied into executable
- Authentication-results: sourceware.org; auth=none
- References: <20161226054448.GC340@bubble.grove.modra.org>
On 26 December 2016 at 06:44, Alan Modra <amodra@gmail.com> wrote:
> Variables defined in shared libraries are copied into an executable's
> .bss section when code in the executable is non-PIC and thus would
> require dynamic text relocations to access the variable directly in
> the shared library. Recent x86 toolchains also copy variables into
> the executable to gain a small speed improvement.
>
> The problem is that if the variable was originally read-only, the copy
> in .bss is writable, potentially opening a security hole. This patch
> cures that problem by putting the copy in a section that becomes
> read-only after ld.so relocation, provided -z relro is in force.
>
> These targets should now be OK: aarch64, arm, hppa, i386, metag,
> microblaze, mips, mips64, nios2, or1k, ppc, ppc64, s390, s390x, sparc,
> sparc64, tic6x, tilegx, tilepro and x86-64. However, not much testing
> has been done yet.. I applied fixes for riscv too, before realizing
> that riscv scripts are broken for relro.
>
> The patch also fixes a microblaze linker segfault on attempting to
> use dynamic bss variables.
>
> Of the targets I regularly test, the following fail the new test:
> am33_2.0-linux +FAIL: pr20995
For the record, I see failures on some arm targets:
FAIL: Build pr20995-2.so
FAIL: pr20995-2
for arm-netbsdelf and arm-none-eabi
The other arm targets I test are OK:
arm-linux-gnueabi
arm-linux-gnueabihf
arm-none-nacl
arm-none-symbianelf
arm-vxworks
arm-wince-pe
armeb-linux-gnueabihf
Christophe
> arc-linux-uclibc +FAIL: pr20995
> crisv32-linux +FAIL: pr20995
> hppa64-hp-hpux11.23 +FAIL: pr20995
> hppa64-linux +FAIL: pr20995
> i370-linux +FAIL: Build pr20995.so
> i370-linux +FAIL: pr20995
> m68k-elf +FAIL: pr20995
> m68k-linux +FAIL: pr20995
> mips64-linux +FAIL: pr20995
> mipsel-linux-gnu +FAIL: pr20995
> mipsisa32el-linux +FAIL: pr20995
> mips-linux +FAIL: pr20995
> mn10300-elf +FAIL: pr20995
> riscv32-elf +FAIL: pr20995
> riscv64-elf +FAIL: pr20995
> score-elf +FAIL: pr20995
> sh-linux +FAIL: pr20995
> shl-unknown-netbsdelf +FAIL: pr20995
> tic6x-elf +FAIL: pr20995
> vax-netbsdelf +FAIL: pr20995
>
> mips apparently needs a tweak to run the testcase with the right
> flags. riscv scripts are hosed for -z relro. tic6x doesn't want to
> create any dynamic relocs for the testcase. The rest are targets that
> I haven't converted over to use the new dynamic sections for read-only
> variables. I don't intend to do much more on this over Christmas
> and New Year, so if your favourite target is one of those that fails
> the test it's likely that 2.28 will go out without the fix unless
> target maintainers step up.
>
> bfd/
> PR ld/20995
> * elf-bfd.h (struct elf_link_hash_table): Add sdynrelro and
> sreldynrelro.
> (struct elf_backend_data): Add want_dynrelro.
> * elfxx-target.h (elf_backend_want_dynrelro): Define.
> (elfNN_bed): Update initializer.
> * elflink.c (_bfd_elf_create_dynamic_sections): Create
> sdynrelro and sreldynrelro sections.
> * elf32-arm.c (elf32_arm_adjust_dynamic_symbol): Place variables
> copied into the executable from read-only sections into sdynrelro.
> (elf32_arm_size_dynamic_sections): Handle sdynrelro.
> (elf32_arm_finish_dynamic_symbol): Select sreldynrelro for
> dynamic relocs in sdynrelro.
> (elf_backend_want_dynrelro): Define.
> * elf32-hppa.c (elf32_hppa_adjust_dynamic_symbol)
> (elf32_hppa_size_dynamic_sections, elf32_hppa_finish_dynamic_symbol)
> (elf_backend_want_dynrelro): As above.
> * elf32-i386.c (elf_i386_adjust_dynamic_symbol)
> (elf_i386_size_dynamic_sections, elf_i386_finish_dynamic_symbol)
> (elf_backend_want_dynrelro): As above.
> * elf32-metag.c (elf_metag_adjust_dynamic_symbol)
> (elf_metag_size_dynamic_sections, elf_metag_finish_dynamic_symbol)
> (elf_backend_want_dynrelro): As above.
> * elf32-microblaze.c (microblaze_elf_adjust_dynamic_symbol)
> (microblaze_elf_size_dynamic_sections)
> (microblaze_elf_finish_dynamic_symbol)
> (elf_backend_want_dynrelro): As above.
> * elf32-nios2.c (nios2_elf32_finish_dynamic_symbol)
> (nios2_elf32_adjust_dynamic_symbol)
> (nios2_elf32_size_dynamic_sections)
> (elf_backend_want_dynrelro): As above.
> * elf32-or1k.c (or1k_elf_finish_dynamic_symbol)
> (or1k_elf_adjust_dynamic_symbol, or1k_elf_size_dynamic_sections)
> (elf_backend_want_dynrelro): As above.
> * elf32-ppc.c (ppc_elf_adjust_dynamic_symbol)
> (ppc_elf_size_dynamic_sections, ppc_elf_finish_dynamic_symbol)
> (elf_backend_want_dynrelro): As above.
> * elf32-s390.c (elf_s390_adjust_dynamic_symbol)
> (elf_s390_size_dynamic_sections, elf_s390_finish_dynamic_symbol)
> (elf_backend_want_dynrelro): As above.
> * elf32-tic6x.c (elf32_tic6x_adjust_dynamic_symbol)
> (elf32_tic6x_size_dynamic_sections)
> (elf32_tic6x_finish_dynamic_symbol)
> (elf_backend_want_dynrelro): As above.
> * elf32-tilepro.c (tilepro_elf_adjust_dynamic_symbol)
> (tilepro_elf_size_dynamic_sections)
> (tilepro_elf_finish_dynamic_symbol)
> (elf_backend_want_dynrelro): As above.
> * elf64-ppc.c (ppc64_elf_adjust_dynamic_symbol)
> (ppc64_elf_size_dynamic_sections, ppc64_elf_finish_dynamic_symbol)
> (elf_backend_want_dynrelro): As above.
> * elf64-s390.c (elf_s390_adjust_dynamic_symbol)
> (elf_s390_size_dynamic_sections, elf_s390_finish_dynamic_symbol)
> (elf_backend_want_dynrelro): As above.
> * elf64-x86-64.c (elf_x86_64_adjust_dynamic_symbol)
> (elf_x86_64_size_dynamic_sections)
> (elf_x86_64_finish_dynamic_symbol)
> (elf_backend_want_dynrelro): As above.
> * elfnn-aarch64.c (elfNN_aarch64_adjust_dynamic_symbol)
> (elfNN_aarch64_size_dynamic_sections)
> (elfNN_aarch64_finish_dynamic_symbol)
> (elf_backend_want_dynrelro): As above.
> * elfnn-riscv.c (riscv_elf_adjust_dynamic_symbol)
> (riscv_elf_size_dynamic_sections, riscv_elf_finish_dynamic_symbol)
> (elf_backend_want_dynrelro): As above.
> * elfxx-mips.c (_bfd_mips_elf_adjust_dynamic_symbol)
> (_bfd_mips_elf_size_dynamic_sections)
> (_bfd_mips_vxworks_finish_dynamic_symbol): As above.
> * elfxx-sparc.c (_bfd_sparc_elf_adjust_dynamic_symbol)
> (_bfd_sparc_elf_size_dynamic_sections)
> (_bfd_sparc_elf_finish_dynamic_symbol): As above.
> * elfxx-tilegx.c (tilegx_elf_adjust_dynamic_symbol)
> (tilegx_elf_size_dynamic_sections)
> (tilegx_elf_finish_dynamic_symbol): As above.
> * elf32-mips.c (elf_backend_want_dynrelro): Define.
> * elf64-mips.c (elf_backend_want_dynrelro): Define.
> * elf32-sparc.c (elf_backend_want_dynrelro): Define.
> * elf64-sparc.c (elf_backend_want_dynrelro): Define.
> * elf32-tilegx.c (elf_backend_want_dynrelro): Define.
> * elf64-tilegx.c (elf_backend_want_dynrelro): Define.
> * elf32-microblaze.c (microblaze_elf_adjust_dynamic_symbol): Tidy.
> (microblaze_elf_size_dynamic_sections): Handle sdynbss.
> * elf32-nios2.c (nios2_elf32_size_dynamic_sections): Make use
> of linker shortcuts to dynamic sections rather than comparing
> names. Correctly set "got" flag.
> ld/
> PR ld/20995
> * testsuite/ld-arm/farcall-mixed-app-v5.d: Update to suit changed
> stub hash table traversal caused by section id increment. Accept
> the previous output too.
> * testsuite/ld-arm/farcall-mixed-app.d: Likewise.
> * testsuite/ld-arm/farcall-mixed-lib-v4t.d: Likewise.
> * testsuite/ld-arm/farcall-mixed-lib.d: Likewise.
> * testsuite/ld-elf/pr20995a.s, * testsuite/ld-elf/pr20995b.s,
> * testsuite/ld-elf/pr20995.r: New test.
> * testsuite/ld-elf/elf.exp: Run it.
>
> diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
> index 4093434..1c634d8 100644
> --- a/bfd/elf-bfd.h
> +++ b/bfd/elf-bfd.h
> @@ -597,6 +597,8 @@ struct elf_link_hash_table
> asection *srelplt;
> asection *sdynbss;
> asection *srelbss;
> + asection *sdynrelro;
> + asection *sreldynrelro;
> asection *igotplt;
> asection *iplt;
> asection *irelplt;
> @@ -1451,6 +1453,7 @@ struct elf_backend_data
> unsigned can_refcount : 1;
> unsigned want_got_sym : 1;
> unsigned want_dynbss : 1;
> + unsigned want_dynrelro : 1;
>
> /* Targets which do not support physical addressing often require
> that the p_paddr field in the section header to be set to zero.
> diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
> index 4761136..384063e 100644
> --- a/bfd/elf32-arm.c
> +++ b/bfd/elf32-arm.c
> @@ -15264,7 +15264,7 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info,
> struct elf_link_hash_entry * h)
> {
> bfd * dynobj;
> - asection * s;
> + asection *s, *srel;
> struct elf32_arm_link_hash_entry * eh;
> struct elf32_arm_link_hash_table *globals;
>
> @@ -15363,20 +15363,24 @@ elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info,
> determine the address it must put in the global offset table, so
> both the dynamic object and the regular object will refer to the
> same memory location for the variable. */
> - s = globals->root.sdynbss;
> - BFD_ASSERT (s != NULL);
> -
> /* If allowed, we must generate a R_ARM_COPY reloc to tell the dynamic
> linker to copy the initial value out of the dynamic object and into
> the runtime process image. We need to remember the offset into the
> .rel(a).bss section we are going to use. */
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + {
> + s = globals->root.sdynrelro;
> + srel = globals->root.sreldynrelro;
> + }
> + else
> + {
> + s = globals->root.sdynbss;
> + srel = globals->root.srelbss;
> + }
> if (info->nocopyreloc == 0
> && (h->root.u.def.section->flags & SEC_ALLOC) != 0
> && h->size != 0)
> {
> - asection *srel;
> -
> - srel = bfd_get_linker_section (dynobj, RELOC_SECTION (globals, ".bss"));
> elf32_arm_allocate_dynrelocs (info, srel, 1);
> h->needs_copy = 1;
> }
> @@ -16091,7 +16095,8 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
> && s != htab->root.sgotplt
> && s != htab->root.iplt
> && s != htab->root.igotplt
> - && s != htab->root.sdynbss)
> + && s != htab->root.sdynbss
> + && s != htab->root.sdynrelro)
> {
> /* It's not one of our sections, so don't allocate space. */
> continue;
> @@ -16301,14 +16306,15 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd,
> && (h->root.type == bfd_link_hash_defined
> || h->root.type == bfd_link_hash_defweak));
>
> - s = htab->root.srelbss;
> - BFD_ASSERT (s != NULL);
> -
> rel.r_addend = 0;
> rel.r_offset = (h->root.u.def.value
> + h->root.u.def.section->output_section->vma
> + h->root.u.def.section->output_offset);
> rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_COPY);
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + s = htab->root.sreldynrelro;
> + else
> + s = htab->root.srelbss;
> elf32_arm_add_dynreloc (output_bfd, info, s, &rel);
> }
>
> @@ -19389,6 +19395,7 @@ elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym)
> #define elf_backend_plt_readonly 1
> #define elf_backend_want_got_plt 1
> #define elf_backend_want_plt_sym 0
> +#define elf_backend_want_dynrelro 1
> #define elf_backend_may_use_rel_p 1
> #define elf_backend_may_use_rela_p 0
> #define elf_backend_default_use_rela_p 0
> diff --git a/bfd/elf32-hppa.c b/bfd/elf32-hppa.c
> index 3ce4b92..cbe42cf 100644
> --- a/bfd/elf32-hppa.c
> +++ b/bfd/elf32-hppa.c
> @@ -1793,7 +1793,7 @@ elf32_hppa_adjust_dynamic_symbol (struct bfd_link_info *info,
> struct elf_link_hash_entry *eh)
> {
> struct elf32_hppa_link_hash_table *htab;
> - asection *sec;
> + asection *sec, *srel;
>
> /* If this is a function, put it in the procedure linkage table. We
> will fill in the contents of the procedure linkage table later. */
> @@ -1899,14 +1899,22 @@ elf32_hppa_adjust_dynamic_symbol (struct bfd_link_info *info,
> /* We must generate a COPY reloc to tell the dynamic linker to
> copy the initial value out of the dynamic object and into the
> runtime process image. */
> + if ((eh->root.u.def.section->flags & SEC_READONLY) != 0)
> + {
> + sec = htab->etab.sdynrelro;
> + srel = htab->etab.sreldynrelro;
> + }
> + else
> + {
> + sec = htab->etab.sdynbss;
> + srel = htab->etab.srelbss;
> + }
> if ((eh->root.u.def.section->flags & SEC_ALLOC) != 0 && eh->size != 0)
> {
> - htab->etab.srelbss->size += sizeof (Elf32_External_Rela);
> + srel->size += sizeof (Elf32_External_Rela);
> eh->needs_copy = 1;
> }
>
> - sec = htab->etab.sdynbss;
> -
> return _bfd_elf_adjust_dynamic_copy (info, eh, sec);
> }
>
> @@ -2374,7 +2382,8 @@ elf32_hppa_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
> }
> }
> else if (sec == htab->etab.sgot
> - || sec == htab->etab.sdynbss)
> + || sec == htab->etab.sdynbss
> + || sec == htab->etab.sdynrelro)
> ;
> else if (CONST_STRNEQ (bfd_get_section_name (dynobj, sec), ".rela"))
> {
> @@ -4427,13 +4436,15 @@ elf32_hppa_finish_dynamic_symbol (bfd *output_bfd,
> || eh->root.type == bfd_link_hash_defweak)))
> abort ();
>
> - sec = htab->etab.srelbss;
> -
> rela.r_offset = (eh->root.u.def.value
> + eh->root.u.def.section->output_offset
> + eh->root.u.def.section->output_section->vma);
> rela.r_addend = 0;
> rela.r_info = ELF32_R_INFO (eh->dynindx, R_PARISC_COPY);
> + if ((eh->root.u.def.section->flags & SEC_READONLY) != 0)
> + sec = htab->etab.sreldynrelro;
> + else
> + sec = htab->etab.srelbss;
> loc = sec->contents + sec->reloc_count++ * sizeof (Elf32_External_Rela);
> bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
> }
> @@ -4641,6 +4652,7 @@ elf32_hppa_elf_get_symbol_type (Elf_Internal_Sym *elf_sym, int type)
> #define elf_backend_plt_readonly 0
> #define elf_backend_want_plt_sym 0
> #define elf_backend_got_header_size 8
> +#define elf_backend_want_dynrelro 1
> #define elf_backend_rela_normal 1
> #define elf_backend_dtrel_excludes_plt 1
>
> diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
> index eb287a8..8f4477d 100644
> --- a/bfd/elf32-i386.c
> +++ b/bfd/elf32-i386.c
> @@ -2424,7 +2424,7 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info,
> struct elf_link_hash_entry *h)
> {
> struct elf_i386_link_hash_table *htab;
> - asection *s;
> + asection *s, *srel;
> struct elf_i386_link_hash_entry *eh;
> struct elf_dyn_relocs *p;
>
> @@ -2584,14 +2584,22 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info,
> /* We must generate a R_386_COPY reloc to tell the dynamic linker to
> copy the initial value out of the dynamic object and into the
> runtime process image. */
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + {
> + s = htab->elf.sdynrelro;
> + srel = htab->elf.sreldynrelro;
> + }
> + else
> + {
> + s = htab->elf.sdynbss;
> + srel = htab->elf.srelbss;
> + }
> if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
> {
> - htab->elf.srelbss->size += sizeof (Elf32_External_Rel);
> + srel->size += sizeof (Elf32_External_Rel);
> h->needs_copy = 1;
> }
>
> - s = htab->elf.sdynbss;
> -
> return _bfd_elf_adjust_dynamic_copy (info, h, s);
> }
>
> @@ -3405,7 +3413,8 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
> || s == htab->elf.igotplt
> || s == htab->plt_got
> || s == htab->plt_eh_frame
> - || s == htab->elf.sdynbss)
> + || s == htab->elf.sdynbss
> + || s == htab->elf.sdynrelro)
> {
> /* Strip these too. */
> }
> @@ -5564,20 +5573,26 @@ do_glob_dat:
> if (h->needs_copy)
> {
> Elf_Internal_Rela rel;
> + asection *s;
>
> /* This symbol needs a copy reloc. Set it up. */
>
> if (h->dynindx == -1
> || (h->root.type != bfd_link_hash_defined
> && h->root.type != bfd_link_hash_defweak)
> - || htab->elf.srelbss == NULL)
> + || htab->elf.srelbss == NULL
> + || htab->elf.sreldynrelro == NULL)
> abort ();
>
> rel.r_offset = (h->root.u.def.value
> + h->root.u.def.section->output_section->vma
> + h->root.u.def.section->output_offset);
> rel.r_info = ELF32_R_INFO (h->dynindx, R_386_COPY);
> - elf_append_rel (output_bfd, htab->elf.srelbss, &rel);
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + s = htab->elf.sreldynrelro;
> + else
> + s = htab->elf.srelbss;
> + elf_append_rel (output_bfd, s, &rel);
> }
>
> return TRUE;
> @@ -6028,6 +6043,7 @@ elf_i386_hash_symbol (struct elf_link_hash_entry *h)
> #define elf_backend_dtrel_excludes_plt 1
> #define elf_backend_extern_protected_data 1
> #define elf_backend_caches_rawsize 1
> +#define elf_backend_want_dynrelro 1
>
> /* Support RELA for objdump of prelink objects. */
> #define elf_info_to_howto elf_i386_info_to_howto_rel
> diff --git a/bfd/elf32-metag.c b/bfd/elf32-metag.c
> index 4ec2266..f4b1e12 100644
> --- a/bfd/elf32-metag.c
> +++ b/bfd/elf32-metag.c
> @@ -2470,7 +2470,7 @@ elf_metag_adjust_dynamic_symbol (struct bfd_link_info *info,
> struct elf_metag_link_hash_table *htab;
> struct elf_metag_link_hash_entry *hh;
> struct elf_metag_dyn_reloc_entry *hdh_p;
> - asection *s;
> + asection *s, *srel;
>
> /* If this is a function, put it in the procedure linkage table. We
> will fill in the contents of the procedure linkage table later,
> @@ -2564,14 +2564,22 @@ elf_metag_adjust_dynamic_symbol (struct bfd_link_info *info,
> /* We must generate a COPY reloc to tell the dynamic linker to
> copy the initial value out of the dynamic object and into the
> runtime process image. */
> + if ((eh->root.u.def.section->flags & SEC_READONLY) != 0)
> + {
> + s = htab->etab.sdynrelro;
> + srel = htab->etab.sreldynrelro;
> + }
> + else
> + {
> + s = htab->etab.sdynbss;
> + srel = htab->etab.srelbss;
> + }
> if ((eh->root.u.def.section->flags & SEC_ALLOC) != 0 && eh->size != 0)
> {
> - htab->etab.srelbss->size += sizeof (Elf32_External_Rela);
> + srel->size += sizeof (Elf32_External_Rela);
> eh->needs_copy = 1;
> }
>
> - s = htab->etab.sdynbss;
> -
> return _bfd_elf_adjust_dynamic_copy (info, eh, s);
> }
>
> @@ -2933,7 +2941,8 @@ elf_metag_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
> if (s == htab->etab.splt
> || s == htab->etab.sgot
> || s == htab->etab.sgotplt
> - || s == htab->etab.sdynbss)
> + || s == htab->etab.sdynbss
> + || s == htab->etab.sdynrelro)
> {
> /* Strip this section if we don't need it; see the
> comment below. */
> @@ -3215,13 +3224,15 @@ elf_metag_finish_dynamic_symbol (bfd *output_bfd,
> || eh->root.type == bfd_link_hash_defweak)))
> abort ();
>
> - s = htab->etab.srelbss;
> -
> rel.r_offset = (eh->root.u.def.value
> + eh->root.u.def.section->output_offset
> + eh->root.u.def.section->output_section->vma);
> rel.r_addend = 0;
> rel.r_info = ELF32_R_INFO (eh->dynindx, R_METAG_COPY);
> + if ((eh->root.u.def.section->flags & SEC_READONLY) != 0)
> + s = htab->etab.sreldynrelro;
> + else
> + s = htab->etab.srelbss;
> loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela);
> bfd_elf32_swap_reloca_out (output_bfd, &rel, loc);
> }
> @@ -4286,6 +4297,7 @@ elf_metag_plt_sym_val (bfd_vma i, const asection *plt,
> #define elf_backend_want_plt_sym 0
> #define elf_backend_plt_readonly 1
> #define elf_backend_dtrel_excludes_plt 1
> +#define elf_backend_want_dynrelro 1
>
> #define bfd_elf32_bfd_reloc_type_lookup metag_reloc_type_lookup
> #define bfd_elf32_bfd_reloc_name_lookup metag_reloc_name_lookup
> diff --git a/bfd/elf32-microblaze.c b/bfd/elf32-microblaze.c
> index 33c6026..31527d5 100644
> --- a/bfd/elf32-microblaze.c
> +++ b/bfd/elf32-microblaze.c
> @@ -2557,9 +2557,8 @@ microblaze_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
> struct elf32_mb_link_hash_table *htab;
> struct elf32_mb_link_hash_entry * eh;
> struct elf32_mb_dyn_relocs *p;
> - asection *sdynbss, *s;
> + asection *s, *srel;
> unsigned int power_of_two;
> - bfd *dynobj;
>
> htab = elf32_mb_hash_table (info);
> if (htab == NULL)
> @@ -2658,11 +2657,19 @@ microblaze_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
> /* We must generate a R_MICROBLAZE_COPY reloc to tell the dynamic linker
> to copy the initial value out of the dynamic object and into the
> runtime process image. */
> - dynobj = elf_hash_table (info)->dynobj;
> - BFD_ASSERT (dynobj != NULL);
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + {
> + s = htab->elf.sdynrelro;
> + srel = htab->elf.sreldynrelro;
> + }
> + else
> + {
> + s = htab->elf.sdynbss;
> + srel = htab->elf.srelbss;
> + }
> if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
> {
> - htab->elf.srelbss->size += sizeof (Elf32_External_Rela);
> + srel->size += sizeof (Elf32_External_Rela);
> h->needs_copy = 1;
> }
>
> @@ -2672,21 +2679,20 @@ microblaze_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
> if (power_of_two > 3)
> power_of_two = 3;
>
> - sdynbss = htab->elf.sdynbss;
> /* Apply the required alignment. */
> - sdynbss->size = BFD_ALIGN (sdynbss->size, (bfd_size_type) (1 << power_of_two));
> - if (power_of_two > bfd_get_section_alignment (dynobj, sdynbss))
> + s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two));
> + if (power_of_two > s->alignment_power)
> {
> - if (! bfd_set_section_alignment (dynobj, sdynbss, power_of_two))
> + if (!bfd_set_section_alignment (s->owner, s, power_of_two))
> return FALSE;
> }
>
> /* Define the symbol as being at this point in the section. */
> - h->root.u.def.section = sdynbss;
> - h->root.u.def.value = sdynbss->size;
> + h->root.u.def.section = s;
> + h->root.u.def.value = s->size;
>
> /* Increment the section size to make room for the symbol. */
> - sdynbss->size += h->size;
> + s->size += h->size;
> return TRUE;
> }
>
> @@ -3050,7 +3056,9 @@ microblaze_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
> }
> else if (s != htab->elf.splt
> && s != htab->elf.sgot
> - && s != htab->elf.sgotplt)
> + && s != htab->elf.sgotplt
> + && s != htab->elf.sdynbss
> + && s != htab->elf.sdynrelro)
> {
> /* It's not one of our sections, so don't allocate space. */
> continue;
> @@ -3256,14 +3264,15 @@ microblaze_elf_finish_dynamic_symbol (bfd *output_bfd,
>
> BFD_ASSERT (h->dynindx != -1);
>
> - s = bfd_get_linker_section (htab->elf.dynobj, ".rela.bss");
> - BFD_ASSERT (s != NULL);
> -
> rela.r_offset = (h->root.u.def.value
> + h->root.u.def.section->output_section->vma
> + h->root.u.def.section->output_offset);
> rela.r_info = ELF32_R_INFO (h->dynindx, R_MICROBLAZE_COPY);
> rela.r_addend = 0;
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + s = htab->elf.sreldynrelro;
> + else
> + s = htab->elf.srelbss;
> loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela);
> bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
> }
> @@ -3439,6 +3448,7 @@ microblaze_elf_add_symbol_hook (bfd *abfd,
> #define elf_backend_want_got_plt 1
> #define elf_backend_plt_readonly 1
> #define elf_backend_got_header_size 12
> +#define elf_backend_want_dynrelro 1
> #define elf_backend_rela_normal 1
> #define elf_backend_dtrel_excludes_plt 1
>
> diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c
> index d398810..f7649eb 100644
> --- a/bfd/elf32-mips.c
> +++ b/bfd/elf32-mips.c
> @@ -2482,6 +2482,7 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = {
> #define elf_backend_ecoff_debug_swap &mips_elf32_ecoff_debug_swap
>
> #define elf_backend_got_header_size (4 * MIPS_RESERVED_GOTNO)
> +#define elf_backend_want_dynrelro 1
> #define elf_backend_may_use_rel_p 1
> #define elf_backend_may_use_rela_p 0
> #define elf_backend_default_use_rela_p 0
> diff --git a/bfd/elf32-nios2.c b/bfd/elf32-nios2.c
> index a4ce99c..541eb6f 100644
> --- a/bfd/elf32-nios2.c
> +++ b/bfd/elf32-nios2.c
> @@ -5275,14 +5275,16 @@ nios2_elf32_finish_dynamic_symbol (bfd *output_bfd,
> && (h->root.type == bfd_link_hash_defined
> || h->root.type == bfd_link_hash_defweak));
>
> - s = htab->root.srelbss;
> - BFD_ASSERT (s != NULL);
> -
> rela.r_offset = (h->root.u.def.value
> + h->root.u.def.section->output_section->vma
> + h->root.u.def.section->output_offset);
> rela.r_info = ELF32_R_INFO (h->dynindx, R_NIOS2_COPY);
> rela.r_addend = 0;
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + s = htab->root.sreldynrelro;
> + else
> + s = htab->root.srelbss;
> + BFD_ASSERT (s != NULL);
> loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela);
> bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
> }
> @@ -5441,7 +5443,7 @@ nios2_elf32_adjust_dynamic_symbol (struct bfd_link_info *info,
> {
> struct elf32_nios2_link_hash_table *htab;
> bfd *dynobj;
> - asection *s;
> + asection *s, *srel;
> unsigned align2;
>
> htab = elf32_nios2_hash_table (info);
> @@ -5523,19 +5525,22 @@ nios2_elf32_adjust_dynamic_symbol (struct bfd_link_info *info,
> determine the address it must put in the global offset table, so
> both the dynamic object and the regular object will refer to the
> same memory location for the variable. */
> - s = htab->root.sdynbss;
> - BFD_ASSERT (s != NULL);
> -
> /* We must generate a R_NIOS2_COPY reloc to tell the dynamic linker to
> copy the initial value out of the dynamic object and into the
> runtime process image. We need to remember the offset into the
> .rela.bss section we are going to use. */
> - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> {
> - asection *srel;
> -
> + s = htab->root.sdynrelro;
> + srel = htab->root.sreldynrelro;
> + }
> + else
> + {
> + s = htab->root.sdynbss;
> srel = htab->root.srelbss;
> - BFD_ASSERT (srel != NULL);
> + }
> + if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
> + {
> srel->size += sizeof (Elf32_External_Rela);
> h->needs_copy = 1;
> }
> @@ -5975,7 +5980,7 @@ nios2_elf32_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
> of the dynobj section names depend upon the input files. */
> name = bfd_get_section_name (dynobj, s);
>
> - if (strcmp (name, ".plt") == 0)
> + if (s == htab->root.splt)
> {
> /* Remember whether there is a PLT. */
> plt = s->size != 0;
> @@ -5998,9 +6003,14 @@ nios2_elf32_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
> s->reloc_count = 0;
> }
> }
> - else if (CONST_STRNEQ (name, ".got"))
> - got = s->size != 0;
> - else if (strcmp (name, ".dynbss") != 0)
> + else if (s == htab->root.sgot
> + || s == htab->root.sgotplt)
> + {
> + if (s->size != 0)
> + got = TRUE;
> + }
> + else if (s != htab->root.sdynbss
> + && s != htab->root.sdynrelro)
> /* It's not one of our sections, so don't allocate space. */
> continue;
>
> @@ -6249,6 +6259,7 @@ const struct bfd_elf_special_section elf32_nios2_special_sections[] =
> #define elf_backend_can_refcount 1
> #define elf_backend_plt_readonly 1
> #define elf_backend_want_got_plt 1
> +#define elf_backend_want_dynrelro 1
> #define elf_backend_rela_normal 1
> #define elf_backend_dtrel_excludes_plt 1
>
> diff --git a/bfd/elf32-or1k.c b/bfd/elf32-or1k.c
> index c75a2ce..7fc6b81 100644
> --- a/bfd/elf32-or1k.c
> +++ b/bfd/elf32-or1k.c
> @@ -1944,17 +1944,16 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
> && (h->root.type == bfd_link_hash_defined
> || h->root.type == bfd_link_hash_defweak));
>
> - s = bfd_get_section_by_name (h->root.u.def.section->owner,
> - ".rela.bss");
> - BFD_ASSERT (s != NULL);
> -
> rela.r_offset = (h->root.u.def.value
> + h->root.u.def.section->output_section->vma
> + h->root.u.def.section->output_offset);
> rela.r_info = ELF32_R_INFO (h->dynindx, R_OR1K_COPY);
> rela.r_addend = 0;
> - loc = s->contents;
> - loc += s->reloc_count * sizeof (Elf32_External_Rela);
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + s = htab->root.sreldynrelro;
> + else
> + s = htab->root.srelbss;
> + loc = s->contents + s->reloc_count * sizeof (Elf32_External_Rela);
> bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
> ++s->reloc_count;
> }
> @@ -1995,7 +1994,7 @@ or1k_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
> struct elf_or1k_link_hash_entry *eh;
> struct elf_or1k_dyn_relocs *p;
> bfd *dynobj;
> - asection *s;
> + asection *s, *srel;
>
> dynobj = elf_hash_table (info)->dynobj;
>
> @@ -2098,19 +2097,22 @@ or1k_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
> if (htab == NULL)
> return FALSE;
>
> - s = htab->root.sdynbss;
> - BFD_ASSERT (s != NULL);
> -
> /* We must generate a R_OR1K_COPY reloc to tell the dynamic linker
> to copy the initial value out of the dynamic object and into the
> runtime process image. We need to remember the offset into the
> .rela.bss section we are going to use. */
> - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> {
> - asection *srel;
> -
> + s = htab->root.sdynrelro;
> + srel = htab->root.sreldynrelro;
> + }
> + else
> + {
> + s = htab->root.sdynbss;
> srel = htab->root.srelbss;
> - BFD_ASSERT (srel != NULL);
> + }
> + if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
> + {
> srel->size += sizeof (Elf32_External_Rela);
> h->needs_copy = 1;
> }
> @@ -2472,7 +2474,8 @@ or1k_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
> if (s == htab->root.splt
> || s == htab->root.sgot
> || s == htab->root.sgotplt
> - || s == htab->root.sdynbss)
> + || s == htab->root.sdynbss
> + || s == htab->root.sdynrelro)
> {
> /* Strip this section if we don't need it; see the
> comment below. */
> @@ -2742,6 +2745,7 @@ elf32_or1k_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
> #define elf_backend_want_plt_sym 0
> #define elf_backend_got_header_size 12
> #define elf_backend_dtrel_excludes_plt 1
> +#define elf_backend_want_dynrelro 1
>
> #define bfd_elf32_bfd_link_hash_table_create or1k_elf_link_hash_table_create
> #define elf_backend_copy_indirect_symbol or1k_elf_copy_indirect_symbol
> diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
> index 7f541d1..e65ff61 100644
> --- a/bfd/elf32-ppc.c
> +++ b/bfd/elf32-ppc.c
> @@ -5806,6 +5806,8 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
>
> if (ppc_elf_hash_entry (h)->has_sda_refs)
> s = htab->dynsbss;
> + else if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + s = htab->elf.sdynrelro;
> else
> s = htab->elf.sdynbss;
> BFD_ASSERT (s != NULL);
> @@ -5820,6 +5822,8 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
>
> if (ppc_elf_hash_entry (h)->has_sda_refs)
> srel = htab->relsbss;
> + else if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + srel = htab->elf.sreldynrelro;
> else
> srel = htab->elf.srelbss;
> BFD_ASSERT (srel != NULL);
> @@ -6636,6 +6640,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
> || s == htab->elf.sgotplt
> || s == htab->sbss
> || s == htab->elf.sdynbss
> + || s == htab->elf.sdynrelro
> || s == htab->dynsbss)
> {
> /* Strip these too. */
> @@ -10356,6 +10361,8 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
>
> if (ppc_elf_hash_entry (h)->has_sda_refs)
> s = htab->relsbss;
> + else if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + s = htab->elf.sreldynrelro;
> else
> s = htab->elf.srelbss;
> BFD_ASSERT (s != NULL);
> @@ -10893,6 +10900,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
> #endif
>
> #define elf_backend_plt_not_loaded 1
> +#define elf_backend_want_dynrelro 1
> #define elf_backend_can_gc_sections 1
> #define elf_backend_can_refcount 1
> #define elf_backend_rela_normal 1
> diff --git a/bfd/elf32-s390.c b/bfd/elf32-s390.c
> index 79c4050..b52144a 100644
> --- a/bfd/elf32-s390.c
> +++ b/bfd/elf32-s390.c
> @@ -1607,7 +1607,7 @@ elf_s390_adjust_dynamic_symbol (struct bfd_link_info *info,
> struct elf_link_hash_entry *h)
> {
> struct elf_s390_link_hash_table *htab;
> - asection *s;
> + asection *s, *srel;
>
> /* STT_GNU_IFUNC symbol must go through PLT. */
> if (s390_is_ifunc_symbol_p (h))
> @@ -1757,14 +1757,22 @@ elf_s390_adjust_dynamic_symbol (struct bfd_link_info *info,
> /* We must generate a R_390_COPY reloc to tell the dynamic linker to
> copy the initial value out of the dynamic object and into the
> runtime process image. */
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + {
> + s = htab->elf.sdynrelro;
> + srel = htab->elf.sreldynrelro;
> + }
> + else
> + {
> + s = htab->elf.sdynbss;
> + srel = htab->elf.srelbss;
> + }
> if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
> {
> - htab->elf.srelbss->size += sizeof (Elf32_External_Rela);
> + srel->size += sizeof (Elf32_External_Rela);
> h->needs_copy = 1;
> }
>
> - s = htab->elf.sdynbss;
> -
> return _bfd_elf_adjust_dynamic_copy (info, h, s);
> }
>
> @@ -2157,6 +2165,7 @@ elf_s390_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
> || s == htab->elf.sgot
> || s == htab->elf.sgotplt
> || s == htab->elf.sdynbss
> + || s == htab->elf.sdynrelro
> || s == htab->elf.iplt
> || s == htab->elf.igotplt
> || s == htab->irelifunc)
> @@ -3800,6 +3809,7 @@ elf_s390_finish_dynamic_symbol (bfd *output_bfd,
> if (h->needs_copy)
> {
> Elf_Internal_Rela rela;
> + asection *s;
> bfd_byte *loc;
>
> /* This symbols needs a copy reloc. Set it up. */
> @@ -3807,7 +3817,8 @@ elf_s390_finish_dynamic_symbol (bfd *output_bfd,
> if (h->dynindx == -1
> || (h->root.type != bfd_link_hash_defined
> && h->root.type != bfd_link_hash_defweak)
> - || htab->elf.srelbss == NULL)
> + || htab->elf.srelbss == NULL
> + || htab->elf.sreldynrelro == NULL)
> abort ();
>
> rela.r_offset = (h->root.u.def.value
> @@ -3815,8 +3826,11 @@ elf_s390_finish_dynamic_symbol (bfd *output_bfd,
> + h->root.u.def.section->output_offset);
> rela.r_info = ELF32_R_INFO (h->dynindx, R_390_COPY);
> rela.r_addend = 0;
> - loc = htab->elf.srelbss->contents;
> - loc += htab->elf.srelbss->reloc_count++ * sizeof (Elf32_External_Rela);
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + s = htab->elf.sreldynrelro;
> + else
> + s = htab->elf.srelbss;
> + loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela);
> bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
> }
>
> @@ -4154,6 +4168,7 @@ elf32_s390_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
> #define elf_backend_plt_readonly 1
> #define elf_backend_want_plt_sym 0
> #define elf_backend_got_header_size 12
> +#define elf_backend_want_dynrelro 1
> #define elf_backend_rela_normal 1
>
> #define elf_info_to_howto elf_s390_info_to_howto
> diff --git a/bfd/elf32-sparc.c b/bfd/elf32-sparc.c
> index 528cba2..8610945 100644
> --- a/bfd/elf32-sparc.c
> +++ b/bfd/elf32-sparc.c
> @@ -245,6 +245,7 @@ elf32_sparc_add_symbol_hook (bfd * abfd,
> #define elf_backend_plt_readonly 0
> #define elf_backend_want_plt_sym 1
> #define elf_backend_got_header_size 4
> +#define elf_backend_want_dynrelro 1
> #define elf_backend_rela_normal 1
>
> #define elf_backend_add_symbol_hook elf32_sparc_add_symbol_hook
> diff --git a/bfd/elf32-tic6x.c b/bfd/elf32-tic6x.c
> index c2b22ee..1ccbf9c 100644
> --- a/bfd/elf32-tic6x.c
> +++ b/bfd/elf32-tic6x.c
> @@ -1860,13 +1860,15 @@ elf32_tic6x_finish_dynamic_symbol (bfd * output_bfd,
> if (h->needs_copy)
> {
> Elf_Internal_Rela rel;
> + asection *s;
>
> /* This symbol needs a copy reloc. Set it up. */
>
> if (h->dynindx == -1
> || (h->root.type != bfd_link_hash_defined
> && h->root.type != bfd_link_hash_defweak)
> - || htab->elf.srelbss == NULL)
> + || htab->elf.srelbss == NULL
> + || htab->elf.sreldynrelro == NULL)
> abort ();
>
> rel.r_offset = (h->root.u.def.value
> @@ -1874,8 +1876,12 @@ elf32_tic6x_finish_dynamic_symbol (bfd * output_bfd,
> + h->root.u.def.section->output_offset);
> rel.r_info = ELF32_R_INFO (h->dynindx, R_C6000_COPY);
> rel.r_addend = 0;
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + s = htab->elf.sreldynrelro;
> + else
> + s = htab->elf.srelbss;
>
> - elf32_tic6x_install_rela (output_bfd, htab->elf.srelbss, &rel);
> + elf32_tic6x_install_rela (output_bfd, s, &rel);
> }
>
> /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */
> @@ -2061,7 +2067,7 @@ elf32_tic6x_adjust_dynamic_symbol (struct bfd_link_info *info,
> {
> struct elf32_tic6x_link_hash_table *htab;
> bfd *dynobj;
> - asection *s;
> + asection *s, *srel;
>
> dynobj = elf_hash_table (info)->dynobj;
>
> @@ -2146,14 +2152,22 @@ elf32_tic6x_adjust_dynamic_symbol (struct bfd_link_info *info,
> /* We must generate a R_C6000_COPY reloc to tell the dynamic linker to
> copy the initial value out of the dynamic object and into the
> runtime process image. */
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + {
> + s = htab->elf.sdynrelro;
> + srel = htab->elf.sreldynrelro;
> + }
> + else
> + {
> + s = htab->elf.sdynbss;
> + srel = htab->elf.srelbss;
> + }
> if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
> {
> - htab->elf.srelbss->size += sizeof (Elf32_External_Rela);
> + srel->size += sizeof (Elf32_External_Rela);
> h->needs_copy = 1;
> }
>
> - s = htab->elf.sdynbss;
> -
> return _bfd_elf_adjust_dynamic_copy (info, h, s);
> }
>
> @@ -3376,7 +3390,8 @@ elf32_tic6x_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
> else if (s == htab->elf.splt
> || s == htab->elf.sgot
> || s == htab->elf.sgotplt
> - || s == htab->elf.sdynbss)
> + || s == htab->elf.sdynbss
> + || s == htab->elf.sdynrelro)
> {
> /* Strip this section if we don't need it; see the
> comment below. */
> @@ -4369,6 +4384,7 @@ elf32_tic6x_write_section (bfd *output_bfd,
> #define elf_backend_can_refcount 1
> #define elf_backend_want_got_plt 1
> #define elf_backend_want_dynbss 1
> +#define elf_backend_want_dynrelro 1
> #define elf_backend_plt_readonly 1
> #define elf_backend_rela_normal 1
> #define elf_backend_got_header_size 8
> diff --git a/bfd/elf32-tilegx.c b/bfd/elf32-tilegx.c
> index bf1ad6b..1b4aa8f 100644
> --- a/bfd/elf32-tilegx.c
> +++ b/bfd/elf32-tilegx.c
> @@ -128,6 +128,7 @@ tilegx_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
> #define elf_backend_plt_alignment 6
> #define elf_backend_want_plt_sym 1
> #define elf_backend_got_header_size 4
> +#define elf_backend_want_dynrelro 1
> #define elf_backend_rela_normal 1
> #define elf_backend_default_execstack 0
>
> diff --git a/bfd/elf32-tilepro.c b/bfd/elf32-tilepro.c
> index 18aabb0..f95cd27 100644
> --- a/bfd/elf32-tilepro.c
> +++ b/bfd/elf32-tilepro.c
> @@ -2062,7 +2062,7 @@ tilepro_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
> struct tilepro_elf_link_hash_table *htab;
> struct tilepro_elf_link_hash_entry * eh;
> struct tilepro_elf_dyn_relocs *p;
> - asection *s;
> + asection *s, *srel;
>
> htab = tilepro_elf_hash_table (info);
> BFD_ASSERT (htab != NULL);
> @@ -2164,13 +2164,23 @@ tilepro_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
> to copy the initial value out of the dynamic object and into the
> runtime process image. We need to remember the offset into the
> .rel.bss section we are going to use. */
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + {
> + s = htab->elf.sdynrelro;
> + srel = htab->elf.sreldynrelro;
> + }
> + else
> + {
> + s = htab->elf.sdynbss;
> + srel = htab->elf.srelbss;
> + }
> if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
> {
> - htab->elf.srelbss->size += TILEPRO_ELF_RELA_BYTES;
> + srel->size += TILEPRO_ELF_RELA_BYTES;
> h->needs_copy = 1;
> }
>
> - return _bfd_elf_adjust_dynamic_copy (info, h, htab->elf.sdynbss);
> + return _bfd_elf_adjust_dynamic_copy (info, h, s);
> }
>
> /* Allocate space in .plt, .got and associated reloc sections for
> @@ -2565,7 +2575,8 @@ tilepro_elf_size_dynamic_sections (bfd *output_bfd,
> if (s == htab->elf.splt
> || s == htab->elf.sgot
> || s == htab->elf.sgotplt
> - || s == htab->elf.sdynbss)
> + || s == htab->elf.sdynbss
> + || s == htab->elf.sdynrelro)
> {
> /* Strip this section if we don't need it; see the
> comment below. */
> @@ -3797,14 +3808,15 @@ tilepro_elf_finish_dynamic_symbol (bfd *output_bfd,
> /* This symbols needs a copy reloc. Set it up. */
> BFD_ASSERT (h->dynindx != -1);
>
> - s = htab->elf.srelbss;
> - BFD_ASSERT (s != NULL);
> -
> rela.r_offset = (h->root.u.def.value
> + h->root.u.def.section->output_section->vma
> + h->root.u.def.section->output_offset);
> rela.r_info = ELF32_R_INFO (h->dynindx, R_TILEPRO_COPY);
> rela.r_addend = 0;
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + s = htab->elf.sreldynrelro;
> + else
> + s = htab->elf.srelbss;
> tilepro_elf_append_rela_32 (output_bfd, s, &rela);
> }
>
> @@ -4045,6 +4057,7 @@ tilepro_additional_program_headers (bfd *abfd,
> #define elf_backend_plt_alignment 6
> #define elf_backend_want_plt_sym 1
> #define elf_backend_got_header_size GOT_ENTRY_SIZE
> +#define elf_backend_want_dynrelro 1
> #define elf_backend_rela_normal 1
> #define elf_backend_default_execstack 0
>
> diff --git a/bfd/elf64-mips.c b/bfd/elf64-mips.c
> index 8cd0a73..1a39522 100644
> --- a/bfd/elf64-mips.c
> +++ b/bfd/elf64-mips.c
> @@ -4467,6 +4467,7 @@ const struct elf_size_info mips_elf64_size_info =
> #define elf_backend_grok_psinfo elf64_mips_grok_psinfo
>
> #define elf_backend_got_header_size (8 * MIPS_RESERVED_GOTNO)
> +#define elf_backend_want_dynrelro 1
>
> /* MIPS ELF64 can use a mixture of REL and RELA, but some Relocations
> work better/work only in RELA, so we default to this. */
> diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
> index c421426..9520777 100644
> --- a/bfd/elf64-ppc.c
> +++ b/bfd/elf64-ppc.c
> @@ -72,6 +72,7 @@ static bfd_vma opd_entry_value
> #define elf_backend_plt_alignment 3
> #define elf_backend_plt_not_loaded 1
> #define elf_backend_got_header_size 8
> +#define elf_backend_want_dynrelro 1
> #define elf_backend_can_gc_sections 1
> #define elf_backend_can_refcount 1
> #define elf_backend_rela_normal 1
> @@ -7235,7 +7236,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
> struct elf_link_hash_entry *h)
> {
> struct ppc_link_hash_table *htab;
> - asection *s;
> + asection *s, *srel;
>
> htab = ppc_hash_table (info);
> if (htab == NULL)
> @@ -7365,14 +7366,22 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
> to copy the initial value out of the dynamic object and into the
> runtime process image. We need to remember the offset into the
> .rela.bss section we are going to use. */
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + {
> + s = htab->elf.sdynrelro;
> + srel = htab->elf.sreldynrelro;
> + }
> + else
> + {
> + s = htab->elf.sdynbss;
> + srel = htab->elf.srelbss;
> + }
> if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
> {
> - htab->elf.srelbss->size += sizeof (Elf64_External_Rela);
> + srel->size += sizeof (Elf64_External_Rela);
> h->needs_copy = 1;
> }
>
> - s = htab->elf.sdynbss;
> -
> return _bfd_elf_adjust_dynamic_copy (info, h, s);
> }
>
> @@ -10174,7 +10183,8 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
> || s == htab->elf.splt
> || s == htab->elf.iplt
> || s == htab->glink
> - || s == htab->elf.sdynbss)
> + || s == htab->elf.sdynbss
> + || s == htab->elf.sdynrelro)
> {
> /* Strip this section if we don't need it; see the
> comment below. */
> @@ -10227,7 +10237,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
> but this way if it does we get a R_PPC64_NONE reloc in .rela
> sections instead of garbage.
> We also rely on the section contents being zero when writing
> - the GOT. */
> + the GOT and .dynrelro. */
> s->contents = bfd_zalloc (dynobj, s->size);
> if (s->contents == NULL)
> return FALSE;
> @@ -15421,11 +15431,13 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
> if (h->needs_copy)
> {
> /* This symbol needs a copy reloc. Set it up. */
> + asection *srel;
>
> if (h->dynindx == -1
> || (h->root.type != bfd_link_hash_defined
> && h->root.type != bfd_link_hash_defweak)
> - || htab->elf.srelbss == NULL)
> + || htab->elf.srelbss == NULL
> + || htab->elf.sreldynrelro == NULL)
> abort ();
>
> rela.r_offset = (h->root.u.def.value
> @@ -15433,8 +15445,12 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
> + h->root.u.def.section->output_offset);
> rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_COPY);
> rela.r_addend = 0;
> - loc = htab->elf.srelbss->contents;
> - loc += htab->elf.srelbss->reloc_count++ * sizeof (Elf64_External_Rela);
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + srel = htab->elf.sreldynrelro;
> + else
> + srel = htab->elf.srelbss;
> + loc = srel->contents;
> + loc += srel->reloc_count++ * sizeof (Elf64_External_Rela);
> bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
> }
>
> diff --git a/bfd/elf64-s390.c b/bfd/elf64-s390.c
> index ab2bbaa..64a74c5 100644
> --- a/bfd/elf64-s390.c
> +++ b/bfd/elf64-s390.c
> @@ -1541,7 +1541,7 @@ elf_s390_adjust_dynamic_symbol (struct bfd_link_info *info,
> struct elf_link_hash_entry *h)
> {
> struct elf_s390_link_hash_table *htab;
> - asection *s;
> + asection *s, *srel;
>
> /* STT_GNU_IFUNC symbol must go through PLT. */
> if (s390_is_ifunc_symbol_p (h))
> @@ -1693,14 +1693,22 @@ elf_s390_adjust_dynamic_symbol (struct bfd_link_info *info,
> /* We must generate a R_390_COPY reloc to tell the dynamic linker to
> copy the initial value out of the dynamic object and into the
> runtime process image. */
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + {
> + s = htab->elf.sdynrelro;
> + srel = htab->elf.sreldynrelro;
> + }
> + else
> + {
> + s = htab->elf.sdynbss;
> + srel = htab->elf.srelbss;
> + }
> if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
> {
> - htab->elf.srelbss->size += sizeof (Elf64_External_Rela);
> + srel->size += sizeof (Elf64_External_Rela);
> h->needs_copy = 1;
> }
>
> - s = htab->elf.sdynbss;
> -
> return _bfd_elf_adjust_dynamic_copy (info, h, s);
> }
>
> @@ -2099,6 +2107,7 @@ elf_s390_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
> || s == htab->elf.sgot
> || s == htab->elf.sgotplt
> || s == htab->elf.sdynbss
> + || s == htab->elf.sdynrelro
> || s == htab->elf.iplt
> || s == htab->elf.igotplt
> || s == htab->irelifunc)
> @@ -3585,6 +3594,7 @@ elf_s390_finish_dynamic_symbol (bfd *output_bfd,
> if (h->needs_copy)
> {
> Elf_Internal_Rela rela;
> + asection *s;
> bfd_byte *loc;
>
> /* This symbols needs a copy reloc. Set it up. */
> @@ -3600,8 +3610,11 @@ elf_s390_finish_dynamic_symbol (bfd *output_bfd,
> + h->root.u.def.section->output_offset);
> rela.r_info = ELF64_R_INFO (h->dynindx, R_390_COPY);
> rela.r_addend = 0;
> - loc = htab->elf.srelbss->contents;
> - loc += htab->elf.srelbss->reloc_count++ * sizeof (Elf64_External_Rela);
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + s = htab->elf.sreldynrelro;
> + else
> + s = htab->elf.srelbss;
> + loc = s->contents + s->reloc_count++ * sizeof (Elf64_External_Rela);
> bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
> }
>
> @@ -3979,6 +3992,7 @@ const struct elf_size_info s390_elf64_size_info =
> #define elf_backend_plt_readonly 1
> #define elf_backend_want_plt_sym 0
> #define elf_backend_got_header_size 24
> +#define elf_backend_want_dynrelro 1
> #define elf_backend_rela_normal 1
>
> #define elf_info_to_howto elf_s390_info_to_howto
> diff --git a/bfd/elf64-sparc.c b/bfd/elf64-sparc.c
> index 65fb5e4..eecccd1 100644
> --- a/bfd/elf64-sparc.c
> +++ b/bfd/elf64-sparc.c
> @@ -920,6 +920,7 @@ const struct elf_size_info elf64_sparc_size_info =
> #define elf_backend_plt_readonly 0
> #define elf_backend_want_plt_sym 1
> #define elf_backend_got_header_size 8
> +#define elf_backend_want_dynrelro 1
> #define elf_backend_rela_normal 1
>
> /* Section 5.2.4 of the ABI specifies a 256-byte boundary for the table. */
> diff --git a/bfd/elf64-tilegx.c b/bfd/elf64-tilegx.c
> index c281474..f3f9076 100644
> --- a/bfd/elf64-tilegx.c
> +++ b/bfd/elf64-tilegx.c
> @@ -129,6 +129,7 @@ tilegx_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
> #define elf_backend_plt_alignment 6
> #define elf_backend_want_plt_sym 1
> #define elf_backend_got_header_size 8
> +#define elf_backend_want_dynrelro 1
> #define elf_backend_rela_normal 1
> #define elf_backend_default_execstack 0
>
> diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
> index d5a36bc..5b3dd8a 100644
> --- a/bfd/elf64-x86-64.c
> +++ b/bfd/elf64-x86-64.c
> @@ -2828,7 +2828,7 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
> struct elf_link_hash_entry *h)
> {
> struct elf_x86_64_link_hash_table *htab;
> - asection *s;
> + asection *s, *srel;
> struct elf_x86_64_link_hash_entry *eh;
> struct elf_dyn_relocs *p;
>
> @@ -2986,16 +2986,24 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
> /* We must generate a R_X86_64_COPY reloc to tell the dynamic linker
> to copy the initial value out of the dynamic object and into the
> runtime process image. */
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + {
> + s = htab->elf.sdynrelro;
> + srel = htab->elf.sreldynrelro;
> + }
> + else
> + {
> + s = htab->elf.sdynbss;
> + srel = htab->elf.srelbss;
> + }
> if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
> {
> const struct elf_backend_data *bed;
> bed = get_elf_backend_data (info->output_bfd);
> - htab->elf.srelbss->size += bed->s->sizeof_rela;
> + srel->size += bed->s->sizeof_rela;
> h->needs_copy = 1;
> }
>
> - s = htab->elf.sdynbss;
> -
> return _bfd_elf_adjust_dynamic_copy (info, h, s);
> }
>
> @@ -3811,7 +3819,8 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
> || s == htab->plt_bnd
> || s == htab->plt_got
> || s == htab->plt_eh_frame
> - || s == htab->elf.sdynbss)
> + || s == htab->elf.sdynbss
> + || s == htab->elf.sdynrelro)
> {
> /* Strip this section if we don't need it; see the
> comment below. */
> @@ -6024,13 +6033,15 @@ do_glob_dat:
> if (h->needs_copy)
> {
> Elf_Internal_Rela rela;
> + asection *s;
>
> /* This symbol needs a copy reloc. Set it up. */
>
> if (h->dynindx == -1
> || (h->root.type != bfd_link_hash_defined
> && h->root.type != bfd_link_hash_defweak)
> - || htab->elf.srelbss == NULL)
> + || htab->elf.srelbss == NULL
> + || htab->elf.sreldynrelro == NULL)
> abort ();
>
> rela.r_offset = (h->root.u.def.value
> @@ -6038,7 +6049,11 @@ do_glob_dat:
> + h->root.u.def.section->output_offset);
> rela.r_info = htab->r_info (h->dynindx, R_X86_64_COPY);
> rela.r_addend = 0;
> - elf_append_rela (output_bfd, htab->elf.srelbss, &rela);
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + s = htab->elf.sreldynrelro;
> + else
> + s = htab->elf.srelbss;
> + elf_append_rela (output_bfd, s, &rela);
> }
>
> return TRUE;
> @@ -6719,6 +6734,7 @@ static const struct bfd_elf_special_section
> #define elf_backend_extern_protected_data 1
> #define elf_backend_caches_rawsize 1
> #define elf_backend_dtrel_excludes_plt 1
> +#define elf_backend_want_dynrelro 1
>
> #define elf_info_to_howto elf_x86_64_info_to_howto
>
> diff --git a/bfd/elflink.c b/bfd/elflink.c
> index 9728e29..d8d40f1 100644
> --- a/bfd/elflink.c
> +++ b/bfd/elflink.c
> @@ -429,6 +429,19 @@ _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
> return FALSE;
> htab->sdynbss = s;
>
> + if (bed->want_dynrelro)
> + {
> + /* Similarly, but for symbols that were originally in read-only
> + sections. */
> + s = bfd_make_section_anyway_with_flags (abfd, ".data.rel.ro",
> + (SEC_ALLOC | SEC_READONLY
> + | SEC_HAS_CONTENTS
> + | SEC_LINKER_CREATED));
> + if (s == NULL)
> + return FALSE;
> + htab->sdynrelro = s;
> + }
> +
> /* The .rel[a].bss section holds copy relocs. This section is not
> normally needed. We need to create it here, though, so that the
> linker will map it to an output section. We can't just create it
> @@ -450,6 +463,19 @@ _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
> || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
> return FALSE;
> htab->srelbss = s;
> +
> + if (bed->want_dynrelro)
> + {
> + s = (bfd_make_section_anyway_with_flags
> + (abfd, (bed->rela_plts_and_copies_p
> + ? ".rela.data.rel.ro" : ".rel.data.rel.ro"),
> + flags | SEC_READONLY));
> + if (s == NULL
> + || ! bfd_set_section_alignment (abfd, s,
> + bed->s->log_file_align))
> + return FALSE;
> + htab->sreldynrelro = s;
> + }
> }
> }
>
> diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
> index 8a55596..0103b01 100644
> --- a/bfd/elfnn-aarch64.c
> +++ b/bfd/elfnn-aarch64.c
> @@ -6833,7 +6833,7 @@ elfNN_aarch64_adjust_dynamic_symbol (struct bfd_link_info *info,
> struct elf_link_hash_entry *h)
> {
> struct elf_aarch64_link_hash_table *htab;
> - asection *s;
> + asection *s, *srel;
>
> /* If this is a function, put it in the procedure linkage table. We
> will fill in the contents of the procedure linkage table later,
> @@ -6910,14 +6910,22 @@ elfNN_aarch64_adjust_dynamic_symbol (struct bfd_link_info *info,
> /* We must generate a R_AARCH64_COPY reloc to tell the dynamic linker
> to copy the initial value out of the dynamic object and into the
> runtime process image. */
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + {
> + s = htab->root.sdynrelro;
> + srel = htab->root.sreldynrelro;
> + }
> + else
> + {
> + s = htab->root.sdynbss;
> + srel = htab->root.srelbss;
> + }
> if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
> {
> - htab->root.srelbss->size += RELOC_SIZE (htab);
> + srel->size += RELOC_SIZE (htab);
> h->needs_copy = 1;
> }
>
> - s = htab->root.sdynbss;
> -
> return _bfd_elf_adjust_dynamic_copy (info, h, s);
>
> }
> @@ -8517,7 +8525,8 @@ elfNN_aarch64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
> || s == htab->root.sgotplt
> || s == htab->root.iplt
> || s == htab->root.igotplt
> - || s == htab->root.sdynbss)
> + || s == htab->root.sdynbss
> + || s == htab->root.sdynrelro)
> {
> /* Strip this section if we don't need it; see the
> comment below. */
> @@ -8921,6 +8930,7 @@ do_glob_dat:
> if (h->needs_copy)
> {
> Elf_Internal_Rela rela;
> + asection *s;
> bfd_byte *loc;
>
> /* This symbol needs a copy reloc. Set it up. */
> @@ -8936,8 +8946,11 @@ do_glob_dat:
> + h->root.u.def.section->output_offset);
> rela.r_info = ELFNN_R_INFO (h->dynindx, AARCH64_R (COPY));
> rela.r_addend = 0;
> - loc = htab->root.srelbss->contents;
> - loc += htab->root.srelbss->reloc_count++ * RELOC_SIZE (htab);
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + s = htab->root.sreldynrelro;
> + else
> + s = htab->root.srelbss;
> + loc = s->contents + s->reloc_count++ * RELOC_SIZE (htab);
> bfd_elfNN_swap_reloca_out (output_bfd, &rela, loc);
> }
>
> @@ -9390,6 +9403,7 @@ const struct elf_size_info elfNN_aarch64_size_info =
> #define elf_backend_plt_readonly 1
> #define elf_backend_want_got_plt 1
> #define elf_backend_want_plt_sym 0
> +#define elf_backend_want_dynrelro 1
> #define elf_backend_may_use_rel_p 0
> #define elf_backend_may_use_rela_p 1
> #define elf_backend_default_use_rela_p 1
> diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
> index db4b782..69907bd 100644
> --- a/bfd/elfnn-riscv.c
> +++ b/bfd/elfnn-riscv.c
> @@ -862,7 +862,7 @@ riscv_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
> struct riscv_elf_link_hash_entry * eh;
> struct riscv_elf_dyn_relocs *p;
> bfd *dynobj;
> - asection *s;
> + asection *s, *srel;
>
> htab = riscv_elf_hash_table (info);
> BFD_ASSERT (htab != NULL);
> @@ -965,16 +965,26 @@ riscv_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
> to copy the initial value out of the dynamic object and into the
> runtime process image. We need to remember the offset into the
> .rel.bss section we are going to use. */
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + {
> + s = htab->elf.sdynrelro;
> + srel = htab->elf.sreldynrelro;
> + }
> + else
> + {
> + s = htab->elf.sdynbss;
> + srel = htab->elf.srelbss;
> + }
> if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
> {
> - htab->elf.srelbss->size += sizeof (ElfNN_External_Rela);
> + srel->size += sizeof (ElfNN_External_Rela);
> h->needs_copy = 1;
> }
>
> if (eh->tls_type & ~GOT_NORMAL)
> return _bfd_elf_adjust_dynamic_copy (info, h, htab->sdyntdata);
>
> - return _bfd_elf_adjust_dynamic_copy (info, h, htab->elf.sdynbss);
> + return _bfd_elf_adjust_dynamic_copy (info, h, s);
> }
>
> /* Allocate space in .plt, .got and associated reloc sections for
> @@ -1328,7 +1338,8 @@ riscv_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
> if (s == htab->elf.splt
> || s == htab->elf.sgot
> || s == htab->elf.sgotplt
> - || s == htab->elf.sdynbss)
> + || s == htab->elf.sdynbss
> + || s == htab->elf.sdynrelro)
> {
> /* Strip this section if we don't need it; see the
> comment below. */
> @@ -2389,6 +2400,7 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
> if (h->needs_copy)
> {
> Elf_Internal_Rela rela;
> + asection *s;
>
> /* This symbols needs a copy reloc. Set it up. */
> BFD_ASSERT (h->dynindx != -1);
> @@ -2396,7 +2408,11 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
> rela.r_offset = sec_addr (h->root.u.def.section) + h->root.u.def.value;
> rela.r_info = ELFNN_R_INFO (h->dynindx, R_RISCV_COPY);
> rela.r_addend = 0;
> - riscv_elf_append_rela (output_bfd, htab->elf.srelbss, &rela);
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + s = htab->elf.sreldynrelro;
> + else
> + s = htab->elf.srelbss;
> + riscv_elf_append_rela (output_bfd, s, &rela);
> }
>
> /* Mark some specially defined symbols as absolute. */
> @@ -3213,6 +3229,7 @@ riscv_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
> #define elf_backend_plt_alignment 4
> #define elf_backend_want_plt_sym 1
> #define elf_backend_got_header_size (ARCH_SIZE / 8)
> +#define elf_backend_want_dynrelro 1
> #define elf_backend_rela_normal 1
> #define elf_backend_default_execstack 0
>
> diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
> index 086d537..7c7cd38 100644
> --- a/bfd/elfxx-mips.c
> +++ b/bfd/elfxx-mips.c
> @@ -9129,6 +9129,7 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
> bfd *dynobj;
> struct mips_elf_link_hash_entry *hmips;
> struct mips_elf_link_hash_table *htab;
> + asection *s, *srel;
>
> htab = mips_elf_hash_table (info);
> BFD_ASSERT (htab != NULL);
> @@ -9371,10 +9372,20 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
> both the dynamic object and the regular object will refer to the
> same memory location for the variable. */
>
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + {
> + s = htab->root.sdynrelro;
> + srel = htab->root.sreldynrelro;
> + }
> + else
> + {
> + s = htab->root.sdynbss;
> + srel = htab->root.srelbss;
> + }
> if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
> {
> if (htab->is_vxworks)
> - htab->root.srelbss->size += sizeof (Elf32_External_Rela);
> + srel->size += sizeof (Elf32_External_Rela);
> else
> mips_elf_allocate_dynamic_relocations (dynobj, info, 1);
> h->needs_copy = 1;
> @@ -9384,7 +9395,7 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
> dynamic will now refer to the local copy instead. */
> hmips->possibly_dynamic_relocs = 0;
>
> - return _bfd_elf_adjust_dynamic_copy (info, h, htab->root.sdynbss);
> + return _bfd_elf_adjust_dynamic_copy (info, h, s);
> }
>
> /* This function is called after all the input files have been read,
> @@ -9906,7 +9917,8 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
> && s != htab->root.sgot
> && s != htab->root.sgotplt
> && s != htab->sstubs
> - && s != htab->root.sdynbss)
> + && s != htab->root.sdynbss
> + && s != htab->root.sdynrelro)
> {
> /* It's not one of our sections, so don't allocate space. */
> continue;
> @@ -11296,6 +11308,8 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
> if (h->needs_copy)
> {
> Elf_Internal_Rela rel;
> + asection *srel;
> + bfd_byte *loc;
>
> BFD_ASSERT (h->dynindx != -1);
>
> @@ -11304,11 +11318,13 @@ _bfd_mips_vxworks_finish_dynamic_symbol (bfd *output_bfd,
> + h->root.u.def.value);
> rel.r_info = ELF32_R_INFO (h->dynindx, R_MIPS_COPY);
> rel.r_addend = 0;
> - bfd_elf32_swap_reloca_out (output_bfd, &rel,
> - htab->root.srelbss->contents
> - + (htab->root.srelbss->reloc_count
> - * sizeof (Elf32_External_Rela)));
> - ++htab->root.srelbss->reloc_count;
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + srel = htab->root.sreldynrelro;
> + else
> + srel = htab->root.srelbss;
> + loc = srel->contents + srel->reloc_count * sizeof (Elf32_External_Rela);
> + bfd_elf32_swap_reloca_out (output_bfd, &rel, loc);
> + ++srel->reloc_count;
> }
>
> /* If this is a mips16/microMIPS symbol, force the value to be even. */
> diff --git a/bfd/elfxx-sparc.c b/bfd/elfxx-sparc.c
> index 050993c..d7b2688 100644
> --- a/bfd/elfxx-sparc.c
> +++ b/bfd/elfxx-sparc.c
> @@ -2086,7 +2086,7 @@ _bfd_sparc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
> struct _bfd_sparc_elf_link_hash_table *htab;
> struct _bfd_sparc_elf_link_hash_entry * eh;
> struct _bfd_sparc_elf_dyn_relocs *p;
> - asection *s;
> + asection *s, *srel;
>
> htab = _bfd_sparc_elf_hash_table (info);
> BFD_ASSERT (htab != NULL);
> @@ -2199,14 +2199,22 @@ _bfd_sparc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
> to copy the initial value out of the dynamic object and into the
> runtime process image. We need to remember the offset into the
> .rel.bss section we are going to use. */
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + {
> + s = htab->elf.sdynrelro;
> + srel = htab->elf.sreldynrelro;
> + }
> + else
> + {
> + s = htab->elf.sdynbss;
> + srel = htab->elf.srelbss;
> + }
> if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
> {
> - htab->elf.srelbss->size += SPARC_ELF_RELA_BYTES (htab);
> + srel->size += SPARC_ELF_RELA_BYTES (htab);
> h->needs_copy = 1;
> }
>
> - s = htab->elf.sdynbss;
> -
> return _bfd_elf_adjust_dynamic_copy (info, h, s);
> }
>
> @@ -2686,6 +2694,7 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd,
> if (s == htab->elf.splt
> || s == htab->elf.sgot
> || s == htab->elf.sdynbss
> + || s == htab->elf.sdynrelro
> || s == htab->elf.iplt
> || s == htab->elf.sgotplt)
> {
> @@ -4527,15 +4536,15 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd,
> /* This symbols needs a copy reloc. Set it up. */
> BFD_ASSERT (h->dynindx != -1);
>
> - s = bfd_get_linker_section (h->root.u.def.section->owner,
> - ".rela.bss");
> - BFD_ASSERT (s != NULL);
> -
> rela.r_offset = (h->root.u.def.value
> + h->root.u.def.section->output_section->vma
> + h->root.u.def.section->output_offset);
> rela.r_info = SPARC_ELF_R_INFO (htab, NULL, h->dynindx, R_SPARC_COPY);
> rela.r_addend = 0;
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + s = htab->elf.sreldynrelro;
> + else
> + s = htab->elf.srelbss;
> sparc_elf_append_rela (output_bfd, s, &rela);
> }
>
> diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
> index aff8621..7f08128 100644
> --- a/bfd/elfxx-target.h
> +++ b/bfd/elfxx-target.h
> @@ -108,6 +108,9 @@
> #ifndef elf_backend_want_dynbss
> #define elf_backend_want_dynbss 1
> #endif
> +#ifndef elf_backend_want_dynrelro
> +#define elf_backend_want_dynrelro 0
> +#endif
> #ifndef elf_backend_want_p_paddr_set_to_zero
> #define elf_backend_want_p_paddr_set_to_zero 0
> #endif
> @@ -855,6 +858,7 @@ static struct elf_backend_data elfNN_bed =
> elf_backend_can_refcount,
> elf_backend_want_got_sym,
> elf_backend_want_dynbss,
> + elf_backend_want_dynrelro,
> elf_backend_want_p_paddr_set_to_zero,
> elf_backend_default_execstack,
> elf_backend_caches_rawsize,
> diff --git a/bfd/elfxx-tilegx.c b/bfd/elfxx-tilegx.c
> index 92b9de8..ce4fb07 100644
> --- a/bfd/elfxx-tilegx.c
> +++ b/bfd/elfxx-tilegx.c
> @@ -2327,7 +2327,7 @@ tilegx_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
> struct tilegx_elf_link_hash_entry * eh;
> struct tilegx_elf_dyn_relocs *p;
> bfd *dynobj;
> - asection *s;
> + asection *s, *srel;
>
> htab = tilegx_elf_hash_table (info);
> BFD_ASSERT (htab != NULL);
> @@ -2431,13 +2431,23 @@ tilegx_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
> to copy the initial value out of the dynamic object and into the
> runtime process image. We need to remember the offset into the
> .rel.bss section we are going to use. */
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + {
> + s = htab->elf.sdynrelro;
> + srel = htab->elf.sreldynrelro;
> + }
> + else
> + {
> + s = htab->elf.sdynbss;
> + srel = htab->elf.srelbss;
> + }
> if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
> {
> - htab->elf.srelbss->size += TILEGX_ELF_RELA_BYTES (htab);
> + srel->size += TILEGX_ELF_RELA_BYTES (htab);
> h->needs_copy = 1;
> }
>
> - return _bfd_elf_adjust_dynamic_copy (info, h, htab->elf.sdynbss);
> + return _bfd_elf_adjust_dynamic_copy (info, h, s);
> }
>
> /* Allocate space in .plt, .got and associated reloc sections for
> @@ -2826,7 +2836,8 @@ tilegx_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
> if (s == htab->elf.splt
> || s == htab->elf.sgot
> || s == htab->elf.sgotplt
> - || s == htab->elf.sdynbss)
> + || s == htab->elf.sdynbss
> + || s == htab->elf.sdynrelro)
> {
> /* Strip this section if we don't need it; see the
> comment below. */
> @@ -4187,7 +4198,10 @@ tilegx_elf_finish_dynamic_symbol (bfd *output_bfd,
> /* This symbols needs a copy reloc. Set it up. */
> BFD_ASSERT (h->dynindx != -1);
>
> - s = htab->elf.srelbss;
> + if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
> + s = htab->elf.sreldynrelro;
> + else
> + s = htab->elf.srelbss;
> BFD_ASSERT (s != NULL);
>
> rela.r_offset = (h->root.u.def.value
> diff --git a/ld/testsuite/ld-arm/farcall-mixed-app-v5.d b/ld/testsuite/ld-arm/farcall-mixed-app-v5.d
> index b570bad..af44198 100644
> --- a/ld/testsuite/ld-arm/farcall-mixed-app-v5.d
> +++ b/ld/testsuite/ld-arm/farcall-mixed-app-v5.d
> @@ -50,8 +50,8 @@ Disassembly of section .far_arm:
> .* <app_func>:
> .*: e1a0c00d mov ip, sp
> .*: e92dd800 push {fp, ip, lr, pc}
> - .*: eb0000.. bl .* <__lib_func1_veneer>
> - .*: eb0000.. bl .* <__lib_func2_veneer>
> + .*: eb00000(6|8) bl .* <__lib_func1_veneer>
> + .*: eb00000(7|5) bl .* <__lib_func2_veneer>
> .*: e89d6800 ldm sp, {fp, sp, lr}
> .*: e12fff1e bx lr
> .*: e1a00000 nop ; \(mov r0, r0\)
> @@ -61,12 +61,12 @@ Disassembly of section .far_arm:
> .*: e12fff1e bx lr
> #...
>
> -.* <__lib_func1_veneer>:
> - .*: e51ff004 ldr pc, \[pc, #-4\] ; .* <__lib_func1_veneer\+0x4>
> - .*: 000081e8 .word 0x000081e8
> -.* <__lib_func2_veneer>:
> - .*: e51ff004 ldr pc, \[pc, #-4\] ; .* <__lib_func2_veneer\+0x4>
> - .*: 000081dc .word 0x000081dc
> +.* <__lib_func(1|2)_veneer>:
> + .*: e51ff004 ldr pc, \[pc, #-4\] ; .* <__lib_func(1|2)_veneer\+0x4>
> + .*: 000081(e8|dc) .word 0x000081(e8|dc)
> +.* <__lib_func(2|1)_veneer>:
> + .*: e51ff004 ldr pc, \[pc, #-4\] ; .* <__lib_func(2|1)_veneer\+0x4>
> + .*: 000081(dc|e8) .word 0x000081(dc|e8)
>
> Disassembly of section .far_thumb:
>
> diff --git a/ld/testsuite/ld-arm/farcall-mixed-app.d b/ld/testsuite/ld-arm/farcall-mixed-app.d
> index 9fa97dc..f3be54f 100644
> --- a/ld/testsuite/ld-arm/farcall-mixed-app.d
> +++ b/ld/testsuite/ld-arm/farcall-mixed-app.d
> @@ -52,8 +52,8 @@ Disassembly of section .far_arm:
> .* <app_func>:
> .*: e1a0c00d mov ip, sp
> .*: e92dd800 push {fp, ip, lr, pc}
> - .*: eb000006 bl .* <__lib_func1_veneer>
> - .*: eb000007 bl .* <__lib_func2_veneer>
> + .*: eb00000(6|8) bl .* <__lib_func1_veneer>
> + .*: eb00000(7|5) bl .* <__lib_func2_veneer>
> .*: e89d6800 ldm sp, {fp, sp, lr}
> .*: e12fff1e bx lr
> .*: e1a00000 nop ; \(mov r0, r0\)
> @@ -63,12 +63,12 @@ Disassembly of section .far_arm:
> .*: e12fff1e bx lr
> #...
>
> -.* <__lib_func1_veneer>:
> - .*: e51ff004 ldr pc, \[pc, #-4\] ; .* <__lib_func1_veneer\+0x4>
> - .*: 000081ec .word 0x000081ec
> -.* <__lib_func2_veneer>:
> - .*: e51ff004 ldr pc, \[pc, #-4\] ; .* <__lib_func2_veneer\+0x4>
> - .*: 000081e0 .word 0x000081e0
> +.* <__lib_func(1|2)_veneer>:
> + .*: e51ff004 ldr pc, \[pc, #-4\] ; .* <__lib_func(1|2)_veneer\+0x4>
> + .*: 000081e(c|0) .word 0x000081e(c|0)
> +.* <__lib_func(2|1)_veneer>:
> + .*: e51ff004 ldr pc, \[pc, #-4\] ; .* <__lib_func(2|1)_veneer\+0x4>
> + .*: 000081e(0|c) .word 0x000081e(0|c)
>
> Disassembly of section .far_thumb:
>
> diff --git a/ld/testsuite/ld-arm/farcall-mixed-lib-v4t.d b/ld/testsuite/ld-arm/farcall-mixed-lib-v4t.d
> index fa52ad1..83b15a0 100644
> --- a/ld/testsuite/ld-arm/farcall-mixed-lib-v4t.d
> +++ b/ld/testsuite/ld-arm/farcall-mixed-lib-v4t.d
> @@ -87,24 +87,24 @@ Disassembly of section .text:
> ...
>
> .* <__real_lib_func3>:
> - .*: f000 f80e bl 2000390 <__app_func_from_thumb>
> - .*: f000 f804 bl 2000380 <__app_func_weak_from_thumb>
> + .*: f000 f80(e|6) bl .* <__app_func_from_thumb>
> + .*: f000 f80(4|c) bl .* <__app_func_weak_from_thumb>
> .*: 4770 bx lr
> #...
>
> -.* <__app_func_weak_from_thumb>:
> +.* <__app_func(_weak)?_from_thumb>:
> .*: 4778 bx pc
> .*: 46c0 nop ; \(mov r8, r8\)
> - .*: e59fc000 ldr ip, \[pc\] ; 200038c <__app_func_weak_from_thumb\+0xc>
> + .*: e59fc000 ldr ip, \[pc\] ; 200038c <__app_func(_weak)?_from_thumb\+0xc>
> .*: e08cf00f add pc, ip, pc
> - .*: fdffff28 .word 0xfdffff28
> + .*: fdffff(2|1)8 .word 0xfdffff(2|1)8
>
> -.* <__app_func_from_thumb>:
> +.* <__app_func(_weak)?_from_thumb>:
> .*: 4778 bx pc
> .*: 46c0 nop ; \(mov r8, r8\)
> - .*: e59fc000 ldr ip, \[pc\] ; 200039c <__app_func_from_thumb\+0xc>
> + .*: e59fc000 ldr ip, \[pc\] ; 200039c <__app_func(_weak)?_from_thumb\+0xc>
> .*: e08cf00f add pc, ip, pc
> - .*: fdffff08 .word 0xfdffff08
> + .*: fdffff(0|1)8 .word 0xfdffff(0|1)8
>
> .* <lib_func3>:
> .*: e59fc004 ldr ip, \[pc, #4\] ; 20003ac <lib_func3\+0xc>
> diff --git a/ld/testsuite/ld-arm/farcall-mixed-lib.d b/ld/testsuite/ld-arm/farcall-mixed-lib.d
> index ad7352b..d256477 100644
> --- a/ld/testsuite/ld-arm/farcall-mixed-lib.d
> +++ b/ld/testsuite/ld-arm/farcall-mixed-lib.d
> @@ -72,18 +72,18 @@ Disassembly of section .text:
> ...
>
> .* <lib_func3>:
> - .*: f000 e80c blx 200037c <__app_func_from_thumb>
> - .*: f000 e804 blx 2000370 <__app_func_weak_from_thumb>
> + .*: f000 e80(c|6) blx .* <__app_func_from_thumb>
> + .*: f000 e80(4|a) blx .* <__app_func_weak_from_thumb>
> .*: 4770 bx lr
> #...
>
> -.* <__app_func_weak_from_thumb>:
> - .*: e59fc000 ldr ip, \[pc\] ; 2000378 <__app_func_weak_from_thumb\+0x8>
> +.* <__app_func(_weak)?_from_thumb>:
> + .*: e59fc000 ldr ip, \[pc\] ; 2000378 <__app_func(_weak)?_from_thumb\+0x8>
> .*: e08ff00c add pc, pc, ip
> - .*: fdffff34 .word 0xfdffff34
> + .*: fdffff(34|28) .word 0xfdffff(34|28)
>
> -.* <__app_func_from_thumb>:
> - .*: e59fc000 ldr ip, \[pc\] ; 2000384 <__app_func_from_thumb\+0x8>
> +.* <__app_func(_weak)?_from_thumb>:
> + .*: e59fc000 ldr ip, \[pc\] ; 2000384 <__app_func(_weak)?_from_thumb\+0x8>
> .*: e08ff00c add pc, pc, ip
> - .*: fdffff1c .word 0xfdffff1c
> + .*: fdffff(1c|28) .word 0xfdffff(1c|28)
> ...
> diff --git a/ld/testsuite/ld-elf/elf.exp b/ld/testsuite/ld-elf/elf.exp
> index f93ad46..9b1fbeb 100644
> --- a/ld/testsuite/ld-elf/elf.exp
> +++ b/ld/testsuite/ld-elf/elf.exp
> @@ -127,6 +127,20 @@ if { [check_shared_lib_support] } then {
> {symbolic-func.s} {{readelf {-r --wide} symbolic-func.r}}
> "symbolic-func.so"}
> }
> + # xfail on tic6x due to non-PIC/non-PID warnings
> + setup_xfail "tic6x-*-*"
> + run_ld_link_tests {
> + {"Build pr20995.so"
> + "-shared" "" ""
> + {pr20995b.s} {} "pr20995.so"}
> + }
> + # These targets don't copy dynamic variables into .bss.
> + setup_xfail "alpha-*-*" "bfin-*-*" "ia64-*-*" "xtensa-*-*"
> + run_ld_link_tests {
> + {"pr20995"
> + "" "tmpdir/pr20995.so" ""
> + {pr20995a.s} {{readelf {-S --wide} pr20995.r}} "pr20995"}
> + }
> }
>
> set test_list [lsort [glob -nocomplain $srcdir/$subdir/*.d]]
> diff --git a/ld/testsuite/ld-elf/pr20995.r b/ld/testsuite/ld-elf/pr20995.r
> new file mode 100644
> index 0000000..7336de6
> --- /dev/null
> +++ b/ld/testsuite/ld-elf/pr20995.r
> @@ -0,0 +1,5 @@
> +#...
> +.* \.data\.rel\.ro +PROGBITS +[^ ]+ [^ ]+ [^ ]*[1-9a-f]0* .*
> +#...
> +.* \.bss +NOBITS +[^ ]+ [^ ]+ [^ ]*[1-9a-f]0* .*
> +#...
> diff --git a/ld/testsuite/ld-elf/pr20995a.s b/ld/testsuite/ld-elf/pr20995a.s
> new file mode 100644
> index 0000000..8da589c
> --- /dev/null
> +++ b/ld/testsuite/ld-elf/pr20995a.s
> @@ -0,0 +1,11 @@
> + .text
> + .global start
> +start:
> + .global _start
> +_start:
> + .global __start
> +__start:
> + .global main
> +main:
> + .dc.a rw
> + .dc.a ro
> diff --git a/ld/testsuite/ld-elf/pr20995b.s b/ld/testsuite/ld-elf/pr20995b.s
> new file mode 100644
> index 0000000..7ff76ee
> --- /dev/null
> +++ b/ld/testsuite/ld-elf/pr20995b.s
> @@ -0,0 +1,13 @@
> + .data
> + .type rw,%object
> + .globl rw
> +rw:
> + .dc.a 0
> + .size rw, . - rw
> +
> + .text
> + .type ro,%object
> + .globl ro
> +ro:
> + .dc.a 0
> + .size ro, . - ro
>
> --
> Alan Modra
> Australia Development Lab, IBM