diff options
author | Jiong Wang <jiong.wang@arm.com> | 2016-01-20 16:57:59 +0000 |
---|---|---|
committer | Jiong Wang <jiong.wang@arm.com> | 2016-01-21 09:57:09 +0000 |
commit | 2f340668a9a7c00f8813b097b157b07fba8cfa82 (patch) | |
tree | e5cf0bc883324833481f0352a698c54bf21d9096 /bfd/elfnn-aarch64.c | |
parent | aeb7056972f1b383578204b9151b0ae6d8c1df81 (diff) | |
download | gdb-2f340668a9a7c00f8813b097b157b07fba8cfa82.zip gdb-2f340668a9a7c00f8813b097b157b07fba8cfa82.tar.gz gdb-2f340668a9a7c00f8813b097b157b07fba8cfa82.tar.bz2 |
[AArch64] Relax long branch veneer insertion for non STT_FUNC symbol
As defined at AArch64 ELF Specification (4.6.7 Call and Jump
relocations), symbol with type of non STT_FUNC but in different input
section with relocation place should insert long branch veneer also.
Meanwhile the current long branch veneer infrastructure havn't considered
the situation where the branch destination is "sym_value + rela->addend".
This was OK because we only insert veneer for long call destination is
STT_FUNC symbol for which the addend is always zero. But as we relax the
support to other situations by this patch, we need to handle addend be
non-zero value. For example, for static function, relocation against
"local symbol" are turned into relocation against "section symbol + offset"
where there is a valid addend.
bfd/
* elfnn-aarch64.c (aarch64_type_of_stub): Allow insert long branch
veneer for sym_sec != input_sec.
(elfNN_aarch64_size_stub): Support STT_SECTION symbol.
(elfNN_aarch64_final_link_relocate): Take rela addend into account when
calculation destination.
ld/
* testsuite/ld-aarch64/farcall-section.d: Delete.
* testsuite/ld-aarch64/farcall-section.s: Delete.
* testsuite/ld-aarch64/farcall-b-section.d: New expectation file.
* testsuite/ld-aarch64/farcall-bl-section.d: Likewise.
* testsuite/ld-aarch64/farcall-b-section.s: New testcase.
* testsuite/ld-aarch64/farcall-bl-section.s: Likewise.
* testsuite/ld-aarch64/aarch64-elf.exp: Likewise.
Diffstat (limited to 'bfd/elfnn-aarch64.c')
-rw-r--r-- | bfd/elfnn-aarch64.c | 25 |
1 files changed, 19 insertions, 6 deletions
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c index 70251f1..292470df 100644 --- a/bfd/elfnn-aarch64.c +++ b/bfd/elfnn-aarch64.c @@ -2655,7 +2655,7 @@ aarch64_type_of_stub (struct bfd_link_info *info, bfd_boolean via_plt_p; if (st_type != STT_FUNC - && (sym_sec != bfd_abs_section_ptr)) + && (sym_sec == input_sec)) return stub_type; globals = elf_aarch64_hash_table (info); @@ -4174,7 +4174,7 @@ elfNN_aarch64_size_stubs (bfd *output_bfd, goto error_ret_free_internal; } - stub_entry->target_value = sym_value; + stub_entry->target_value = sym_value + irela->r_addend; stub_entry->target_section = sym_sec; stub_entry->stub_type = stub_type; stub_entry->h = hash; @@ -5280,15 +5280,28 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto, /* Check if a stub has to be inserted because the destination is too far away. */ struct elf_aarch64_stub_hash_entry *stub_entry = NULL; - if (! aarch64_valid_branch_p (value, place)) + + /* If the branch destination is directed to plt stub, "value" will be + the final destination, otherwise we should plus signed_addend, it may + contain non-zero value, for example call to local function symbol + which are turned into "sec_sym + sec_off", and sec_off is kept in + signed_addend. */ + if (! aarch64_valid_branch_p (via_plt_p ? value : value + signed_addend, + place)) /* The target is out of reach, so redirect the branch to the local stub for this function. */ stub_entry = elfNN_aarch64_get_stub_entry (input_section, sym_sec, h, rel, globals); if (stub_entry != NULL) - value = (stub_entry->stub_offset - + stub_entry->stub_sec->output_offset - + stub_entry->stub_sec->output_section->vma); + { + value = (stub_entry->stub_offset + + stub_entry->stub_sec->output_offset + + stub_entry->stub_sec->output_section->vma); + + /* We have redirected the destination to stub entry address, + so ignore any addend record in the original rela entry. */ + signed_addend = 0; + } } value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value, signed_addend, weak_undef_p); |