#include "as.h"
#include "safe-ctype.h"
#include "subsegs.h"
-
+#include "dw2gencfi.h"
#include "opcode/ppc.h"
#ifdef OBJ_ELF
static void ppc_ef PARAMS ((int));
static void ppc_es PARAMS ((int));
static void ppc_csect PARAMS ((int));
-static void ppc_change_csect PARAMS ((symbolS *));
+static void ppc_change_csect PARAMS ((symbolS *, offsetT));
static void ppc_function PARAMS ((int));
static void ppc_extern PARAMS ((int));
static void ppc_lglobl PARAMS ((int));
/* Characters which mean that a number is a floating point constant,
as in 0d1.0. */
const char FLT_CHARS[] = "dD";
+
+/* '+' and '-' can be used as postfix predicate predictors for conditional
+ branches. So they need to be accepted as symbol characters. */
+const char ppc_symbol_chars[] = "+-";
+
+/* The dwarf2 data alignment, adjusted for 32 or 64 bit. */
+int ppc_cie_data_alignment;
\f
/* The target specific pseudo-ops which we support. */
{ "rdata", ppc_elf_rdata, 0 },
{ "rodata", ppc_elf_rdata, 0 },
{ "lcomm", ppc_elf_lcomm, 0 },
- { "file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0 },
- { "loc", dwarf2_directive_loc, 0 },
#endif
#ifdef TE_PE
|| strcmp (arg, "405") == 0)
ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
| PPC_OPCODE_403 | PPC_OPCODE_32);
+ else if (strcmp (arg, "440") == 0)
+ ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_32
+ | PPC_OPCODE_440 | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI);
else if (strcmp (arg, "7400") == 0
|| strcmp (arg, "7410") == 0
|| strcmp (arg, "7450") == 0
{
fprintf (stream, _("\
PowerPC options:\n\
+-a32 generate ELF32/XCOFF32\n\
+-a64 generate ELF64/XCOFF64\n\
-u ignored\n\
-mpwrx, -mpwr2 generate code for POWER/2 (RIOS2)\n\
-mpwr generate code for POWER (RIOS1)\n\
-m601 generate code for PowerPC 601\n\
-mppc, -mppc32, -m603, -m604\n\
generate code for PowerPC 603/604\n\
--m403, -m405 generate code for PowerPC 403/405\n\
+-m403, -m405 generate code for PowerPC 403/405\n\
+-m440 generate code for PowerPC 440\n\
-m7400, -m7410, -m7450, -m7455\n\
- generate code For PowerPC 7400/7410/7450/7455\n\
+ generate code For PowerPC 7400/7410/7450/7455\n"));
+ fprintf (stream, _("\
-mppc64, -m620 generate code for PowerPC 620/625/630\n\
-mppc64bridge generate code for PowerPC 64, including bridge insns\n\
-mbooke64 generate code for 64-bit PowerPC BookE\n\
-mbooke, mbooke32 generate code for 32-bit PowerPC BookE\n\
-mpower4 generate code for Power4 architecture\n\
--maltivec generate code for AltiVec\n\
-mcom generate code Power/PowerPC common instructions\n\
--many generate code for any architecture (PWR/PWRX/PPC)\n\
--mregnames Allow symbolic names for registers\n\
--mno-regnames Do not allow symbolic names for registers\n"));
+-many generate code for any architecture (PWR/PWRX/PPC)\n"));
fprintf (stream, _("\
+-maltivec generate code for AltiVec\n\
-me500, -me500x2 generate code for Motorola e500 core complex\n\
--mspe generate code for Motorola SPE instructions\n"));
+-mspe generate code for Motorola SPE instructions\n\
+-mregnames Allow symbolic names for registers\n\
+-mno-regnames Do not allow symbolic names for registers\n"));
#ifdef OBJ_ELF
fprintf (stream, _("\
-mrelocatable support for GCC's -mrelocatble option\n\
-mrelocatable-lib support for GCC's -mrelocatble-lib option\n\
-memb set PPC_EMB bit in ELF flags\n\
--mlittle, -mlittle-endian\n\
+-mlittle, -mlittle-endian, -l, -le\n\
generate code for a little endian machine\n\
--mbig, -mbig-endian generate code for a big endian machine\n\
+-mbig, -mbig-endian, -b, -be\n\
+ generate code for a big endian machine\n\
-msolaris generate code for Solaris\n\
-mno-solaris do not generate code for Solaris\n\
-V print assembler version number\n\
ppc_set_cpu ();
+ ppc_cie_data_alignment = ppc_obj64 ? -8 : -4;
+
#ifdef OBJ_ELF
/* Set the ELF flags if desired. */
if (ppc_flags && !msolaris)
md_number_to_chars (p, (valueT) 8, 4);
p = frag_more (4);
- md_number_to_chars (p, (valueT) ppc_apuinfo_num, 4);
+ md_number_to_chars (p, (valueT) ppc_apuinfo_num * 4, 4);
p = frag_more (4);
md_number_to_chars (p, (valueT) 2, 4);
}
if (!ppc_obj64)
+ if (exp_p->X_add_number != 0
+ && (reloc == (int) BFD_RELOC_16_GOTOFF
+ || reloc == (int) BFD_RELOC_LO16_GOTOFF
+ || reloc == (int) BFD_RELOC_HI16_GOTOFF
+ || reloc == (int) BFD_RELOC_HI16_S_GOTOFF))
+ as_warn (_("identifier+constant@got means identifier@got+constant"));
+
+ /* Now check for identifier@suffix+constant. */
+ if (*str == '-' || *str == '+')
{
- if (exp_p->X_add_number != 0
- && (reloc == (int) BFD_RELOC_16_GOTOFF
- || reloc == (int) BFD_RELOC_LO16_GOTOFF
- || reloc == (int) BFD_RELOC_HI16_GOTOFF
- || reloc == (int) BFD_RELOC_HI16_S_GOTOFF))
- as_warn (_("identifier+constant@got means identifier@got+constant"));
-
- /* Now check for identifier@suffix+constant. */
- if (*str == '-' || *str == '+')
+ char *orig_line = input_line_pointer;
+ expressionS new_exp;
+
+ input_line_pointer = str;
+ expression (&new_exp);
+ if (new_exp.X_op == O_constant)
{
- char *orig_line = input_line_pointer;
- expressionS new_exp;
-
- input_line_pointer = str;
- expression (&new_exp);
- if (new_exp.X_op == O_constant)
- {
- exp_p->X_add_number += new_exp.X_add_number;
- str = input_line_pointer;
- }
-
- if (&input_line_pointer != str_p)
- input_line_pointer = orig_line;
+ exp_p->X_add_number += new_exp.X_add_number;
+ str = input_line_pointer;
}
+
+ if (&input_line_pointer != str_p)
+ input_line_pointer = orig_line;
}
*str_p = str;
if (reloc == (int) BFD_RELOC_PPC64_TOC
- && exp_p->X_op == O_symbol)
+ && exp_p->X_op == O_symbol
+ && strcmp (S_GET_NAME (exp_p->X_add_symbol), ".TOC.") == 0)
{
- /* This reloc type ignores the symbol. Change the symbol
- so that the dummy .TOC. symbol can be omitted from the
- object file. */
+ /* Change the symbol so that the dummy .TOC. symbol can be
+ omitted from the object file. */
exp_p->X_add_symbol = &abs_symbol;
}
}
if (ppc_obj64
- && (operand->flags & PPC_OPERAND_DS) != 0)
+ && (operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0)
{
switch (reloc)
{
return SHF_EXCLUDE;
*ptr_msg = _("Bad .section directive: want a,e,w,x,M,S,G,T in string");
- return 0;
+ return -1;
}
int
char *name;
char endc;
symbolS *sym;
+ offsetT align;
name = input_line_pointer;
endc = get_symbol_end ();
symbol_get_tc (sym)->class = XMC_PR;
}
- ppc_change_csect (sym);
-
+ align = 2;
if (*input_line_pointer == ',')
{
++input_line_pointer;
- symbol_get_tc (sym)->align = get_absolute_expression ();
+ align = get_absolute_expression ();
}
+ ppc_change_csect (sym, align);
+
demand_empty_rest_of_line ();
}
/* Change to a different csect. */
static void
-ppc_change_csect (sym)
+ppc_change_csect (sym, align)
symbolS *sym;
+ offsetT align;
{
if (S_IS_DEFINED (sym))
subseg_set (S_GET_SEGMENT (sym), symbol_get_tc (sym)->subseg);
int after_toc;
int hold_chunksize;
symbolS *list;
+ int is_code;
+ segT sec;
/* This is a new csect. We need to look at the symbol class to
figure out whether it should go in the text section or the
data section. */
after_toc = 0;
+ is_code = 0;
switch (symbol_get_tc (sym)->class)
{
case XMC_PR:
symbol_get_tc (sym)->subseg = ppc_text_subsegment;
++ppc_text_subsegment;
list_ptr = &ppc_text_csects;
+ is_code = 1;
break;
case XMC_RW:
case XMC_TC0:
hold_chunksize = chunksize;
chunksize = 64;
- subseg_new (segment_name (S_GET_SEGMENT (sym)),
- symbol_get_tc (sym)->subseg);
+ sec = subseg_new (segment_name (S_GET_SEGMENT (sym)),
+ symbol_get_tc (sym)->subseg);
chunksize = hold_chunksize;
if (after_toc)
ppc_after_toc_frag = frag_now;
+ record_alignment (sec, align);
+ if (is_code)
+ frag_align_code (align, 0);
+ else
+ frag_align (align, 0, 0);
+
symbol_set_frag (sym, frag_now);
S_SET_VALUE (sym, (valueT) frag_now_fix ());
- symbol_get_tc (sym)->align = 2;
+ symbol_get_tc (sym)->align = align;
symbol_get_tc (sym)->output = 1;
symbol_get_tc (sym)->within = sym;
sym = symbol_find_or_make (name);
- ppc_change_csect (sym);
+ ppc_change_csect (sym, 2);
demand_empty_rest_of_line ();
}
sym = symbol_find_or_make (real_name);
- ppc_change_csect (sym);
+ ppc_change_csect (sym, 2);
demand_empty_rest_of_line ();
}
give to this location in the toc; this will be a symbol with class
TC. The rest of the arguments are N-byte values to actually put at
this location in the TOC; often there is just one more argument, a
- relocateable symbol reference. The size of the value to store
+ relocatable symbol reference. The size of the value to store
depends on target word size. A 32-bit target uses 4-byte values, a
64-bit target uses 8-byte values.
ppc_frob_section (sec)
asection *sec;
{
- static bfd_size_type vma = 0;
+ static bfd_vma vma = 0;
+ vma = md_section_align (sec, vma);
bfd_set_section_vma (stdoutput, sec, vma);
vma += bfd_section_size (stdoutput, sec);
}
#if defined (OBJ_XCOFF) || defined (OBJ_ELF)
else if ((operand->flags & PPC_OPERAND_PARENS) != 0
&& operand->bits == 16
- && operand->shift == 0
- && ppc_is_toc_sym (fixP->fx_addsy))
+ && operand->shift == 0)
{
- fixP->fx_r_type = BFD_RELOC_PPC_TOC16;
+ if (ppc_is_toc_sym (fixP->fx_addsy))
+ {
+ fixP->fx_r_type = BFD_RELOC_PPC_TOC16;
#ifdef OBJ_ELF
- if (ppc_obj64
- && (operand->flags & PPC_OPERAND_DS) != 0)
- fixP->fx_r_type = BFD_RELOC_PPC64_TOC16_DS;
+ if (ppc_obj64
+ && (operand->flags & PPC_OPERAND_DS) != 0)
+ fixP->fx_r_type = BFD_RELOC_PPC64_TOC16_DS;
#endif
+ }
+ else
+ {
+ fixP->fx_r_type = BFD_RELOC_16;
+#ifdef OBJ_ELF
+ if (ppc_obj64
+ && (operand->flags & PPC_OPERAND_DS) != 0)
+ fixP->fx_r_type = BFD_RELOC_PPC64_ADDR16_DS;
+#endif
+ }
fixP->fx_size = 2;
if (target_big_endian)
fixP->fx_where += 2;
abort ();
{
unsigned char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
- unsigned long val;
+ unsigned long val, mask;
if (target_big_endian)
- val = bfd_getb16 (where);
+ val = bfd_getb32 (where - 2);
else
- val = bfd_getl16 (where);
- val |= (value & 0xfffc);
+ val = bfd_getl32 (where);
+ mask = 0xfffc;
+ /* lq insns reserve the four lsbs. */
+ if ((ppc_cpu & PPC_OPCODE_POWER4) != 0
+ && (val & (0x3f << 26)) == (56u << 26))
+ mask = 0xfff0;
+ val |= value & mask;
if (target_big_endian)
bfd_putb16 ((bfd_vma) val, where);
else
}
break;
+ case BFD_RELOC_PPC_B16_BRTAKEN:
+ case BFD_RELOC_PPC_B16_BRNTAKEN:
+ case BFD_RELOC_PPC_BA16_BRTAKEN:
+ case BFD_RELOC_PPC_BA16_BRNTAKEN:
+ break;
+
case BFD_RELOC_PPC_TLS:
case BFD_RELOC_PPC_DTPMOD:
case BFD_RELOC_PPC_TPREL16:
return reloc;
}
+
+void
+ppc_cfi_frame_initial_instructions ()
+{
+ cfi_add_CFA_def_cfa (1, 0);
+}
+
+int
+tc_ppc_regname_to_dw2regnum (const char *regname)
+{
+ unsigned int regnum = -1;
+ unsigned int i;
+ const char *p;
+ char *q;
+ static struct { char *name; int dw2regnum; } regnames[] =
+ {
+ { "sp", 1 }, { "r.sp", 1 }, { "rtoc", 2 }, { "r.toc", 2 },
+ { "mq", 64 }, { "lr", 65 }, { "ctr", 66 }, { "ap", 67 },
+ { "cc", 68 }, { "xer", 76 }, { "vrsave", 109 }, { "vscr", 110 },
+ { "spe_acc", 111 }, { "spefscr", 112 }
+ };
+
+ for (i = 0; i < ARRAY_SIZE (regnames); ++i)
+ if (strcmp (regnames[i].name, regname) == 0)
+ return regnames[i].dw2regnum;
+
+ if (regname[0] == 'r' || regname[0] == 'f' || regname[0] == 'v')
+ {
+ p = regname + 1 + (regname[1] == '.');
+ regnum = strtoul (p, &q, 10);
+ if (p == q || *q || regnum >= 32)
+ return -1;
+ if (regname[0] == 'f')
+ regnum += 32;
+ else if (regname[0] == 'v')
+ regnum += 77;
+ }
+ else if (regname[0] == 'c' && regname[1] == 'r')
+ {
+ p = regname + 2 + (regname[2] == '.');
+ if (p[0] < '0' || p[0] > '7' || p[1])
+ return -1;
+ regnum = p[0] - '0' + 68;
+ }
+ return regnum;
+}