aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-ppc.c
diff options
context:
space:
mode:
authorMichael Meissner <gnu@the-meissners.org>1995-09-25 20:15:13 +0000
committerMichael Meissner <gnu@the-meissners.org>1995-09-25 20:15:13 +0000
commit4ecbc1efeac6511a5b0b7a27ccdab5e61a3d2008 (patch)
treee84030f580e2f8f7cda33445343d351400adb638 /gas/config/tc-ppc.c
parentcc47d19a93bdfa9ac0719e854993a1ca246214f0 (diff)
downloadgdb-4ecbc1efeac6511a5b0b7a27ccdab5e61a3d2008.zip
gdb-4ecbc1efeac6511a5b0b7a27ccdab5e61a3d2008.tar.gz
gdb-4ecbc1efeac6511a5b0b7a27ccdab5e61a3d2008.tar.bz2
Better reloc support
Diffstat (limited to 'gas/config/tc-ppc.c')
-rw-r--r--gas/config/tc-ppc.c94
1 files changed, 69 insertions, 25 deletions
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index 435d0fb..6760b61 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -560,26 +560,21 @@ ppc_elf_suffix (str_p)
bfd_reloc_code_real_type reloc;
};
+ char ident[20];
char *str = *str_p;
+ char *str2;
int ch;
+ int len;
struct map_bfd *ptr;
static struct map_bfd mapping[] = {
- { "GOT", 3, BFD_RELOC_PPC_TOC16 },
{ "got", 3, BFD_RELOC_PPC_TOC16 },
- { "L", 1, BFD_RELOC_LO16 },
{ "l", 1, BFD_RELOC_LO16 },
- { "HA", 2, BFD_RELOC_HI16_S },
{ "ha", 2, BFD_RELOC_HI16_S },
- { "H", 1, BFD_RELOC_HI16 },
{ "h", 1, BFD_RELOC_HI16 },
- { "SDAREL", 6, BFD_RELOC_GPREL16 },
{ "sdarel", 6, BFD_RELOC_GPREL16 },
- { "FIXUP", 5, BFD_RELOC_CTOR }, /* synonym for BFD_RELOC_32 that doesn't get */
{ "fixup", 5, BFD_RELOC_CTOR }, /* warnings with -mrelocatable */
- { "BRTAKEN", 7, BFD_RELOC_PPC_B16_BRTAKEN },
{ "brtaken", 7, BFD_RELOC_PPC_B16_BRTAKEN },
- { "BRNTAKEN", 8, BFD_RELOC_PPC_B16_BRNTAKEN },
{ "brntaken", 8, BFD_RELOC_PPC_B16_BRNTAKEN },
{ (char *)0, 0, BFD_RELOC_UNUSED }
};
@@ -587,11 +582,17 @@ ppc_elf_suffix (str_p)
if (*str++ != '@')
return BFD_RELOC_UNUSED;
- ch = *str;
+ for (ch = *str, str2 = ident; str2 < ident + sizeof(ident) - 1 && isalpha (ch); ch = *++str)
+ *str2++ = (islower (ch)) ? ch : tolower (ch);
+
+ *str2 = '\0';
+ len = str2 - ident;
+
+ ch = ident[0];
for (ptr = &mapping[0]; ptr->length > 0; ptr++)
- if (ch == ptr->string[0] && strncmp (str, ptr->string, ptr->length) == 0)
+ if (ch == ptr->string[0] && len == ptr->length && memcmp (ident, ptr->string, ptr->length) == 0)
{
- *str_p = str + ptr->length;
+ *str_p = str;
return ptr->reloc;
}
@@ -935,15 +936,21 @@ md_assemble (str)
if (fixups[i].reloc != BFD_RELOC_UNUSED)
{
reloc_howto_type *reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc);
- int size = (!reloc_howto) ? 0 : bfd_get_reloc_size (reloc_howto);
- int offset = target_big_endian ? (4 - size) : 0;
+ int size;
+ int offset;
fixS *fixP;
- if (size > 4)
+ if (!reloc_howto)
+ abort ();
+
+ size = bfd_get_reloc_size (reloc_howto);
+ offset = target_big_endian ? (4 - size) : 0;
+
+ if (size < 1 || size > 4)
abort();
fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset, size,
- &fixups[i].exp, (reloc_howto && reloc_howto->pc_relative),
+ &fixups[i].exp, reloc_howto->pc_relative,
fixups[i].reloc);
/* Turn off complaints that the addend is too large for things like
@@ -2642,6 +2649,9 @@ md_apply_fix3 (fixp, valuep, seg)
segT seg;
{
valueT value;
+ char *where;
+ unsigned long insn;
+ unsigned long mask;
/* FIXME FIXME FIXME: The value we are passed in *valuep includes
the symbol values. Since we are using BFD_ASSEMBLER, if we are
@@ -2681,8 +2691,6 @@ md_apply_fix3 (fixp, valuep, seg)
{
int opindex;
const struct powerpc_operand *operand;
- char *where;
- unsigned long insn;
opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED;
@@ -2735,17 +2743,24 @@ md_apply_fix3 (fixp, valuep, seg)
We are only prepared to turn a few of the operands into
relocs.
FIXME: We need to handle the DS field at the very least.
- FIXME: Handling 16 bit branches would also be reasonable.
FIXME: Selecting the reloc type is a bit haphazard; perhaps
there should be a new field in the operand table. */
if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
&& operand->bits == 26
&& operand->shift == 0)
fixp->fx_r_type = BFD_RELOC_PPC_B26;
+ else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
+ && operand->bits == 16
+ && operand->shift == 0)
+ fixp->fx_r_type = BFD_RELOC_PPC_B16;
else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
&& operand->bits == 26
&& operand->shift == 0)
fixp->fx_r_type = BFD_RELOC_PPC_BA26;
+ else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
+ && operand->bits == 26
+ && operand->shift == 0)
+ fixp->fx_r_type = BFD_RELOC_PPC_BA16;
else if ((operand->flags & PPC_OPERAND_PARENS) != 0
&& operand->bits == 16
&& operand->shift == 0
@@ -2771,6 +2786,7 @@ md_apply_fix3 (fixp, valuep, seg)
#ifdef OBJ_ELF
ppc_elf_validate_fix (fixp, seg);
#endif
+ mask = 0;
switch (fixp->fx_r_type)
{
case BFD_RELOC_32:
@@ -2795,24 +2811,52 @@ md_apply_fix3 (fixp, valuep, seg)
if (fixp->fx_pcrel)
abort ();
- case BFD_RELOC_PPC_B16_BRTAKEN:
- case BFD_RELOC_PPC_B16_BRNTAKEN:
- value <<= 2;
- md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
- value, 2);
+ mask = 0xffff;
break;
case BFD_RELOC_8:
if (fixp->fx_pcrel)
abort ();
- md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
- value, 1);
+ mask = 0xff;
+ break;
+
+ case BFD_RELOC_PPC_B16:
+ case BFD_RELOC_PPC_B16_BRTAKEN:
+ case BFD_RELOC_PPC_B16_BRNTAKEN:
+ case BFD_RELOC_PPC_BA16:
+ case BFD_RELOC_PPC_BA16_BRTAKEN:
+ case BFD_RELOC_PPC_BA16_BRNTAKEN:
+ mask = 0xfffc;
+ break;
+
+ case BFD_RELOC_PPC_B26:
+ case BFD_RELOC_PPC_BA26:
+ mask = 0x3fffffc;
break;
default:
abort ();
}
+
+ /* Fetch the instruction, insert the fully resolved operand
+ value, and stuff the instruction back again. */
+ if (mask != 0)
+ {
+ where = fixp->fx_frag->fr_literal + fixp->fx_where;
+ if (target_big_endian)
+ insn = bfd_getb32 ((unsigned char *) where);
+ else
+ insn = bfd_getl32 ((unsigned char *) where);
+
+ insn = (insn & ~mask) | (value & mask);
+
+ if (target_big_endian)
+ bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
+ else
+ bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
+ }
+
}
#ifdef OBJ_ELF