Partially revert patch for PR 20815 - do not sort the PT_LOAD segments. Non-ordered segments are needed by the Linux kernel.

PR ld/20815
	* elf.c (phdr_sorter): Delete.
	(assign_file_positions_except_relocs): Do not sort program
	headers.
This commit is contained in:
Nick Clifton 2016-11-28 17:45:22 +00:00
parent abfcb414b9
commit cd58485720
2 changed files with 21 additions and 65 deletions

View File

@ -5,6 +5,13 @@
(elf_link_output_extsym): Don't change bind from global to (elf_link_output_extsym): Don't change bind from global to
local when linking executable. local when linking executable.
2016-11-28 Nick Clifton <nickc@redhat.com>
PR ld/20815
* elf.c (phdr_sorter): Delete.
(assign_file_positions_except_relocs): Do not sort program
headers.
2016-11-25 Jon Turney <jon.turney@dronecode.org.uk> 2016-11-25 Jon Turney <jon.turney@dronecode.org.uk>
PR ld/20193 PR ld/20193

View File

@ -5854,52 +5854,6 @@ find_section_in_list (unsigned int i, elf_section_list * list)
return list; return list;
} }
/* Compare function used when sorting the program header table.
The ELF standard requires that a PT_PHDR segment, if present,
must appear before any PT_LOAD segments. It also requires
that all PT_LOAD segments are sorted into order of increasing
p_vaddr. */
static signed int
phdr_sorter (const void * a, const void * b)
{
Elf_Internal_Phdr * ahdr = (Elf_Internal_Phdr *) a;
Elf_Internal_Phdr * bhdr = (Elf_Internal_Phdr *) b;
switch (ahdr->p_type)
{
case PT_LOAD:
switch (bhdr->p_type)
{
case PT_PHDR:
return 1;
case PT_LOAD:
if (ahdr->p_vaddr < bhdr->p_vaddr)
return -1;
if (ahdr->p_vaddr > bhdr->p_vaddr)
return 1;
return 0;
default:
return 0;
}
break;
case PT_PHDR:
switch (bhdr->p_type)
{
case PT_PHDR:
_bfd_error_handler (_("error: multiple PHDR segments detecetd"));
return 0;
case PT_LOAD:
return -1;
default:
return 0;
}
break;
default:
return 0;
}
}
/* Work out the file positions of all the sections. This is called by /* Work out the file positions of all the sections. This is called by
_bfd_elf_compute_section_file_positions. All the section sizes and _bfd_elf_compute_section_file_positions. All the section sizes and
VMAs must be known before this is called. VMAs must be known before this is called.
@ -5963,7 +5917,6 @@ assign_file_positions_except_relocs (bfd *abfd,
} }
else else
{ {
Elf_Internal_Phdr * map;
unsigned int alloc; unsigned int alloc;
/* Assign file positions for the loaded sections based on the /* Assign file positions for the loaded sections based on the
@ -6007,22 +5960,24 @@ assign_file_positions_except_relocs (bfd *abfd,
if (alloc == 0) if (alloc == 0)
return TRUE; return TRUE;
map = (Elf_Internal_Phdr *) xmalloc (alloc * sizeof (* tdata->phdr));
memcpy (map, tdata->phdr, alloc * sizeof (* tdata->phdr));
qsort (map, alloc, sizeof (* tdata->phdr), phdr_sorter);
/* PR ld/20815 - Check that the program header segment, if present, will /* PR ld/20815 - Check that the program header segment, if present, will
be loaded into memory. FIXME: The check below is not sufficient as be loaded into memory. FIXME: The check below is not sufficient as
really all PT_LOAD segments should be checked before issuing an error really all PT_LOAD segments should be checked before issuing an error
message. Plus the PHDR segment does not have to be the first segment message. Plus the PHDR segment does not have to be the first segment
in the program header table. But this version of the check should in the program header table. But this version of the check should
catch all real world use cases. */ catch all real world use cases.
FIXME: We used to have code here to sort the PT_LOAD segments into
ascending order, as per the ELF spec. But this breaks some programs,
including the Linux kernel. But really either the spec should be
changed or the programs updated. */
if (alloc > 1 if (alloc > 1
&& map[0].p_type == PT_PHDR && tdata->phdr[0].p_type == PT_PHDR
&& ! bed->elf_backend_allow_non_load_phdr (abfd, map, alloc) && ! bed->elf_backend_allow_non_load_phdr (abfd, tdata->phdr, alloc)
&& map[1].p_type == PT_LOAD && tdata->phdr[1].p_type == PT_LOAD
&& (map[1].p_vaddr > map[0].p_vaddr && (tdata->phdr[1].p_vaddr > tdata->phdr[0].p_vaddr
|| (map[1].p_vaddr + map[1].p_memsz) < (map[0].p_vaddr + map[0].p_memsz))) || (tdata->phdr[1].p_vaddr + tdata->phdr[1].p_memsz)
< (tdata->phdr[0].p_vaddr + tdata->phdr[0].p_memsz)))
{ {
/* The fix for this error is usually to edit the linker script being /* The fix for this error is usually to edit the linker script being
used and set up the program headers manually. Either that or used and set up the program headers manually. Either that or
@ -6030,18 +5985,12 @@ assign_file_positions_except_relocs (bfd *abfd,
_bfd_error_handler (_("\ _bfd_error_handler (_("\
%B: error: PHDR segment not covered by LOAD segment"), %B: error: PHDR segment not covered by LOAD segment"),
abfd); abfd);
free (map);
return FALSE; return FALSE;
} }
if (bfd_seek (abfd, (bfd_signed_vma) bed->s->sizeof_ehdr, SEEK_SET) != 0 if (bfd_seek (abfd, (bfd_signed_vma) bed->s->sizeof_ehdr, SEEK_SET) != 0
|| bed->s->write_out_phdrs (abfd, map, alloc) != 0) || bed->s->write_out_phdrs (abfd, tdata->phdr, alloc) != 0)
{ return FALSE;
free (map);
return FALSE;
}
free (map);
} }
return TRUE; return TRUE;