X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-sparc.c;h=7a7a3f7571a66be597f9c143673eecf9ec4d75b7;hb=refs%2Fheads%2Fconcurrent-displaced-stepping-2020-04-01;hp=37bbbdd5444da6d4c71c32ef11fba0de68791f1e;hpb=ec668d69b9517c6344f8c659f2014197b780f2da;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-sparc.c b/gas/config/tc-sparc.c index 37bbbdd544..7a7a3f7571 100644 --- a/gas/config/tc-sparc.c +++ b/gas/config/tc-sparc.c @@ -1,8 +1,5 @@ /* tc-sparc.c -- Assemble for the SPARC - Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - 2011 - Free Software Foundation, Inc. + Copyright (C) 1989-2020 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify @@ -27,10 +24,8 @@ #include "opcode/sparc.h" #include "dw2gencfi.h" -#ifdef OBJ_ELF #include "elf/sparc.h" #include "dwarf2dbg.h" -#endif /* Some ancient Sun C compilers would not take such hex constants as unsigned, and would end up sign-extending them to form an offsetT, @@ -39,6 +34,7 @@ #define U0x80000000 ((((unsigned long) 1 << 16) << 15)) static int sparc_ip (char *, const struct sparc_opcode **); +static int parse_sparc_asi (char **, const sparc_asi **); static int parse_keyword_arg (int (*) (const char *), char **, int *); static int parse_const_expr_arg (char **, int *); static int get_expression (char *); @@ -50,7 +46,7 @@ static int get_expression (char *); #ifndef DEFAULT_ARCH #define DEFAULT_ARCH "sparclite" #endif -static char *default_arch = DEFAULT_ARCH; +static const char *default_arch = DEFAULT_ARCH; /* Non-zero if the initial values of `max_architecture' and `sparc_arch_size' have been set. */ @@ -72,7 +68,6 @@ static int sparc_arch_size; changes the value before md_show_usage is called. */ static int default_arch_size; -#ifdef OBJ_ELF /* The currently selected v9 memory model. Currently only used for ELF. */ static enum { MM_TSO, MM_PSO, MM_RMO } sparc_memory_model = MM_RMO; @@ -80,11 +75,10 @@ static enum { MM_TSO, MM_PSO, MM_RMO } sparc_memory_model = MM_RMO; #ifndef TE_SOLARIS /* Bitmask of instruction types seen so far, used to populate the GNU attributes section with hwcap information. */ -static int hwcap_seen; -#endif +static bfd_uint64_t hwcap_seen; #endif -static int hwcap_allowed; +static bfd_uint64_t hwcap_allowed; static int architecture_requested; static int warn_on_bump; @@ -93,10 +87,15 @@ static int warn_on_bump; architecture, issue a warning. */ static enum sparc_opcode_arch_val warn_after_architecture; -/* Non-zero if as should generate error if an undeclared g[23] register - has been used in -64. */ +/* Non-zero if the assembler should generate error if an undeclared + g[23] register has been used in -64. */ static int no_undeclared_regs; +/* Non-zero if the assembler should generate a warning if an + unpredictable DCTI (delayed control transfer instruction) couple is + found. */ +static int dcti_couples_detect; + /* Non-zero if we should try to relax jumps and calls. */ static int sparc_relax; @@ -137,9 +136,7 @@ static void s_common (int); static void s_empty (int); static void s_uacons (int); static void s_ncons (int); -#ifdef OBJ_ELF static void s_register (int); -#endif const pseudo_typeS md_pseudo_table[] = { @@ -159,13 +156,11 @@ const pseudo_typeS md_pseudo_table[] = {"uahalf", s_uacons, 2}, {"uaword", s_uacons, 4}, {"uaxword", s_uacons, 8}, -#ifdef OBJ_ELF /* These are specific to sparc/svr4. */ {"2byte", s_uacons, 2}, {"4byte", s_uacons, 4}, {"8byte", s_uacons, 8}, {"register", s_register, 0}, -#endif {NULL, 0, 0}, }; @@ -203,7 +198,7 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP"; struct sparc_it { - char *error; + const char *error; unsigned long opcode; struct nlist *nlistp; expressionS exp; @@ -221,57 +216,76 @@ static void output_insn (const struct sparc_opcode *, struct sparc_it *); for this use. That table is for opcodes only. This table is for opcodes and file formats. */ -enum sparc_arch_types {v6, v7, v8, sparclet, sparclite, sparc86x, v8plus, +enum sparc_arch_types {v6, v7, v8, leon, sparclet, sparclite, sparc86x, v8plus, v8plusa, v9, v9a, v9b, v9_64}; static struct sparc_arch { - char *name; - char *opcode_arch; + const char *name; + const char *opcode_arch; enum sparc_arch_types arch_type; /* Default word size, as specified during configuration. A value of zero means can't be used to specify default architecture. */ int default_arch_size; /* Allowable arg to -A? */ int user_option_p; + /* Extra hardware capabilities allowed. These are added to the + hardware capabilities associated with the opcode + architecture. */ int hwcap_allowed; + int hwcap2_allowed; } sparc_arch_table[] = { - { "v6", "v6", v6, 0, 1, 0 }, - { "v7", "v7", v7, 0, 1, 0 }, - { "v8", "v8", v8, 32, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD }, - { "v8a", "v8", v8, 32, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD }, - { "sparc", "v9", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_V8PLUS }, - { "sparcvis", "v9a", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS }, - { "sparcvis2", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS|HWCAP_VIS2 }, - { "sparcfmaf", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS|HWCAP_VIS2|HWCAP_FMAF }, - { "sparcima", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS|HWCAP_VIS2|HWCAP_FMAF|HWCAP_IMA }, - { "sparcvis3", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS|HWCAP_VIS2|HWCAP_FMAF|HWCAP_VIS3|HWCAP_HPC }, - { "sparcvis3r", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS|HWCAP_VIS2|HWCAP_FMAF|HWCAP_VIS3|HWCAP_HPC|HWCAP_RANDOM|HWCAP_TRANS|HWCAP_FJFMAU }, - { "sparclet", "sparclet", sparclet, 32, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD }, - { "sparclite", "sparclite", sparclite, 32, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD }, - { "sparc86x", "sparclite", sparc86x, 32, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD }, - { "v8plus", "v9", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_V8PLUS }, - { "v8plusa", "v9a", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_V8PLUS|HWCAP_VIS }, - { "v8plusb", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_V8PLUS|HWCAP_VIS|HWCAP_VIS2 }, - { "v8plusc", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_V8PLUS|HWCAP_VIS|HWCAP_VIS2|HWCAP_ASI_BLK_INIT }, - { "v8plusd", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_V8PLUS|HWCAP_VIS|HWCAP_VIS2|HWCAP_ASI_BLK_INIT|HWCAP_FMAF|HWCAP_VIS3|HWCAP_HPC }, - { "v8plusv", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_V8PLUS|HWCAP_VIS|HWCAP_VIS2|HWCAP_ASI_BLK_INIT|HWCAP_FMAF|HWCAP_VIS3|HWCAP_HPC|HWCAP_RANDOM|HWCAP_TRANS|HWCAP_FJFMAU|HWCAP_IMA|HWCAP_ASI_CACHE_SPARING }, - { "v9", "v9", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC }, - { "v9a", "v9a", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS }, - { "v9b", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS|HWCAP_VIS2 }, - { "v9c", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS|HWCAP_VIS2|HWCAP_ASI_BLK_INIT }, - { "v9d", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS|HWCAP_VIS2|HWCAP_ASI_BLK_INIT|HWCAP_FMAF|HWCAP_VIS3|HWCAP_HPC }, - { "v9v", "v9b", v9, 0, 1, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC|HWCAP_VIS|HWCAP_VIS2|HWCAP_ASI_BLK_INIT|HWCAP_FMAF|HWCAP_VIS3|HWCAP_HPC|HWCAP_RANDOM|HWCAP_TRANS|HWCAP_FJFMAU|HWCAP_IMA|HWCAP_ASI_CACHE_SPARING }, - /* This exists to allow configure.in/Makefile.in to pass one + { "v6", "v6", v6, 0, 1, 0, 0 }, + { "v7", "v7", v7, 0, 1, 0, 0 }, + { "v8", "v8", v8, 32, 1, 0, 0 }, + { "v8a", "v8", v8, 32, 1, 0, 0 }, + { "sparc", "v9", v9, 0, 1, HWCAP_V8PLUS, 0 }, + { "sparcvis", "v9a", v9, 0, 1, 0, 0 }, + { "sparcvis2", "v9b", v9, 0, 1, 0, 0 }, + { "sparcfmaf", "v9b", v9, 0, 1, HWCAP_FMAF, 0 }, + { "sparcima", "v9b", v9, 0, 1, HWCAP_FMAF|HWCAP_IMA, 0 }, + { "sparcvis3", "v9b", v9, 0, 1, HWCAP_FMAF|HWCAP_VIS3|HWCAP_HPC, 0 }, + { "sparcvis3r", "v9b", v9, 0, 1, HWCAP_FMAF|HWCAP_VIS3|HWCAP_HPC|HWCAP_FJFMAU, 0 }, + + { "sparc4", "v9v", v9, 0, 1, 0, 0 }, + { "sparc5", "v9m", v9, 0, 1, 0, 0 }, + { "sparc6", "m8", v9, 0, 1, 0, 0 }, + + { "leon", "leon", leon, 32, 1, 0, 0 }, + { "sparclet", "sparclet", sparclet, 32, 1, 0, 0 }, + { "sparclite", "sparclite", sparclite, 32, 1, 0, 0 }, + { "sparc86x", "sparclite", sparc86x, 32, 1, 0, 0 }, + + { "v8plus", "v9", v9, 0, 1, HWCAP_V8PLUS, 0 }, + { "v8plusa", "v9a", v9, 0, 1, HWCAP_V8PLUS, 0 }, + { "v8plusb", "v9b", v9, 0, 1, HWCAP_V8PLUS, 0 }, + { "v8plusc", "v9c", v9, 0, 1, HWCAP_V8PLUS, 0 }, + { "v8plusd", "v9d", v9, 0, 1, HWCAP_V8PLUS, 0 }, + { "v8pluse", "v9e", v9, 0, 1, HWCAP_V8PLUS, 0 }, + { "v8plusv", "v9v", v9, 0, 1, HWCAP_V8PLUS, 0 }, + { "v8plusm", "v9m", v9, 0, 1, HWCAP_V8PLUS, 0 }, + { "v8plusm8", "m8", v9, 0, 1, HWCAP_V8PLUS, 0 }, + + { "v9", "v9", v9, 0, 1, 0, 0 }, + { "v9a", "v9a", v9, 0, 1, 0, 0 }, + { "v9b", "v9b", v9, 0, 1, 0, 0 }, + { "v9c", "v9c", v9, 0, 1, 0, 0 }, + { "v9d", "v9d", v9, 0, 1, 0, 0 }, + { "v9e", "v9e", v9, 0, 1, 0, 0 }, + { "v9v", "v9v", v9, 0, 1, 0, 0 }, + { "v9m", "v9m", v9, 0, 1, 0, 0 }, + { "v9m8", "m8", v9, 0, 1, 0, 0 }, + + /* This exists to allow configure.tgt to pass one value to specify both the default machine and default word size. */ - { "v9-64", "v9", v9, 64, 0, HWCAP_MUL32|HWCAP_DIV32|HWCAP_FSMULD|HWCAP_POPC }, - { NULL, NULL, v8, 0, 0, 0 } + { "v9-64", "v9", v9, 64, 0, 0, 0 }, + { NULL, NULL, v8, 0, 0, 0, 0 } }; /* Variant of default_arch */ static enum sparc_arch_types default_arch_type; static struct sparc_arch * -lookup_arch (char *name) +lookup_arch (const char *name) { struct sparc_arch *sa; @@ -303,54 +317,34 @@ init_default_arch (void) default_arch_type = sa->arch_type; } -/* Called by TARGET_FORMAT. */ +/* Called by TARGET_MACH. */ -const char * -sparc_target_format (void) +unsigned long +sparc_mach (void) { /* We don't get a chance to initialize anything before we're called, so handle that now. */ if (! default_init_p) init_default_arch (); -#ifdef OBJ_AOUT -#ifdef TE_NetBSD - return "a.out-sparc-netbsd"; -#else -#ifdef TE_SPARCAOUT - if (target_big_endian) - return "a.out-sunos-big"; - else if (default_arch_type == sparc86x && target_little_endian_data) - return "a.out-sunos-big"; - else - return "a.out-sparc-little"; -#else - return "a.out-sunos-big"; -#endif -#endif -#endif + return sparc_arch_size == 64 ? bfd_mach_sparc_v9 : bfd_mach_sparc; +} -#ifdef OBJ_BOUT - return "b.out.big"; -#endif +/* Called by TARGET_FORMAT. */ -#ifdef OBJ_COFF -#ifdef TE_LYNX - return "coff-sparc-lynx"; -#else - return "coff-sparc"; -#endif -#endif +const char * +sparc_target_format (void) +{ + /* We don't get a chance to initialize anything before we're called, + so handle that now. */ + if (! default_init_p) + init_default_arch (); #ifdef TE_VXWORKS return "elf32-sparc-vxworks"; #endif -#ifdef OBJ_ELF return sparc_arch_size == 64 ? ELF64_TARGET_FORMAT : ELF_TARGET_FORMAT; -#endif - - abort (); } /* md_parse_option @@ -360,7 +354,7 @@ sparc_target_format (void) * -bump * Warn on architecture bumps. See also -A. * - * -Av6, -Av7, -Av8, -Asparclite, -Asparclet + * -Av6, -Av7, -Av8, -Aleon, -Asparclite, -Asparclet * Standard 32 bit architectures. * -Av9, -Av9a, -Av9b * Sparc64 in either a 32 or 64 bit world (-32/-64 says which). @@ -407,15 +401,7 @@ sparc_target_format (void) * error. For example, from sparclite to v9. */ -#ifdef OBJ_ELF const char *md_shortopts = "A:K:VQ:sq"; -#else -#ifdef OBJ_AOUT -const char *md_shortopts = "A:k"; -#else -const char *md_shortopts = "A:"; -#endif -#endif struct option md_longopts[] = { #define OPTION_BUMP (OPTION_MD_BASE) {"bump", no_argument, NULL, OPTION_BUMP}, @@ -423,7 +409,6 @@ struct option md_longopts[] = { {"sparc", no_argument, NULL, OPTION_SPARC}, #define OPTION_XARCH (OPTION_MD_BASE + 2) {"xarch", required_argument, NULL, OPTION_XARCH}, -#ifdef OBJ_ELF #define OPTION_32 (OPTION_MD_BASE + 3) {"32", no_argument, NULL, OPTION_32}, #define OPTION_64 (OPTION_MD_BASE + 4) @@ -434,7 +419,6 @@ struct option md_longopts[] = { {"PSO", no_argument, NULL, OPTION_PSO}, #define OPTION_RMO (OPTION_MD_BASE + 7) {"RMO", no_argument, NULL, OPTION_RMO}, -#endif #ifdef SPARC_BIENDIAN #define OPTION_LITTLE_ENDIAN (OPTION_MD_BASE + 8) {"EL", no_argument, NULL, OPTION_LITTLE_ENDIAN}, @@ -445,23 +429,23 @@ struct option md_longopts[] = { {"enforce-aligned-data", no_argument, NULL, OPTION_ENFORCE_ALIGNED_DATA}, #define OPTION_LITTLE_ENDIAN_DATA (OPTION_MD_BASE + 11) {"little-endian-data", no_argument, NULL, OPTION_LITTLE_ENDIAN_DATA}, -#ifdef OBJ_ELF #define OPTION_NO_UNDECLARED_REGS (OPTION_MD_BASE + 12) {"no-undeclared-regs", no_argument, NULL, OPTION_NO_UNDECLARED_REGS}, #define OPTION_UNDECLARED_REGS (OPTION_MD_BASE + 13) {"undeclared-regs", no_argument, NULL, OPTION_UNDECLARED_REGS}, -#endif #define OPTION_RELAX (OPTION_MD_BASE + 14) {"relax", no_argument, NULL, OPTION_RELAX}, #define OPTION_NO_RELAX (OPTION_MD_BASE + 15) {"no-relax", no_argument, NULL, OPTION_NO_RELAX}, +#define OPTION_DCTI_COUPLES_DETECT (OPTION_MD_BASE + 16) + {"dcti-couples-detect", no_argument, NULL, OPTION_DCTI_COUPLES_DETECT}, {NULL, no_argument, NULL, 0} }; size_t md_longopts_size = sizeof (md_longopts); int -md_parse_option (int c, char *arg) +md_parse_option (int c, const char *arg) { /* We don't get a chance to initialize anything before we're called, so handle that now. */ @@ -476,12 +460,18 @@ md_parse_option (int c, char *arg) break; case OPTION_XARCH: -#ifdef OBJ_ELF - if (strncmp (arg, "v9", 2) != 0) - md_parse_option (OPTION_32, NULL); - else + if (!strncmp (arg, "v9", 2)) md_parse_option (OPTION_64, NULL); -#endif + else + { + if (!strncmp (arg, "v8", 2) + || !strncmp (arg, "v7", 2) + || !strncmp (arg, "v6", 2) + || !strcmp (arg, "sparclet") + || !strcmp (arg, "sparclite") + || !strcmp (arg, "sparc86x")) + md_parse_option (OPTION_32, NULL); + } /* Fall through. */ case 'A': @@ -507,7 +497,16 @@ md_parse_option (int c, char *arg) if (!architecture_requested || opcode_arch > max_architecture) max_architecture = opcode_arch; - hwcap_allowed |= sa->hwcap_allowed; + + /* The allowed hardware capabilities are the implied by the + opcodes arch plus any extra capabilities defined in the GAS + arch. */ + hwcap_allowed + = (hwcap_allowed + | (((bfd_uint64_t) sparc_opcode_archs[opcode_arch].hwcaps2) << 32) + | (((bfd_uint64_t) sa->hwcap2_allowed) << 32) + | sparc_opcode_archs[opcode_arch].hwcaps + | sa->hwcap_allowed); architecture_requested = 1; } break; @@ -538,13 +537,6 @@ md_parse_option (int c, char *arg) break; #endif -#ifdef OBJ_AOUT - case 'k': - sparc_pic_code = 1; - break; -#endif - -#ifdef OBJ_ELF case OPTION_32: case OPTION_64: { @@ -619,7 +611,6 @@ md_parse_option (int c, char *arg) case OPTION_UNDECLARED_REGS: no_undeclared_regs = 0; break; -#endif case OPTION_RELAX: sparc_relax = 1; @@ -629,6 +620,10 @@ md_parse_option (int c, char *arg) sparc_relax = 0; break; + case OPTION_DCTI_COUPLES_DETECT: + dcti_couples_detect = 1; + break; + default: return 0; } @@ -683,11 +678,6 @@ md_show_usage (FILE *stream) --enforce-aligned-data force .long, etc., to be aligned correctly\n\ -relax relax jumps and branches (default)\n\ -no-relax avoid changing any jumps and branches\n")); -#ifdef OBJ_AOUT - fprintf (stream, _("\ --k generate PIC\n")); -#endif -#ifdef OBJ_ELF fprintf (stream, _("\ -32 create 32 bit object file\n\ -64 create 64 bit object file\n")); @@ -706,10 +696,10 @@ md_show_usage (FILE *stream) appropriate .register directive (default)\n\ -no-undeclared-regs force error on application global register usage\n\ without appropriate .register directive\n\ +--dcti-couples-detect warn when an unpredictable DCTI couple is found\n\ -q ignored\n\ -Qy, -Qn ignored\n\ -s ignored\n")); -#endif #ifdef SPARC_BIENDIAN fprintf (stream, _("\ -EL generate code for a little endian machine\n\ @@ -720,11 +710,11 @@ md_show_usage (FILE *stream) } /* Native operand size opcode translation. */ -struct +static struct { - char *name; - char *name32; - char *name64; + const char *name; + const char *name32; + const char *name64; } native_op_table[] = { {"ldn", "ld", "ldx"}, @@ -744,7 +734,7 @@ struct struct priv_reg_entry { - char *name; + const char *name; int regnum; }; @@ -767,8 +757,9 @@ struct priv_reg_entry priv_reg_table[] = {"wstate", 14}, {"fq", 15}, {"gl", 16}, + {"pmcdper", 23}, {"ver", 31}, - {"", -1}, /* End marker. */ + {NULL, -1}, /* End marker. */ }; struct priv_reg_entry hpriv_reg_table[] = @@ -778,12 +769,16 @@ struct priv_reg_entry hpriv_reg_table[] = {"hintp", 3}, {"htba", 5}, {"hver", 6}, + {"hmcdper", 23}, + {"hmcddfr", 24}, + {"hva_mask_nz", 27}, + {"hstick_offset", 28}, + {"hstick_enable", 29}, {"hstick_cmpr", 31}, - {"", -1}, /* End marker. */ + {NULL, -1}, /* End marker. */ }; -/* v9a specific asrs. This table is ordered by initial - letter, in reverse. */ +/* v9a or later specific ancillary state registers. */ struct priv_reg_entry v9a_asr_table[] = { @@ -796,13 +791,15 @@ struct priv_reg_entry v9a_asr_table[] = {"softint_set", 20}, {"softint", 22}, {"set_softint", 20}, + {"pause", 27}, {"pic", 17}, {"pcr", 16}, + {"mwait", 28}, {"gsr", 19}, {"dcr", 18}, - {"cps", 28}, + {"cfr", 26}, {"clear_softint", 21}, - {"", -1}, /* End marker. */ + {NULL, -1}, /* End marker. */ }; static int @@ -811,7 +808,130 @@ cmp_reg_entry (const void *parg, const void *qarg) const struct priv_reg_entry *p = (const struct priv_reg_entry *) parg; const struct priv_reg_entry *q = (const struct priv_reg_entry *) qarg; - return strcmp (q->name, p->name); + if (p->name == q->name) + return 0; + else if (p->name == NULL) + return 1; + else if (q->name == NULL) + return -1; + else + return strcmp (q->name, p->name); +} + +/* sparc %-pseudo-operations. */ + + +#define F_POP_V9 0x1 /* The pseudo-op is for v9 only. */ +#define F_POP_PCREL 0x2 /* The pseudo-op can be used in pc-relative + contexts. */ +#define F_POP_TLS_CALL 0x4 /* The pseudo-op marks a tls call. */ +#define F_POP_POSTFIX 0x8 /* The pseudo-op should appear after the + last operand of an + instruction. (Generally they can appear + anywhere an immediate operand is + expected. */ +struct pop_entry +{ + /* The name as it appears in assembler. */ + const char *name; + /* The reloc this pseudo-op translates to. */ + bfd_reloc_code_real_type reloc; + /* Flags. See F_POP_* above. */ + int flags; +}; + +struct pop_entry pop_table[] = +{ + { "hix", BFD_RELOC_SPARC_HIX22, F_POP_V9 }, + { "lox", BFD_RELOC_SPARC_LOX10, F_POP_V9 }, + { "hi", BFD_RELOC_HI22, F_POP_PCREL }, + { "lo", BFD_RELOC_LO10, F_POP_PCREL }, + { "pc22", BFD_RELOC_SPARC_PC22, F_POP_PCREL }, + { "pc10", BFD_RELOC_SPARC_PC10, F_POP_PCREL }, + { "hh", BFD_RELOC_SPARC_HH22, F_POP_V9|F_POP_PCREL }, + { "hm", BFD_RELOC_SPARC_HM10, F_POP_V9|F_POP_PCREL }, + { "lm", BFD_RELOC_SPARC_LM22, F_POP_V9|F_POP_PCREL }, + { "h34", BFD_RELOC_SPARC_H34, F_POP_V9 }, + { "l34", BFD_RELOC_SPARC_L44, F_POP_V9 }, + { "h44", BFD_RELOC_SPARC_H44, F_POP_V9 }, + { "m44", BFD_RELOC_SPARC_M44, F_POP_V9 }, + { "l44", BFD_RELOC_SPARC_L44, F_POP_V9 }, + { "uhi", BFD_RELOC_SPARC_HH22, F_POP_V9 }, + { "ulo", BFD_RELOC_SPARC_HM10, F_POP_V9 }, + { "tgd_hi22", BFD_RELOC_SPARC_TLS_GD_HI22, 0 }, + { "tgd_lo10", BFD_RELOC_SPARC_TLS_GD_LO10, 0 }, + { "tldm_hi22", BFD_RELOC_SPARC_TLS_LDM_HI22, 0 }, + { "tldm_lo10", BFD_RELOC_SPARC_TLS_LDM_LO10, 0 }, + { "tldo_hix22", BFD_RELOC_SPARC_TLS_LDO_HIX22, 0 }, + { "tldo_lox10", BFD_RELOC_SPARC_TLS_LDO_LOX10, 0 }, + { "tie_hi22", BFD_RELOC_SPARC_TLS_IE_HI22, 0 }, + { "tie_lo10", BFD_RELOC_SPARC_TLS_IE_LO10, 0 }, + { "tle_hix22", BFD_RELOC_SPARC_TLS_LE_HIX22, 0 }, + { "tle_lox10", BFD_RELOC_SPARC_TLS_LE_LOX10, 0 }, + { "gdop_hix22", BFD_RELOC_SPARC_GOTDATA_OP_HIX22, 0 }, + { "gdop_lox10", BFD_RELOC_SPARC_GOTDATA_OP_LOX10, 0 }, + { "tgd_add", BFD_RELOC_SPARC_TLS_GD_ADD, F_POP_POSTFIX }, + { "tgd_call", BFD_RELOC_SPARC_TLS_GD_CALL, F_POP_POSTFIX|F_POP_TLS_CALL }, + { "tldm_add", BFD_RELOC_SPARC_TLS_LDM_ADD, F_POP_POSTFIX }, + { "tldm_call", BFD_RELOC_SPARC_TLS_LDM_CALL, F_POP_POSTFIX|F_POP_TLS_CALL }, + { "tldo_add", BFD_RELOC_SPARC_TLS_LDO_ADD, F_POP_POSTFIX }, + { "tie_ldx", BFD_RELOC_SPARC_TLS_IE_LDX, F_POP_POSTFIX }, + { "tie_ld", BFD_RELOC_SPARC_TLS_IE_LD, F_POP_POSTFIX }, + { "tie_add", BFD_RELOC_SPARC_TLS_IE_ADD, F_POP_POSTFIX }, + { "gdop", BFD_RELOC_SPARC_GOTDATA_OP, F_POP_POSTFIX } +}; + +/* Table of %-names that can appear in a sparc assembly program. This + table is initialized in md_begin and contains entries for each + privileged/hyperprivileged/alternate register and %-pseudo-op. */ + +enum perc_entry_type +{ + perc_entry_none = 0, + perc_entry_reg, + perc_entry_post_pop, + perc_entry_imm_pop +}; + +struct perc_entry +{ + /* Entry type. */ + enum perc_entry_type type; + /* Name of the %-entity. */ + const char *name; + /* strlen (name). */ + int len; + /* Value. Either a pop or a reg depending on type.*/ + union + { + struct pop_entry *pop; + struct priv_reg_entry *reg; + }; +}; + +#define NUM_PERC_ENTRIES \ + (((sizeof (priv_reg_table) / sizeof (priv_reg_table[0])) - 1) \ + + ((sizeof (hpriv_reg_table) / sizeof (hpriv_reg_table[0])) - 1) \ + + ((sizeof (v9a_asr_table) / sizeof (v9a_asr_table[0])) - 1) \ + + ARRAY_SIZE (pop_table) \ + + 1) + +struct perc_entry perc_table[NUM_PERC_ENTRIES]; + +static int +cmp_perc_entry (const void *parg, const void *qarg) +{ + const struct perc_entry *p = (const struct perc_entry *) parg; + const struct perc_entry *q = (const struct perc_entry *) qarg; + + if (p->name == q->name) + return 0; + else if (p->name == NULL) + return 1; + else if (q->name == NULL) + return -1; + else + return strcmp (q->name, p->name); } /* This function is called once, at assembler startup time. It should @@ -821,9 +941,9 @@ cmp_reg_entry (const void *parg, const void *qarg) void md_begin (void) { - register const char *retval = NULL; + const char *retval = NULL; int lose = 0; - register unsigned int i = 0; + unsigned int i = 0; /* We don't get a chance to initialize anything before md_parse_option is called, and it may not be called, so handle default initialization @@ -861,7 +981,7 @@ md_begin (void) for (i = 0; native_op_table[i].name; i++) { const struct sparc_opcode *insn; - char *name = ((sparc_arch_size == 32) + const char *name = ((sparc_arch_size == 32) ? native_op_table[i].name32 : native_op_table[i].name64); insn = (struct sparc_opcode *) hash_find (op_hash, name); @@ -889,7 +1009,11 @@ md_begin (void) qsort (priv_reg_table, sizeof (priv_reg_table) / sizeof (priv_reg_table[0]), sizeof (priv_reg_table[0]), cmp_reg_entry); - + qsort (hpriv_reg_table, sizeof (hpriv_reg_table) / sizeof (hpriv_reg_table[0]), + sizeof (hpriv_reg_table[0]), cmp_reg_entry); + qsort (v9a_asr_table, sizeof (v9a_asr_table) / sizeof (v9a_asr_table[0]), + sizeof (v9a_asr_table[0]), cmp_reg_entry); + /* If -bump, record the architecture level at which we start issuing warnings. The behaviour is different depending upon whether an architecture was explicitly specified. If it wasn't, we issue warnings @@ -903,16 +1027,64 @@ md_begin (void) /* `max_architecture' records the requested architecture. Issue warnings if we go above it. */ warn_after_architecture = max_architecture; - - /* Find the highest architecture level that doesn't conflict with - the requested one. */ - for (max_architecture = SPARC_OPCODE_ARCH_MAX; - max_architecture > warn_after_architecture; - --max_architecture) - if (! SPARC_OPCODE_CONFLICT_P (max_architecture, - warn_after_architecture)) - break; } + + /* Find the highest architecture level that doesn't conflict with + the requested one. */ + + if (warn_on_bump + || !architecture_requested) + { + enum sparc_opcode_arch_val current_max_architecture + = max_architecture; + + for (max_architecture = SPARC_OPCODE_ARCH_MAX; + max_architecture > warn_after_architecture; + --max_architecture) + if (! SPARC_OPCODE_CONFLICT_P (max_architecture, + current_max_architecture)) + break; + } + + /* Prepare the tables of %-pseudo-ops. */ + { + struct priv_reg_entry *reg_tables[] + = {priv_reg_table, hpriv_reg_table, v9a_asr_table, NULL}; + struct priv_reg_entry **reg_table; + int entry = 0; + + /* Add registers. */ + for (reg_table = reg_tables; reg_table[0]; reg_table++) + { + struct priv_reg_entry *reg; + for (reg = *reg_table; reg->name; reg++) + { + struct perc_entry *p = &perc_table[entry++]; + p->type = perc_entry_reg; + p->name = reg->name; + p->len = strlen (reg->name); + p->reg = reg; + } + } + + /* Add %-pseudo-ops. */ + for (i = 0; i < ARRAY_SIZE (pop_table); i++) + { + struct perc_entry *p = &perc_table[entry++]; + p->type = (pop_table[i].flags & F_POP_POSTFIX + ? perc_entry_post_pop : perc_entry_imm_pop); + p->name = pop_table[i].name; + p->len = strlen (pop_table[i].name); + p->pop = &pop_table[i]; + } + + /* Last entry is the sentinel. */ + perc_table[entry].type = perc_entry_none; + + qsort (perc_table, sizeof (perc_table) / sizeof (perc_table[0]), + sizeof (perc_table[0]), cmp_perc_entry); + + } } /* Called after all assembly has been done. */ @@ -920,13 +1092,22 @@ md_begin (void) void sparc_md_end (void) { - unsigned long mach = bfd_mach_sparc; + unsigned long mach; +#ifndef TE_SOLARIS + int hwcaps, hwcaps2; +#endif if (sparc_arch_size == 64) switch (current_architecture) { case SPARC_OPCODE_ARCH_V9A: mach = bfd_mach_sparc_v9a; break; case SPARC_OPCODE_ARCH_V9B: mach = bfd_mach_sparc_v9b; break; + case SPARC_OPCODE_ARCH_V9C: mach = bfd_mach_sparc_v9c; break; + case SPARC_OPCODE_ARCH_V9D: mach = bfd_mach_sparc_v9d; break; + case SPARC_OPCODE_ARCH_V9E: mach = bfd_mach_sparc_v9e; break; + case SPARC_OPCODE_ARCH_V9V: mach = bfd_mach_sparc_v9v; break; + case SPARC_OPCODE_ARCH_V9M: mach = bfd_mach_sparc_v9m; break; + case SPARC_OPCODE_ARCH_M8: mach = bfd_mach_sparc_v9m8; break; default: mach = bfd_mach_sparc_v9; break; } else @@ -936,16 +1117,27 @@ sparc_md_end (void) case SPARC_OPCODE_ARCH_V9: mach = bfd_mach_sparc_v8plus; break; case SPARC_OPCODE_ARCH_V9A: mach = bfd_mach_sparc_v8plusa; break; case SPARC_OPCODE_ARCH_V9B: mach = bfd_mach_sparc_v8plusb; break; + case SPARC_OPCODE_ARCH_V9C: mach = bfd_mach_sparc_v8plusc; break; + case SPARC_OPCODE_ARCH_V9D: mach = bfd_mach_sparc_v8plusd; break; + case SPARC_OPCODE_ARCH_V9E: mach = bfd_mach_sparc_v8pluse; break; + case SPARC_OPCODE_ARCH_V9V: mach = bfd_mach_sparc_v8plusv; break; + case SPARC_OPCODE_ARCH_V9M: mach = bfd_mach_sparc_v8plusm; break; + case SPARC_OPCODE_ARCH_M8: mach = bfd_mach_sparc_v8plusm8; break; /* The sparclite is treated like a normal sparc. Perhaps it shouldn't be but for now it is (since that's the way it's always been treated). */ - default: break; + default: mach = bfd_mach_sparc; break; } bfd_set_arch_mach (stdoutput, bfd_arch_sparc, mach); -#if defined(OBJ_ELF) && !defined(TE_SOLARIS) - if (hwcap_seen) - bfd_elf_add_obj_attr_int (stdoutput, OBJ_ATTR_GNU, Tag_GNU_Sparc_HWCAPS, hwcap_seen); +#ifndef TE_SOLARIS + hwcaps = hwcap_seen & U0xffffffff; + hwcaps2 = hwcap_seen >> 32; + + if (hwcaps) + bfd_elf_add_obj_attr_int (stdoutput, OBJ_ATTR_GNU, Tag_GNU_Sparc_HWCAPS, hwcaps); + if (hwcaps2) + bfd_elf_add_obj_attr_int (stdoutput, OBJ_ATTR_GNU, Tag_GNU_Sparc_HWCAPS2, hwcaps2); #endif } @@ -1021,7 +1213,7 @@ BSR (bfd_vma val, int amount) static char *expr_end; /* Values for `special_case'. - Instructions that require wierd handling because they're longer than + Instructions that require weird handling because they're longer than 4 bytes. */ #define SPECIAL_CASE_NONE 0 #define SPECIAL_CASE_SET 1 @@ -1153,7 +1345,7 @@ synthetize_setsw (const struct sparc_opcode *insn) output_insn (insn, &the_insn); } -/* Handle the setsw synthetic instruction. */ +/* Handle the setx synthetic instruction. */ static void synthetize_setx (const struct sparc_opcode *insn) @@ -1332,31 +1524,54 @@ md_assemble (char *str) if (insn == NULL) return; - /* We warn about attempts to put a floating point branch in a delay slot, - unless the delay slot has been annulled. */ + /* Certain instructions may not appear on delay slots. Check for + these situations. */ if (last_insn != NULL - && (insn->flags & F_FBR) != 0 - && (last_insn->flags & F_DELAYED) != 0 - /* ??? This test isn't completely accurate. We assume anything with - F_{UNBR,CONDBR,FBR} set is annullable. */ - && ((last_insn->flags & (F_UNBR | F_CONDBR | F_FBR)) == 0 - || (last_opcode & ANNUL) == 0)) - as_warn (_("FP branch in delay slot")); - - /* SPARC before v9 requires a nop instruction between a floating - point instruction and a floating point branch. We insert one - automatically, with a warning. */ + && (last_insn->flags & F_DELAYED) != 0) + { + /* Before SPARC V9 the effect of having a delayed branch + instruction in the delay slot of a conditional delayed branch + was undefined. + + In SPARC V9 DCTI couples are well defined. + + However, starting with the UltraSPARC Architecture 2005, DCTI + couples (of all kind) are deprecated and should not be used, + as they may be slow or behave differently to what the + programmer expects. */ + if (dcti_couples_detect + && (insn->flags & F_DELAYED) != 0 + && ((max_architecture < SPARC_OPCODE_ARCH_V9 + && (last_insn->flags & F_CONDBR) != 0) + || max_architecture >= SPARC_OPCODE_ARCH_V9C)) + as_warn (_("unpredictable DCTI couple")); + + + /* We warn about attempts to put a floating point branch in a + delay slot, unless the delay slot has been annulled. */ + if ((insn->flags & F_FBR) != 0 + /* ??? This test isn't completely accurate. We assume anything with + F_{UNBR,CONDBR,FBR} set is annullable. */ + && ((last_insn->flags & (F_UNBR | F_CONDBR | F_FBR)) == 0 + || (last_opcode & ANNUL) == 0)) + as_warn (_("FP branch in delay slot")); + } + + /* SPARC before v9 does not allow a floating point compare + directly before a floating point branch. Insert a nop + instruction if needed, with a warning. */ if (max_architecture < SPARC_OPCODE_ARCH_V9 && last_insn != NULL && (insn->flags & F_FBR) != 0 - && (last_insn->flags & F_FLOAT) != 0) + && (last_insn->flags & F_FLOAT) != 0 + && (last_insn->match & OP3 (0x35)) == OP3 (0x35)) { struct sparc_it nop_insn; nop_insn.opcode = NOP_INSN; nop_insn.reloc = BFD_RELOC_NONE; output_insn (insn, &nop_insn); - as_warn (_("FP branch preceded by FP instruction; NOP inserted")); + as_warn (_("FP branch preceded by FP compare; NOP inserted")); } switch (special_case) @@ -1401,7 +1616,7 @@ md_assemble (char *str) } static const char * -get_hwcap_name (int mask) +get_hwcap_name (bfd_uint64_t mask) { if (mask & HWCAP_MUL32) return "mul32"; @@ -1461,6 +1676,41 @@ get_hwcap_name (int mask) return "cbcond"; if (mask & HWCAP_CRC32C) return "crc32c"; + + mask = mask >> 32; + if (mask & HWCAP2_FJATHPLUS) + return "fjathplus"; + if (mask & HWCAP2_VIS3B) + return "vis3b"; + if (mask & HWCAP2_ADP) + return "adp"; + if (mask & HWCAP2_SPARC5) + return "sparc5"; + if (mask & HWCAP2_MWAIT) + return "mwait"; + if (mask & HWCAP2_XMPMUL) + return "xmpmul"; + if (mask & HWCAP2_XMONT) + return "xmont"; + if (mask & HWCAP2_NSEC) + return "nsec"; + if (mask & HWCAP2_SPARC6) + return "sparc6"; + if (mask & HWCAP2_ONADDSUB) + return "onaddsub"; + if (mask & HWCAP2_ONMUL) + return "onmul"; + if (mask & HWCAP2_ONDIV) + return "ondiv"; + if (mask & HWCAP2_DICTUNP) + return "dictunp"; + if (mask & HWCAP2_FPCMPSHL) + return "fpcmpshl"; + if (mask & HWCAP2_RLE) + return "rle"; + if (mask & HWCAP2_SHA3) + return "sha3"; + return "UNKNOWN"; } @@ -1469,7 +1719,7 @@ get_hwcap_name (int mask) static int sparc_ip (char *str, const struct sparc_opcode **pinsn) { - char *error_message = ""; + const char *error_message = ""; char *s; const char *args; char c; @@ -1481,13 +1731,14 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) int comma = 0; int v9_arg_p; int special_case = SPECIAL_CASE_NONE; + const sparc_asi *sasi = NULL; s = str; if (ISLOWER (*s)) { do ++s; - while (ISLOWER (*s) || ISDIGIT (*s)); + while (ISLOWER (*s) || ISDIGIT (*s) || *s == '_'); } switch (*s) @@ -1631,28 +1882,30 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) /* Parse a sparc64 privileged register. */ if (*s == '%') { - struct priv_reg_entry *p = priv_reg_table; + struct priv_reg_entry *p; unsigned int len = 9999999; /* Init to make gcc happy. */ s += 1; - while (p->name[0] > s[0]) - p++; - while (p->name[0] == s[0]) - { - len = strlen (p->name); - if (strncmp (p->name, s, len) == 0) - break; - p++; - } - if (p->name[0] != s[0]) + for (p = priv_reg_table; p->name; p++) + if (p->name[0] == s[0]) + { + len = strlen (p->name); + if (strncmp (p->name, s, len) == 0) + break; + } + + if (!p->name) { error_message = _(": unrecognizable privileged register"); goto error; } - if (*args == '?') - opcode |= (p->regnum << 14); - else - opcode |= (p->regnum << 25); + + if (((opcode >> (*args == '?' ? 14 : 25)) & 0x1f) != (unsigned) p->regnum) + { + error_message = _(": unrecognizable privileged register"); + goto error; + } + s += len; continue; } @@ -1667,29 +1920,31 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) /* Parse a sparc64 hyperprivileged register. */ if (*s == '%') { - struct priv_reg_entry *p = hpriv_reg_table; + struct priv_reg_entry *p; unsigned int len = 9999999; /* Init to make gcc happy. */ s += 1; - while (p->name[0] > s[0]) - p++; - while (p->name[0] == s[0]) - { - len = strlen (p->name); - if (strncmp (p->name, s, len) == 0) - break; - p++; - } - if (p->name[0] != s[0]) + for (p = hpriv_reg_table; p->name; p++) + if (p->name[0] == s[0]) + { + len = strlen (p->name); + if (strncmp (p->name, s, len) == 0) + break; + } + + if (!p->name) { error_message = _(": unrecognizable hyperprivileged register"); goto error; } - if (*args == '$') - opcode |= (p->regnum << 14); - else - opcode |= (p->regnum << 25); - s += len; + + if (((opcode >> (*args == '$' ? 14 : 25)) & 0x1f) != (unsigned) p->regnum) + { + error_message = _(": unrecognizable hyperprivileged register"); + goto error; + } + + s += len; continue; } else @@ -1700,50 +1955,39 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) case '_': case '/': - /* Parse a v9a/v9b ancillary state register. */ + /* Parse a v9a or later ancillary state register. */ if (*s == '%') { - struct priv_reg_entry *p = v9a_asr_table; + struct priv_reg_entry *p; unsigned int len = 9999999; /* Init to make gcc happy. */ s += 1; - while (p->name[0] > s[0]) - p++; - while (p->name[0] == s[0]) - { - len = strlen (p->name); - if (strncmp (p->name, s, len) == 0) - break; - p++; - } - if (p->name[0] != s[0]) + for (p = v9a_asr_table; p->name; p++) + if (p->name[0] == s[0]) + { + len = strlen (p->name); + if (strncmp (p->name, s, len) == 0) + break; + } + + if (!p->name) { - error_message = _(": unrecognizable v9a or v9b ancillary state register"); + error_message = _(": unrecognizable ancillary state register"); goto error; } - if (*args == '/' && (p->regnum == 20 || p->regnum == 21)) - { - error_message = _(": rd on write only ancillary state register"); - goto error; - } - if (p->regnum >= 24 - && (insn->architecture - & SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A))) - { - /* %sys_tick and %sys_tick_cmpr are v9bnotv9a */ - error_message = _(": unrecognizable v9a ancillary state register"); - goto error; - } - if (*args == '/') - opcode |= (p->regnum << 14); - else - opcode |= (p->regnum << 25); + + if (((opcode >> (*args == '/' ? 14 : 25)) & 0x1f) != (unsigned) p->regnum) + { + error_message = _(": unrecognizable ancillary state register"); + goto error; + } + s += len; continue; } else { - error_message = _(": unrecognizable v9a or v9b ancillary state register"); + error_message = _(": unrecognizable ancillary state register"); goto error; } @@ -1763,22 +2007,22 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) ++s; } - if (current_architecture >= SPARC_OPCODE_ARCH_V9) - { - if (num < 16 || 31 < num) - { - error_message = _(": asr number must be between 16 and 31"); - goto error; - } - } - else - { - if (num < 0 || 31 < num) - { - error_message = _(": asr number must be between 0 and 31"); - goto error; - } - } + /* We used to check here for the asr number to + be between 16 and 31 in V9 and later, as + mandated by the section C.1.1 "Register + Names" in the SPARC spec. However, we + decided to remove this restriction as a) it + introduces problems when new V9 asr registers + are introduced, b) the Solaris assembler + doesn't implement this restriction and c) the + restriction will go away in future revisions + of the Oracle SPARC Architecture. */ + + if (num < 0 || 31 < num) + { + error_message = _(": asr number must be between 0 and 31"); + goto error; + } opcode |= (*args == 'M' ? RS1 (num) : RD (num)); continue; @@ -1799,6 +2043,47 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) the_insn.reloc = BFD_RELOC_SPARC_10; goto immediate; + case ')': + if (*s == ' ') + s++; + if ((s[0] == '0' && s[1] == 'x' && ISXDIGIT (s[2])) + || ISDIGIT (*s)) + { + long num = 0; + + if (s[0] == '0' && s[1] == 'x') + { + s += 2; + while (ISXDIGIT (*s)) + { + num <<= 4; + num |= hex_value (*s); + ++s; + } + } + else + { + while (ISDIGIT (*s)) + { + num = num * 10 + *s - '0'; + ++s; + } + } + if (num < 0 || num > 31) + { + error_message = _(": crypto immediate must be between 0 and 31"); + goto error; + } + + opcode |= RS3 (num); + continue; + } + else + { + error_message = _(": expecting crypto immediate"); + goto error; + } + case 'X': /* V8 systems don't understand BFD_RELOC_SPARC_5. */ if (SPARC_OPCODE_ARCH_V9_P (max_architecture)) @@ -1855,7 +2140,8 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) { ++s; } - if (strncmp (s, "%icc", 4) == 0) + if ((strncmp (s, "%icc", 4) == 0) + || (sparc_arch_size == 32 && strncmp (s, "%ncc", 4) == 0)) { s += 4; continue; @@ -1867,7 +2153,8 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) { ++s; } - if (strncmp (s, "%xcc", 4) == 0) + if ((strncmp (s, "%xcc", 4) == 0) + || (sparc_arch_size == 64 && strncmp (s, "%ncc", 4) == 0)) { s += 4; continue; @@ -1941,67 +2228,45 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) case '\0': /* End of args. */ if (s[0] == ',' && s[1] == '%') { - static const struct ops - { - /* The name as it appears in assembler. */ - char *name; - /* strlen (name), precomputed for speed */ - int len; - /* The reloc this pseudo-op translates to. */ - int reloc; - /* 1 if tls call. */ - int tls_call; - } - ops[] = - { - { "tgd_add", 7, BFD_RELOC_SPARC_TLS_GD_ADD, 0 }, - { "tgd_call", 8, BFD_RELOC_SPARC_TLS_GD_CALL, 1 }, - { "tldm_add", 8, BFD_RELOC_SPARC_TLS_LDM_ADD, 0 }, - { "tldm_call", 9, BFD_RELOC_SPARC_TLS_LDM_CALL, 1 }, - { "tldo_add", 8, BFD_RELOC_SPARC_TLS_LDO_ADD, 0 }, - { "tie_ldx", 7, BFD_RELOC_SPARC_TLS_IE_LDX, 0 }, - { "tie_ld", 6, BFD_RELOC_SPARC_TLS_IE_LD, 0 }, - { "tie_add", 7, BFD_RELOC_SPARC_TLS_IE_ADD, 0 }, - { "gdop", 4, BFD_RELOC_SPARC_GOTDATA_OP, 0 }, - { NULL, 0, 0, 0 } - }; - const struct ops *o; char *s1; int npar = 0; + const struct perc_entry *p; - for (o = ops; o->name; o++) - if (strncmp (s + 2, o->name, o->len) == 0) - break; - if (o->name == NULL) - break; + for (p = perc_table; p->type != perc_entry_none; p++) + if ((p->type == perc_entry_post_pop || p->type == perc_entry_reg) + && strncmp (s + 2, p->name, p->len) == 0) + break; + if (p->type == perc_entry_none || p->type == perc_entry_reg) + break; - if (s[o->len + 2] != '(') + if (s[p->len + 2] != '(') { - as_bad (_("Illegal operands: %%%s requires arguments in ()"), o->name); + as_bad (_("Illegal operands: %%%s requires arguments in ()"), p->name); return special_case; } - if (! o->tls_call && the_insn.reloc != BFD_RELOC_NONE) + if (! (p->pop->flags & F_POP_TLS_CALL) + && the_insn.reloc != BFD_RELOC_NONE) { as_bad (_("Illegal operands: %%%s cannot be used together with other relocs in the insn ()"), - o->name); + p->name); return special_case; } - if (o->tls_call + if ((p->pop->flags & F_POP_TLS_CALL) && (the_insn.reloc != BFD_RELOC_32_PCREL_S2 || the_insn.exp.X_add_number != 0 || the_insn.exp.X_add_symbol != symbol_find_or_make ("__tls_get_addr"))) { as_bad (_("Illegal operands: %%%s can be only used with call __tls_get_addr"), - o->name); + p->name); return special_case; } - the_insn.reloc = o->reloc; + the_insn.reloc = p->pop->reloc; memset (&the_insn.exp, 0, sizeof (the_insn.exp)); - s += o->len + 3; + s += p->len + 3; for (s1 = s; *s1 && *s1 != ',' && *s1 != ']'; s1++) if (*s1 == '(') @@ -2015,7 +2280,7 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) if (*s1 != ')') { - as_bad (_("Illegal operands: %%%s requires arguments in ()"), o->name); + as_bad (_("Illegal operands: %%%s requires arguments in ()"), p->name); return special_case; } @@ -2233,10 +2498,13 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) case 'e': /* next operand is a floating point register */ case 'v': case 'V': + case ';': case 'f': case 'B': case 'R': + case ':': + case '\'': case '4': case '5': @@ -2244,11 +2512,15 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) case 'g': case 'H': case 'J': + case '}': + case '^': { char format; if (*s++ == '%' - && ((format = *s) == 'f') + && ((format = *s) == 'f' + || format == 'd' + || format == 'q') && ISDIGIT (*++s)) { for (mask = 0; ISDIGIT (*s); ++s) @@ -2259,19 +2531,39 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) if ((*args == 'v' || *args == 'B' || *args == '5' - || *args == 'H') + || *args == 'H' + || *args == '\'' + || format == 'd') && (mask & 1)) { + /* register must be even numbered */ break; - } /* register must be even numbered */ + } if ((*args == 'V' || *args == 'R' - || *args == 'J') + || *args == 'J' + || format == 'q') && (mask & 3)) { + /* register must be multiple of 4 */ break; - } /* register must be multiple of 4 */ + } + + if ((*args == ':' + || *args == ';' + || *args == '^') + && (mask & 7)) + { + /* register must be multiple of 8 */ + break; + } + + if (*args == '\'' && mask < 48) + { + /* register must be higher or equal than %f48 */ + break; + } if (mask >= 64) { @@ -2306,20 +2598,33 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) break; } /* if not an 'f' register. */ + if (*args == '}' && mask != RS2 (opcode)) + { + error_message + = _(": Instruction requires frs2 and frsd must be the same register"); + goto error; + } + switch (*args) { case 'v': case 'V': case 'e': + case ';': opcode |= RS1 (mask); continue; case 'f': case 'B': case 'R': + case ':': opcode |= RS2 (mask); continue; + case '\'': + opcode |= RS2 (mask & 0xe); + continue; + case '4': case '5': opcode |= RS3 (mask); @@ -2328,6 +2633,8 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) case 'g': case 'H': case 'J': + case '}': + case '^': opcode |= RD (mask); continue; } /* Pack it in. */ @@ -2382,79 +2689,32 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) { char *s1; - char *op_arg = NULL; + const char *op_arg = NULL; static expressionS op_exp; bfd_reloc_code_real_type old_reloc = the_insn.reloc; /* Check for %hi, etc. */ if (*s == '%') { - static const struct ops { - /* The name as it appears in assembler. */ - char *name; - /* strlen (name), precomputed for speed */ - int len; - /* The reloc this pseudo-op translates to. */ - int reloc; - /* Non-zero if for v9 only. */ - int v9_p; - /* Non-zero if can be used in pc-relative contexts. */ - int pcrel_p;/*FIXME:wip*/ - } ops[] = { - /* hix/lox must appear before hi/lo so %hix won't be - mistaken for %hi. */ - { "hix", 3, BFD_RELOC_SPARC_HIX22, 1, 0 }, - { "lox", 3, BFD_RELOC_SPARC_LOX10, 1, 0 }, - { "hi", 2, BFD_RELOC_HI22, 0, 1 }, - { "lo", 2, BFD_RELOC_LO10, 0, 1 }, - { "pc22", 4, BFD_RELOC_SPARC_PC22, 0, 1 }, - { "pc10", 4, BFD_RELOC_SPARC_PC10, 0, 1 }, - { "hh", 2, BFD_RELOC_SPARC_HH22, 1, 1 }, - { "hm", 2, BFD_RELOC_SPARC_HM10, 1, 1 }, - { "lm", 2, BFD_RELOC_SPARC_LM22, 1, 1 }, - { "h34", 3, BFD_RELOC_SPARC_H34, 1, 0 }, - { "l34", 3, BFD_RELOC_SPARC_L44, 1, 0 }, - { "h44", 3, BFD_RELOC_SPARC_H44, 1, 0 }, - { "m44", 3, BFD_RELOC_SPARC_M44, 1, 0 }, - { "l44", 3, BFD_RELOC_SPARC_L44, 1, 0 }, - { "uhi", 3, BFD_RELOC_SPARC_HH22, 1, 0 }, - { "ulo", 3, BFD_RELOC_SPARC_HM10, 1, 0 }, - { "tgd_hi22", 8, BFD_RELOC_SPARC_TLS_GD_HI22, 0, 0 }, - { "tgd_lo10", 8, BFD_RELOC_SPARC_TLS_GD_LO10, 0, 0 }, - { "tldm_hi22", 9, BFD_RELOC_SPARC_TLS_LDM_HI22, 0, 0 }, - { "tldm_lo10", 9, BFD_RELOC_SPARC_TLS_LDM_LO10, 0, 0 }, - { "tldo_hix22", 10, BFD_RELOC_SPARC_TLS_LDO_HIX22, 0, - 0 }, - { "tldo_lox10", 10, BFD_RELOC_SPARC_TLS_LDO_LOX10, 0, - 0 }, - { "tie_hi22", 8, BFD_RELOC_SPARC_TLS_IE_HI22, 0, 0 }, - { "tie_lo10", 8, BFD_RELOC_SPARC_TLS_IE_LO10, 0, 0 }, - { "tle_hix22", 9, BFD_RELOC_SPARC_TLS_LE_HIX22, 0, 0 }, - { "tle_lox10", 9, BFD_RELOC_SPARC_TLS_LE_LOX10, 0, 0 }, - { "gdop_hix22", 10, BFD_RELOC_SPARC_GOTDATA_OP_HIX22, - 0, 0 }, - { "gdop_lox10", 10, BFD_RELOC_SPARC_GOTDATA_OP_LOX10, - 0, 0 }, - { NULL, 0, 0, 0, 0 } - }; - const struct ops *o; - - for (o = ops; o->name; o++) - if (strncmp (s + 1, o->name, o->len) == 0) - break; - if (o->name == NULL) - break; - - if (s[o->len + 1] != '(') + const struct perc_entry *p; + + for (p = perc_table; p->type != perc_entry_none; p++) + if ((p->type == perc_entry_imm_pop || p->type == perc_entry_reg) + && strncmp (s + 1, p->name, p->len) == 0) + break; + if (p->type == perc_entry_none || p->type == perc_entry_reg) + break; + + if (s[p->len + 1] != '(') { - as_bad (_("Illegal operands: %%%s requires arguments in ()"), o->name); + as_bad (_("Illegal operands: %%%s requires arguments in ()"), p->name); return special_case; } - op_arg = o->name; - the_insn.reloc = o->reloc; - s += o->len + 2; - v9_arg_p = o->v9_p; + op_arg = p->name; + the_insn.reloc = p->pop->reloc; + s += p->len + 2; + v9_arg_p = p->pop->flags & F_POP_V9; } /* Note that if the get_expression() fails, we will still @@ -2490,6 +2750,11 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) *s1 = '\0'; (void) get_expression (s); *s1 = ')'; + if (expr_end != s1) + { + as_bad (_("Expression inside %%%s could not be parsed"), op_arg); + return special_case; + } s = s1 + 1; if (*s == ',' || *s == ']' || !*s) continue; @@ -2659,6 +2924,27 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) all the various cases (e.g. in md_apply_fix and bfd_install_relocation) so duplicating all that code here isn't right. */ + + /* This is a special case to handle cbcond instructions + properly, which can need two relocations. The first + one is for the 5-bit immediate field and the latter + is going to be for the WDISP10 branch part. We + handle the R_SPARC_5 immediate directly here so that + we don't need to add support for multiple relocations + in one instruction just yet. */ + if (the_insn.reloc == BFD_RELOC_SPARC_5 + && ((insn->match & OP(0x3)) == 0)) + { + valueT val = the_insn.exp.X_add_number; + + the_insn.reloc = BFD_RELOC_NONE; + if (! in_bitfield_range (val, 0x1f)) + { + error_message = _(": Immediate value in cbcond is out of range."); + goto error; + } + opcode |= val & 0x1f; + } } continue; @@ -2678,11 +2964,12 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) /* Parse an asi. */ if (*s == '#') { - if (! parse_keyword_arg (sparc_encode_asi, &s, &asi)) + if (! parse_sparc_asi (&s, &sasi)) { error_message = _(": invalid ASI name"); goto error; } + asi = sasi->value; } else { @@ -2761,6 +3048,18 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) s += 5; continue; + case '{': + if (strncmp (s, "%mcdper",7) != 0) + break; + s += 7; + continue; + + case '&': + if (strncmp (s, "%entropy", 8) != 0) + break; + s += 8; + continue; + case 'E': if (strncmp (s, "%ccr", 4) != 0) break; @@ -2779,6 +3078,26 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) s += 4; continue; + case '|': + { + int imm2 = 0; + + /* Parse a 2-bit immediate. */ + if (! parse_const_expr_arg (&s, &imm2)) + { + error_message = _(": non-immdiate imm2 operand"); + goto error; + } + if ((imm2 & ~0x3) != 0) + { + error_message = _(": imm2 immediate operand out of range (0-3)"); + goto error; + } + + opcode |= ((imm2 & 0x2) << 3) | (imm2 & 0x1); + continue; + } + case 'x': { char *push = input_line_pointer; @@ -2850,10 +3169,21 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) else { /* We have a match. Now see if the architecture is OK. */ + /* String to use in case of architecture warning. */ + const char *msg_str = str; int needed_arch_mask = insn->architecture; - int hwcaps = insn->hwcaps; -#if defined(OBJ_ELF) && !defined(TE_SOLARIS) + /* Include the ASI architecture needed as well */ + if (sasi && needed_arch_mask > sasi->architecture) + { + needed_arch_mask = sasi->architecture; + msg_str = sasi->name; + } + + bfd_uint64_t hwcaps + = (((bfd_uint64_t) insn->hwcaps2) << 32) | insn->hwcaps; + +#ifndef TE_SOLARIS if (hwcaps) hwcap_seen |= hwcaps; #endif @@ -2885,10 +3215,15 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) as_warn (_("architecture bumped from \"%s\" to \"%s\" on \"%s\""), sparc_opcode_archs[current_architecture].name, sparc_opcode_archs[needed_architecture].name, - str); + msg_str); warn_after_architecture = needed_architecture; } current_architecture = needed_architecture; + hwcap_allowed + = (hwcap_allowed + | hwcaps + | (((bfd_uint64_t) sparc_opcode_archs[current_architecture].hwcaps2) << 32) + | sparc_opcode_archs[current_architecture].hwcaps); } /* Conflict. */ /* ??? This seems to be a bit fragile. What if the next entry in @@ -2918,14 +3253,14 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) ++arch; } - as_bad (_("Architecture mismatch on \"%s\"."), str); - as_tsktsk (_(" (Requires %s; requested architecture is %s.)"), + as_bad (_("Architecture mismatch on \"%s %s\"."), str, argsStart); + as_tsktsk (_("(Requires %s; requested architecture is %s.)"), required_archs, sparc_opcode_archs[max_architecture].name); return special_case; } - /* Make sure the the hwcaps used by the instruction are + /* Make sure the hwcaps used by the instruction are currently enabled. */ if (hwcaps & ~hwcap_allowed) { @@ -2944,6 +3279,35 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn) return special_case; } +static char * +skip_over_keyword (char *q) +{ + for (q = q + (*q == '#' || *q == '%'); + ISALNUM (*q) || *q == '_'; + ++q) + continue; + return q; +} + +static int +parse_sparc_asi (char **input_pointer_p, const sparc_asi **value_p) +{ + const sparc_asi *value; + char c, *p, *q; + + p = *input_pointer_p; + q = skip_over_keyword(p); + c = *q; + *q = 0; + value = sparc_encode_asi (p); + *q = c; + if (value == NULL) + return 0; + *value_p = value; + *input_pointer_p = q; + return 1; +} + /* Parse an argument that can be expressed as a keyword. (eg: #StoreStore or %ccfr). The result is a boolean indicating success. @@ -2958,10 +3322,7 @@ parse_keyword_arg (int (*lookup_fn) (const char *), char c, *p, *q; p = *input_pointerP; - for (q = p + (*p == '#' || *p == '%'); - ISALNUM (*q) || *q == '_'; - ++q) - continue; + q = skip_over_keyword(p); c = *q; *q = 0; value = (*lookup_fn) (p); @@ -3065,12 +3426,10 @@ output_insn (const struct sparc_opcode *insn, struct sparc_it *theinsn) last_insn = insn; last_opcode = theinsn->opcode; -#ifdef OBJ_ELF dwarf2_emit_insn (4); -#endif } -char * +const char * md_atof (int type, char *litP, int *sizeP) { return ieee_md_atof (type, litP, sizeP, target_big_endian); @@ -3107,7 +3466,6 @@ md_apply_fix (fixS *fixP, valueT *valP, segT segment ATTRIBUTE_UNUSED) fixP->fx_addnumber = val; /* Remember value for emit_reloc. */ -#ifdef OBJ_ELF /* SPARC ELF relocations don't use an addend in the data field. */ if (fixP->fx_addsy != NULL) { @@ -3145,7 +3503,6 @@ md_apply_fix (fixS *fixP, valueT *valP, segT segment ATTRIBUTE_UNUSED) return; } -#endif /* This is a hack. There should be a better way to handle this. Probably in terms of howto fields, once @@ -3153,45 +3510,6 @@ md_apply_fix (fixS *fixP, valueT *valP, segT segment ATTRIBUTE_UNUSED) if (fixP->fx_r_type == BFD_RELOC_32_PCREL_S2 && fixP->fx_addsy) val += fixP->fx_where + fixP->fx_frag->fr_address; -#ifdef OBJ_AOUT - /* FIXME: More ridiculous gas reloc hacking. If we are going to - generate a reloc, then we just want to let the reloc addend set - the value. We do not want to also stuff the addend into the - object file. Including the addend in the object file works when - doing a static link, because the linker will ignore the object - file contents. However, the dynamic linker does not ignore the - object file contents. */ - if (fixP->fx_addsy != NULL - && fixP->fx_r_type != BFD_RELOC_32_PCREL_S2) - val = 0; - - /* When generating PIC code, we do not want an addend for a reloc - against a local symbol. We adjust fx_addnumber to cancel out the - value already included in val, and to also cancel out the - adjustment which bfd_install_relocation will create. */ - if (sparc_pic_code - && fixP->fx_r_type != BFD_RELOC_32_PCREL_S2 - && fixP->fx_addsy != NULL - && ! S_IS_COMMON (fixP->fx_addsy) - && symbol_section_p (fixP->fx_addsy)) - fixP->fx_addnumber -= 2 * S_GET_VALUE (fixP->fx_addsy); - - /* When generating PIC code, we need to fiddle to get - bfd_install_relocation to do the right thing for a PC relative - reloc against a local symbol which we are going to keep. */ - if (sparc_pic_code - && fixP->fx_r_type == BFD_RELOC_32_PCREL_S2 - && fixP->fx_addsy != NULL - && (S_IS_EXTERNAL (fixP->fx_addsy) - || S_IS_WEAK (fixP->fx_addsy)) - && S_IS_DEFINED (fixP->fx_addsy) - && ! S_IS_COMMON (fixP->fx_addsy)) - { - val = 0; - fixP->fx_addnumber -= 2 * S_GET_VALUE (fixP->fx_addsy); - } -#endif - /* If this is a data relocation, just output VAL. */ if (fixP->fx_r_type == BFD_RELOC_8) @@ -3242,8 +3560,13 @@ md_apply_fix (fixS *fixP, valueT *valP, segT segment ATTRIBUTE_UNUSED) insn |= val & 0x3fffffff; - /* See if we have a delay slot. */ - if (sparc_relax && fixP->fx_where + 8 <= fixP->fx_frag->fr_fix) + /* See if we have a delay slot. In that case we attempt to + optimize several cases transforming CALL instructions + into branches. But we can only do that if the relocation + can be completely resolved here, i.e. if no undefined + symbol is associated with it. */ + if (sparc_relax && fixP->fx_addsy == NULL + && fixP->fx_where + 8 <= fixP->fx_frag->fr_fix) { #define G0 0 #define O7 15 @@ -3516,17 +3839,42 @@ tc_gen_reloc (asection *section, fixS *fixp) arelent *reloc; bfd_reloc_code_real_type code; - relocs[0] = reloc = (arelent *) xmalloc (sizeof (arelent)); + relocs[0] = reloc = XNEW (arelent); relocs[1] = NULL; - reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + reloc->sym_ptr_ptr = XNEW (asymbol *); *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; switch (fixp->fx_r_type) { + case BFD_RELOC_8: case BFD_RELOC_16: case BFD_RELOC_32: + case BFD_RELOC_64: + if (fixp->fx_pcrel) + { + switch (fixp->fx_size) + { + default: + as_bad_where (fixp->fx_file, fixp->fx_line, + _("can not do %d byte pc-relative relocation"), + fixp->fx_size); + code = fixp->fx_r_type; + fixp->fx_pcrel = 0; + break; + case 1: code = BFD_RELOC_8_PCREL; break; + case 2: code = BFD_RELOC_16_PCREL; break; + case 4: code = BFD_RELOC_32_PCREL; break; +#ifdef BFD64 + case 8: code = BFD_RELOC_64_PCREL; break; +#endif + } + if (fixp->fx_pcrel) + fixp->fx_addnumber = fixp->fx_offset; + break; + } + /* Fall through. */ case BFD_RELOC_HI22: case BFD_RELOC_LO10: case BFD_RELOC_32_PCREL_S2: @@ -3539,7 +3887,6 @@ tc_gen_reloc (asection *section, fixS *fixp) case BFD_RELOC_SPARC_WDISP16: case BFD_RELOC_SPARC_WDISP19: case BFD_RELOC_SPARC_WDISP22: - case BFD_RELOC_64: case BFD_RELOC_SPARC_5: case BFD_RELOC_SPARC_6: case BFD_RELOC_SPARC_7: @@ -3600,21 +3947,16 @@ tc_gen_reloc (asection *section, fixS *fixp) return NULL; } -#if defined (OBJ_ELF) || defined (OBJ_AOUT) /* If we are generating PIC code, we need to generate a different set of relocs. */ -#ifdef OBJ_ELF #define GOT_NAME "_GLOBAL_OFFSET_TABLE_" -#else -#define GOT_NAME "__GLOBAL_OFFSET_TABLE_" -#endif #ifdef TE_VXWORKS #define GOTT_BASE "__GOTT_BASE__" #define GOTT_INDEX "__GOTT_INDEX__" #endif - /* This code must be parallel to the OBJ_ELF tc_fix_adjustable. */ + /* This code must be parallel to tc_fix_adjustable. */ if (sparc_pic_code) { @@ -3657,10 +3999,9 @@ tc_gen_reloc (asection *section, fixS *fixp) break; } } -#endif /* defined (OBJ_ELF) || defined (OBJ_AOUT) */ /* Nothing is aligned in DWARF debugging sections. */ - if (bfd_get_section_flags (stdoutput, section) & SEC_DEBUGGING) + if (bfd_section_flags (section) & SEC_DEBUGGING) switch (code) { case BFD_RELOC_16: code = BFD_RELOC_SPARC_UA16; break; @@ -3684,25 +4025,6 @@ tc_gen_reloc (asection *section, fixS *fixp) } /* @@ Why fx_addnumber sometimes and fx_offset other times? */ -#ifdef OBJ_AOUT - - if (reloc->howto->pc_relative == 0 - || code == BFD_RELOC_SPARC_PC10 - || code == BFD_RELOC_SPARC_PC22) - reloc->addend = fixp->fx_addnumber; - else if (sparc_pic_code - && fixp->fx_r_type == BFD_RELOC_32_PCREL_S2 - && fixp->fx_addsy != NULL - && (S_IS_EXTERNAL (fixp->fx_addsy) - || S_IS_WEAK (fixp->fx_addsy)) - && S_IS_DEFINED (fixp->fx_addsy) - && ! S_IS_COMMON (fixp->fx_addsy)) - reloc->addend = fixp->fx_addnumber; - else - reloc->addend = fixp->fx_offset - reloc->address; - -#else /* elf or coff */ - if (code != BFD_RELOC_32_PCREL_S2 && code != BFD_RELOC_SPARC_WDISP22 && code != BFD_RELOC_SPARC_WDISP16 @@ -3718,16 +4040,15 @@ tc_gen_reloc (asection *section, fixS *fixp) + md_pcrel_from (fixp)); else reloc->addend = fixp->fx_offset; -#endif /* We expand R_SPARC_OLO10 to R_SPARC_LO10 and R_SPARC_13 on the same location. */ if (code == BFD_RELOC_SPARC_OLO10) { - relocs[1] = reloc = (arelent *) xmalloc (sizeof (arelent)); + relocs[1] = reloc = XNEW (arelent); relocs[2] = NULL; - reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + reloc->sym_ptr_ptr = XNEW (asymbol *); *reloc->sym_ptr_ptr = symbol_get_bfdsym (section_symbol (absolute_section)); reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; @@ -3751,20 +4072,7 @@ md_undefined_symbol (char *name ATTRIBUTE_UNUSED) valueT md_section_align (segT segment ATTRIBUTE_UNUSED, valueT size) { -#ifndef OBJ_ELF - /* This is not right for ELF; a.out wants it, and COFF will force - the alignment anyways. */ - valueT align = ((valueT) 1 - << (valueT) bfd_get_section_alignment (stdoutput, segment)); - valueT newsize; - - /* Turn alignment value into a mask. */ - align--; - newsize = (size + align) & ~align; - return newsize; -#else return size; -#endif } /* Exactly what point is a PC-relative offset relative TO? @@ -3803,10 +4111,6 @@ mylog2 (int value) /* Sort of like s_lcomm. */ -#ifndef OBJ_ELF -static int max_alignment = 15; -#endif - static void s_reserve (int ignore ATTRIBUTE_UNUSED) { @@ -3818,11 +4122,10 @@ s_reserve (int ignore ATTRIBUTE_UNUSED) int temp; symbolS *symbolP; - name = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (&name); p = input_line_pointer; *p = c; - SKIP_WHITESPACE (); + SKIP_WHITESPACE_AFTER_NAME (); if (*input_line_pointer != ',') { @@ -3871,14 +4174,6 @@ s_reserve (int ignore ATTRIBUTE_UNUSED) align = (int) get_absolute_expression (); -#ifndef OBJ_ELF - if (align > max_alignment) - { - align = max_alignment; - as_warn (_("alignment too large; assuming %d"), align); - } -#endif - if (align < 0) { as_bad (_("negative alignment")); @@ -3904,12 +4199,7 @@ s_reserve (int ignore ATTRIBUTE_UNUSED) else align = 0; - if (!S_IS_DEFINED (symbolP) -#ifdef OBJ_AOUT - && S_GET_OTHER (symbolP) == 0 - && S_GET_DESC (symbolP) == 0 -#endif - ) + if (!S_IS_DEFINED (symbolP)) { if (! need_pass_2) { @@ -3937,9 +4227,7 @@ s_reserve (int ignore ATTRIBUTE_UNUSED) subseg_set (current_seg, current_subseg); -#ifdef OBJ_ELF S_SET_SIZE (symbolP, size); -#endif } } else @@ -3960,12 +4248,11 @@ s_common (int ignore ATTRIBUTE_UNUSED) offsetT temp, size; symbolS *symbolP; - name = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (&name); /* Just after name is now '\0'. */ p = input_line_pointer; *p = c; - SKIP_WHITESPACE (); + SKIP_WHITESPACE_AFTER_NAME (); if (*input_line_pointer != ',') { as_bad (_("Expected comma after symbol-name")); @@ -4001,13 +4288,6 @@ s_common (int ignore ATTRIBUTE_UNUSED) S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), (long) size); } } - else - { -#ifndef OBJ_ELF - S_SET_VALUE (symbolP, (valueT) size); - S_SET_EXTERNAL (symbolP); -#endif - } know (symbol_get_frag (symbolP) == &zero_address_frag); if (*input_line_pointer != ',') { @@ -4021,14 +4301,6 @@ s_common (int ignore ATTRIBUTE_UNUSED) { temp = get_absolute_expression (); -#ifndef OBJ_ELF - if (temp > max_alignment) - { - temp = max_alignment; - as_warn (_("alignment too large; assuming %ld"), (long) temp); - } -#endif - if (temp < 0) { as_bad (_("negative alignment")); @@ -4036,7 +4308,6 @@ s_common (int ignore ATTRIBUTE_UNUSED) return; } -#ifdef OBJ_ELF if (symbol_get_obj (symbolP)->local) { segT old_sec; @@ -4074,14 +4345,11 @@ s_common (int ignore ATTRIBUTE_UNUSED) subseg_set (old_sec, old_subsec); } else -#endif /* OBJ_ELF */ { allocate_common: S_SET_VALUE (symbolP, (valueT) size); -#ifdef OBJ_ELF S_SET_ALIGN (symbolP, temp); S_SET_SIZE (symbolP, size); -#endif S_SET_EXTERNAL (symbolP); S_SET_SEGMENT (symbolP, bfd_com_section_ptr); } @@ -4194,11 +4462,6 @@ s_proc (int ignore ATTRIBUTE_UNUSED) static int sparc_no_align_cons = 0; -/* This static variable is set by sparc_cons to emit requested types - of relocations in cons_fix_new_sparc. */ - -static const char *sparc_cons_special_reloc; - /* This handles the unaligned space allocation pseudo-ops, such as .uaword. .uaword is just like .word, but the value does not need to be aligned. */ @@ -4222,7 +4485,6 @@ s_ncons (int bytes ATTRIBUTE_UNUSED) cons (sparc_arch_size == 32 ? 4 : 8); } -#ifdef OBJ_ELF /* Handle the SPARC ELF .register pseudo-op. This sets the binding of a global register. The syntax is: @@ -4236,7 +4498,7 @@ s_register (int ignore ATTRIBUTE_UNUSED) char c; int reg; int flags; - const char *regname; + char *regname; if (input_line_pointer[0] != '%' || input_line_pointer[1] != 'g' @@ -4250,20 +4512,19 @@ s_register (int ignore ATTRIBUTE_UNUSED) if (*input_line_pointer == '#') { ++input_line_pointer; - regname = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (®name); if (strcmp (regname, "scratch") && strcmp (regname, "ignore")) as_bad (_("register syntax is .register %%g[2367],{#scratch|symbolname|#ignore}")); if (regname[0] == 'i') regname = NULL; else - regname = ""; + regname = (char *) ""; } else { - regname = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (®name); } + if (sparc_arch_size == 64) { if (globals[reg]) @@ -4310,7 +4571,7 @@ s_register (int ignore ATTRIBUTE_UNUSED) } } - *input_line_pointer = c; + (void) restore_line_pointer (c); demand_empty_rest_of_line (); } @@ -4336,7 +4597,6 @@ sparc_adjust_symtab (void) S_SET_SEGMENT (sym, undefined_section); } } -#endif /* If the --enforce-aligned-data option is used, we require .word, et. al., to be aligned correctly. We do it by setting up an @@ -4436,7 +4696,6 @@ sparc_handle_align (fragS *fragp) } } -#ifdef OBJ_ELF /* Some special processing for a Sparc ELF file. */ void @@ -4466,13 +4725,13 @@ sparc_elf_final_processing (void) elf_elfheader (stdoutput)->e_flags |= EF_SPARC_SUN_US1|EF_SPARC_SUN_US3; } -void +const char * sparc_cons (expressionS *exp, int size) { char *save; + const char *sparc_cons_special_reloc = NULL; SKIP_WHITESPACE (); - sparc_cons_special_reloc = NULL; save = input_line_pointer; if (input_line_pointer[0] == '%' && input_line_pointer[1] == 'r' @@ -4599,10 +4858,9 @@ sparc_cons (expressionS *exp, int size) } if (sparc_cons_special_reloc == NULL) expression (exp); + return sparc_cons_special_reloc; } -#endif - /* This is called by emit_expr via TC_CONS_FIX_NEW when creating a reloc for a cons. We could use the definition there, except that we want to handle little endian relocs specially. */ @@ -4611,7 +4869,8 @@ void cons_fix_new_sparc (fragS *frag, int where, unsigned int nbytes, - expressionS *exp) + expressionS *exp, + const char *sparc_cons_special_reloc) { bfd_reloc_code_real_type r; @@ -4624,6 +4883,15 @@ cons_fix_new_sparc (fragS *frag, && now_seg->flags & SEC_ALLOC) r = BFD_RELOC_SPARC_REV32; +#ifdef TE_SOLARIS + /* The Solaris linker does not allow R_SPARC_UA64 + relocations for 32-bit executables. */ + if (!target_little_endian_data + && sparc_arch_size != 64 + && r == BFD_RELOC_64) + r = BFD_RELOC_32; +#endif + if (sparc_cons_special_reloc) { if (*sparc_cons_special_reloc == 'd') @@ -4648,19 +4916,28 @@ cons_fix_new_sparc (fragS *frag, case 8: r = BFD_RELOC_SPARC_TLS_DTPOFF64; break; } } - else if (sparc_no_align_cons) + else if (sparc_no_align_cons + || /* PR 20803 - relocs in the .eh_frame section + need to support unaligned access. */ + strcmp (now_seg->name, ".eh_frame") == 0) { switch (nbytes) { case 2: r = BFD_RELOC_SPARC_UA16; break; case 4: r = BFD_RELOC_SPARC_UA32; break; +#ifdef TE_SOLARIS + /* The Solaris linker does not allow R_SPARC_UA64 + relocations for 32-bit executables. */ + case 8: r = sparc_arch_size == 64 ? + BFD_RELOC_SPARC_UA64 : BFD_RELOC_SPARC_UA32; break; +#else case 8: r = BFD_RELOC_SPARC_UA64; break; +#endif default: abort (); } } fix_new_exp (frag, where, (int) nbytes, exp, 0, r); - sparc_cons_special_reloc = NULL; } void @@ -4672,18 +4949,25 @@ sparc_cfi_frame_initial_instructions (void) int sparc_regname_to_dw2regnum (char *regname) { - char *p, *q; + char *q; + int i; if (!regname[0]) return -1; - q = "goli"; - p = strchr (q, regname[0]); - if (p) + switch (regname[0]) + { + case 'g': i = 0; break; + case 'o': i = 1; break; + case 'l': i = 2; break; + case 'i': i = 3; break; + default: i = -1; break; + } + if (i != -1) { if (regname[1] < '0' || regname[1] > '8' || regname[2]) return -1; - return (p - q) * 8 + regname[1] - '0'; + return i * 8 + regname[1] - '0'; } if (regname[0] == 's' && regname[1] == 'p' && !regname[2]) return 14; @@ -4694,7 +4978,7 @@ sparc_regname_to_dw2regnum (char *regname) unsigned int regnum; regnum = strtoul (regname + 1, &q, 10); - if (p == q || *q) + if (q == NULL || *q) return -1; if (regnum >= ((regname[0] == 'f' && SPARC_OPCODE_ARCH_V9_P (max_architecture)) @@ -4714,9 +4998,7 @@ sparc_regname_to_dw2regnum (char *regname) void sparc_cfi_emit_pcrel_expr (expressionS *exp, unsigned int nbytes) { - sparc_cons_special_reloc = "disp"; sparc_no_align_cons = 1; - emit_expr (exp, nbytes); + emit_expr_with_reloc (exp, nbytes, "disp"); sparc_no_align_cons = 0; - sparc_cons_special_reloc = NULL; }