aboutsummaryrefslogtreecommitdiff
path: root/gas/config
diff options
context:
space:
mode:
authorMichael Meissner <gnu@the-meissners.org>1995-09-26 19:17:10 +0000
committerMichael Meissner <gnu@the-meissners.org>1995-09-26 19:17:10 +0000
commit65c91be516a93b940ffdc04fd732775fcbe46f8b (patch)
tree917054bd80d1e30513b7674cb4c3b607a0e7d2f8 /gas/config
parente6cb7b411b926d51f26c7bec0be74fff4f4fa6d3 (diff)
downloadgdb-65c91be516a93b940ffdc04fd732775fcbe46f8b.zip
gdb-65c91be516a93b940ffdc04fd732775fcbe46f8b.tar.gz
gdb-65c91be516a93b940ffdc04fd732775fcbe46f8b.tar.bz2
Support all of the V.4 relocations
Diffstat (limited to 'gas/config')
-rw-r--r--gas/config/tc-ppc.c143
-rw-r--r--gas/config/tc-ppc.h20
2 files changed, 77 insertions, 86 deletions
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index 6760b61..053b2f1 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -567,23 +567,46 @@ ppc_elf_suffix (str_p)
int len;
struct map_bfd *ptr;
+#define MAP(str,reloc) { str, sizeof(str)-1, reloc }
+
static struct map_bfd mapping[] = {
- { "got", 3, BFD_RELOC_PPC_TOC16 },
- { "l", 1, BFD_RELOC_LO16 },
- { "ha", 2, BFD_RELOC_HI16_S },
- { "h", 1, BFD_RELOC_HI16 },
- { "sdarel", 6, BFD_RELOC_GPREL16 },
- { "fixup", 5, BFD_RELOC_CTOR }, /* warnings with -mrelocatable */
- { "brtaken", 7, BFD_RELOC_PPC_B16_BRTAKEN },
- { "brntaken", 8, BFD_RELOC_PPC_B16_BRNTAKEN },
+ MAP ("got", BFD_RELOC_PPC_TOC16),
+ MAP ("l", BFD_RELOC_LO16),
+ MAP ("h", BFD_RELOC_HI16),
+ MAP ("ha", BFD_RELOC_HI16_S),
+ MAP ("brtaken", BFD_RELOC_PPC_B16_BRTAKEN),
+ MAP ("brntaken", BFD_RELOC_PPC_B16_BRNTAKEN),
+ MAP ("got@l", BFD_RELOC_LO16_GOTOFF),
+ MAP ("got@h", BFD_RELOC_HI16_GOTOFF),
+ MAP ("got@ha", BFD_RELOC_HI16_S_GOTOFF),
+ MAP ("fixup", BFD_RELOC_CTOR), /* warnings with -mrelocatable */
+ MAP ("pltrel24", BFD_RELOC_24_PLT_PCREL),
+ MAP ("copy", BFD_RELOC_PPC_COPY),
+ MAP ("globdat", BFD_RELOC_PPC_GLOB_DAT),
+ MAP ("local24pc", BFD_RELOC_PPC_LOCAL24PC),
+ MAP ("plt", BFD_RELOC_32_PLTOFF),
+ MAP ("pltrel", BFD_RELOC_32_PLT_PCREL),
+ MAP ("plt@l", BFD_RELOC_LO16_PLTOFF),
+ MAP ("plt@h", BFD_RELOC_HI16_PLTOFF),
+ MAP ("plt@ha", BFD_RELOC_HI16_S_PLTOFF),
+ MAP ("sdarel", BFD_RELOC_GPREL16),
+ MAP ("sectoff", BFD_RELOC_32_BASEREL),
+ MAP ("sectoff@l", BFD_RELOC_LO16_BASEREL),
+ MAP ("sectoff@h", BFD_RELOC_HI16_BASEREL),
+ MAP ("sectoff@ha", BFD_RELOC_HI16_S_BASEREL),
+
{ (char *)0, 0, BFD_RELOC_UNUSED }
};
if (*str++ != '@')
return BFD_RELOC_UNUSED;
- for (ch = *str, str2 = ident; str2 < ident + sizeof(ident) - 1 && isalpha (ch); ch = *++str)
- *str2++ = (islower (ch)) ? ch : tolower (ch);
+ for (ch = *str, str2 = ident;
+ str2 < ident + sizeof(ident) - 1 && isalnum (ch) || ch == '@';
+ ch = *++str)
+ {
+ *str2++ = (islower (ch)) ? ch : tolower (ch);
+ }
*str2 = '\0';
len = str2 - ident;
@@ -618,19 +641,23 @@ ppc_elf_cons (nbytes)
do
{
expression (&exp);
- if (nbytes == 4
- && exp.X_op == O_symbol
+ if (exp.X_op == O_symbol
&& *input_line_pointer == '@'
&& (reloc = ppc_elf_suffix (&input_line_pointer)) != BFD_RELOC_UNUSED)
{
- register char *p = frag_more ((int) nbytes);
reloc_howto_type *reloc_howto = bfd_reloc_type_lookup (stdoutput, reloc);
- int offset = (!reloc_howto) ? 0 : (nbytes - bfd_get_reloc_size (reloc_howto));
+ int size = bfd_get_reloc_size (reloc_howto);
- if (offset < 0)
- offset = 0;
+ if (size > nbytes)
+ as_bad ("%s relocations do not fit in %d bytes\n", reloc_howto->name, nbytes);
- fix_new_exp (frag_now, p - frag_now->fr_literal + offset, (int) nbytes - offset, &exp, 0, reloc);
+ else
+ {
+ register char *p = frag_more ((int) nbytes);
+ int offset = nbytes - size;
+
+ fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size, &exp, 0, reloc);
+ }
}
else
emit_expr (&exp, (unsigned int) nbytes);
@@ -865,6 +892,17 @@ md_assemble (str)
#ifdef OBJ_ELF
else if ((reloc = ppc_elf_suffix (&str)) != BFD_RELOC_UNUSED)
{
+ /* For the absoulte forms of branchs, convert the PC relative form back into
+ the absolute. */
+ if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
+ switch (reloc)
+ {
+ case BFD_RELOC_PPC_B26: reloc = BFD_RELOC_PPC_BA26; break;
+ case BFD_RELOC_PPC_B16: reloc = BFD_RELOC_PPC_BA16; break;
+ case BFD_RELOC_PPC_B16_BRTAKEN: reloc = BFD_RELOC_PPC_BA16_BRTAKEN; break;
+ case BFD_RELOC_PPC_B16_BRNTAKEN: reloc = BFD_RELOC_PPC_BA16_BRNTAKEN; break;
+ }
+
/* We need to generate a fixup for this expression. */
if (fc >= MAX_INSN_FIXUPS)
as_fatal ("too many fixups");
@@ -2518,7 +2556,8 @@ md_pcrel_from (fixp)
{
#ifdef OBJ_ELF
if (fixp->fx_addsy != (symbolS *) NULL
- && ! S_IS_DEFINED (fixp->fx_addsy))
+ && (! S_IS_DEFINED (fixp->fx_addsy)
+ || TC_FORCE_RELOCATION (fixp)))
return 0;
#endif
@@ -2651,7 +2690,6 @@ md_apply_fix3 (fixp, valuep, 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
@@ -2758,7 +2796,7 @@ md_apply_fix3 (fixp, valuep, seg)
&& operand->shift == 0)
fixp->fx_r_type = BFD_RELOC_PPC_BA26;
else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
- && operand->bits == 26
+ && operand->bits == 16
&& operand->shift == 0)
fixp->fx_r_type = BFD_RELOC_PPC_BA16;
else if ((operand->flags & PPC_OPERAND_PARENS) != 0
@@ -2786,77 +2824,16 @@ 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:
+ case BFD_RELOC_32: /* fixup errant PC relative relocations */
case BFD_RELOC_CTOR:
if (fixp->fx_pcrel)
{
fixp->fx_r_type = BFD_RELOC_32_PCREL;
value += fixp->fx_frag->fr_address + fixp->fx_where;
- } /* fall through */
-
- case BFD_RELOC_32_PCREL:
- md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
- value, 4);
- break;
-
- case BFD_RELOC_LO16:
- case BFD_RELOC_HI16:
- case BFD_RELOC_HI16_S:
- case BFD_RELOC_PPC_TOC16:
- case BFD_RELOC_16:
- case BFD_RELOC_GPREL16:
- if (fixp->fx_pcrel)
- abort ();
-
- mask = 0xffff;
- break;
-
- case BFD_RELOC_8:
- if (fixp->fx_pcrel)
- abort ();
-
- 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
diff --git a/gas/config/tc-ppc.h b/gas/config/tc-ppc.h
index 03588d9..c31a98b 100644
--- a/gas/config/tc-ppc.h
+++ b/gas/config/tc-ppc.h
@@ -16,7 +16,7 @@
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+ the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#define TC_PPC
@@ -28,12 +28,15 @@
#define TARGET_ARCH (ppc_arch ())
extern enum bfd_architecture ppc_arch PARAMS ((void));
+/* Whether or not the target is big endian */
+extern int target_big_endian;
+
/* The target BFD format. */
#ifdef OBJ_COFF
#define TARGET_FORMAT "aixcoff-rs6000"
#endif
#ifdef OBJ_ELF
-#define TARGET_FORMAT "elf32-powerpc"
+#define TARGET_FORMAT (target_big_endian) ? "elf32-powerpc" : "elf32-powerpcle"
#endif
/* Permit temporary numeric labels. */
@@ -63,7 +66,7 @@ extern enum bfd_architecture ppc_arch PARAMS ((void));
/* Set the endianness we are using. Default to big endian. */
#ifndef TARGET_BYTES_BIG_ENDIAN
#ifndef TARGET_BYTES_LITTLE_ENDIAN
-#define TARGET_BYTES_BIG_ENDIAN
+#define TARGET_BYTES_BIG_ENDIAN 1
#endif
#endif
@@ -145,6 +148,9 @@ extern void ppc_frob_section PARAMS ((asection *));
#define tc_frob_symbol(sym, punt) punt = ppc_frob_symbol (sym)
extern int ppc_frob_symbol PARAMS ((struct symbol *));
+/* Niclas Andersson <nican@ida.liu.se> says this is needed. */
+#define SUB_SEGMENT_ALIGN(SEG) 2
+
/* Finish up the file. */
#define tc_frob_file() ppc_frob_file ()
extern void ppc_frob_file PARAMS ((void));
@@ -157,6 +163,14 @@ extern void ppc_frob_file PARAMS ((void));
#ifndef GLOBAL_OFFSET_TABLE_NAME
#define GLOBAL_OFFSET_TABLE_NAME "_GLOBAL_OFFSET_TABLE_"
#endif
+
+/* Branch prediction relocations must force relocation */
+#define TC_FORCE_RELOCATION(FIXP) \
+((FIXP)->fx_r_type == BFD_RELOC_PPC_B16_BRTAKEN \
+ || (FIXP)->fx_r_type == BFD_RELOC_PPC_B16_BRNTAKEN \
+ || (FIXP)->fx_r_type == BFD_RELOC_PPC_BA16_BRTAKEN \
+ || (FIXP)->fx_r_type == BFD_RELOC_PPC_BA16_BRNTAKEN)
+
#endif /* OBJ_ELF */
/* call md_apply_fix3 with segment instead of md_apply_fix */