diff options
author | Michael Meissner <gnu@the-meissners.org> | 1995-09-25 20:15:13 +0000 |
---|---|---|
committer | Michael Meissner <gnu@the-meissners.org> | 1995-09-25 20:15:13 +0000 |
commit | 4ecbc1efeac6511a5b0b7a27ccdab5e61a3d2008 (patch) | |
tree | e84030f580e2f8f7cda33445343d351400adb638 /gas | |
parent | cc47d19a93bdfa9ac0719e854993a1ca246214f0 (diff) | |
download | gdb-4ecbc1efeac6511a5b0b7a27ccdab5e61a3d2008.zip gdb-4ecbc1efeac6511a5b0b7a27ccdab5e61a3d2008.tar.gz gdb-4ecbc1efeac6511a5b0b7a27ccdab5e61a3d2008.tar.bz2 |
Better reloc support
Diffstat (limited to 'gas')
-rw-r--r-- | gas/ChangeLog | 9 | ||||
-rw-r--r-- | gas/config/tc-ppc.c | 94 |
2 files changed, 78 insertions, 25 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index ed3e4a7..4e3798d 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,12 @@ +Mon Sep 25 16:08:43 1995 Michael Meissner <meissner@tiktok.cygnus.com> + + * config/tc-ppc.c (ppc_elf_suffix): Lower case reloc before + testing. + (md_assemble): Be more robust in terms of relocations. + (md_apply_fix3): Allow 14 bit relocs to be emitted for external + symbols in addition to 26 bit relocs. Properly insert 26/14 bit + reloc value fields into the instruction stream. + Mon Sep 25 00:23:16 1995 Ian Lance Taylor <ian@cygnus.com> * config/tc-arm.c (md_atof): Output little endian constants in 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 |