summaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2000-09-15 18:07:28 +0000
committerNick Clifton <nickc@redhat.com>2000-09-15 18:07:28 +0000
commit4097282b8ebb7a4c448e486c09ffeeb7213c83f5 (patch)
treeaa8e41add58941d0465e7f249f8b062ee9336e08 /bfd
parent9a51392eda44f956a27b57637f2ad57e07a8822d (diff)
downloadgdb-4097282b8ebb7a4c448e486c09ffeeb7213c83f5.tar.gz
ld performs LITUSE relocations incorrectly if -relax is specified on the ld
command line and the displacement field of the load or store instruction is non-zero.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog7
-rw-r--r--bfd/elf64-alpha.c29
2 files changed, 26 insertions, 10 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index f0e8ea96d5e..d4c8889c993 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,10 @@
+2000-09-15 Kenneth Block <Kenneth.Block@compaq.com>
+
+ * bfd/elf64-alpha.c (elf64_alpha_relax_with_lituse): ld performs
+ LITUSE relocations incorrectly if -relax is specified on the ld
+ command line and the displacement field of the load or store
+ instruction is non-zero. (Patch by paul.winalski@compaq.com)
+
2000-09-15 Alan Modra <alan@linuxcare.com.au>
* elf32-hppa.c (hppa_add_stub): Dont set first_init_sec and
diff --git a/bfd/elf64-alpha.c b/bfd/elf64-alpha.c
index b4025c0228f..73620eb9b58 100644
--- a/bfd/elf64-alpha.c
+++ b/bfd/elf64-alpha.c
@@ -1127,12 +1127,13 @@ elf64_alpha_relax_with_lituse (info, symval, irel, irelend)
/* A little preparation for the loop... */
disp = symval - info->gp;
- fits16 = (disp >= -(bfd_signed_vma)0x8000 && disp < 0x8000);
- fits32 = (disp >= -(bfd_signed_vma)0x80000000 && disp < 0x7fff8000);
for (urel = irel+1, i = 0; i < count; ++i, ++urel)
{
unsigned int insn;
+ int insn_disp;
+ bfd_signed_vma xdisp;
+
insn = bfd_get_32 (info->abfd, info->contents + urel->r_offset);
switch (urel->r_addend)
@@ -1145,14 +1146,23 @@ elf64_alpha_relax_with_lituse (info, symval, irel, irelend)
case 1: /* MEM FORMAT */
/* We can always optimize 16-bit displacements. */
+
+ /* Extract the displacement from the instruction, sign-extending
+ it if necessary, then test whether it is within 16 or 32 bits
+ displacement from GP. */
+ insn_disp = insn & 0x0000ffff;
+ if (insn_disp & 0x00008000)
+ insn_disp |= 0xffff0000; /* Negative: sign-extend. */
+
+ xdisp = disp + insn_disp;
+ fits16 = (xdisp >= - (bfd_signed_vma) 0x00008000 && xdisp < 0x00008000);
+ fits32 = (xdisp >= - (bfd_signed_vma) 0x80000000 && xdisp < 0x7fff8000);
+
if (fits16)
{
- /* FIXME: sanity check the insn for mem format with
- zero addend. */
-
- /* Take the op code and dest from this insn, take the base
- register from the literal insn. Leave the offset alone. */
- insn = (insn & 0xffe00000) | (lit_insn & 0x001f0000);
+ /* Take the op code and dest from this insn, take the base
+ register from the literal insn. Leave the offset alone. */
+ insn = (insn & 0xffe0ffff) | (lit_insn & 0x001f0000);
urel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
R_ALPHA_GPRELLOW);
urel->r_addend = irel->r_addend;
@@ -1165,8 +1175,7 @@ elf64_alpha_relax_with_lituse (info, symval, irel, irelend)
/* If all mem+byte, we can optimize 32-bit mem displacements. */
else if (fits32 && !(flags & ~6))
{
- /* FIXME: sanity check that lit insn Ra is mem insn Rb, and
- that mem_insn disp is zero. */
+ /* FIXME: sanity check that lit insn Ra is mem insn Rb. */
irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
R_ALPHA_GPRELHIGH);