diff options
author | Sterling Augustine <augustine.sterling@gmail.com> | 2011-01-25 13:59:13 -0800 |
---|---|---|
committer | Max Filippov <jcmvbkbc@gmail.com> | 2014-09-23 03:41:35 +0400 |
commit | 331ed1307b93d3ff77d248bdf2f7b79a20851457 (patch) | |
tree | 826cae7557e96829755e148e166d3af207796208 /bfd | |
parent | 68f34464821105e0c74a0ce16c5d26d4c3e1d20c (diff) | |
download | gdb-331ed1307b93d3ff77d248bdf2f7b79a20851457.zip gdb-331ed1307b93d3ff77d248bdf2f7b79a20851457.tar.gz gdb-331ed1307b93d3ff77d248bdf2f7b79a20851457.tar.bz2 |
Fix 'call8: call target out of range' xtensa ld relaxation bug
During link-time relaxation distance between cross-section call site and
its target may grow, producing 'call target out of range' error for
relaxed calls. Be more conservative when calculating whether or not a
callx can be converted to a straight call.
2014-09-23 Sterling Augustine <augustine.sterling@gmail.com>
bfd/
* elf32-xtensa.c (is_resolvable_asm_expansion): for cross-section
call relaxation use furthermost addresses where call source and
destination can be to check whether it's in the range of a direct
call.
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 7 | ||||
-rw-r--r-- | bfd/elf32-xtensa.c | 41 |
2 files changed, 44 insertions, 4 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 2fc0e1e..d8559ea 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,10 @@ +2014-09-23 Sterling Augustine <augustine.sterling@gmail.com> + + * elf32-xtensa.c (is_resolvable_asm_expansion): for cross-section + call relaxation use furthermost addresses where call source and + destination can be to check whether it's in the range of a direct + call. + 2014-09-22 Alan Modra <amodra@gmail.com> * elf-eh-frame.c (_bfd_elf_write_section_eh_frame_hdr): Don't return diff --git a/bfd/elf32-xtensa.c b/bfd/elf32-xtensa.c index 09862e3..e32496a 100644 --- a/bfd/elf32-xtensa.c +++ b/bfd/elf32-xtensa.c @@ -7124,10 +7124,43 @@ is_resolvable_asm_expansion (bfd *abfd, || is_reloc_sym_weak (abfd, irel))) return FALSE; - self_address = (sec->output_section->vma - + sec->output_offset + irel->r_offset + 3); - dest_address = (target_sec->output_section->vma - + target_sec->output_offset + target_offset); + if (target_sec->output_section != sec->output_section) + { + /* If the two sections are sufficiently far away that relaxation + might take the call out of range, we can't simplify. For + example, a positive displacement call into another memory + could get moved to a lower address due to literal removal, + but the destination won't move, and so the displacment might + get larger. + + If the displacement is negative, assume the destination could + move as far back as the start of the output section. The + self_address will be at least as far into the output section + as it is prior to relaxation. + + If the displacement is postive, assume the destination will be in + it's pre-relaxed location (because relaxation only makes sections + smaller). The self_address could go all the way to the beginning + of the output section. */ + + dest_address = target_sec->output_section->vma; + self_address = sec->output_section->vma; + + if (sec->output_section->vma > target_sec->output_section->vma) + self_address += sec->output_offset + irel->r_offset + 3; + else + dest_address += bfd_get_section_limit (abfd, target_sec->output_section); + /* Call targets should be four-byte aligned. */ + dest_address = (dest_address + 3) & ~3; + } + else + { + + self_address = (sec->output_section->vma + + sec->output_offset + irel->r_offset + 3); + dest_address = (target_sec->output_section->vma + + target_sec->output_offset + target_offset); + } *is_reachable_p = pcrel_reloc_fits (direct_call_opcode, 0, self_address, dest_address); |