aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorSenthil Kumar Selvaraj <senthilkumar.selvaraj@microchip.com>2019-05-16 12:12:33 +0530
committerSenthil Kumar Selvaraj <senthilkumar.selvaraj@microchip.com>2019-05-21 12:48:06 +0530
commit7622049e0bef81fab900860400838bc977449892 (patch)
tree31038b59df87994bae534de94b70c8c7d7441634 /bfd
parent338ba75534fbfeb64d7009f29a89f25826a1f4d2 (diff)
downloadgdb-7622049e0bef81fab900860400838bc977449892.zip
gdb-7622049e0bef81fab900860400838bc977449892.tar.gz
gdb-7622049e0bef81fab900860400838bc977449892.tar.bz2
Fix PR 24571 - Relaxation does not shorten jmp or call to target at pc-relative range boundary
The range check done to transform an absolute call/jump to a pc-relative one is off-by-one, and that causes this shortening optimization to be missed if the branch target is right at the range boundary. In the non-shrinkable case, the range is what is mentioned in the ISA - -4094 bytes in the backward direction, and 4096 bytes in the positive direction. In the shrinkable case, the forward jump range increases by two bytes (deleted because of the shortening from call/jmp to rcall/rjmp), and therefore, the range is -4094 in the reverse, and 4098 in the positive direction. Fix the ranges for !shrinkable and shrinkable cases, and add a test caes to ensure jumps to max forward and backward ranges get relaxed to rjmp.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog6
-rw-r--r--bfd/elf32-avr.c18
2 files changed, 21 insertions, 3 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 0d7eda4..7d22cc0 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,11 @@
2019-05-21 Senthil Kumar Selvaraj <senthilkumar.selvaraj@microchip.com>
+ PR ld/24571
+ * bfd/elf32-avr.c (elf32_avr_relax_section): Adjust range check
+ when computing distance_short_enough.
+
+2019-05-21 Senthil Kumar Selvaraj <senthilkumar.selvaraj@microchip.com>
+
PR ld/24564
* bfd/elf32-avr.c (avr_relative_distance_considering_wrap_around):
Wrap around even if distance equals avr_pc_wrap_around.
diff --git a/bfd/elf32-avr.c b/bfd/elf32-avr.c
index f8a843e..34ad423 100644
--- a/bfd/elf32-avr.c
+++ b/bfd/elf32-avr.c
@@ -2643,16 +2643,28 @@ elf32_avr_relax_section (bfd *abfd,
/* Compute the distance from this insn to the branch target. */
gap = value - dot;
+ /* The ISA manual states that addressable range is PC - 2k + 1 to
+ PC + 2k. In bytes, that would be -4094 <= PC <= 4096. The range
+ is shifted one word to the right, because pc-relative instructions
+ implicitly add one word i.e. rjmp 0 jumps to next insn, not the
+ current one.
+ Therefore, for the !shrinkable case, the range is as above.
+ If shrinkable, then the current code only deletes bytes 3 and
+ 4 of the absolute call/jmp, so the forward jump range increases
+ by 2 bytes, but the backward (negative) jump range remains
+ the same. */
+
+
/* Check if the gap falls in the range that can be accommodated
in 13bits signed (It is 12bits when encoded, as we deal with
word addressing). */
- if (!shrinkable && ((int) gap >= -4096 && (int) gap <= 4095))
+ if (!shrinkable && ((int) gap >= -4094 && (int) gap <= 4096))
distance_short_enough = 1;
/* If shrinkable, then we can check for a range of distance which
- is two bytes farther on both the directions because the call
+ is two bytes farther on the positive direction because the call
or jump target will be closer by two bytes after the
relaxation. */
- else if (shrinkable && ((int) gap >= -4094 && (int) gap <= 4097))
+ else if (shrinkable && ((int) gap >= -4094 && (int) gap <= 4098))
distance_short_enough = 1;
/* Here we handle the wrap-around case. E.g. for a 16k device