This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
PATCH: PR ld/5149: Set PF_X for PT_GNU_RELRO segment only when needed
- From: "H.J. Lu" <hjl at lucon dot org>
- To: binutils at sources dot redhat dot com
- Date: Mon, 22 Oct 2007 15:31:09 -0700
- Subject: PATCH: PR ld/5149: Set PF_X for PT_GNU_RELRO segment only when needed
We currently set PF_X for PT_GNU_RELRO segment when the corresponding
PT_LOAD segment has PF_X. It isn't necessary. This patch checks
sections in PT_GNU_RELRO segment before setting PF_X.
H.J.
---
2007-10-22 H.J. Lu <hongjiu.lu@intel.com>
PR ld/5149
* elf.c (assign_file_positions_for_non_load_sections): Set
PF_X for PT_GNU_RELRO segment only if a section has
SHF_EXECINSTR.
--- bfd/elf.c.relro 2007-10-22 12:22:32.000000000 -0700
+++ bfd/elf.c 2007-10-22 15:25:55.000000000 -0700
@@ -4728,27 +4728,57 @@ assign_file_positions_for_non_load_secti
else if (p->p_type == PT_GNU_RELRO)
{
Elf_Internal_Phdr *lp;
+ struct elf_segment_map *lm;
- for (lp = phdrs; lp < phdrs + count; ++lp)
+ for (lm = elf_tdata (abfd)->segment_map, lp = phdrs;
+ lm != NULL; lm = lm->next, lp++)
{
if (lp->p_type == PT_LOAD
- && lp->p_vaddr <= link_info->relro_end
+ && lp->p_vaddr < link_info->relro_end
&& lp->p_vaddr >= link_info->relro_start
- && (lp->p_vaddr + lp->p_filesz
+ && ((lp->p_vaddr + lp->p_filesz)
>= link_info->relro_end))
break;
}
- if (lp < phdrs + count
- && link_info->relro_end > lp->p_vaddr)
+ if (lm != NULL)
{
+ unsigned long p_flags = lp->p_flags & ~PF_W;
+
p->p_vaddr = lp->p_vaddr;
p->p_paddr = lp->p_paddr;
p->p_offset = lp->p_offset;
p->p_filesz = link_info->relro_end - lp->p_vaddr;
p->p_memsz = p->p_filesz;
p->p_align = 1;
- p->p_flags = (lp->p_flags & ~PF_W);
+
+ if ((p_flags & PF_X) != 0)
+ {
+ Elf_Internal_Shdr *hdr;
+
+ /* Clear PF_X. */
+ p_flags &= ~PF_X;
+
+ for (i = 0; i < lm->count; i++)
+ {
+ hdr = &elf_section_data (lm->sections[i])->this_hdr;
+
+ if (hdr->sh_addr >= link_info->relro_start)
+ {
+ if (hdr->sh_addr >= link_info->relro_end)
+ break;
+
+ /* Set PF_X only if a section has
+ SHF_EXECINSTR. */
+ if ((hdr->sh_flags & SHF_EXECINSTR))
+ {
+ p_flags |= PF_X;
+ break;
+ }
+ }
+ }
+ }
+ p->p_flags = p_flags;
}
else
{