This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: PATCH: Fix relro strip test for MIPS
On Fri, Sep 21, 2007 at 09:59:00AM -0700, H.J. Lu wrote:
> On Thu, Sep 20, 2007 at 11:58:20AM -0700, H.J. Lu wrote:
> > On Thu, Sep 20, 2007 at 02:07:51PM -0400, Daniel Jacobowitz wrote:
> > > On Thu, Sep 20, 2007 at 10:57:25AM -0700, H.J. Lu wrote:
> > > > What happens is linker will allocate a segment for PT_GNU_RELRO
> > > > if there is a .dynamic section. But it doesn't work for MIPS.
> > > > Is there a way for linker to remove a segment reserved for
> > > > PT_GNU_RELRO?
> > >
> > > Not and reclaim its space. That's why we convert it to PT_NULL.
> > >
> >
> > That was done before Alan wrote a patch to remove the empty PT_LOAD
> > segment. Maybe we can use the similar approach to remove empty
> > PT_GNU_RELRO segment.
> >
> >
>
> This patch may not be perfect. We may need to a better way to check if
> a PT_GNU_RELRO segment is needed in _bfd_elf_map_sections_to_segments.
>
>
I believe each call to assign_file_positions_for_load_sections
will assign file positions for load sections based on the current
segment layout. For -z relro, we only need to know if we need
to make a PT_GNU_RELRO segment in _bfd_elf_map_sections_to_segments.
We can call assign_file_positions_for_load_sections to get the
load section layout and find out if the PT_GNU_RELRO segment will
be empty or not. If it will be empty, we don't need to make the
PT_GNU_RELRO segment. I don't think a PT_GNU_RELRO segment will
affect load section lay out due to extra segment in such a way
that the PT_GNU_RELRO segment won't be empty. If it is the case,
we don't need to call assign_file_positions_for_load_sections with
an argument of extra segments.
assign_file_positions_for_load_sections needs to know ELF section
header. I break set_elf_section from elf_fake_sections and call
it before calling assign_file_positions_for_load_sections.
H.J.
----
2007-09-22 H.J. Lu <hongjiu.lu@intel.com>
* elf.c (assign_file_positions_for_load_sections): Declared.
Take an argument of extra segments.
(set_elf_section): New.
(elf_fake_sections ): Use set_elf_section.
(get_program_header_size): Always add a PT_GNU_RELRO segment
for -z relro.
(_bfd_elf_map_sections_to_segments): For -z relro, call
assign_file_positions_for_load_sections and make a PT_GNU_RELRO
segment only when it isn't empty.
(assign_file_positions_for_non_load_sections): Abort when
the PT_GNU_RELRO segment is empty.
(assign_file_positions_except_relocs): Updated.
(prep_headers): Don't set e_phentsize and e_phoff twice.
--- bfd/elf.c.relro 2007-09-22 08:26:46.000000000 -0700
+++ bfd/elf.c 2007-09-22 14:09:55.000000000 -0700
@@ -51,6 +51,8 @@ static bfd_boolean swap_out_syms (bfd *,
static bfd_boolean elf_read_notes (bfd *, file_ptr, bfd_size_type) ;
static bfd_boolean elf_parse_notes (bfd *abfd, char *buf, size_t size,
file_ptr offset);
+static bfd_boolean assign_file_positions_for_load_sections
+ (bfd *abfd, struct bfd_link_info *link_info, unsigned int extra);
/* Swap version information in and out. The version information is
currently size independent. If that ever changes, this code will
@@ -2434,15 +2436,18 @@ _bfd_elf_init_reloc_shdr (bfd *abfd,
return TRUE;
}
-/* Set up an ELF internal section header for a section. */
+/* Set the ELF internal section header fields for a section, except for
+ sh_name
+ */
static void
-elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
+set_elf_section (bfd *abfd, asection *asect, void *failedptrarg)
{
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
bfd_boolean *failedptr = failedptrarg;
Elf_Internal_Shdr *this_hdr;
unsigned int sh_type;
+ bfd_vma sh_flags;
if (*failedptr)
{
@@ -2453,14 +2458,6 @@ elf_fake_sections (bfd *abfd, asection *
this_hdr = &elf_section_data (asect)->this_hdr;
- this_hdr->sh_name = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd),
- asect->name, FALSE);
- if (this_hdr->sh_name == (unsigned int) -1)
- {
- *failedptr = TRUE;
- return;
- }
-
/* Don't clear sh_flags. Assembler may set additional bits. */
if ((asect->flags & SEC_ALLOC) != 0
@@ -2470,13 +2467,15 @@ elf_fake_sections (bfd *abfd, asection *
this_hdr->sh_addr = 0;
this_hdr->sh_offset = 0;
- this_hdr->sh_size = asect->size;
+ if (this_hdr->bfd_section)
+ BFD_ASSERT (this_hdr->sh_size == asect->size);
+ else
+ this_hdr->sh_size = asect->size;
this_hdr->sh_link = 0;
this_hdr->sh_addralign = 1 << asect->alignment_power;
/* The sh_entsize and sh_info fields may have been set already by
copy_private_section_data. */
- this_hdr->bfd_section = asect;
this_hdr->contents = NULL;
/* If the section type is unspecified, we set it based on
@@ -2578,24 +2577,25 @@ elf_fake_sections (bfd *abfd, asection *
break;
}
+ sh_flags = this_hdr->sh_flags;
if ((asect->flags & SEC_ALLOC) != 0)
- this_hdr->sh_flags |= SHF_ALLOC;
+ sh_flags |= SHF_ALLOC;
if ((asect->flags & SEC_READONLY) == 0)
- this_hdr->sh_flags |= SHF_WRITE;
+ sh_flags |= SHF_WRITE;
if ((asect->flags & SEC_CODE) != 0)
- this_hdr->sh_flags |= SHF_EXECINSTR;
+ sh_flags |= SHF_EXECINSTR;
if ((asect->flags & SEC_MERGE) != 0)
{
- this_hdr->sh_flags |= SHF_MERGE;
+ sh_flags |= SHF_MERGE;
this_hdr->sh_entsize = asect->entsize;
if ((asect->flags & SEC_STRINGS) != 0)
- this_hdr->sh_flags |= SHF_STRINGS;
+ sh_flags |= SHF_STRINGS;
}
if ((asect->flags & SEC_GROUP) == 0 && elf_group_name (asect) != NULL)
- this_hdr->sh_flags |= SHF_GROUP;
+ sh_flags |= SHF_GROUP;
if ((asect->flags & SEC_THREAD_LOCAL) != 0)
{
- this_hdr->sh_flags |= SHF_TLS;
+ sh_flags |= SHF_TLS;
if (asect->size == 0
&& (asect->flags & SEC_HAS_CONTENTS) == 0)
{
@@ -2611,6 +2611,16 @@ elf_fake_sections (bfd *abfd, asection *
}
}
+ if (this_hdr->bfd_section)
+ BFD_ASSERT (this_hdr->sh_flags == sh_flags);
+ else
+ this_hdr->sh_flags = sh_flags;
+
+ if (this_hdr->bfd_section)
+ BFD_ASSERT (this_hdr->bfd_section == asect);
+ else
+ this_hdr->bfd_section = asect;
+
/* Check for processor-specific section types. */
sh_type = this_hdr->sh_type;
if (bed->elf_backend_fake_sections
@@ -2623,6 +2633,34 @@ elf_fake_sections (bfd *abfd, asection *
called for objcopy --only-keep-debug. */
this_hdr->sh_type = sh_type;
}
+}
+
+/* Set up an ELF internal section header for a section. */
+
+static void
+elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
+{
+ bfd_boolean *failedptr = failedptrarg;
+ Elf_Internal_Shdr *this_hdr;
+
+ set_elf_section (abfd, asect, failedptrarg);
+
+ if (*failedptr)
+ {
+ /* We already failed; just get out of the bfd_map_over_sections
+ loop. */
+ return;
+ }
+
+ this_hdr = &elf_section_data (asect)->this_hdr;
+
+ this_hdr->sh_name = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd),
+ asect->name, FALSE);
+ if (this_hdr->sh_name == (unsigned int) -1)
+ {
+ *failedptr = TRUE;
+ return;
+ }
/* If the section has relocs, set up a section header for the
SHT_REL[A] section. If two relocation sections are required for
@@ -3362,13 +3400,12 @@ get_program_header_size (bfd *abfd, stru
{
/* We need a PT_DYNAMIC segment. */
++segs;
+ }
- if (info->relro)
- {
- /* We need a PT_GNU_RELRO segment only when there is a
- PT_DYNAMIC segment. */
- ++segs;
- }
+ if (info->relro)
+ {
+ /* We need a PT_GNU_RELRO segment. */
+ ++segs;
}
if (elf_tdata (abfd)->eh_frame_hdr)
@@ -3991,25 +4028,58 @@ _bfd_elf_map_sections_to_segments (bfd *
pm = &m->next;
}
- if (dynsec != NULL && info->relro)
+ elf_tdata (abfd)->segment_map = mfirst;
+
+ if (info->relro)
{
- /* We make a PT_GNU_RELRO segment only when there is a
- PT_DYNAMIC segment. */
- amt = sizeof (struct elf_segment_map);
- m = bfd_zalloc (abfd, amt);
- if (m == NULL)
- goto error_return;
- m->next = NULL;
- m->p_type = PT_GNU_RELRO;
- m->p_flags = PF_R;
- m->p_flags_valid = 1;
+ Elf_Internal_Phdr *p;
+ bfd_boolean failed = FALSE;
+
+ if (!elf_modify_segment_map (abfd, info, no_user_phdrs))
+ return FALSE;
- *pm = m;
- pm = &m->next;
+ bfd_map_over_sections (abfd, set_elf_section, &failed);
+ if (failed)
+ return FALSE;
+
+ /* We need file positions of loaded sectons to check if
+ the PT_GNU_RELRO segment is needed. Assign file positions
+ for the loaded sections based on the assignment of sections
+ to segments. */
+ if (!assign_file_positions_for_load_sections (abfd, info, 1))
+ {
+ elf_tdata (abfd)->segment_map = NULL;
+ return FALSE;
+ }
+
+ p = elf_tdata (abfd)->phdr;
+ for (m = mfirst; m != NULL; m = m->next, p++)
+ {
+ if (p->p_type == PT_LOAD
+ && p->p_vaddr <= info->relro_end
+ && p->p_vaddr >= info->relro_start
+ && (p->p_vaddr + p->p_filesz >= info->relro_end))
+ break;
+ }
+
+ /* Make a PT_GNU_RELRO segment only when it isn't empty. */
+ if (m != NULL && info->relro_end > p->p_vaddr)
+ {
+ amt = sizeof (struct elf_segment_map);
+ m = bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_GNU_RELRO;
+ m->p_flags = PF_R;
+ m->p_flags_valid = 1;
+
+ *pm = m;
+ pm = &m->next;
+ }
}
free (sections);
- elf_tdata (abfd)->segment_map = mfirst;
}
if (!elf_modify_segment_map (abfd, info, no_user_phdrs))
@@ -4146,7 +4216,8 @@ print_segment_map (const struct elf_segm
static bfd_boolean
assign_file_positions_for_load_sections (bfd *abfd,
- struct bfd_link_info *link_info)
+ struct bfd_link_info *link_info,
+ unsigned int extra)
{
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
struct elf_segment_map *m;
@@ -4169,7 +4240,9 @@ assign_file_positions_for_load_sections
elf_elfheader (abfd)->e_phentsize = bed->s->sizeof_phdr;
elf_elfheader (abfd)->e_phnum = alloc;
- if (elf_tdata (abfd)->program_header_size == (bfd_size_type) -1)
+ /* When extra is 0, number of segments won't change. */
+ if (extra == 0
+ || elf_tdata (abfd)->program_header_size == (bfd_size_type) -1)
elf_tdata (abfd)->program_header_size = alloc * bed->s->sizeof_phdr;
else
BFD_ASSERT (elf_tdata (abfd)->program_header_size
@@ -4191,7 +4264,7 @@ assign_file_positions_for_load_sections
maxpagesize = bed->maxpagesize;
off = bed->s->sizeof_ehdr;
- off += alloc * bed->s->sizeof_phdr;
+ off += (alloc + extra) * bed->s->sizeof_phdr;
for (m = elf_tdata (abfd)->segment_map, p = phdrs, j = 0;
m != NULL;
@@ -4380,8 +4453,8 @@ assign_file_positions_for_load_sections
}
}
- p->p_filesz += alloc * bed->s->sizeof_phdr;
- p->p_memsz += alloc * bed->s->sizeof_phdr;
+ p->p_filesz += (alloc + extra) * bed->s->sizeof_phdr;
+ p->p_memsz += (alloc + extra) * bed->s->sizeof_phdr;
}
if (p->p_type == PT_LOAD
@@ -4735,10 +4808,7 @@ assign_file_positions_for_non_load_secti
p->p_flags = (lp->p_flags & ~PF_W);
}
else
- {
- memset (p, 0, sizeof *p);
- p->p_type = PT_NULL;
- }
+ abort ();
}
}
}
@@ -4814,7 +4884,7 @@ assign_file_positions_except_relocs (bfd
/* Assign file positions for the loaded sections based on the
assignment of sections to segments. */
- if (!assign_file_positions_for_load_sections (abfd, link_info))
+ if (!assign_file_positions_for_load_sections (abfd, link_info, 0))
return FALSE;
/* And for non-load sections. */
@@ -4918,11 +4988,7 @@ prep_headers (bfd *abfd)
/* It all happens later. */
;
else
- {
- i_ehdrp->e_phentsize = 0;
- i_phdrp = 0;
- i_ehdrp->e_phoff = 0;
- }
+ i_phdrp = 0;
elf_tdata (abfd)->symtab_hdr.sh_name =
(unsigned int) _bfd_elf_strtab_add (shstrtab, ".symtab", FALSE);