PR29495, rewrite_elf_program_header looping
This patch, in order of significance: 1) Replaces some macros with inline functions. 2) Those inline functions catch and avoid arithmetic overflows when comparing addresses. 3) When assigning sections to segments (IS_SECTION_IN_INPUT_SEGMENT) use bed->want_p_paddr_set_to_zero to decide whether lma vs p_paddr or vma vs p_vaddr should be tested. When remapping, use the same test, and use is_note rather than the more restrictive IS_COREFILE_NOTE. It's important that the later tests not be more restrictive. If they are it can lead to the situation triggered by the testcases, where a section seemingly didn't fit and thus needed a new mapping. It didn't fit the new mapping either, and this repeated until memory exhausted. PR 29495 * elf.c (SEGMENT_END, SECTION_SIZE, IS_CONTAINED_BY_VMA): Delete. (IS_CONTAINED_BY_LMA, IS_NOTE, IS_COREFILE_NOTE): Delete. (segment_size, segment_end, section_size): New inline function. (is_contained_by, is_note): Likewise. (rewrite_elf_program_header): Use new functions.
This commit is contained in:
parent
390ddd6f68
commit
45d92439ae
1 changed files with 75 additions and 65 deletions
140
bfd/elf.c
140
bfd/elf.c
|
@ -6886,6 +6886,66 @@ _bfd_elf_symbol_from_bfd_symbol (bfd *abfd, asymbol **asym_ptr_ptr)
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bfd_vma
|
||||||
|
segment_size (Elf_Internal_Phdr *segment)
|
||||||
|
{
|
||||||
|
return (segment->p_memsz > segment->p_filesz
|
||||||
|
? segment->p_memsz : segment->p_filesz);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Returns the end address of the segment + 1. */
|
||||||
|
static inline bfd_vma
|
||||||
|
segment_end (Elf_Internal_Phdr *segment, bfd_vma start)
|
||||||
|
{
|
||||||
|
return start + segment_size (segment);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bfd_size_type
|
||||||
|
section_size (asection *section, Elf_Internal_Phdr *segment)
|
||||||
|
{
|
||||||
|
if ((section->flags & SEC_HAS_CONTENTS) != 0
|
||||||
|
|| (section->flags & SEC_THREAD_LOCAL) == 0
|
||||||
|
|| segment->p_type == PT_TLS)
|
||||||
|
return section->size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns TRUE if the given section is contained within the given
|
||||||
|
segment. LMA addresses are compared against PADDR when
|
||||||
|
bed->want_p_paddr_set_to_zero is false, VMA against VADDR when true. */
|
||||||
|
static bool
|
||||||
|
is_contained_by (asection *section, Elf_Internal_Phdr *segment,
|
||||||
|
bfd_vma paddr, bfd_vma vaddr, unsigned int opb,
|
||||||
|
const struct elf_backend_data *bed)
|
||||||
|
{
|
||||||
|
bfd_vma seg_addr = !bed->want_p_paddr_set_to_zero ? paddr : vaddr;
|
||||||
|
bfd_vma addr = !bed->want_p_paddr_set_to_zero ? section->lma : section->vma;
|
||||||
|
bfd_vma octet;
|
||||||
|
if (_bfd_mul_overflow (addr, opb, &octet))
|
||||||
|
return false;
|
||||||
|
/* The third and fourth lines below are testing that the section end
|
||||||
|
address is within the segment. It's written this way to avoid
|
||||||
|
overflow. Add seg_addr + section_size to both sides of the
|
||||||
|
inequality to make it obvious. */
|
||||||
|
return (octet >= seg_addr
|
||||||
|
&& segment_size (segment) >= section_size (section, segment)
|
||||||
|
&& (octet - seg_addr
|
||||||
|
<= segment_size (segment) - section_size (section, segment)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle PT_NOTE segment. */
|
||||||
|
static bool
|
||||||
|
is_note (Elf_Internal_Phdr *p, asection *s)
|
||||||
|
{
|
||||||
|
return (p->p_type == PT_NOTE
|
||||||
|
&& elf_section_type (s) == SHT_NOTE
|
||||||
|
&& (ufile_ptr) s->filepos >= p->p_offset
|
||||||
|
&& p->p_filesz >= s->size
|
||||||
|
&& ((ufile_ptr) s->filepos - p->p_offset
|
||||||
|
<= p->p_filesz - s->size));
|
||||||
|
}
|
||||||
|
|
||||||
/* Rewrite program header information. */
|
/* Rewrite program header information. */
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -6914,47 +6974,6 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd, bfd_vma maxpagesize)
|
||||||
|
|
||||||
num_segments = elf_elfheader (ibfd)->e_phnum;
|
num_segments = elf_elfheader (ibfd)->e_phnum;
|
||||||
|
|
||||||
/* Returns the end address of the segment + 1. */
|
|
||||||
#define SEGMENT_END(segment, start) \
|
|
||||||
(start + (segment->p_memsz > segment->p_filesz \
|
|
||||||
? segment->p_memsz : segment->p_filesz))
|
|
||||||
|
|
||||||
#define SECTION_SIZE(section, segment) \
|
|
||||||
(((section->flags & (SEC_HAS_CONTENTS | SEC_THREAD_LOCAL)) \
|
|
||||||
!= SEC_THREAD_LOCAL || segment->p_type == PT_TLS) \
|
|
||||||
? section->size : 0)
|
|
||||||
|
|
||||||
/* Returns TRUE if the given section is contained within
|
|
||||||
the given segment. VMA addresses are compared. */
|
|
||||||
#define IS_CONTAINED_BY_VMA(section, segment, opb) \
|
|
||||||
(section->vma * (opb) >= segment->p_vaddr \
|
|
||||||
&& (section->vma * (opb) + SECTION_SIZE (section, segment) \
|
|
||||||
<= (SEGMENT_END (segment, segment->p_vaddr))))
|
|
||||||
|
|
||||||
/* Returns TRUE if the given section is contained within
|
|
||||||
the given segment. LMA addresses are compared. */
|
|
||||||
#define IS_CONTAINED_BY_LMA(section, segment, base, opb) \
|
|
||||||
(section->lma * (opb) >= base \
|
|
||||||
&& (section->lma + SECTION_SIZE (section, segment) / (opb) >= section->lma) \
|
|
||||||
&& (section->lma * (opb) + SECTION_SIZE (section, segment) \
|
|
||||||
<= SEGMENT_END (segment, base)))
|
|
||||||
|
|
||||||
/* Handle PT_NOTE segment. */
|
|
||||||
#define IS_NOTE(p, s) \
|
|
||||||
(p->p_type == PT_NOTE \
|
|
||||||
&& elf_section_type (s) == SHT_NOTE \
|
|
||||||
&& (bfd_vma) s->filepos >= p->p_offset \
|
|
||||||
&& ((bfd_vma) s->filepos + s->size \
|
|
||||||
<= p->p_offset + p->p_filesz))
|
|
||||||
|
|
||||||
/* Special case: corefile "NOTE" section containing regs, prpsinfo
|
|
||||||
etc. */
|
|
||||||
#define IS_COREFILE_NOTE(p, s) \
|
|
||||||
(IS_NOTE (p, s) \
|
|
||||||
&& bfd_get_format (ibfd) == bfd_core \
|
|
||||||
&& s->vma == 0 \
|
|
||||||
&& s->lma == 0)
|
|
||||||
|
|
||||||
/* The complicated case when p_vaddr is 0 is to handle the Solaris
|
/* The complicated case when p_vaddr is 0 is to handle the Solaris
|
||||||
linker, which generates a PT_INTERP section with p_vaddr and
|
linker, which generates a PT_INTERP section with p_vaddr and
|
||||||
p_memsz set to 0. */
|
p_memsz set to 0. */
|
||||||
|
@ -6983,11 +7002,10 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd, bfd_vma maxpagesize)
|
||||||
8. PT_DYNAMIC should not contain empty sections at the beginning
|
8. PT_DYNAMIC should not contain empty sections at the beginning
|
||||||
(with the possible exception of .dynamic). */
|
(with the possible exception of .dynamic). */
|
||||||
#define IS_SECTION_IN_INPUT_SEGMENT(section, segment, bed, opb) \
|
#define IS_SECTION_IN_INPUT_SEGMENT(section, segment, bed, opb) \
|
||||||
((((segment->p_paddr \
|
(((is_contained_by (section, segment, segment->p_paddr, \
|
||||||
? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr, opb) \
|
segment->p_vaddr, opb, bed) \
|
||||||
: IS_CONTAINED_BY_VMA (section, segment, opb)) \
|
|
||||||
&& (section->flags & SEC_ALLOC) != 0) \
|
&& (section->flags & SEC_ALLOC) != 0) \
|
||||||
|| IS_NOTE (segment, section)) \
|
|| is_note (segment, section)) \
|
||||||
&& segment->p_type != PT_GNU_STACK \
|
&& segment->p_type != PT_GNU_STACK \
|
||||||
&& (segment->p_type != PT_TLS \
|
&& (segment->p_type != PT_TLS \
|
||||||
|| (section->flags & SEC_THREAD_LOCAL)) \
|
|| (section->flags & SEC_THREAD_LOCAL)) \
|
||||||
|
@ -6995,7 +7013,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd, bfd_vma maxpagesize)
|
||||||
|| segment->p_type == PT_TLS \
|
|| segment->p_type == PT_TLS \
|
||||||
|| (section->flags & SEC_THREAD_LOCAL) == 0) \
|
|| (section->flags & SEC_THREAD_LOCAL) == 0) \
|
||||||
&& (segment->p_type != PT_DYNAMIC \
|
&& (segment->p_type != PT_DYNAMIC \
|
||||||
|| SECTION_SIZE (section, segment) > 0 \
|
|| section_size (section, segment) > 0 \
|
||||||
|| (segment->p_paddr \
|
|| (segment->p_paddr \
|
||||||
? segment->p_paddr != section->lma * (opb) \
|
? segment->p_paddr != section->lma * (opb) \
|
||||||
: segment->p_vaddr != section->vma * (opb)) \
|
: segment->p_vaddr != section->vma * (opb)) \
|
||||||
|
@ -7010,7 +7028,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd, bfd_vma maxpagesize)
|
||||||
|
|
||||||
/* Returns TRUE iff seg1 starts after the end of seg2. */
|
/* Returns TRUE iff seg1 starts after the end of seg2. */
|
||||||
#define SEGMENT_AFTER_SEGMENT(seg1, seg2, field) \
|
#define SEGMENT_AFTER_SEGMENT(seg1, seg2, field) \
|
||||||
(seg1->field >= SEGMENT_END (seg2, seg2->field))
|
(seg1->field >= segment_end (seg2, seg2->field))
|
||||||
|
|
||||||
/* Returns TRUE iff seg1 and seg2 overlap. Segments overlap iff both
|
/* Returns TRUE iff seg1 and seg2 overlap. Segments overlap iff both
|
||||||
their VMA address ranges and their LMA address ranges overlap.
|
their VMA address ranges and their LMA address ranges overlap.
|
||||||
|
@ -7090,8 +7108,8 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd, bfd_vma maxpagesize)
|
||||||
{
|
{
|
||||||
/* Extend SEGMENT2 to include SEGMENT and then delete
|
/* Extend SEGMENT2 to include SEGMENT and then delete
|
||||||
SEGMENT. */
|
SEGMENT. */
|
||||||
extra_length = (SEGMENT_END (segment, segment->p_vaddr)
|
extra_length = (segment_end (segment, segment->p_vaddr)
|
||||||
- SEGMENT_END (segment2, segment2->p_vaddr));
|
- segment_end (segment2, segment2->p_vaddr));
|
||||||
|
|
||||||
if (extra_length > 0)
|
if (extra_length > 0)
|
||||||
{
|
{
|
||||||
|
@ -7110,8 +7128,8 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd, bfd_vma maxpagesize)
|
||||||
{
|
{
|
||||||
/* Extend SEGMENT to include SEGMENT2 and then delete
|
/* Extend SEGMENT to include SEGMENT2 and then delete
|
||||||
SEGMENT2. */
|
SEGMENT2. */
|
||||||
extra_length = (SEGMENT_END (segment2, segment2->p_vaddr)
|
extra_length = (segment_end (segment2, segment2->p_vaddr)
|
||||||
- SEGMENT_END (segment, segment->p_vaddr));
|
- segment_end (segment, segment->p_vaddr));
|
||||||
|
|
||||||
if (extra_length > 0)
|
if (extra_length > 0)
|
||||||
{
|
{
|
||||||
|
@ -7311,11 +7329,9 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd, bfd_vma maxpagesize)
|
||||||
|
|
||||||
/* Match up the physical address of the segment with the
|
/* Match up the physical address of the segment with the
|
||||||
LMA address of the output section. */
|
LMA address of the output section. */
|
||||||
if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr,
|
if (is_contained_by (output_section, segment, map->p_paddr,
|
||||||
opb)
|
map->p_paddr + map->p_vaddr_offset, opb, bed)
|
||||||
|| IS_COREFILE_NOTE (segment, section)
|
|| is_note (segment, section))
|
||||||
|| (bed->want_p_paddr_set_to_zero
|
|
||||||
&& IS_CONTAINED_BY_VMA (output_section, segment, opb)))
|
|
||||||
{
|
{
|
||||||
if (matching_lma == NULL
|
if (matching_lma == NULL
|
||||||
|| output_section->lma < matching_lma->lma)
|
|| output_section->lma < matching_lma->lma)
|
||||||
|
@ -7431,9 +7447,9 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd, bfd_vma maxpagesize)
|
||||||
|
|
||||||
BFD_ASSERT (output_section != NULL);
|
BFD_ASSERT (output_section != NULL);
|
||||||
|
|
||||||
if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr,
|
if (is_contained_by (output_section, segment, map->p_paddr,
|
||||||
opb)
|
map->p_paddr + map->p_vaddr_offset, opb, bed)
|
||||||
|| IS_COREFILE_NOTE (segment, section))
|
|| is_note (segment, section))
|
||||||
{
|
{
|
||||||
if (map->count == 0)
|
if (map->count == 0)
|
||||||
{
|
{
|
||||||
|
@ -7556,12 +7572,6 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd, bfd_vma maxpagesize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef SEGMENT_END
|
|
||||||
#undef SECTION_SIZE
|
|
||||||
#undef IS_CONTAINED_BY_VMA
|
|
||||||
#undef IS_CONTAINED_BY_LMA
|
|
||||||
#undef IS_NOTE
|
|
||||||
#undef IS_COREFILE_NOTE
|
|
||||||
#undef IS_SOLARIS_PT_INTERP
|
#undef IS_SOLARIS_PT_INTERP
|
||||||
#undef IS_SECTION_IN_INPUT_SEGMENT
|
#undef IS_SECTION_IN_INPUT_SEGMENT
|
||||||
#undef INCLUDE_SECTION_IN_SEGMENT
|
#undef INCLUDE_SECTION_IN_SEGMENT
|
||||||
|
|
Loading…
Add table
Reference in a new issue