mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-28 23:39:35 +08:00
Don't convert R_X86_64_GOTPCREL if it will overflow
When converting "mov foo@GOTPCREL(%rip), %reg" to "lea foo(%rip), %reg" with R_X86_64_PC32 relocation, it may overflow if the target section is more than 2GB away. This patch estimates distance between mov instruction and the target section. We convert R_X86_64_GOTPCREL to R_X86_64_PC32 only if their distance is less than 2GB. PR ld/18591 * elf64-x86-64.c (elf_x86_64_convert_mov_to_lea): Don't convert R_X86_64_GOTPCREL to R_X86_64_PC32 if it will cause relocation overflow.
This commit is contained in:
@ -1,3 +1,10 @@
|
|||||||
|
2015-06-24 H.J. Lu <hongjiu.lu@intel.com>
|
||||||
|
|
||||||
|
PR ld/18591
|
||||||
|
* elf64-x86-64.c (elf_x86_64_convert_mov_to_lea): Don't convert
|
||||||
|
R_X86_64_GOTPCREL to R_X86_64_PC32 if it will cause relocation
|
||||||
|
overflow.
|
||||||
|
|
||||||
2015-06-23 Jiong Wang <jiong.wang@arm.com>
|
2015-06-23 Jiong Wang <jiong.wang@arm.com>
|
||||||
|
|
||||||
* elfnn-aarch64.c (aarch64_readonly_dynrelocs): New function.
|
* elfnn-aarch64.c (aarch64_readonly_dynrelocs): New function.
|
||||||
|
@ -2901,6 +2901,7 @@ elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec,
|
|||||||
bfd_boolean changed_contents;
|
bfd_boolean changed_contents;
|
||||||
bfd_boolean changed_relocs;
|
bfd_boolean changed_relocs;
|
||||||
bfd_signed_vma *local_got_refcounts;
|
bfd_signed_vma *local_got_refcounts;
|
||||||
|
bfd_vma maxpagesize;
|
||||||
|
|
||||||
/* Don't even try to convert non-ELF outputs. */
|
/* Don't even try to convert non-ELF outputs. */
|
||||||
if (!is_elf_hash_table (link_info->hash))
|
if (!is_elf_hash_table (link_info->hash))
|
||||||
@ -2925,6 +2926,7 @@ elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec,
|
|||||||
changed_contents = FALSE;
|
changed_contents = FALSE;
|
||||||
changed_relocs = FALSE;
|
changed_relocs = FALSE;
|
||||||
local_got_refcounts = elf_local_got_refcounts (abfd);
|
local_got_refcounts = elf_local_got_refcounts (abfd);
|
||||||
|
maxpagesize = get_elf_backend_data (abfd)->maxpagesize;
|
||||||
|
|
||||||
/* Get the section contents. */
|
/* Get the section contents. */
|
||||||
if (elf_section_data (sec)->this_hdr.contents != NULL)
|
if (elf_section_data (sec)->this_hdr.contents != NULL)
|
||||||
@ -2942,10 +2944,27 @@ elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec,
|
|||||||
unsigned int r_symndx = htab->r_sym (irel->r_info);
|
unsigned int r_symndx = htab->r_sym (irel->r_info);
|
||||||
unsigned int indx;
|
unsigned int indx;
|
||||||
struct elf_link_hash_entry *h;
|
struct elf_link_hash_entry *h;
|
||||||
|
asection *tsec;
|
||||||
|
char symtype;
|
||||||
|
bfd_vma toff, roff;
|
||||||
|
enum {
|
||||||
|
none, local, global
|
||||||
|
} convert_mov_to_lea;
|
||||||
|
|
||||||
if (r_type != R_X86_64_GOTPCREL)
|
if (r_type != R_X86_64_GOTPCREL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
roff = irel->r_offset;
|
||||||
|
|
||||||
|
/* Don't convert R_X86_64_GOTPCREL relocation if it isn't for mov
|
||||||
|
instruction. */
|
||||||
|
if (roff < 2
|
||||||
|
|| bfd_get_8 (abfd, contents + roff - 2) != 0x8b)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tsec = NULL;
|
||||||
|
convert_mov_to_lea = none;
|
||||||
|
|
||||||
/* Get the symbol referred to by the reloc. */
|
/* Get the symbol referred to by the reloc. */
|
||||||
if (r_symndx < symtab_hdr->sh_info)
|
if (r_symndx < symtab_hdr->sh_info)
|
||||||
{
|
{
|
||||||
@ -2954,46 +2973,140 @@ elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec,
|
|||||||
isym = bfd_sym_from_r_symndx (&htab->sym_cache,
|
isym = bfd_sym_from_r_symndx (&htab->sym_cache,
|
||||||
abfd, r_symndx);
|
abfd, r_symndx);
|
||||||
|
|
||||||
/* STT_GNU_IFUNC must keep R_X86_64_GOTPCREL relocation. */
|
symtype = ELF_ST_TYPE (isym->st_info);
|
||||||
if (ELF_ST_TYPE (isym->st_info) != STT_GNU_IFUNC
|
|
||||||
&& irel->r_offset >= 2
|
/* STT_GNU_IFUNC must keep R_X86_64_GOTPCREL relocation and
|
||||||
&& bfd_get_8 (abfd, contents + irel->r_offset - 2) == 0x8b)
|
skip relocation against undefined symbols. */
|
||||||
|
if (symtype != STT_GNU_IFUNC && isym->st_shndx != SHN_UNDEF)
|
||||||
{
|
{
|
||||||
bfd_put_8 (abfd, 0x8d, contents + irel->r_offset - 2);
|
if (isym->st_shndx == SHN_ABS)
|
||||||
irel->r_info = htab->r_info (r_symndx, R_X86_64_PC32);
|
tsec = bfd_abs_section_ptr;
|
||||||
if (local_got_refcounts != NULL
|
else if (isym->st_shndx == SHN_COMMON)
|
||||||
&& local_got_refcounts[r_symndx] > 0)
|
tsec = bfd_com_section_ptr;
|
||||||
local_got_refcounts[r_symndx] -= 1;
|
else if (isym->st_shndx == SHN_X86_64_LCOMMON)
|
||||||
changed_contents = TRUE;
|
tsec = &_bfd_elf_large_com_section;
|
||||||
changed_relocs = TRUE;
|
else
|
||||||
|
tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
|
||||||
|
|
||||||
|
toff = isym->st_value;
|
||||||
|
convert_mov_to_lea = local;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
indx = r_symndx - symtab_hdr->sh_info;
|
||||||
|
h = elf_sym_hashes (abfd)[indx];
|
||||||
|
BFD_ASSERT (h != NULL);
|
||||||
|
|
||||||
|
while (h->root.type == bfd_link_hash_indirect
|
||||||
|
|| h->root.type == bfd_link_hash_warning)
|
||||||
|
h = (struct elf_link_hash_entry *) h->root.u.i.link;
|
||||||
|
|
||||||
|
/* STT_GNU_IFUNC must keep R_X86_64_GOTPCREL relocation. We also
|
||||||
|
avoid optimizing _DYNAMIC since ld.so may use its link-time
|
||||||
|
address. */
|
||||||
|
if (h->def_regular
|
||||||
|
&& h->type != STT_GNU_IFUNC
|
||||||
|
&& h != htab->elf.hdynamic
|
||||||
|
&& SYMBOL_REFERENCES_LOCAL (link_info, h))
|
||||||
|
{
|
||||||
|
tsec = h->root.u.def.section;
|
||||||
|
toff = h->root.u.def.value;
|
||||||
|
symtype = h->type;
|
||||||
|
convert_mov_to_lea = global;
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
indx = r_symndx - symtab_hdr->sh_info;
|
if (convert_mov_to_lea == none)
|
||||||
h = elf_sym_hashes (abfd)[indx];
|
continue;
|
||||||
BFD_ASSERT (h != NULL);
|
|
||||||
|
|
||||||
while (h->root.type == bfd_link_hash_indirect
|
if (tsec->sec_info_type == SEC_INFO_TYPE_MERGE)
|
||||||
|| h->root.type == bfd_link_hash_warning)
|
{
|
||||||
h = (struct elf_link_hash_entry *) h->root.u.i.link;
|
/* At this stage in linking, no SEC_MERGE symbol has been
|
||||||
|
adjusted, so all references to such symbols need to be
|
||||||
/* STT_GNU_IFUNC must keep R_X86_64_GOTPCREL relocation. We also
|
passed through _bfd_merged_section_offset. (Later, in
|
||||||
avoid optimizing _DYNAMIC since ld.so may use its link-time
|
relocate_section, all SEC_MERGE symbols *except* for
|
||||||
address. */
|
section symbols have been adjusted.)
|
||||||
if (h->def_regular
|
|
||||||
&& h->type != STT_GNU_IFUNC
|
gas may reduce relocations against symbols in SEC_MERGE
|
||||||
&& h != htab->elf.hdynamic
|
sections to a relocation against the section symbol when
|
||||||
&& SYMBOL_REFERENCES_LOCAL (link_info, h)
|
the original addend was zero. When the reloc is against
|
||||||
&& irel->r_offset >= 2
|
a section symbol we should include the addend in the
|
||||||
&& bfd_get_8 (abfd, contents + irel->r_offset - 2) == 0x8b)
|
offset passed to _bfd_merged_section_offset, since the
|
||||||
|
location of interest is the original symbol. On the
|
||||||
|
other hand, an access to "sym+addend" where "sym" is not
|
||||||
|
a section symbol should not include the addend; Such an
|
||||||
|
access is presumed to be an offset from "sym"; The
|
||||||
|
location of interest is just "sym". */
|
||||||
|
if (symtype == STT_SECTION)
|
||||||
|
toff += irel->r_addend;
|
||||||
|
|
||||||
|
toff = _bfd_merged_section_offset (abfd, &tsec,
|
||||||
|
elf_section_data (tsec)->sec_info,
|
||||||
|
toff);
|
||||||
|
|
||||||
|
if (symtype != STT_SECTION)
|
||||||
|
toff += irel->r_addend;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
toff += irel->r_addend;
|
||||||
|
|
||||||
|
/* Don't convert if R_X86_64_PC32 relocation overflows. */
|
||||||
|
if (tsec->output_section == sec->output_section)
|
||||||
|
{
|
||||||
|
if ((toff - roff + 0x80000000) > 0xffffffff)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
asection *asect;
|
||||||
|
bfd_size_type size;
|
||||||
|
|
||||||
|
/* At this point, we don't know the load addresses of TSEC
|
||||||
|
section nor SEC section. We estimate the distrance between
|
||||||
|
SEC and TSEC. */
|
||||||
|
size = 0;
|
||||||
|
for (asect = sec->output_section;
|
||||||
|
asect != NULL && asect != tsec->output_section;
|
||||||
|
asect = asect->next)
|
||||||
|
{
|
||||||
|
asection *i;
|
||||||
|
for (i = asect->output_section->map_head.s;
|
||||||
|
i != NULL;
|
||||||
|
i = i->map_head.s)
|
||||||
|
{
|
||||||
|
size = align_power (size, i->alignment_power);
|
||||||
|
size += i->size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't convert R_X86_64_GOTPCREL if TSEC isn't placed after
|
||||||
|
SEC. */
|
||||||
|
if (asect == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Take PT_GNU_RELRO segment into account by adding
|
||||||
|
maxpagesize. */
|
||||||
|
if ((toff + size + maxpagesize - roff + 0x80000000)
|
||||||
|
> 0xffffffff)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bfd_put_8 (abfd, 0x8d, contents + roff - 2);
|
||||||
|
irel->r_info = htab->r_info (r_symndx, R_X86_64_PC32);
|
||||||
|
changed_contents = TRUE;
|
||||||
|
changed_relocs = TRUE;
|
||||||
|
|
||||||
|
if (convert_mov_to_lea == local)
|
||||||
|
{
|
||||||
|
if (local_got_refcounts != NULL
|
||||||
|
&& local_got_refcounts[r_symndx] > 0)
|
||||||
|
local_got_refcounts[r_symndx] -= 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
bfd_put_8 (abfd, 0x8d, contents + irel->r_offset - 2);
|
|
||||||
irel->r_info = htab->r_info (r_symndx, R_X86_64_PC32);
|
|
||||||
if (h->got.refcount > 0)
|
if (h->got.refcount > 0)
|
||||||
h->got.refcount -= 1;
|
h->got.refcount -= 1;
|
||||||
changed_contents = TRUE;
|
|
||||||
changed_relocs = TRUE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user