X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-ppc.c;h=c4c32d1aeab00689d296b4954e3c0431d1517ae3;hb=ba0b21743576bcc16dcc7f0cd8f17b55519e5913;hp=ea8ddd600f2a6342160bbab259e9b247ec76dec1;hpb=418c17428467b9fbf59a61493d353d7edf1aed4a;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index ea8ddd600f..c4c32d1aea 100644 --- a/gas/config/tc-ppc.c +++ b/gas/config/tc-ppc.c @@ -1,5 +1,5 @@ /* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000) - Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 + Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support. @@ -47,9 +47,9 @@ static int set_target_endian = 0; /* Whether to use user friendly register names. */ #ifndef TARGET_REG_NAMES_P #ifdef TE_PE -#define TARGET_REG_NAMES_P true +#define TARGET_REG_NAMES_P TRUE #else -#define TARGET_REG_NAMES_P false +#define TARGET_REG_NAMES_P FALSE #endif #endif @@ -65,32 +65,27 @@ static int set_target_endian = 0; /* #ha(value) denotes the high adjusted value: bits 16 through 31 of the indicated value, compensating for #lo() being treated as a signed number. */ -#define PPC_HA(v) ((((v) >> 16) + (((v) >> 15) & 1)) & 0xffff) +#define PPC_HA(v) PPC_HI ((v) + 0x8000) /* #higher(value) denotes bits 32 through 47 of the indicated value. */ -#define PPC_HIGHER(v) (((v) >> 32) & 0xffff) +#define PPC_HIGHER(v) (((v) >> 16 >> 16) & 0xffff) /* #highera(value) denotes bits 32 through 47 of the indicated value, compensating for #lo() being treated as a signed number. */ -#define PPC_HIGHERA(v) \ - ((((v) >> 32) + (((v) & 0xffff8000) == 0xffff8000)) & 0xffff) +#define PPC_HIGHERA(v) PPC_HIGHER ((v) + 0x8000) /* #highest(value) denotes bits 48 through 63 of the indicated value. */ -#define PPC_HIGHEST(v) (((v) >> 48) & 0xffff) +#define PPC_HIGHEST(v) (((v) >> 24 >> 24) & 0xffff) /* #highesta(value) denotes bits 48 through 63 of the indicated value, - compensating for #lo being treated as a signed number. - Generate 0xffffffff8000 with arithmetic here, for portability. */ -#define PPC_HIGHESTA(v) \ - ((((v) >> 48) \ - + (((v) & (((valueT) 1 << 48) - 0x8000)) == ((valueT) 1 << 48) - 0x8000)) \ - & 0xffff) + compensating for #lo being treated as a signed number. */ +#define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000) #define SEX16(val) ((((val) & 0xffff) ^ 0x8000) - 0x8000) -static boolean reg_names_p = TARGET_REG_NAMES_P; +static bfd_boolean reg_names_p = TARGET_REG_NAMES_P; -static boolean register_name PARAMS ((expressionS *)); +static bfd_boolean register_name PARAMS ((expressionS *)); static void ppc_set_cpu PARAMS ((void)); static unsigned long ppc_insert_operand PARAMS ((unsigned long insn, const struct powerpc_operand *operand, @@ -135,6 +130,7 @@ static void ppc_elf_cons PARAMS ((int)); static void ppc_elf_rdata PARAMS ((int)); static void ppc_elf_lcomm PARAMS ((int)); static void ppc_elf_validate_fix PARAMS ((fixS *, segT)); +static void ppc_apuinfo_section_add PARAMS ((unsigned int apu, unsigned int version)); #endif #ifdef TE_PE @@ -186,6 +182,10 @@ const char EXP_CHARS[] = "eE"; /* 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 target specific pseudo-ops which we support. */ @@ -237,8 +237,6 @@ const pseudo_typeS md_pseudo_table[] = { "rdata", ppc_elf_rdata, 0 }, { "rodata", ppc_elf_rdata, 0 }, { "lcomm", ppc_elf_lcomm, 0 }, - { "file", dwarf2_directive_file, 0 }, - { "loc", dwarf2_directive_loc, 0 }, #endif #ifdef TE_PE @@ -607,7 +605,7 @@ reg_name_search (regs, regcount, name) * original state. */ -static boolean +static bfd_boolean register_name (expressionP) expressionS *expressionP; { @@ -622,7 +620,7 @@ register_name (expressionP) name = ++input_line_pointer; else if (!reg_names_p || !ISALPHA (name[0])) - return false; + return FALSE; c = get_symbol_end (); reg_number = reg_name_search (pre_defined_registers, REG_NAME_CNT, name); @@ -639,12 +637,12 @@ register_name (expressionP) /* Make the rest nice. */ expressionP->X_add_symbol = NULL; expressionP->X_op_symbol = NULL; - return true; + return TRUE; } /* Reset the line as if we had not done anything. */ input_line_pointer = start; - return false; + return FALSE; } /* This function is called for each symbol seen in an expression. It @@ -652,7 +650,7 @@ register_name (expressionP) to use for condition codes. */ /* Whether to do the special parsing. */ -static boolean cr_operand; +static bfd_boolean cr_operand; /* Names to recognize in a condition code. This table is sorted. */ static const struct pd_reg cr_names[] = @@ -700,14 +698,10 @@ ppc_parse_name (name, expr) /* The type of processor we are assembling for. This is one or more of the PPC_OPCODE flags defined in opcode/ppc.h. */ -static int ppc_cpu = 0; - -/* The size of the processor we are assembling for. This is either - PPC_OPCODE_32 or PPC_OPCODE_64. */ -static unsigned long ppc_size = PPC_OPCODE_32; +static unsigned long ppc_cpu = 0; -/* Whether to target xcoff64. */ -static int ppc_xcoff64 = 0; +/* Whether to target xcoff64/elf64. */ +static unsigned int ppc_obj64 = BFD_DEFAULT_TARGET_SIZE == 64; /* Opcode hash table. */ static struct hash_control *ppc_hash; @@ -724,12 +718,12 @@ static flagword ppc_flags = 0; /* Whether this is Solaris or not. */ #ifdef TARGET_SOLARIS_COMMENT -#define SOLARIS_P true +#define SOLARIS_P TRUE #else -#define SOLARIS_P false +#define SOLARIS_P FALSE #endif -static boolean msolaris = SOLARIS_P; +static bfd_boolean msolaris = SOLARIS_P; #endif #ifdef OBJ_XCOFF @@ -796,17 +790,31 @@ static segT ppc_current_section; #ifdef OBJ_ELF symbolS *GOT_symbol; /* Pre-defined "_GLOBAL_OFFSET_TABLE" */ +#define PPC_APUINFO_ISEL 0x40 +#define PPC_APUINFO_PMR 0x41 +#define PPC_APUINFO_RFMCI 0x42 +#define PPC_APUINFO_CACHELCK 0x43 +#define PPC_APUINFO_SPE 0x100 +#define PPC_APUINFO_EFS 0x101 +#define PPC_APUINFO_BRLOCK 0x102 + +/* + * We keep a list of APUinfo + */ +unsigned long *ppc_apuinfo_list; +unsigned int ppc_apuinfo_num; +unsigned int ppc_apuinfo_num_alloc; #endif /* OBJ_ELF */ #ifdef OBJ_ELF -CONST char *md_shortopts = "b:l:usm:K:VQ:"; +const char *const md_shortopts = "b:l:usm:K:VQ:"; #else -CONST char *md_shortopts = "um:"; +const char *const md_shortopts = "um:"; #endif -struct option md_longopts[] = { +const struct option md_longopts[] = { {NULL, no_argument, NULL, 0} }; -size_t md_longopts_size = sizeof (md_longopts); +const size_t md_longopts_size = sizeof (md_longopts); int md_parse_option (c, arg) @@ -861,82 +869,112 @@ md_parse_option (c, arg) /* a64 and a32 determine whether to use XCOFF64 or XCOFF32. */ case 'a': if (strcmp (arg, "64") == 0) - ppc_xcoff64 = 1; + { +#ifdef BFD64 + ppc_obj64 = 1; +#else + as_fatal (_("%s unsupported"), "-a64"); +#endif + } else if (strcmp (arg, "32") == 0) - ppc_xcoff64 = 0; + ppc_obj64 = 0; else return 0; break; case 'm': - /* Most CPU's are 32 bit. Exceptions are listed below. */ - ppc_size = PPC_OPCODE_32; - /* -mpwrx and -mpwr2 mean to assemble for the IBM POWER/2 (RIOS2). */ if (strcmp (arg, "pwrx") == 0 || strcmp (arg, "pwr2") == 0) - ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_POWER2; + ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_POWER2 | PPC_OPCODE_32; /* -mpwr means to assemble for the IBM POWER (RIOS1). */ else if (strcmp (arg, "pwr") == 0) - ppc_cpu = PPC_OPCODE_POWER; - /* -m601 means to assemble for the Motorola PowerPC 601, which includes + ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_32; + /* -m601 means to assemble for the PowerPC 601, which includes instructions that are holdovers from the Power. */ else if (strcmp (arg, "601") == 0) - ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_601; + ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC + | PPC_OPCODE_601 | PPC_OPCODE_32); /* -mppc, -mppc32, -m603, and -m604 mean to assemble for the - Motorola PowerPC 603/604. */ + PowerPC 603/604. */ else if (strcmp (arg, "ppc") == 0 || strcmp (arg, "ppc32") == 0 || strcmp (arg, "603") == 0 || strcmp (arg, "604") == 0) - ppc_cpu = PPC_OPCODE_PPC; - /* -m403 and -m405 mean to assemble for the Motorola PowerPC 403/405. */ + ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32; + /* -m403 and -m405 mean to assemble for the PowerPC 403/405. */ else if (strcmp (arg, "403") == 0 - || strcmp (arg, "405") == 0) - ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_403; + || strcmp (arg, "405") == 0) + ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC + | PPC_OPCODE_403 | PPC_OPCODE_32); else if (strcmp (arg, "7400") == 0 - || strcmp (arg, "7410") == 0 - || strcmp (arg, "7450") == 0 - || strcmp (arg, "7455") == 0) - ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC; + || strcmp (arg, "7410") == 0 + || strcmp (arg, "7450") == 0 + || strcmp (arg, "7455") == 0) + ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC + | PPC_OPCODE_ALTIVEC | PPC_OPCODE_32); else if (strcmp (arg, "altivec") == 0) - ppc_cpu |= PPC_OPCODE_ALTIVEC; + { + if (ppc_cpu == 0) + ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_ALTIVEC; + else + ppc_cpu |= PPC_OPCODE_ALTIVEC; + } + else if (strcmp (arg, "e500") == 0 || strcmp (arg, "e500x2") == 0) + { + ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_SPE + | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK + | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK + | PPC_OPCODE_RFMCI); + } + else if (strcmp (arg, "spe") == 0) + { + if (ppc_cpu == 0) + ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_SPE | PPC_OPCODE_EFS; + else + ppc_cpu |= PPC_OPCODE_SPE; + } /* -mppc64 and -m620 mean to assemble for the 64-bit PowerPC 620. */ else if (strcmp (arg, "ppc64") == 0 || strcmp (arg, "620") == 0) { - ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_64; - ppc_size = PPC_OPCODE_64; + ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64; } else if (strcmp (arg, "ppc64bridge") == 0) { - ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_64_BRIDGE | PPC_OPCODE_64; - ppc_size = PPC_OPCODE_64; + ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC + | PPC_OPCODE_64_BRIDGE | PPC_OPCODE_64); } /* -mbooke/-mbooke32 mean enable 32-bit BookE support. */ else if (strcmp (arg, "booke") == 0 || strcmp (arg, "booke32") == 0) - ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_BOOKE; + { + ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_32; + } /* -mbooke64 means enable 64-bit BookE support. */ else if (strcmp (arg, "booke64") == 0) { - ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | - PPC_OPCODE_BOOKE64 | PPC_OPCODE_64; - ppc_size = PPC_OPCODE_64; + ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE + | PPC_OPCODE_BOOKE64 | PPC_OPCODE_64); + } + else if (strcmp (arg, "power4") == 0) + { + ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC + | PPC_OPCODE_64 | PPC_OPCODE_POWER4); } /* -mcom means assemble for the common intersection between Power and PowerPC. At present, we just allow the union, rather than the intersection. */ else if (strcmp (arg, "com") == 0) - ppc_cpu = PPC_OPCODE_COMMON; + ppc_cpu = PPC_OPCODE_COMMON | PPC_OPCODE_32; /* -many means to assemble for any architecture (PWR/PWRX/PPC). */ else if (strcmp (arg, "any") == 0) - ppc_cpu = PPC_OPCODE_ANY; + ppc_cpu = PPC_OPCODE_ANY | PPC_OPCODE_32; else if (strcmp (arg, "regnames") == 0) - reg_names_p = true; + reg_names_p = TRUE; else if (strcmp (arg, "no-regnames") == 0) - reg_names_p = false; + reg_names_p = FALSE; #ifdef OBJ_ELF /* -mrelocatable/-mrelocatable-lib -- warn about initializations @@ -973,13 +1011,13 @@ md_parse_option (c, arg) else if (strcmp (arg, "solaris") == 0) { - msolaris = true; + msolaris = TRUE; ppc_comment_chars = ppc_solaris_comment_chars; } else if (strcmp (arg, "no-solaris") == 0) { - msolaris = false; + msolaris = FALSE; ppc_comment_chars = ppc_eabi_comment_chars; } #endif @@ -1024,19 +1062,29 @@ md_show_usage (stream) { fprintf (stream, _("\ PowerPC options:\n\ +-a32 generate ELF32/XCOFF32\n\ +-a64 generate ELF64/XCOFF64\n\ -u ignored\n\ --mpwrx, -mpwr2 generate code for IBM POWER/2 (RIOS2)\n\ --mpwr generate code for IBM POWER (RIOS1)\n\ --m601 generate code for Motorola PowerPC 601\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 Motorola PowerPC 603/604\n\ --m403, -m405 generate code for Motorola PowerPC 403/405\n\ --mppc64, -m620 generate code for Motorola PowerPC 620\n\ + generate code for PowerPC 603/604\n\ +-m403, -m405 generate code for PowerPC 403/405\n\ +-m7400, -m7410, -m7450, -m7455\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 Motorola BookE\n\ --mbooke, mbooke32 generate code for 32-bit Motorola BookE\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\ -mcom generate code Power/PowerPC common instructions\n\ --many generate code for any architecture (PWR/PWRX/PPC)\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\ -mregnames Allow symbolic names for registers\n\ -mno-regnames Do not allow symbolic names for registers\n")); #ifdef OBJ_ELF @@ -1044,9 +1092,10 @@ PowerPC options:\n\ -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\ @@ -1064,15 +1113,22 @@ ppc_set_cpu () if (ppc_cpu == 0) { - if (strncmp (default_os, "aix", 3) == 0 - && default_os[3] >= '4' && default_os[3] <= '9') - ppc_cpu = PPC_OPCODE_COMMON; + if (ppc_obj64) + ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64; + else if (strncmp (default_os, "aix", 3) == 0 + && default_os[3] >= '4' && default_os[3] <= '9') + ppc_cpu = PPC_OPCODE_COMMON | PPC_OPCODE_32; else if (strncmp (default_os, "aix3", 4) == 0) - ppc_cpu = PPC_OPCODE_POWER; + ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_32; else if (strcmp (default_cpu, "rs6000") == 0) - ppc_cpu = PPC_OPCODE_POWER; + ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_32; else if (strncmp (default_cpu, "powerpc", 7) == 0) - ppc_cpu = PPC_OPCODE_PPC; + { + if (default_cpu[7] == '6' && default_cpu[8] == '4') + ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64; + else + ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32; + } else as_fatal (_("Unknown default cpu = %s, os = %s"), default_cpu, default_os); @@ -1106,16 +1162,13 @@ ppc_arch () unsigned long ppc_mach () { - return ppc_size == PPC_OPCODE_64 ? 620 : 0; -} - -#ifdef OBJ_XCOFF -int -ppc_subseg_align () -{ - return ppc_xcoff64 ? 3 : 2; + if (ppc_obj64) + return bfd_mach_ppc64; + else if (ppc_arch () == bfd_arch_rs6000) + return bfd_mach_rs6k; + else + return bfd_mach_ppc; } -#endif extern char* ppc_target_format () @@ -1126,13 +1179,17 @@ ppc_target_format () #elif TE_POWERMAC return "xcoff-powermac"; #else - return ppc_xcoff64 ? "aixcoff64-rs6000" : "aixcoff-rs6000"; +# ifdef TE_AIX5 + return (ppc_obj64 ? "aix5coff64-rs6000" : "aixcoff-rs6000"); +# else + return (ppc_obj64 ? "aixcoff64-rs6000" : "aixcoff-rs6000"); +# endif #endif #endif #ifdef OBJ_ELF return (target_big_endian - ? (BFD_DEFAULT_TARGET_SIZE == 64 ? "elf64-powerpc" : "elf32-powerpc") - : (BFD_DEFAULT_TARGET_SIZE == 64 ? "elf64-powerpcle" : "elf32-powerpcle")); + ? (ppc_obj64 ? "elf64-powerpc" : "elf32-powerpc") + : (ppc_obj64 ? "elf64-powerpcle" : "elf32-powerpcle")); #endif } @@ -1147,16 +1204,11 @@ md_begin () const struct powerpc_opcode *op_end; const struct powerpc_macro *macro; const struct powerpc_macro *macro_end; - boolean dup_insn = false; + bfd_boolean dup_insn = FALSE; ppc_set_cpu (); #ifdef OBJ_ELF - /* If we're going to generate a 64-bit ABI file, then we need - the 64-bit capable instructions. */ - if (BFD_DEFAULT_TARGET_SIZE == 64) - ppc_size = PPC_OPCODE_64; - /* Set the ELF flags if desired. */ if (ppc_flags && !msolaris) bfd_set_private_flags (stdoutput, ppc_flags); @@ -1170,10 +1222,22 @@ md_begin () { know ((op->opcode & op->mask) == op->opcode); - if ((op->flags & ppc_cpu) != 0 + if ((op->flags & ppc_cpu & ~(PPC_OPCODE_32 | PPC_OPCODE_64)) != 0 && ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64)) == 0 - || (op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64)) == ppc_size - || (ppc_cpu & PPC_OPCODE_64_BRIDGE) != 0)) + || ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64)) + == (ppc_cpu & (PPC_OPCODE_32 | PPC_OPCODE_64))) + || (ppc_cpu & PPC_OPCODE_64_BRIDGE) != 0) + /* Certain instructions (eg: extsw) do not exist in the + 32-bit BookE instruction set, but they do exist in the + 64-bit BookE instruction set, and other PPC instruction + sets. Check to see if the opcode has the BOOKE64 flag set. + If it does make sure that the target CPU is not the BookE32. */ + && ((op->flags & PPC_OPCODE_BOOKE64) == 0 + || (ppc_cpu & PPC_OPCODE_BOOKE64) == PPC_OPCODE_BOOKE64 + || (ppc_cpu & PPC_OPCODE_BOOKE) == 0) + && ((op->flags & (PPC_OPCODE_POWER4 | PPC_OPCODE_NOPOWER4)) == 0 + || ((op->flags & PPC_OPCODE_POWER4) + == (ppc_cpu & PPC_OPCODE_POWER4)))) { const char *retval; @@ -1187,7 +1251,7 @@ md_begin () as_bad (_("Internal assembler error for instruction %s"), op->name); - dup_insn = true; + dup_insn = TRUE; } } } @@ -1206,7 +1270,7 @@ md_begin () if (retval != (const char *) NULL) { as_bad (_("Internal assembler error for macro %s"), macro->name); - dup_insn = true; + dup_insn = TRUE; } } } @@ -1242,6 +1306,66 @@ md_begin () #endif } +void +ppc_cleanup () +{ +#ifdef OBJ_ELF + if (ppc_apuinfo_list == NULL) + return; + + /* Ok, so write the section info out. We have this layout: + + byte data what + ---- ---- ---- + 0 8 length of "APUinfo\0" + 4 (n*4) number of APU's (4 bytes each) + 8 2 note type 2 + 12 "APUinfo\0" name + 20 APU#1 first APU's info + 24 APU#2 second APU's info + ... ... + */ + { + char *p; + asection *seg = now_seg; + subsegT subseg = now_subseg; + asection *apuinfo_secp = (asection *) NULL; + unsigned int i; + + /* Create the .PPC.EMB.apuinfo section. */ + apuinfo_secp = subseg_new (".PPC.EMB.apuinfo", 0); + bfd_set_section_flags (stdoutput, + apuinfo_secp, + SEC_HAS_CONTENTS | SEC_READONLY); + + p = frag_more (4); + md_number_to_chars (p, (valueT) 8, 4); + + p = frag_more (4); + md_number_to_chars (p, (valueT) ppc_apuinfo_num, 4); + + p = frag_more (4); + md_number_to_chars (p, (valueT) 2, 4); + + p = frag_more (8); + strcpy (p, "APUinfo"); + + for (i = 0; i < ppc_apuinfo_num; i++) + { + p = frag_more (4); + md_number_to_chars (p, (valueT) ppc_apuinfo_list[i], 4); + } + + frag_align (2, 0, 0); + + /* We probably can't restore the current segment, for there likely + isn't one yet... */ + if (seg && subseg) + subseg_set (seg, subseg); + } +#endif +} + /* Insert an operand value into an instruction. */ static unsigned long @@ -1265,7 +1389,7 @@ ppc_insert_operand (insn, operand, val, file, line) max = (1 << (operand->bits - 1)) - 1; min = - (1 << (operand->bits - 1)); - if (ppc_size == PPC_OPCODE_32) + if (!ppc_obj64) { /* Some people write 32 bit hex constants with the sign extension done by hand. This shouldn't really be @@ -1307,7 +1431,7 @@ ppc_insert_operand (insn, operand, val, file, line) const char *errmsg; errmsg = NULL; - insn = (*operand->insert) (insn, (long) val, &errmsg); + insn = (*operand->insert) (insn, (long) val, ppc_cpu, &errmsg); if (errmsg != (const char *) NULL) as_bad_where (file, line, errmsg); } @@ -1329,7 +1453,7 @@ ppc_elf_suffix (str_p, exp_p) struct map_bfd { char *string; int length; - bfd_reloc_code_real_type reloc; + int reloc; }; char ident[20]; @@ -1337,65 +1461,99 @@ ppc_elf_suffix (str_p, exp_p) char *str2; int ch; int len; - struct map_bfd *ptr; + const struct map_bfd *ptr; #define MAP(str,reloc) { str, sizeof (str)-1, reloc } - static struct map_bfd mapping[] = { - 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", BFD_RELOC_16_GOTOFF), - 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 ("plt", BFD_RELOC_24_PLT_PCREL), - 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 ("local", BFD_RELOC_PPC_LOCAL24PC), - 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), - MAP ("naddr", BFD_RELOC_PPC_EMB_NADDR32), - MAP ("naddr16", BFD_RELOC_PPC_EMB_NADDR16), - MAP ("naddr@l", BFD_RELOC_PPC_EMB_NADDR16_LO), - MAP ("naddr@h", BFD_RELOC_PPC_EMB_NADDR16_HI), - MAP ("naddr@ha", BFD_RELOC_PPC_EMB_NADDR16_HA), - MAP ("sdai16", BFD_RELOC_PPC_EMB_SDAI16), - MAP ("sda2rel", BFD_RELOC_PPC_EMB_SDA2REL), - MAP ("sda2i16", BFD_RELOC_PPC_EMB_SDA2I16), - MAP ("sda21", BFD_RELOC_PPC_EMB_SDA21), - MAP ("mrkref", BFD_RELOC_PPC_EMB_MRKREF), - MAP ("relsect", BFD_RELOC_PPC_EMB_RELSEC16), - MAP ("relsect@l", BFD_RELOC_PPC_EMB_RELST_LO), - MAP ("relsect@h", BFD_RELOC_PPC_EMB_RELST_HI), - MAP ("relsect@ha", BFD_RELOC_PPC_EMB_RELST_HA), - MAP ("bitfld", BFD_RELOC_PPC_EMB_BIT_FLD), - MAP ("relsda", BFD_RELOC_PPC_EMB_RELSDA), - MAP ("xgot", BFD_RELOC_PPC_TOC16), -#if BFD_DEFAULT_TARGET_SIZE == 64 - MAP ("higher", BFD_RELOC_PPC64_HIGHER), - MAP ("highera", BFD_RELOC_PPC64_HIGHER_S), - MAP ("highest", BFD_RELOC_PPC64_HIGHEST), - MAP ("highesta", BFD_RELOC_PPC64_HIGHEST_S), - MAP ("tocbase", BFD_RELOC_PPC64_TOC), - MAP ("toc", BFD_RELOC_PPC_TOC16), - MAP ("toc@l", BFD_RELOC_PPC64_TOC16_LO), - MAP ("toc@h", BFD_RELOC_PPC64_TOC16_HI), - MAP ("toc@ha", BFD_RELOC_PPC64_TOC16_HA), -#endif - { (char *) 0, 0, BFD_RELOC_UNUSED } + static const struct map_bfd mapping[] = { + MAP ("l", (int) BFD_RELOC_LO16), + MAP ("h", (int) BFD_RELOC_HI16), + MAP ("ha", (int) BFD_RELOC_HI16_S), + MAP ("brtaken", (int) BFD_RELOC_PPC_B16_BRTAKEN), + MAP ("brntaken", (int) BFD_RELOC_PPC_B16_BRNTAKEN), + MAP ("got", (int) BFD_RELOC_16_GOTOFF), + MAP ("got@l", (int) BFD_RELOC_LO16_GOTOFF), + MAP ("got@h", (int) BFD_RELOC_HI16_GOTOFF), + MAP ("got@ha", (int) BFD_RELOC_HI16_S_GOTOFF), + MAP ("fixup", (int) BFD_RELOC_CTOR), + MAP ("plt", (int) BFD_RELOC_24_PLT_PCREL), + MAP ("pltrel24", (int) BFD_RELOC_24_PLT_PCREL), + MAP ("copy", (int) BFD_RELOC_PPC_COPY), + MAP ("globdat", (int) BFD_RELOC_PPC_GLOB_DAT), + MAP ("local24pc", (int) BFD_RELOC_PPC_LOCAL24PC), + MAP ("local", (int) BFD_RELOC_PPC_LOCAL24PC), + MAP ("pltrel", (int) BFD_RELOC_32_PLT_PCREL), + MAP ("plt@l", (int) BFD_RELOC_LO16_PLTOFF), + MAP ("plt@h", (int) BFD_RELOC_HI16_PLTOFF), + MAP ("plt@ha", (int) BFD_RELOC_HI16_S_PLTOFF), + MAP ("sdarel", (int) BFD_RELOC_GPREL16), + MAP ("sectoff", (int) BFD_RELOC_16_BASEREL), + MAP ("sectoff@l", (int) BFD_RELOC_LO16_BASEREL), + MAP ("sectoff@h", (int) BFD_RELOC_HI16_BASEREL), + MAP ("sectoff@ha", (int) BFD_RELOC_HI16_S_BASEREL), + MAP ("naddr", (int) BFD_RELOC_PPC_EMB_NADDR32), + MAP ("naddr16", (int) BFD_RELOC_PPC_EMB_NADDR16), + MAP ("naddr@l", (int) BFD_RELOC_PPC_EMB_NADDR16_LO), + MAP ("naddr@h", (int) BFD_RELOC_PPC_EMB_NADDR16_HI), + MAP ("naddr@ha", (int) BFD_RELOC_PPC_EMB_NADDR16_HA), + MAP ("sdai16", (int) BFD_RELOC_PPC_EMB_SDAI16), + MAP ("sda2rel", (int) BFD_RELOC_PPC_EMB_SDA2REL), + MAP ("sda2i16", (int) BFD_RELOC_PPC_EMB_SDA2I16), + MAP ("sda21", (int) BFD_RELOC_PPC_EMB_SDA21), + MAP ("mrkref", (int) BFD_RELOC_PPC_EMB_MRKREF), + MAP ("relsect", (int) BFD_RELOC_PPC_EMB_RELSEC16), + MAP ("relsect@l", (int) BFD_RELOC_PPC_EMB_RELST_LO), + MAP ("relsect@h", (int) BFD_RELOC_PPC_EMB_RELST_HI), + MAP ("relsect@ha", (int) BFD_RELOC_PPC_EMB_RELST_HA), + MAP ("bitfld", (int) BFD_RELOC_PPC_EMB_BIT_FLD), + MAP ("relsda", (int) BFD_RELOC_PPC_EMB_RELSDA), + MAP ("xgot", (int) BFD_RELOC_PPC_TOC16), + MAP ("tls", (int) BFD_RELOC_PPC_TLS), + MAP ("dtpmod", (int) BFD_RELOC_PPC_DTPMOD), + MAP ("dtprel", (int) BFD_RELOC_PPC_DTPREL), + MAP ("dtprel@l", (int) BFD_RELOC_PPC_DTPREL16_LO), + MAP ("dtprel@h", (int) BFD_RELOC_PPC_DTPREL16_HI), + MAP ("dtprel@ha", (int) BFD_RELOC_PPC_DTPREL16_HA), + MAP ("tprel", (int) BFD_RELOC_PPC_TPREL), + MAP ("tprel@l", (int) BFD_RELOC_PPC_TPREL16_LO), + MAP ("tprel@h", (int) BFD_RELOC_PPC_TPREL16_HI), + MAP ("tprel@ha", (int) BFD_RELOC_PPC_TPREL16_HA), + MAP ("got@tlsgd", (int) BFD_RELOC_PPC_GOT_TLSGD16), + MAP ("got@tlsgd@l", (int) BFD_RELOC_PPC_GOT_TLSGD16_LO), + MAP ("got@tlsgd@h", (int) BFD_RELOC_PPC_GOT_TLSGD16_HI), + MAP ("got@tlsgd@ha", (int) BFD_RELOC_PPC_GOT_TLSGD16_HA), + MAP ("got@tlsld", (int) BFD_RELOC_PPC_GOT_TLSLD16), + MAP ("got@tlsld@l", (int) BFD_RELOC_PPC_GOT_TLSLD16_LO), + MAP ("got@tlsld@h", (int) BFD_RELOC_PPC_GOT_TLSLD16_HI), + MAP ("got@tlsld@ha", (int) BFD_RELOC_PPC_GOT_TLSLD16_HA), + MAP ("got@dtprel", (int) BFD_RELOC_PPC_GOT_DTPREL16), + MAP ("got@dtprel@l", (int) BFD_RELOC_PPC_GOT_DTPREL16_LO), + MAP ("got@dtprel@h", (int) BFD_RELOC_PPC_GOT_DTPREL16_HI), + MAP ("got@dtprel@ha", (int) BFD_RELOC_PPC_GOT_DTPREL16_HA), + MAP ("got@tprel", (int) BFD_RELOC_PPC_GOT_TPREL16), + MAP ("got@tprel@l", (int) BFD_RELOC_PPC_GOT_TPREL16_LO), + MAP ("got@tprel@h", (int) BFD_RELOC_PPC_GOT_TPREL16_HI), + MAP ("got@tprel@ha", (int) BFD_RELOC_PPC_GOT_TPREL16_HA), + /* The following are only valid for ppc64. Negative values are + used instead of a flag. */ + MAP ("higher", - (int) BFD_RELOC_PPC64_HIGHER), + MAP ("highera", - (int) BFD_RELOC_PPC64_HIGHER_S), + MAP ("highest", - (int) BFD_RELOC_PPC64_HIGHEST), + MAP ("highesta", - (int) BFD_RELOC_PPC64_HIGHEST_S), + MAP ("tocbase", - (int) BFD_RELOC_PPC64_TOC), + MAP ("toc", - (int) BFD_RELOC_PPC_TOC16), + MAP ("toc@l", - (int) BFD_RELOC_PPC64_TOC16_LO), + MAP ("toc@h", - (int) BFD_RELOC_PPC64_TOC16_HI), + MAP ("toc@ha", - (int) BFD_RELOC_PPC64_TOC16_HA), + MAP ("dtprel@higher", - (int) BFD_RELOC_PPC64_DTPREL16_HIGHER), + MAP ("dtprel@highera", - (int) BFD_RELOC_PPC64_DTPREL16_HIGHERA), + MAP ("dtprel@highest", - (int) BFD_RELOC_PPC64_DTPREL16_HIGHEST), + MAP ("dtprel@highesta", - (int) BFD_RELOC_PPC64_DTPREL16_HIGHESTA), + MAP ("tprel@higher", - (int) BFD_RELOC_PPC64_TPREL16_HIGHER), + MAP ("tprel@highera", - (int) BFD_RELOC_PPC64_TPREL16_HIGHERA), + MAP ("tprel@highest", - (int) BFD_RELOC_PPC64_TPREL16_HIGHEST), + MAP ("tprel@highesta", - (int) BFD_RELOC_PPC64_TPREL16_HIGHESTA), + { (char *) 0, 0, (int) BFD_RELOC_UNUSED } }; if (*str++ != '@') @@ -1418,12 +1576,22 @@ ppc_elf_suffix (str_p, exp_p) && len == ptr->length && memcmp (ident, ptr->string, ptr->length) == 0) { - if (exp_p->X_add_number != 0 - && (ptr->reloc == BFD_RELOC_16_GOTOFF - || ptr->reloc == BFD_RELOC_LO16_GOTOFF - || ptr->reloc == BFD_RELOC_HI16_GOTOFF - || ptr->reloc == BFD_RELOC_HI16_S_GOTOFF)) - as_warn (_("identifier+constant@got means identifier@got+constant")); + int reloc = ptr->reloc; + + if (reloc < 0) + { + if (!ppc_obj64) + return BFD_RELOC_UNUSED; + reloc = -reloc; + } + + 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 == '+') @@ -1444,8 +1612,7 @@ ppc_elf_suffix (str_p, exp_p) } *str_p = str; - if (BFD_DEFAULT_TARGET_SIZE == 64 - && ptr->reloc == BFD_RELOC_PPC64_TOC + if (reloc == (int) BFD_RELOC_PPC64_TOC && exp_p->X_op == O_symbol) { /* This reloc type ignores the symbol. Change the symbol @@ -1454,7 +1621,7 @@ ppc_elf_suffix (str_p, exp_p) exp_p->X_add_symbol = &abs_symbol; } - return ptr->reloc; + return (bfd_reloc_code_real_type) reloc; } return BFD_RELOC_UNUSED; @@ -1663,7 +1830,7 @@ ppc_elf_validate_fix (fixp, seg) && fixp->fx_r_type != BFD_RELOC_HI16_GOTOFF && fixp->fx_r_type != BFD_RELOC_LO16_GOTOFF && fixp->fx_r_type != BFD_RELOC_HI16_S_GOTOFF - && fixp->fx_r_type != BFD_RELOC_32_BASEREL + && fixp->fx_r_type != BFD_RELOC_16_BASEREL && fixp->fx_r_type != BFD_RELOC_LO16_BASEREL && fixp->fx_r_type != BFD_RELOC_HI16_BASEREL && fixp->fx_r_type != BFD_RELOC_HI16_S_BASEREL @@ -1687,24 +1854,50 @@ ppc_elf_validate_fix (fixp, seg) } } -#if BFD_DEFAULT_TARGET_SIZE == 64 -/* Don't emit .TOC. symbol. */ -int -ppc_elf_frob_symbol (sym) - symbolS *sym; +/* Prevent elf_frob_file_before_adjust removing a weak undefined + function descriptor sym if the corresponding code sym is used. */ + +void +ppc_frob_file_before_adjust () { - const char *name; + symbolS *symp; + + if (!ppc_obj64) + return; - name = S_GET_NAME (sym); - if (name != NULL && strcmp (name, ".TOC.") == 0) + for (symp = symbol_rootP; symp; symp = symbol_next (symp)) { - S_CLEAR_EXTERNAL (sym); - return 1; + const char *name; + char *dotname; + symbolS *dotsym; + size_t len; + + name = S_GET_NAME (symp); + if (name[0] == '.') + continue; + + if (! S_IS_WEAK (symp) + || S_IS_DEFINED (symp)) + continue; + + len = strlen (name) + 1; + dotname = xmalloc (len + 1); + dotname[0] = '.'; + memcpy (dotname + 1, name, len); + dotsym = symbol_find (dotname); + free (dotname); + if (dotsym != NULL && (symbol_used_p (dotsym) + || symbol_used_in_reloc_p (dotsym))) + { + symbol_mark_used (symp); + } } - return 0; + /* Don't emit .TOC. symbol. */ + symp = symbol_find (".TOC."); + if (symp != NULL) + symbol_remove (symp, &symbol_rootP, &symbol_lastP); } -#endif #endif /* OBJ_ELF */ #ifdef TE_PE @@ -1805,6 +1998,40 @@ parse_toc_entry (toc_kind) #endif +#ifdef OBJ_ELF +#define APUID(a,v) ((((a) & 0xffff) << 16) | ((v) & 0xffff)) +static void +ppc_apuinfo_section_add (apu, version) + unsigned int apu, version; +{ + unsigned int i; + + /* Check we don't already exist. */ + for (i = 0; i < ppc_apuinfo_num; i++) + if (ppc_apuinfo_list[i] == APUID (apu, version)) + return; + + if (ppc_apuinfo_num == ppc_apuinfo_num_alloc) + { + if (ppc_apuinfo_num_alloc == 0) + { + ppc_apuinfo_num_alloc = 4; + ppc_apuinfo_list = (unsigned long *) + xmalloc (sizeof (unsigned long) * ppc_apuinfo_num_alloc); + } + else + { + ppc_apuinfo_num_alloc += 4; + ppc_apuinfo_list = (unsigned long *) xrealloc (ppc_apuinfo_list, + sizeof (unsigned long) * ppc_apuinfo_num_alloc); + } + } + ppc_apuinfo_list[ppc_apuinfo_num++] = APUID (apu, version); +} +#undef APUID +#endif + + /* We need to keep a list of fixups. We can't simply generate them as we go, because that would require us to first create the frag, and that would screw up references to ``.''. */ @@ -1884,6 +2111,8 @@ md_assemble (str) if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0) { unsigned int opcount; + unsigned int num_operands_expected; + unsigned int i; /* There is an optional operand. Count the number of commas in the input line. */ @@ -1900,10 +2129,16 @@ md_assemble (str) } } + /* Compute the number of expected operands. + Do not count fake operands. */ + for (num_operands_expected = 0, i = 0; opcode->operands[i]; i ++) + if ((powerpc_operands [opcode->operands[i]].flags & PPC_OPERAND_FAKE) == 0) + ++ num_operands_expected; + /* If there are fewer operands in the line then are called for by the instruction, we want to skip the optional operand. */ - if (opcount < strlen (opcode->operands)) + if (opcount < num_operands_expected) skip_optional = 1; break; @@ -1929,14 +2164,13 @@ md_assemble (str) operand = &powerpc_operands[next_opindex]; next_opindex = 0; } - errmsg = NULL; /* If this is a fake operand, then we do not expect anything from the input. */ if ((operand->flags & PPC_OPERAND_FAKE) != 0) { - insn = (*operand->insert) (insn, 0L, &errmsg); + insn = (*operand->insert) (insn, 0L, ppc_cpu, &errmsg); if (errmsg != (const char *) NULL) as_bad (errmsg); continue; @@ -1949,7 +2183,7 @@ md_assemble (str) { if (operand->insert) { - insn = (*operand->insert) (insn, 0L, &errmsg); + insn = (*operand->insert) (insn, 0L, ppc_cpu, &errmsg); if (errmsg != (const char *) NULL) as_bad (errmsg); } @@ -2080,9 +2314,9 @@ md_assemble (str) if (! register_name (&ex)) { if ((operand->flags & PPC_OPERAND_CR) != 0) - cr_operand = true; + cr_operand = TRUE; expression (&ex); - cr_operand = false; + cr_operand = FALSE; } } @@ -2135,7 +2369,6 @@ md_assemble (str) ex.X_add_number = SEX16 (PPC_HA (ex.X_add_number)); break; -#if BFD_DEFAULT_TARGET_SIZE == 64 case BFD_RELOC_PPC64_HIGHER: if (ex.X_unsigned && ! (operand->flags & PPC_OPERAND_SIGNED)) ex.X_add_number = PPC_HIGHER (ex.X_add_number); @@ -2163,7 +2396,6 @@ md_assemble (str) else ex.X_add_number = SEX16 (PPC_HIGHESTA (ex.X_add_number)); break; -#endif /* BFD_DEFAULT_TARGET_SIZE == 64 */ } #endif /* OBJ_ELF */ insn = ppc_insert_operand (insn, operand, ex.X_add_number, @@ -2172,6 +2404,25 @@ md_assemble (str) #ifdef OBJ_ELF else if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED) { + /* Some TLS tweaks. */ + switch (reloc) + { + default: + break; + case BFD_RELOC_PPC_TLS: + insn = ppc_insert_operand (insn, operand, ppc_obj64 ? 13 : 2, + (char *) NULL, 0); + break; + /* We'll only use the 32 (or 64) bit form of these relocations + in constants. Instructions get the 16 bit form. */ + case BFD_RELOC_PPC_DTPREL: + reloc = BFD_RELOC_PPC_DTPREL16; + break; + case BFD_RELOC_PPC_TPREL: + reloc = BFD_RELOC_PPC_TPREL16; + break; + } + /* For the absolute forms of branches, convert the PC relative form back into the absolute. */ if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) @@ -2195,9 +2446,8 @@ md_assemble (str) } } - if (BFD_DEFAULT_TARGET_SIZE == 64 - && ppc_size == PPC_OPCODE_64 - && (operand->flags & PPC_OPERAND_DS) != 0) + if (ppc_obj64 + && (operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0) { switch (reloc) { @@ -2216,7 +2466,7 @@ md_assemble (str) case BFD_RELOC_LO16_PLTOFF: reloc = BFD_RELOC_PPC64_PLT16_LO_DS; break; - case BFD_RELOC_32_BASEREL: + case BFD_RELOC_16_BASEREL: reloc = BFD_RELOC_PPC64_SECTOFF_DS; break; case BFD_RELOC_LO16_BASEREL: @@ -2234,6 +2484,23 @@ md_assemble (str) case BFD_RELOC_PPC64_PLTGOT16_LO: reloc = BFD_RELOC_PPC64_PLTGOT16_LO_DS; break; + case BFD_RELOC_PPC_DTPREL16: + reloc = BFD_RELOC_PPC64_DTPREL16_DS; + break; + case BFD_RELOC_PPC_DTPREL16_LO: + reloc = BFD_RELOC_PPC64_DTPREL16_LO_DS; + break; + case BFD_RELOC_PPC_TPREL16: + reloc = BFD_RELOC_PPC64_TPREL16_DS; + break; + case BFD_RELOC_PPC_TPREL16_LO: + reloc = BFD_RELOC_PPC64_TPREL16_LO_DS; + break; + case BFD_RELOC_PPC_GOT_DTPREL16: + case BFD_RELOC_PPC_GOT_DTPREL16_LO: + case BFD_RELOC_PPC_GOT_TPREL16: + case BFD_RELOC_PPC_GOT_TPREL16_LO: + break; default: as_bad (_("unsupported relocation for DS offset field")); break; @@ -2293,6 +2560,31 @@ md_assemble (str) if (*str != '\0') as_bad (_("junk at end of line: `%s'"), str); +#ifdef OBJ_ELF + /* Do we need/want a APUinfo section? */ + if (ppc_cpu & (PPC_OPCODE_SPE + | PPC_OPCODE_ISEL | PPC_OPCODE_EFS + | PPC_OPCODE_BRLOCK | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK + | PPC_OPCODE_RFMCI)) + { + /* These are all version "1". */ + if (opcode->flags & PPC_OPCODE_SPE) + ppc_apuinfo_section_add (PPC_APUINFO_SPE, 1); + if (opcode->flags & PPC_OPCODE_ISEL) + ppc_apuinfo_section_add (PPC_APUINFO_ISEL, 1); + if (opcode->flags & PPC_OPCODE_EFS) + ppc_apuinfo_section_add (PPC_APUINFO_EFS, 1); + if (opcode->flags & PPC_OPCODE_BRLOCK) + ppc_apuinfo_section_add (PPC_APUINFO_BRLOCK, 1); + if (opcode->flags & PPC_OPCODE_PMR) + ppc_apuinfo_section_add (PPC_APUINFO_PMR, 1); + if (opcode->flags & PPC_OPCODE_CACHELCK) + ppc_apuinfo_section_add (PPC_APUINFO_CACHELCK, 1); + if (opcode->flags & PPC_OPCODE_RFMCI) + ppc_apuinfo_section_add (PPC_APUINFO_RFMCI, 1); + } +#endif + /* Write out the instruction. */ f = frag_more (4); md_number_to_chars (f, insn, 4); @@ -2306,7 +2598,7 @@ md_assemble (str) BFD_RELOC_UNUSED plus the operand index. This lets us easily handle fixups for any operand type, although that is admittedly not a very exciting feature. We pick a BFD reloc type in - md_apply_fix. */ + md_apply_fix3. */ for (i = 0; i < fc; i++) { const struct powerpc_operand *operand; @@ -2346,12 +2638,10 @@ md_assemble (str) case BFD_RELOC_HI16: case BFD_RELOC_HI16_S: #ifdef OBJ_ELF -#if BFD_DEFAULT_TARGET_SIZE == 64 case BFD_RELOC_PPC64_HIGHER: case BFD_RELOC_PPC64_HIGHER_S: case BFD_RELOC_PPC64_HIGHEST: case BFD_RELOC_PPC64_HIGHEST_S: -#endif #endif fixP->fx_no_overflow = 1; break; @@ -2461,8 +2751,8 @@ ppc_section_letter (letter, ptr_msg) if (letter == 'e') return SHF_EXCLUDE; - *ptr_msg = _("Bad .section directive: want a,e,w,x,M,S in string"); - return 0; + *ptr_msg = _("Bad .section directive: want a,e,w,x,M,S,G,T in string"); + return -1; } int @@ -2547,7 +2837,7 @@ ppc_byte (ignore) /* This is set if we are creating a .stabx symbol, since we don't want to handle symbol suffixes for such symbols. */ -static boolean ppc_stab_symbol; +static bfd_boolean ppc_stab_symbol; /* The .comm and .lcomm pseudo-ops for XCOFF. XCOFF puts common symbols in the .bss segment as though they were local common @@ -2812,7 +3102,7 @@ ppc_change_csect (sym) symbol_set_frag (sym, frag_now); S_SET_VALUE (sym, (valueT) frag_now_fix ()); - symbol_get_tc (sym)->align = (ppc_xcoff64) ? 3 : 2; + symbol_get_tc (sym)->align = 2; symbol_get_tc (sym)->output = 1; symbol_get_tc (sym)->within = sym; @@ -2990,9 +3280,9 @@ ppc_stabx (ignore) } ++input_line_pointer; - ppc_stab_symbol = true; + ppc_stab_symbol = TRUE; sym = symbol_make (name); - ppc_stab_symbol = false; + ppc_stab_symbol = FALSE; symbol_get_tc (sym)->real_name = name; @@ -3190,7 +3480,7 @@ ppc_function (ignore) /* The .bf pseudo-op. This is just like a COFF C_FCN symbol named ".bf". If the pseudo op .bi was seen before .bf, patch the .bi sym with the correct line number */ - + static symbolS *saved_bi_sym = 0; static void @@ -3211,12 +3501,12 @@ ppc_bf (ignore) SA_SET_SYM_LNNO (sym, coff_line_base); /* Line number for bi. */ - if (saved_bi_sym) + if (saved_bi_sym) { S_SET_VALUE (saved_bi_sym, coff_n_line_nos); saved_bi_sym = 0; } - + symbol_get_tc (sym)->output = 1; @@ -3283,7 +3573,7 @@ ppc_biei (ei) symbol_get_tc (sym)->output = 1; /* Save bi. */ - if (ei) + if (ei) saved_bi_sym = 0; else saved_bi_sym = sym; @@ -3636,7 +3926,7 @@ ppc_tc (ignore) ++input_line_pointer; /* Align to a four/eight byte boundary. */ - align = BFD_DEFAULT_TARGET_SIZE == 64 && ppc_size == PPC_OPCODE_64 ? 3 : 2; + align = ppc_obj64 ? 3 : 2; frag_align (align, 0, 0); record_alignment (now_seg, align); #endif /* OBJ_ELF */ @@ -3646,12 +3936,17 @@ ppc_tc (ignore) else { ++input_line_pointer; - cons ((ppc_size == PPC_OPCODE_64) ? 8 : 4); + cons (ppc_obj64 ? 8 : 4); } } /* Pseudo-op .machine. */ -/* FIXME: `.machine' is a nop for the moment. */ +/* FIXME: `.machine' is a nop for the moment. It would be nice to + accept this directive on the first line of input and set ppc_obj64 + and the target format accordingly. Unfortunately, the target + format is selected in output-file.c:output_file_create before we + even get to md_begin, so it's not possible without changing + as.c:main. */ static void ppc_machine (ignore) @@ -3671,7 +3966,7 @@ ppc_is_toc_sym (sym) #endif #ifdef OBJ_ELF const char *sname = segment_name (S_GET_SEGMENT (sym)); - if (BFD_DEFAULT_TARGET_SIZE == 64 && ppc_size == PPC_OPCODE_64) + if (ppc_obj64) return strcmp (sname, ".toc") == 0; else return strcmp (sname, ".got") == 0; @@ -3716,11 +4011,11 @@ ppc_previous (ignore) /* pseudo-op: .pdata behaviour: predefined read only data section - double word aligned + double word aligned errors: None warnings: None initial: .section .pdata "adr3" - a - don't know -- maybe a misprint + a - don't know -- maybe a misprint d - initialized data r - readable 3 - double word aligned (that would be 4 byte boundary) @@ -3752,11 +4047,11 @@ ppc_pdata (ignore) /* pseudo-op: .ydata behaviour: predefined read only data section - double word aligned + double word aligned errors: None warnings: None initial: .section .ydata "drw3" - a - don't know -- maybe a misprint + a - don't know -- maybe a misprint d - initialized data r - readable 3 - double word aligned (that would be 4 byte boundary) @@ -3786,7 +4081,7 @@ ppc_ydata (ignore) /* pseudo-op: .reldata behaviour: predefined read write data section - double word aligned (4-byte) + double word aligned (4-byte) FIXME: relocation is applied to it FIXME: what's the difference between this and .data? errors: None @@ -3824,7 +4119,7 @@ ppc_reldata (ignore) /* pseudo-op: .rdata behaviour: predefined read only data section - double word aligned + double word aligned errors: None warnings: None initial: .section .rdata "dr3" @@ -3854,7 +4149,7 @@ ppc_rdata (ignore) /* pseudo-op: .ualong behaviour: much like .int, with the exception that no alignment is - performed. + performed. FIXME: test the alignment statement errors: None warnings: None */ @@ -3869,7 +4164,7 @@ ppc_ualong (ignore) /* pseudo-op: .znop behaviour: Issue a nop instruction - Issue a IMAGE_REL_PPC_IFGLUE relocation against it, using + Issue a IMAGE_REL_PPC_IFGLUE relocation against it, using the supplied symbol name. errors: None warnings: Missing symbol name */ @@ -4431,7 +4726,7 @@ ppc_frob_label (sym) seen. It tells ppc_adjust_symtab whether it needs to look through the symbols. */ -static boolean ppc_saw_abs; +static bfd_boolean ppc_saw_abs; /* Change the name of a symbol just before writing it out. Set the real name if the .rename pseudo-op was used. Otherwise, remove any @@ -4454,6 +4749,10 @@ ppc_frob_symbol (sym) && S_GET_STORAGE_CLASS (sym) != C_FILE))) return 1; + /* This one will disappear anyway. Don't make a csect sym for it. */ + if (sym == abs_section_sym) + return 1; + if (symbol_get_tc (sym)->real_name != (char *) NULL) S_SET_NAME (sym, symbol_get_tc (sym)->real_name); else @@ -4570,7 +4869,7 @@ ppc_frob_symbol (sym) { /* This is an absolute symbol. The csect will be created by ppc_adjust_symtab. */ - ppc_saw_abs = true; + ppc_saw_abs = TRUE; a->x_csect.x_smtyp = XTY_LD; if (symbol_get_tc (sym)->class == -1) symbol_get_tc (sym)->class = XMC_XO; @@ -4666,10 +4965,10 @@ ppc_frob_symbol (sym) /* We want the value to be the symbol index of the referenced csect symbol. BFD will do that for us if we set the right flags. */ - S_SET_VALUE (sym, - ((valueT) - coffsymbol (symbol_get_bfdsym - (symbol_get_tc (sym)->within))->native)); + asymbol *bsym = symbol_get_bfdsym (symbol_get_tc (sym)->within); + combined_entry_type *c = coffsymbol (bsym)->native; + + S_SET_VALUE (sym, (valueT) (size_t) c); coffsymbol (symbol_get_bfdsym (sym))->native->fix_value = 1; } else if (S_GET_STORAGE_CLASS (sym) == C_STSYM) @@ -4738,7 +5037,7 @@ ppc_adjust_symtab () coffsymbol (symbol_get_bfdsym (sym))->native[i].fix_scnlen = 1; } - ppc_saw_abs = false; + ppc_saw_abs = FALSE; } /* Set the VMA for a section. This is called on all the sections in @@ -4895,14 +5194,16 @@ int ppc_fix_adjustable (fix) fixS *fix; { - valueT val; + valueT val = resolve_symbol_value (fix->fx_addsy); + segT symseg = S_GET_SEGMENT (fix->fx_addsy); + TC_SYMFIELD_TYPE *tc; + + if (symseg == absolute_section) + return 0; - resolve_symbol_value (fix->fx_addsy); - val = S_GET_VALUE (fix->fx_addsy); if (ppc_toc_csect != (symbolS *) NULL - && fix->fx_addsy != (symbolS *) NULL && fix->fx_addsy != ppc_toc_csect - && S_GET_SEGMENT (fix->fx_addsy) == data_section + && symseg == data_section && val >= ppc_toc_frag->fr_address && (ppc_after_toc_frag == (fragS *) NULL || val < ppc_after_toc_frag->fr_address)) @@ -4913,12 +5214,13 @@ ppc_fix_adjustable (fix) sy != (symbolS *) NULL; sy = symbol_next (sy)) { - if (symbol_get_tc (sy)->class == XMC_TC0) + TC_SYMFIELD_TYPE *sy_tc = symbol_get_tc (sy); + + if (sy_tc->class == XMC_TC0) continue; - if (symbol_get_tc (sy)->class != XMC_TC) + if (sy_tc->class != XMC_TC) break; - resolve_symbol_value (sy); - if (val == S_GET_VALUE (sy)) + if (val == resolve_symbol_value (sy)) { fix->fx_addsy = sy; fix->fx_addnumber = val - ppc_toc_frag->fr_address; @@ -4931,23 +5233,24 @@ ppc_fix_adjustable (fix) } /* Possibly adjust the reloc to be against the csect. */ - if (fix->fx_addsy != (symbolS *) NULL - && symbol_get_tc (fix->fx_addsy)->subseg == 0 - && symbol_get_tc (fix->fx_addsy)->class != XMC_TC0 - && symbol_get_tc (fix->fx_addsy)->class != XMC_TC - && S_GET_SEGMENT (fix->fx_addsy) != bss_section + tc = symbol_get_tc (fix->fx_addsy); + if (tc->subseg == 0 + && tc->class != XMC_TC0 + && tc->class != XMC_TC + && symseg != bss_section /* Don't adjust if this is a reloc in the toc section. */ - && (S_GET_SEGMENT (fix->fx_addsy) != data_section + && (symseg != data_section || ppc_toc_csect == NULL || val < ppc_toc_frag->fr_address || (ppc_after_toc_frag != NULL && val >= ppc_after_toc_frag->fr_address))) { symbolS *csect; + symbolS *next_csect; - if (S_GET_SEGMENT (fix->fx_addsy) == text_section) + if (symseg == text_section) csect = ppc_text_csects; - else if (S_GET_SEGMENT (fix->fx_addsy) == data_section) + else if (symseg == data_section) csect = ppc_data_csects; else abort (); @@ -4957,16 +5260,15 @@ ppc_fix_adjustable (fix) if (csect != (symbolS *) NULL) { - while (symbol_get_tc (csect)->next != (symbolS *) NULL - && (symbol_get_frag (symbol_get_tc (csect)->next)->fr_address - <= val)) + while ((next_csect = symbol_get_tc (csect)->next) != (symbolS *) NULL + && (symbol_get_frag (next_csect)->fr_address <= val)) { /* If the csect address equals the symbol value, then we have to look through the full symbol table to see whether this is the csect we want. Note that we will only get here if the csect has zero length. */ - if ((symbol_get_frag (csect)->fr_address == val) - && S_GET_VALUE (csect) == S_GET_VALUE (fix->fx_addsy)) + if (symbol_get_frag (csect)->fr_address == val + && S_GET_VALUE (csect) == val) { symbolS *scan; @@ -4986,26 +5288,24 @@ ppc_fix_adjustable (fix) break; } - csect = symbol_get_tc (csect)->next; + csect = next_csect; } - fix->fx_offset += (S_GET_VALUE (fix->fx_addsy) - - symbol_get_frag (csect)->fr_address); + fix->fx_offset += val - symbol_get_frag (csect)->fr_address; fix->fx_addsy = csect; } + return 0; } /* Adjust a reloc against a .lcomm symbol to be against the base .lcomm. */ - if (fix->fx_addsy != (symbolS *) NULL - && S_GET_SEGMENT (fix->fx_addsy) == bss_section + if (symseg == bss_section && ! S_IS_EXTERNAL (fix->fx_addsy)) { - resolve_symbol_value (symbol_get_frag (fix->fx_addsy)->fr_symbol); - fix->fx_offset += - (S_GET_VALUE (fix->fx_addsy) - - S_GET_VALUE (symbol_get_frag (fix->fx_addsy)->fr_symbol)); - fix->fx_addsy = symbol_get_frag (fix->fx_addsy)->fr_symbol; + symbolS *sy = symbol_get_frag (fix->fx_addsy)->fr_symbol; + + fix->fx_offset += val - resolve_symbol_value (sy); + fix->fx_addsy = sy; } return 0; @@ -5033,12 +5333,40 @@ ppc_force_relocation (fix) <= fix->fx_frag->fr_address)))) return 1; - return 0; + return generic_force_reloc (fix); } #endif /* OBJ_XCOFF */ #ifdef OBJ_ELF +/* If this function returns non-zero, it guarantees that a relocation + will be emitted for a fixup. */ + +int +ppc_force_relocation (fix) + fixS *fix; +{ + /* Branch prediction relocations must force a relocation, as must + the vtable description relocs. */ + switch (fix->fx_r_type) + { + case BFD_RELOC_PPC_B16_BRTAKEN: + case BFD_RELOC_PPC_B16_BRNTAKEN: + case BFD_RELOC_PPC_BA16_BRTAKEN: + case BFD_RELOC_PPC_BA16_BRNTAKEN: + case BFD_RELOC_PPC64_TOC: + return 1; + default: + break; + } + + if (fix->fx_r_type >= BFD_RELOC_PPC_TLS + && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA) + return 1; + + return generic_force_reloc (fix); +} + int ppc_fix_adjustable (fix) fixS *fix; @@ -5050,8 +5378,8 @@ ppc_fix_adjustable (fix) && fix->fx_r_type != BFD_RELOC_GPREL16 && fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT && fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY - && ! S_IS_EXTERNAL (fix->fx_addsy) - && ! S_IS_WEAK (fix->fx_addsy) + && !(fix->fx_r_type >= BFD_RELOC_PPC_TLS + && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA) && (fix->fx_pcrel || (fix->fx_subsy != NULL && (S_GET_SEGMENT (fix->fx_subsy) @@ -5069,79 +5397,58 @@ ppc_fix_adjustable (fix) that, we determine the correct reloc code and put it back in the fixup. */ -int -md_apply_fix3 (fixp, valuep, seg) - fixS *fixp; - valueT *valuep; +void +md_apply_fix3 (fixP, valP, seg) + fixS *fixP; + valueT * valP; segT seg ATTRIBUTE_UNUSED; { - valueT value; + valueT value = * valP; #ifdef OBJ_ELF - value = *valuep; - if (fixp->fx_addsy != NULL) + if (fixP->fx_addsy != NULL) { - /* `*valuep' may contain the value of the symbol on which the reloc - will be based; we have to remove it. */ - if (symbol_used_in_reloc_p (fixp->fx_addsy) - && S_GET_SEGMENT (fixp->fx_addsy) != absolute_section - && S_GET_SEGMENT (fixp->fx_addsy) != undefined_section - && ! bfd_is_com_section (S_GET_SEGMENT (fixp->fx_addsy))) - value -= S_GET_VALUE (fixp->fx_addsy); - - /* FIXME: Why '+'? Better yet, what exactly is '*valuep' - supposed to be? I think this is related to various similar - FIXMEs in tc-i386.c and tc-sparc.c. */ - if (fixp->fx_pcrel) - value += fixp->fx_frag->fr_address + fixp->fx_where; + /* Hack around bfd_install_relocation brain damage. */ + if (fixP->fx_pcrel) + value += fixP->fx_frag->fr_address + fixP->fx_where; } else - { - fixp->fx_done = 1; - } + fixP->fx_done = 1; #else - /* FIXME FIXME FIXME: The value we are passed in *valuep includes + /* FIXME FIXME FIXME: The value we are passed in *valP includes the symbol values. Since we are using BFD_ASSEMBLER, if we are doing this relocation the code in write.c is going to call bfd_install_relocation, which is also going to use the symbol value. That means that if the reloc is fully resolved we want to - use *valuep since bfd_install_relocation is not being used. + use *valP since bfd_install_relocation is not being used. However, if the reloc is not fully resolved we do not want to use - *valuep, and must use fx_offset instead. However, if the reloc - is PC relative, we do want to use *valuep since it includes the + *valP, and must use fx_offset instead. However, if the reloc + is PC relative, we do want to use *valP since it includes the result of md_pcrel_from. This is confusing. */ - if (fixp->fx_addsy == (symbolS *) NULL) - { - value = *valuep; - fixp->fx_done = 1; - } - else if (fixp->fx_pcrel) - value = *valuep; + if (fixP->fx_addsy == (symbolS *) NULL) + fixP->fx_done = 1; + + else if (fixP->fx_pcrel) + ; + else + value = fixP->fx_offset; +#endif + + if (fixP->fx_subsy != (symbolS *) NULL) { - value = fixp->fx_offset; - if (fixp->fx_subsy != (symbolS *) NULL) - { - if (S_GET_SEGMENT (fixp->fx_subsy) == absolute_section) - value -= S_GET_VALUE (fixp->fx_subsy); - else - { - /* We can't actually support subtracting a symbol. */ - as_bad_where (fixp->fx_file, fixp->fx_line, - _("expression too complex")); - } - } + /* We can't actually support subtracting a symbol. */ + as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex")); } -#endif - if ((int) fixp->fx_r_type >= (int) BFD_RELOC_UNUSED) + if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED) { int opindex; const struct powerpc_operand *operand; char *where; unsigned long insn; - opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED; + opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED; operand = &powerpc_operands[opindex]; @@ -5153,39 +5460,37 @@ md_apply_fix3 (fixp, valuep, seg) if ((operand->flags & PPC_OPERAND_PARENS) != 0 && operand->bits == 16 && operand->shift == 0 - && operand->insert == NULL - && fixp->fx_addsy != NULL - && symbol_get_tc (fixp->fx_addsy)->subseg != 0 - && symbol_get_tc (fixp->fx_addsy)->class != XMC_TC - && symbol_get_tc (fixp->fx_addsy)->class != XMC_TC0 - && S_GET_SEGMENT (fixp->fx_addsy) != bss_section) + && (operand->insert == NULL || ppc_obj64) + && fixP->fx_addsy != NULL + && symbol_get_tc (fixP->fx_addsy)->subseg != 0 + && symbol_get_tc (fixP->fx_addsy)->class != XMC_TC + && symbol_get_tc (fixP->fx_addsy)->class != XMC_TC0 + && S_GET_SEGMENT (fixP->fx_addsy) != bss_section) { - value = fixp->fx_offset; - fixp->fx_done = 1; + value = fixP->fx_offset; + fixP->fx_done = 1; } #endif /* Fetch the instruction, insert the fully resolved operand value, and stuff the instruction back again. */ - where = fixp->fx_frag->fr_literal + fixp->fx_where; + 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 = ppc_insert_operand (insn, operand, (offsetT) value, - fixp->fx_file, fixp->fx_line); + fixP->fx_file, fixP->fx_line); if (target_big_endian) bfd_putb32 ((bfd_vma) insn, (unsigned char *) where); else bfd_putl32 ((bfd_vma) insn, (unsigned char *) where); - if (fixp->fx_done) - { - /* Nothing else to do here. */ - return 1; - } + if (fixP->fx_done) + /* Nothing else to do here. */ + return; - assert (fixp->fx_addsy != NULL); + assert (fixP->fx_addsy != NULL); /* Determine a BFD reloc value based on the operand information. We are only prepared to turn a few of the operands into @@ -5193,35 +5498,59 @@ md_apply_fix3 (fixp, valuep, seg) if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 && operand->bits == 26 && operand->shift == 0) - fixp->fx_r_type = BFD_RELOC_PPC_B26; + 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; + { + fixP->fx_r_type = BFD_RELOC_PPC_B16; +#ifdef OBJ_XCOFF + fixP->fx_size = 2; + if (target_big_endian) + fixP->fx_where += 2; +#endif + } else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0 && operand->bits == 26 && operand->shift == 0) - fixp->fx_r_type = BFD_RELOC_PPC_BA26; + fixP->fx_r_type = BFD_RELOC_PPC_BA26; else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0 && operand->bits == 16 && operand->shift == 0) - fixp->fx_r_type = BFD_RELOC_PPC_BA16; + { + fixP->fx_r_type = BFD_RELOC_PPC_BA16; +#ifdef OBJ_XCOFF + fixP->fx_size = 2; + if (target_big_endian) + fixP->fx_where += 2; +#endif + } #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; +#endif + } + else + { + fixP->fx_r_type = BFD_RELOC_16; #ifdef OBJ_ELF - if (BFD_DEFAULT_TARGET_SIZE == 64 - && ppc_size == PPC_OPCODE_64 - && (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_ADDR16_DS; #endif - fixp->fx_size = 2; + } + fixP->fx_size = 2; if (target_big_endian) - fixp->fx_where += 2; + fixP->fx_where += 2; } #endif /* defined (OBJ_XCOFF) || defined (OBJ_ELF) */ else @@ -5231,50 +5560,49 @@ md_apply_fix3 (fixp, valuep, seg) /* Use expr_symbol_where to see if this is an expression symbol. */ - if (expr_symbol_where (fixp->fx_addsy, &sfile, &sline)) - as_bad_where (fixp->fx_file, fixp->fx_line, + if (expr_symbol_where (fixP->fx_addsy, &sfile, &sline)) + as_bad_where (fixP->fx_file, fixP->fx_line, _("unresolved expression that must be resolved")); else - as_bad_where (fixp->fx_file, fixp->fx_line, + as_bad_where (fixP->fx_file, fixP->fx_line, _("unsupported relocation against %s"), - S_GET_NAME (fixp->fx_addsy)); - fixp->fx_done = 1; - return 1; + S_GET_NAME (fixP->fx_addsy)); + fixP->fx_done = 1; + return; } } else { #ifdef OBJ_ELF - ppc_elf_validate_fix (fixp, seg); + ppc_elf_validate_fix (fixP, seg); #endif - switch (fixp->fx_r_type) + switch (fixP->fx_r_type) { case BFD_RELOC_CTOR: - if (BFD_DEFAULT_TARGET_SIZE == 64 && ppc_size == PPC_OPCODE_64) + if (ppc_obj64) goto ctor64; /* fall through */ case BFD_RELOC_32: - if (fixp->fx_pcrel) - fixp->fx_r_type = BFD_RELOC_32_PCREL; + if (fixP->fx_pcrel) + fixP->fx_r_type = BFD_RELOC_32_PCREL; /* fall through */ case BFD_RELOC_RVA: case BFD_RELOC_32_PCREL: - case BFD_RELOC_32_BASEREL: case BFD_RELOC_PPC_EMB_NADDR32: - md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where, + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, value, 4); break; case BFD_RELOC_64: ctor64: - if (fixp->fx_pcrel) - fixp->fx_r_type = BFD_RELOC_64_PCREL; + if (fixP->fx_pcrel) + fixP->fx_r_type = BFD_RELOC_64_PCREL; /* fall through */ case BFD_RELOC_64_PCREL: - md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where, + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, value, 8); break; @@ -5286,6 +5614,7 @@ md_apply_fix3 (fixp, valuep, seg) case BFD_RELOC_LO16_GOTOFF: case BFD_RELOC_HI16_GOTOFF: case BFD_RELOC_HI16_S_GOTOFF: + case BFD_RELOC_16_BASEREL: case BFD_RELOC_LO16_BASEREL: case BFD_RELOC_HI16_BASEREL: case BFD_RELOC_HI16_S_BASEREL: @@ -5303,26 +5632,24 @@ md_apply_fix3 (fixp, valuep, seg) case BFD_RELOC_PPC_EMB_RELSDA: case BFD_RELOC_PPC_TOC16: #ifdef OBJ_ELF -#if BFD_DEFAULT_TARGET_SIZE == 64 case BFD_RELOC_PPC64_TOC16_LO: case BFD_RELOC_PPC64_TOC16_HI: case BFD_RELOC_PPC64_TOC16_HA: #endif -#endif - if (fixp->fx_pcrel) + if (fixP->fx_pcrel) { - if (fixp->fx_addsy != NULL) - as_bad_where (fixp->fx_file, fixp->fx_line, + if (fixP->fx_addsy != NULL) + as_bad_where (fixP->fx_file, fixP->fx_line, _("cannot emit PC relative %s relocation against %s"), - bfd_get_reloc_code_name (fixp->fx_r_type), - S_GET_NAME (fixp->fx_addsy)); + bfd_get_reloc_code_name (fixP->fx_r_type), + S_GET_NAME (fixP->fx_addsy)); else - as_bad_where (fixp->fx_file, fixp->fx_line, + as_bad_where (fixP->fx_file, fixP->fx_line, _("cannot emit PC relative %s relocation"), - bfd_get_reloc_code_name (fixp->fx_r_type)); + bfd_get_reloc_code_name (fixP->fx_r_type)); } - md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where, + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, value, 2); break; @@ -5330,46 +5657,45 @@ md_apply_fix3 (fixp, valuep, seg) lis %r3,(L1-L2)@ha where L1 and L2 are defined later. */ case BFD_RELOC_HI16: - if (fixp->fx_pcrel) + if (fixP->fx_pcrel) abort (); - md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where, + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, PPC_HI (value), 2); break; case BFD_RELOC_HI16_S: - if (fixp->fx_pcrel) + if (fixP->fx_pcrel) abort (); - md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where, + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, PPC_HA (value), 2); break; #ifdef OBJ_ELF -#if BFD_DEFAULT_TARGET_SIZE == 64 case BFD_RELOC_PPC64_HIGHER: - if (fixp->fx_pcrel) + if (fixP->fx_pcrel) abort (); - md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where, + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, PPC_HIGHER (value), 2); break; case BFD_RELOC_PPC64_HIGHER_S: - if (fixp->fx_pcrel) + if (fixP->fx_pcrel) abort (); - md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where, + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, PPC_HIGHERA (value), 2); break; case BFD_RELOC_PPC64_HIGHEST: - if (fixp->fx_pcrel) + if (fixP->fx_pcrel) abort (); - md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where, + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, PPC_HIGHEST (value), 2); break; case BFD_RELOC_PPC64_HIGHEST_S: - if (fixp->fx_pcrel) + if (fixP->fx_pcrel) abort (); - md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where, + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, PPC_HIGHESTA (value), 2); break; @@ -5384,67 +5710,119 @@ md_apply_fix3 (fixp, valuep, seg) case BFD_RELOC_PPC64_TOC16_LO_DS: case BFD_RELOC_PPC64_PLTGOT16_DS: case BFD_RELOC_PPC64_PLTGOT16_LO_DS: - if (fixp->fx_pcrel) + if (fixP->fx_pcrel) abort (); { - unsigned char *where = fixp->fx_frag->fr_literal + fixp->fx_where; - unsigned long val; + unsigned char *where = fixP->fx_frag->fr_literal + fixP->fx_where; + 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)) == (56 << 26)) + mask = 0xfff0; + val |= value & mask; if (target_big_endian) bfd_putb16 ((bfd_vma) val, where); else bfd_putl16 ((bfd_vma) val, where); } break; -#endif + + 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: + case BFD_RELOC_PPC_TPREL16_LO: + case BFD_RELOC_PPC_TPREL16_HI: + case BFD_RELOC_PPC_TPREL16_HA: + case BFD_RELOC_PPC_TPREL: + case BFD_RELOC_PPC_DTPREL16: + case BFD_RELOC_PPC_DTPREL16_LO: + case BFD_RELOC_PPC_DTPREL16_HI: + case BFD_RELOC_PPC_DTPREL16_HA: + case BFD_RELOC_PPC_DTPREL: + case BFD_RELOC_PPC_GOT_TLSGD16: + case BFD_RELOC_PPC_GOT_TLSGD16_LO: + case BFD_RELOC_PPC_GOT_TLSGD16_HI: + case BFD_RELOC_PPC_GOT_TLSGD16_HA: + case BFD_RELOC_PPC_GOT_TLSLD16: + case BFD_RELOC_PPC_GOT_TLSLD16_LO: + case BFD_RELOC_PPC_GOT_TLSLD16_HI: + case BFD_RELOC_PPC_GOT_TLSLD16_HA: + case BFD_RELOC_PPC_GOT_TPREL16: + case BFD_RELOC_PPC_GOT_TPREL16_LO: + case BFD_RELOC_PPC_GOT_TPREL16_HI: + case BFD_RELOC_PPC_GOT_TPREL16_HA: + case BFD_RELOC_PPC_GOT_DTPREL16: + case BFD_RELOC_PPC_GOT_DTPREL16_LO: + case BFD_RELOC_PPC_GOT_DTPREL16_HI: + case BFD_RELOC_PPC_GOT_DTPREL16_HA: + case BFD_RELOC_PPC64_TPREL16_DS: + case BFD_RELOC_PPC64_TPREL16_LO_DS: + case BFD_RELOC_PPC64_TPREL16_HIGHER: + case BFD_RELOC_PPC64_TPREL16_HIGHERA: + case BFD_RELOC_PPC64_TPREL16_HIGHEST: + case BFD_RELOC_PPC64_TPREL16_HIGHESTA: + case BFD_RELOC_PPC64_DTPREL16_DS: + case BFD_RELOC_PPC64_DTPREL16_LO_DS: + case BFD_RELOC_PPC64_DTPREL16_HIGHER: + case BFD_RELOC_PPC64_DTPREL16_HIGHERA: + case BFD_RELOC_PPC64_DTPREL16_HIGHEST: + case BFD_RELOC_PPC64_DTPREL16_HIGHESTA: + break; #endif /* Because SDA21 modifies the register field, the size is set to 4 bytes, rather than 2, so offset it here appropriately. */ case BFD_RELOC_PPC_EMB_SDA21: - if (fixp->fx_pcrel) + if (fixP->fx_pcrel) abort (); - md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where + ((target_big_endian) ? 2 : 0), value, 2); break; case BFD_RELOC_8: - if (fixp->fx_pcrel) + if (fixP->fx_pcrel) abort (); - md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where, + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, value, 1); break; case BFD_RELOC_24_PLT_PCREL: case BFD_RELOC_PPC_LOCAL24PC: - if (!fixp->fx_pcrel && !fixp->fx_done) + if (!fixP->fx_pcrel && !fixP->fx_done) abort (); - if (fixp->fx_done) + if (fixP->fx_done) { char *where; unsigned long insn; /* Fetch the instruction, insert the fully resolved operand value, and stuff the instruction back again. */ - where = fixp->fx_frag->fr_literal + fixp->fx_where; + 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); if ((value & 3) != 0) - as_bad_where (fixp->fx_file, fixp->fx_line, + as_bad_where (fixP->fx_file, fixP->fx_line, _("must branch to an address a multiple of 4")); if ((offsetT) value < -0x40000000 || (offsetT) value >= 0x40000000) - as_bad_where (fixp->fx_file, fixp->fx_line, + as_bad_where (fixP->fx_file, fixP->fx_line, _("@local or @plt branch destination is too far away, %ld bytes"), (long) value); insn = insn | (value & 0x03fffffc); @@ -5456,53 +5834,49 @@ md_apply_fix3 (fixp, valuep, seg) break; case BFD_RELOC_VTABLE_INHERIT: - fixp->fx_done = 0; - if (fixp->fx_addsy - && !S_IS_DEFINED (fixp->fx_addsy) - && !S_IS_WEAK (fixp->fx_addsy)) - S_SET_WEAK (fixp->fx_addsy); + fixP->fx_done = 0; + if (fixP->fx_addsy + && !S_IS_DEFINED (fixP->fx_addsy) + && !S_IS_WEAK (fixP->fx_addsy)) + S_SET_WEAK (fixP->fx_addsy); break; case BFD_RELOC_VTABLE_ENTRY: - fixp->fx_done = 0; + fixP->fx_done = 0; break; #ifdef OBJ_ELF -#if BFD_DEFAULT_TARGET_SIZE == 64 /* Generated by reference to `sym@tocbase'. The sym is ignored by the linker. */ case BFD_RELOC_PPC64_TOC: - fixp->fx_done = 0; + fixP->fx_done = 0; break; -#endif #endif default: fprintf (stderr, - _("Gas failure, reloc value %d\n"), fixp->fx_r_type); + _("Gas failure, reloc value %d\n"), fixP->fx_r_type); fflush (stderr); abort (); } } #ifdef OBJ_ELF - fixp->fx_addnumber = value; + fixP->fx_addnumber = value; #else - if (fixp->fx_r_type != BFD_RELOC_PPC_TOC16) - fixp->fx_addnumber = 0; + if (fixP->fx_r_type != BFD_RELOC_PPC_TOC16) + fixP->fx_addnumber = 0; else { #ifdef TE_PE - fixp->fx_addnumber = 0; + fixP->fx_addnumber = 0; #else /* We want to use the offset within the data segment of the symbol, not the actual VMA of the symbol. */ - fixp->fx_addnumber = - - bfd_get_section_vma (stdoutput, S_GET_SEGMENT (fixp->fx_addsy)); + fixP->fx_addnumber = + - bfd_get_section_vma (stdoutput, S_GET_SEGMENT (fixP->fx_addsy)); #endif } #endif - - return 1; } /* Generate a reloc for a fixup. */