X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-hppa.c;h=5f938c5df44c91a029a8af59757326094cdc76dc;hb=e7c1f43c29d3e1d681c2dbc7aacf33d78af2b929;hp=c0f532c36266cfad42e9f62612bdf36025046d2a;hpb=90700a534134b4c10d1a1991485b906f2cac7ea5;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-hppa.c b/gas/config/tc-hppa.c index c0f532c362..5f938c5df4 100644 --- a/gas/config/tc-hppa.c +++ b/gas/config/tc-hppa.c @@ -1,5 +1,6 @@ /* tc-hppa.c -- Assemble for the PA - Copyright (C) 1989, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc. + Copyright (C) 1989, 93, 94, 95, 96, 97, 98, 1999 + Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -34,32 +35,32 @@ /* Be careful, this file includes data *declarations*. */ #include "opcode/hppa.h" +#if defined (OBJ_ELF) && defined (OBJ_SOM) +error only one of OBJ_ELF and OBJ_SOM can be defined +#endif + /* A "convient" place to put object file dependencies which do not need to be seen outside of tc-hppa.c. */ #ifdef OBJ_ELF -/* Names of various debugging spaces/subspaces. */ -#define GDB_DEBUG_SPACE_NAME ".stab" -#define GDB_STRINGS_SUBSPACE_NAME ".stabstr" -#define GDB_SYMBOLS_SUBSPACE_NAME ".stab" -#define UNWIND_SECTION_NAME ".PARISC.unwind" -/* Nonzero if CODE is a fixup code needing further processing. */ - /* Object file formats specify relocation types. */ -typedef elf32_hppa_reloc_type reloc_type; +typedef elf_hppa_reloc_type reloc_type; /* Object file formats specify BFD symbol types. */ typedef elf_symbol_type obj_symbol_type; +#ifdef BFD64 /* How to generate a relocation. */ -#define hppa_gen_reloc_type hppa_elf_gen_reloc_type +#define hppa_gen_reloc_type _bfd_elf64_hppa_gen_reloc_type +#else +#define hppa_gen_reloc_type _bfd_elf32_hppa_gen_reloc_type +#endif /* ELF objects can have versions, but apparently do not have anywhere to store a copyright string. */ #define obj_version obj_elf_version #define obj_copyright obj_elf_version -/* Use space aliases. */ -#define USE_ALIASES 1 +#define UNWIND_SECTION_NAME ".PARISC.unwind" #endif #ifdef OBJ_SOM @@ -76,9 +77,6 @@ typedef int reloc_type; #define obj_version obj_som_version #define obj_copyright obj_som_copyright -/* Do not use space aliases. */ -#define USE_ALIASES 0 - /* How to generate a relocation. */ #define hppa_gen_reloc_type hppa_som_gen_reloc_type @@ -267,6 +265,7 @@ struct call_desc unsigned int arg_count; }; +#ifdef OBJ_SOM /* This structure defines an entry in the subspace dictionary chain. */ @@ -321,17 +320,6 @@ struct space_dictionary_chain typedef struct space_dictionary_chain sd_chain_struct; -/* Structure for previous label tracking. Needed so that alignments, - callinfo declarations, etc can be easily attached to a particular - label. */ -typedef struct label_symbol_struct - { - struct symbol *lss_label; - sd_chain_struct *lss_space; - struct label_symbol_struct *lss_next; - } -label_symbol_struct; - /* This structure defines attributes of the default subspace dictionary entries. */ @@ -378,9 +366,6 @@ struct default_subspace_dict /* An index into the default spaces array. */ int def_space_index; - /* An alias for this section (or NULL if no alias exists). */ - char *alias; - /* Subsegment associated with this subspace. */ subsegT subsegment; }; @@ -411,10 +396,24 @@ struct default_space_dict /* Segment associated with this space. */ asection *segment; - - /* An alias for this section (or NULL if no alias exists). */ - char *alias; }; +#endif + +/* Structure for previous label tracking. Needed so that alignments, + callinfo declarations, etc can be easily attached to a particular + label. */ +typedef struct label_symbol_struct + { + struct symbol *lss_label; +#ifdef OBJ_SOM + sd_chain_struct *lss_space; +#endif +#ifdef OBJ_ELF + segT lss_segment; +#endif + struct label_symbol_struct *lss_next; + } +label_symbol_struct; /* Extra information needed to perform fixups (relocations) on the PA. */ struct hppa_fix_struct @@ -461,7 +460,10 @@ struct selector_entry /* Prototypes for functions local to tc-hppa.c. */ +#ifdef OBJ_SOM static void pa_check_current_space_and_subspace PARAMS ((void)); +#endif + static fp_operand_format pa_parse_fp_format PARAMS ((char **s)); static void pa_cons PARAMS ((int)); static void pa_data PARAMS ((int)); @@ -483,7 +485,6 @@ static int pa_parse_nonneg_cmpsub_cmpltr PARAMS ((char **, int)); static int pa_parse_neg_cmpsub_cmpltr PARAMS ((char **, int)); static int pa_parse_neg_add_cmpltr PARAMS ((char **, int)); static int pa_parse_nonneg_add_cmpltr PARAMS ((char **, int)); -static void pa_align PARAMS ((int)); static void pa_block PARAMS ((int)); static void pa_brtab PARAMS ((int)); static void pa_try PARAMS ((int)); @@ -492,9 +493,6 @@ static void pa_call_args PARAMS ((struct call_desc *)); static void pa_callinfo PARAMS ((int)); static void pa_code PARAMS ((int)); static void pa_comm PARAMS ((int)); -#ifdef OBJ_SOM -static void pa_compiler PARAMS ((int)); -#endif static void pa_copyright PARAMS ((int)); static void pa_end PARAMS ((int)); static void pa_enter PARAMS ((int)); @@ -510,15 +508,18 @@ static void pa_level PARAMS ((int)); static void pa_origin PARAMS ((int)); static void pa_proc PARAMS ((int)); static void pa_procend PARAMS ((int)); -static void pa_space PARAMS ((int)); -static void pa_spnum PARAMS ((int)); -static void pa_subspace PARAMS ((int)); static void pa_param PARAMS ((int)); static void pa_undefine_label PARAMS ((void)); static int need_pa11_opcode PARAMS ((struct pa_it *, struct pa_11_fp_reg_struct *)); static int pa_parse_number PARAMS ((char **, struct pa_11_fp_reg_struct *)); static label_symbol_struct *pa_get_label PARAMS ((void)); +#ifdef OBJ_SOM +static void pa_compiler PARAMS ((int)); +static void pa_align PARAMS ((int)); +static void pa_space PARAMS ((int)); +static void pa_spnum PARAMS ((int)); +static void pa_subspace PARAMS ((int)); static sd_chain_struct *create_new_space PARAMS ((char *, int, int, int, int, int, asection *, int)); @@ -539,6 +540,10 @@ static ssd_chain_struct *pa_subsegment_to_subspace PARAMS ((asection *, subsegT)); static sd_chain_struct *pa_find_space_by_number PARAMS ((int)); static unsigned int pa_subspace_start PARAMS ((sd_chain_struct *, int)); +static sd_chain_struct *pa_parse_space_stmt PARAMS ((char *, int)); +static int pa_next_subseg PARAMS ((sd_chain_struct *)); +static void pa_spaces_begin PARAMS ((void)); +#endif static void pa_ip PARAMS ((char *)); static void fix_new_hppa PARAMS ((fragS *, int, int, symbolS *, long, expressionS *, int, @@ -550,11 +555,8 @@ static int reg_name_search PARAMS ((char *)); static int pa_chk_field_selector PARAMS ((char **)); static int is_same_frag PARAMS ((fragS *, fragS *)); static void process_exit PARAMS ((void)); -static sd_chain_struct *pa_parse_space_stmt PARAMS ((char *, int)); static int log2 PARAMS ((int)); -static int pa_next_subseg PARAMS ((sd_chain_struct *)); static unsigned int pa_stringer_aux PARAMS ((char *)); -static void pa_spaces_begin PARAMS ((void)); #ifdef OBJ_ELF static void hppa_elf_mark_end_of_function PARAMS ((void)); @@ -563,6 +565,7 @@ static void pa_build_unwind_subspace PARAMS ((struct call_info *)); /* File and gloally scoped variable declarations. */ +#ifdef OBJ_SOM /* Root and final entry in the space chain. */ static sd_chain_struct *space_dict_root; static sd_chain_struct *space_dict_last; @@ -570,6 +573,7 @@ static sd_chain_struct *space_dict_last; /* The current space and subspace. */ static sd_chain_struct *current_space; static ssd_chain_struct *current_subspace; +#endif /* Root of the call_info chain. */ static struct call_info *call_info_root; @@ -596,7 +600,12 @@ const pseudo_typeS md_pseudo_table[] = { /* align pseudo-ops on the PA specify the actual alignment requested, not the log2 of the requested alignment. */ +#ifdef OBJ_SOM {"align", pa_align, 8}, +#endif +#ifdef OBJ_ELF + {"align", s_align_bytes, 8}, +#endif {"begin_brtab", pa_brtab, 1}, {"begin_try", pa_try, 1}, {"block", pa_block, 1}, @@ -612,6 +621,7 @@ const pseudo_typeS md_pseudo_table[] = {"copyright", pa_copyright, 0}, {"data", pa_data, 0}, {"double", pa_float_cons, 'd'}, + {"dword", pa_cons, 8}, {"end", pa_end, 0}, {"end_brtab", pa_brtab, 0}, {"end_try", pa_try, 0}, @@ -631,7 +641,9 @@ const pseudo_typeS md_pseudo_table[] = {"level", pa_level, 0}, {"long", pa_cons, 4}, {"lsym", pa_lsym, 0}, +#ifdef OBJ_SOM {"nsubspa", pa_subspace, 1}, +#endif {"octa", pa_cons, 16}, {"org", pa_origin, 0}, {"origin", pa_origin, 0}, @@ -642,11 +654,15 @@ const pseudo_typeS md_pseudo_table[] = {"reg", pa_equ, 1}, {"short", pa_cons, 2}, {"single", pa_float_cons, 'f'}, +#ifdef OBJ_SOM {"space", pa_space, 0}, {"spnum", pa_spnum, 0}, +#endif {"string", pa_stringer, 0}, {"stringz", pa_stringer, 1}, +#ifdef OBJ_SOM {"subspa", pa_subspace, 0}, +#endif {"text", pa_text, 0}, {"version", pa_version, 0}, {"word", pa_cons, 4}, @@ -701,9 +717,16 @@ static label_symbol_struct *label_symbols_rootp = NULL; /* Holds the last field selector. */ static int hppa_field_selector; +/* Nonzero when strict syntax checking is enabled. Zero otherwise. + + Each opcode in the table has a flag which indicates whether or not + strict syntax checking should be enabled for that instruction. */ +static int strict = 0; +#ifdef OBJ_SOM /* A dummy bfd symbol so that all relocations have symbols of some kind. */ static symbolS *dummy_symbol; +#endif /* Nonzero if errors are to be printed. */ static int print_errors = 1; @@ -982,6 +1005,7 @@ static const struct selector_entry selector_table[] = {"lr", e_lrsel}, {"ls", e_lssel}, {"lt", e_ltsel}, + {"ltp", e_ltpsel}, {"n", e_nsel}, {"nl", e_nlsel}, {"nlr", e_nlrsel}, @@ -992,9 +1016,11 @@ static const struct selector_entry selector_table[] = {"rr", e_rrsel}, {"rs", e_rssel}, {"rt", e_rtsel}, + {"rtp", e_rtpsel}, {"t", e_tsel}, }; +#ifdef OBJ_SOM /* default space and subspace dictionaries */ #define GDB_SYMBOLS GDB_SYMBOLS_SUBSPACE_NAME @@ -1012,31 +1038,23 @@ static const struct selector_entry selector_table[] = static struct default_subspace_dict pa_def_subspaces[] = { - {"$CODE$", 1, 1, 1, 0, 0, 0, 24, 0x2c, 0, 8, 0, 0, ".text", SUBSEG_CODE}, - {"$DATA$", 1, 1, 0, 0, 0, 0, 24, 0x1f, 1, 8, 1, 1, ".data", SUBSEG_DATA}, - {"$LIT$", 1, 1, 0, 0, 0, 0, 16, 0x2c, 0, 8, 0, 0, ".text", SUBSEG_LIT}, - {"$MILLICODE$", 1, 1, 0, 0, 0, 0, 8, 0x2c, 0, 8, 0, 0, ".text", SUBSEG_MILLI}, - {"$BSS$", 1, 1, 0, 0, 0, 1, 80, 0x1f, 1, 8, 1, 1, ".bss", SUBSEG_BSS}, -#ifdef OBJ_ELF - {"$UNWIND$", 1, 1, 0, 0, 0, 0, 64, 0x2c, 0, 4, 0, 0, ".PARISC.unwind", SUBSEG_UNWIND}, -#endif + {"$CODE$", 1, 1, 1, 0, 0, 0, 24, 0x2c, 0, 8, 0, 0, SUBSEG_CODE}, + {"$DATA$", 1, 1, 0, 0, 0, 0, 24, 0x1f, 1, 8, 1, 1, SUBSEG_DATA}, + {"$LIT$", 1, 1, 0, 0, 0, 0, 16, 0x2c, 0, 8, 0, 0, SUBSEG_LIT}, + {"$MILLICODE$", 1, 1, 0, 0, 0, 0, 8, 0x2c, 0, 8, 0, 0, SUBSEG_MILLI}, + {"$BSS$", 1, 1, 0, 0, 0, 1, 80, 0x1f, 1, 8, 1, 1, SUBSEG_BSS}, {NULL, 0, 1, 0, 0, 0, 0, 255, 0x1f, 0, 4, 0, 0, 0} }; static struct default_space_dict pa_def_spaces[] = { - {"$TEXT$", 0, 1, 1, 0, 8, ASEC_NULL, ".text"}, - {"$PRIVATE$", 1, 1, 1, 1, 16, ASEC_NULL, ".data"}, - {NULL, 0, 0, 0, 0, 0, ASEC_NULL, NULL} + {"$TEXT$", 0, 1, 1, 0, 8, ASEC_NULL}, + {"$PRIVATE$", 1, 1, 1, 1, 16, ASEC_NULL}, + {NULL, 0, 0, 0, 0, 0, ASEC_NULL} }; /* Misc local definitions used by the assembler. */ -/* Return nonzero if the string pointed to by S potentially represents - a right or left half of a FP register */ -#define IS_R_SELECT(S) (*(S) == 'R' || *(S) == 'r') -#define IS_L_SELECT(S) (*(S) == 'L' || *(S) == 'l') - /* These macros are used to maintain spaces/subspaces. */ #define SPACE_DEFINED(space_chain) (space_chain)->sd_defined #define SPACE_USER_DEFINED(space_chain) (space_chain)->sd_user_defined @@ -1045,6 +1063,12 @@ static struct default_space_dict pa_def_spaces[] = #define SUBSPACE_DEFINED(ss_chain) (ss_chain)->ssd_defined #define SUBSPACE_NAME(ss_chain) (ss_chain)->ssd_name +#endif + +/* Return nonzero if the string pointed to by S potentially represents + a right or left half of a FP register */ +#define IS_R_SELECT(S) (*(S) == 'R' || *(S) == 'r') +#define IS_L_SELECT(S) (*(S) == 'L' || *(S) == 'l') /* Insert FIELD into OPCODE starting at bit START. Continue pa_ip main loop after insertion. */ @@ -1071,11 +1095,11 @@ static struct default_space_dict pa_def_spaces[] = #define is_DP_relative(exp) \ ((exp).X_op == O_subtract \ - && strcmp((exp).X_op_symbol->bsym->name, "$global$") == 0) + && strcmp (S_GET_NAME ((exp).X_op_symbol), "$global$") == 0) #define is_PC_relative(exp) \ ((exp).X_op == O_subtract \ - && strcmp((exp).X_op_symbol->bsym->name, "$PIC_pcrel$0") == 0) + && strcmp (S_GET_NAME ((exp).X_op_symbol), "$PIC_pcrel$0") == 0) /* We need some complex handling for stabs (sym1 - sym2). Luckily, we'll always be able to reduce the expression to a constant, so we don't @@ -1098,18 +1122,6 @@ pa_check_eof () as_fatal (_("Missing .procend\n")); } -/* Check to make sure we have a valid space and subspace. */ - -static void -pa_check_current_space_and_subspace () -{ - if (current_space == NULL) - as_fatal (_("Not in a space.\n")); - - if (current_subspace == NULL) - as_fatal (_("Not in a subspace.\n")); -} - /* Returns a pointer to the label_symbol_struct for the current space. or NULL if no label_symbol_struct exists for the current space. */ @@ -1117,13 +1129,20 @@ static label_symbol_struct * pa_get_label () { label_symbol_struct *label_chain; - sd_chain_struct *space_chain = current_space; for (label_chain = label_symbols_rootp; label_chain; label_chain = label_chain->lss_next) - if (space_chain == label_chain->lss_space && label_chain->lss_label) + { +#ifdef OBJ_SOM + if (current_space == label_chain->lss_space && label_chain->lss_label) return label_chain; +#endif +#ifdef OBJ_ELF + if (now_seg == label_chain->lss_segment && label_chain->lss_label) + return label_chain; +#endif + } return NULL; } @@ -1136,7 +1155,6 @@ pa_define_label (symbol) symbolS *symbol; { label_symbol_struct *label_chain = pa_get_label (); - sd_chain_struct *space_chain = current_space; if (label_chain) label_chain->lss_label = symbol; @@ -1146,7 +1164,12 @@ pa_define_label (symbol) label_chain = (label_symbol_struct *) xmalloc (sizeof (label_symbol_struct)); label_chain->lss_label = symbol; - label_chain->lss_space = space_chain; +#ifdef OBJ_SOM + label_chain->lss_space = current_space; +#endif +#ifdef OBJ_ELF + label_chain->lss_segment = now_seg; +#endif label_chain->lss_next = NULL; if (label_symbols_rootp) @@ -1164,13 +1187,19 @@ pa_undefine_label () { label_symbol_struct *label_chain; label_symbol_struct *prev_label_chain = NULL; - sd_chain_struct *space_chain = current_space; for (label_chain = label_symbols_rootp; label_chain; label_chain = label_chain->lss_next) { - if (space_chain == label_chain->lss_space && label_chain->lss_label) + if (1 +#ifdef OBJ_SOM + && current_space == label_chain->lss_space && label_chain->lss_label +#endif +#ifdef OBJ_ELF + && now_seg == label_chain->lss_segment && label_chain->lss_label +#endif + ) { /* Remove the label from the chain and free its memory. */ if (prev_label_chain) @@ -1273,7 +1302,7 @@ cons_fix_new_hppa (frag, where, size, exp) fix_new_hppa (frag, where, size, (symbolS *) NULL, (offsetT) 0, exp, 0, rel_type, - hppa_field_selector, 32, 0, NULL); + hppa_field_selector, size * 8, 0, NULL); /* Reset field selector to its default state. */ hppa_field_selector = 0; @@ -1304,7 +1333,9 @@ md_begin () flag_readonly_data_in_text = 0; } +#ifdef OBJ_SOM pa_spaces_begin (); +#endif op_hash = hash_new (); @@ -1334,12 +1365,18 @@ md_begin () if (lose) as_fatal (_("Broken assembler. No assembly attempted.")); +#ifdef OBJ_SOM /* SOM will change text_section. To make sure we never put anything into the old one switch to the new one now. */ subseg_set (text_section, 0); +#endif +#ifdef OBJ_SOM dummy_symbol = symbol_find_or_make ("L$dummy"); S_SET_SEGMENT (dummy_symbol, text_section); + /* Force the symbol to be converted to a real symbol. */ + (void) symbol_get_bfdsym (dummy_symbol); +#endif } /* Assemble a single instruction storing it into a frag. */ @@ -1368,7 +1405,8 @@ md_assemble (str) if (label_symbol->lss_label) { last_call_info->start_symbol = label_symbol->lss_label; - label_symbol->lss_label->bsym->flags |= BSF_FUNCTION; + symbol_get_bfdsym (label_symbol->lss_label)->flags + |= BSF_FUNCTION; #ifdef OBJ_SOM /* Also handle allocation of a fixup to hold the unwind information when the label appears after the proc/procend. */ @@ -1423,8 +1461,16 @@ pa_ip (str) unsigned long opcode; struct pa_opcode *insn; +#ifdef OBJ_SOM /* We must have a valid space and subspace. */ pa_check_current_space_and_subspace (); +#endif + + /* Convert everything up to the first whitespace character into lower + case. */ + for (s = str; *s != ' ' && *s != '\t' && *s != '\n' && *s != '\0'; s++) + if (isupper (*s)) + *s = tolower (*s); /* Skip to something interesting. */ for (s = str; isupper (*s) || islower (*s) || (*s >= '0' && *s <= '3'); ++s) @@ -1451,14 +1497,6 @@ pa_ip (str) save_s = str; - /* Convert everything into lower case. */ - while (*save_s) - { - if (isupper (*save_s)) - *save_s = tolower (*save_s); - save_s++; - } - /* Look up the opcode in the has table. */ if ((insn = (struct pa_opcode *) hash_find (op_hash, str)) == NULL) { @@ -1478,6 +1516,7 @@ pa_ip (str) { /* Do some initialization. */ opcode = insn->match; + strict = (insn->flags & FLAG_STRICT); memset (&the_insn, 0, sizeof (the_insn)); the_insn.reloc = R_HPPA_NONE; @@ -1502,6 +1541,10 @@ pa_ip (str) sure that the operands match. */ for (args = insn->args;; ++args) { + /* Absorb white space in instruction. */ + while (*s == ' ' || *s == '\t') + s++; + switch (*args) { @@ -1533,26 +1576,65 @@ pa_ip (str) /* Handle a 5 bit register or control register field at 10. */ case 'b': case '^': + /* This should be more strict. Small steps. */ + if (strict && *s != '%') + break; num = pa_parse_number (&s, 0); CHECK_FIELD (num, 31, 0, 0); INSERT_FIELD_AND_CONTINUE (opcode, num, 21); + /* Handle %sar or %cr11. No bits get set, we just verify that it + is there. */ + case '!': + /* Skip whitespace before register. */ + while (*s == ' ' || *s == '\t') + s = s + 1; + + if (!strncasecmp(s, "%sar", 4)) + { + s += 4; + continue; + } + else if (!strncasecmp(s, "%cr11", 5)) + { + s += 5; + continue; + } + break; + /* Handle a 5 bit register field at 15. */ case 'x': + /* This should be more strict. Small steps. */ + if (strict && *s != '%') + break; num = pa_parse_number (&s, 0); CHECK_FIELD (num, 31, 0, 0); INSERT_FIELD_AND_CONTINUE (opcode, num, 16); /* Handle a 5 bit register field at 31. */ - case 'y': case 't': + /* This should be more strict. Small steps. */ + if (strict && *s != '%') + break; num = pa_parse_number (&s, 0); CHECK_FIELD (num, 31, 0, 0); INSERT_FIELD_AND_CONTINUE (opcode, num, 0); + /* Handle a 5 bit register field at 10 and 15. */ + case 'a': + /* This should be more strict. Small steps. */ + if (strict && *s != '%') + break; + num = pa_parse_number (&s, 0); + CHECK_FIELD (num, 31, 0, 0); + opcode |= num << 16; + INSERT_FIELD_AND_CONTINUE (opcode, num, 21); + /* Handle a 5 bit field length at 31. */ case 'T': num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; s = expr_end; CHECK_FIELD (num, 32, 1, 0); INSERT_FIELD_AND_CONTINUE (opcode, 32 - num, 0); @@ -1560,546 +1642,1004 @@ pa_ip (str) /* Handle a 5 bit immediate at 15. */ case '5': num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; s = expr_end; - CHECK_FIELD (num, 15, -16, 0); + /* When in strict mode, we want to just reject this + match instead of giving an out of range error. */ + CHECK_FIELD (num, 15, -16, strict); low_sign_unext (num, 5, &num); INSERT_FIELD_AND_CONTINUE (opcode, num, 16); /* Handle a 5 bit immediate at 31. */ case 'V': num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; s = expr_end; - CHECK_FIELD (num, 15, -16, 0) + /* When in strict mode, we want to just reject this + match instead of giving an out of range error. */ + CHECK_FIELD (num, 15, -16, strict) low_sign_unext (num, 5, &num); INSERT_FIELD_AND_CONTINUE (opcode, num, 0); /* Handle an unsigned 5 bit immediate at 31. */ case 'r': num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; s = expr_end; CHECK_FIELD (num, 31, 0, 0); - INSERT_FIELD_AND_CONTINUE (opcode, num, 0); + INSERT_FIELD_AND_CONTINUE (opcode, num, strict); /* Handle an unsigned 5 bit immediate at 15. */ case 'R': num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; s = expr_end; - CHECK_FIELD (num, 31, 0, 0); + CHECK_FIELD (num, 31, 0, strict); + INSERT_FIELD_AND_CONTINUE (opcode, num, 16); + + /* Handle an unsigned 10 bit immediate at 15. */ + case 'U': + num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; + s = expr_end; + CHECK_FIELD (num, 1023, 0, strict); INSERT_FIELD_AND_CONTINUE (opcode, num, 16); /* Handle a 2 bit space identifier at 17. */ case 's': + /* This should be more strict. Small steps. */ + if (strict && *s != '%') + break; num = pa_parse_number (&s, 0); CHECK_FIELD (num, 3, 0, 1); INSERT_FIELD_AND_CONTINUE (opcode, num, 14); /* Handle a 3 bit space identifier at 18. */ case 'S': + /* This should be more strict. Small steps. */ + if (strict && *s != '%') + break; num = pa_parse_number (&s, 0); CHECK_FIELD (num, 7, 0, 1); dis_assemble_3 (num, &num); INSERT_FIELD_AND_CONTINUE (opcode, num, 13); - /* Handle a completer for an indexing load or store. */ + /* Handle all completers. */ case 'c': - { - int uu = 0; - int m = 0; - int i = 0; - while (*s == ',' && i < 2) + switch (*++args) + { + + /* Handle a completer for an indexing load or store. */ + case 'x': { - s++; - if (strncasecmp (s, "sm", 2) == 0) + int uu = 0; + int m = 0; + int i = 0; + while (*s == ',' && i < 2) { - uu = 1; - m = 1; + s++; + if (strncasecmp (s, "sm", 2) == 0) + { + uu = 1; + m = 1; + s++; + i++; + } + else if (strncasecmp (s, "m", 1) == 0) + m = 1; + else if (strncasecmp (s, "s", 1) == 0) + uu = 1; + /* When in strict mode this is a match failure. */ + else if (strict) + break; + else + as_bad (_("Invalid Indexed Load Completer.")); s++; i++; } - else if (strncasecmp (s, "m", 1) == 0) - m = 1; - else if (strncasecmp (s, "s", 1) == 0) - uu = 1; - else - as_bad (_("Invalid Indexed Load Completer.")); - s++; - i++; + if (i > 2) + as_bad (_("Invalid Indexed Load Completer Syntax.")); + opcode |= m << 5; + INSERT_FIELD_AND_CONTINUE (opcode, uu, 13); } - if (i > 2) - as_bad (_("Invalid Indexed Load Completer Syntax.")); - opcode |= m << 5; - INSERT_FIELD_AND_CONTINUE (opcode, uu, 13); - } - /* Handle a short load/store completer. */ - case 'C': - { - int a = 0; - int m = 0; - if (*s == ',') + /* Handle a short load/store completer. */ + case 'm': { - s++; - if (strncasecmp (s, "ma", 2) == 0) + int a = 0; + int m = 0; + if (*s == ',') { - a = 0; - m = 1; - } - else if (strncasecmp (s, "mb", 2) == 0) - { - a = 1; - m = 1; + s++; + if (strncasecmp (s, "ma", 2) == 0) + { + a = 0; + m = 1; + } + else if (strncasecmp (s, "mb", 2) == 0) + { + a = 1; + m = 1; + } + /* When in strict mode this is a match failure. */ + else if (strict) + break; + else + as_bad (_("Invalid Short Load/Store Completer.")); + s += 2; } - else - as_bad (_("Invalid Short Load/Store Completer.")); - s += 2; - } - if (*args == 'C') - { opcode |= m << 5; INSERT_FIELD_AND_CONTINUE (opcode, a, 13); } - } - /* Handle a stbys completer. */ - case 'Y': - { - int a = 0; - int m = 0; - int i = 0; - while (*s == ',' && i < 2) + /* Handle a stbys completer. */ + case 's': { - s++; - if (strncasecmp (s, "m", 1) == 0) - m = 1; - else if (strncasecmp (s, "b", 1) == 0) - a = 0; - else if (strncasecmp (s, "e", 1) == 0) - a = 1; - else + int a = 0; + int m = 0; + int i = 0; + while (*s == ',' && i < 2) + { + s++; + if (strncasecmp (s, "m", 1) == 0) + m = 1; + else if (strncasecmp (s, "b", 1) == 0) + a = 0; + else if (strncasecmp (s, "e", 1) == 0) + a = 1; + /* When in strict mode this is a match failure. */ + else if (strict) + break; + else + as_bad (_("Invalid Store Bytes Short Completer")); + s++; + i++; + } + if (i > 2) as_bad (_("Invalid Store Bytes Short Completer")); - s++; - i++; + opcode |= m << 5; + INSERT_FIELD_AND_CONTINUE (opcode, a, 13); } - if (i > 2) - as_bad (_("Invalid Store Bytes Short Completer")); - opcode |= m << 5; - INSERT_FIELD_AND_CONTINUE (opcode, a, 13); - } - /* Handle a non-negated compare/stubtract condition. */ - case '<': - cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s, 1); - if (cmpltr < 0) - { - as_bad (_("Invalid Compare/Subtract Condition: %c"), *s); - cmpltr = 0; - } - INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13); + /* Handle a local processor completer. */ + case 'L': + if (strncasecmp (s, ",l", 2) != 0) + break; + s += 2; + continue; - /* Handle a negated or non-negated compare/subtract condition. */ - case '?': - save_s = s; - cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s, 1); - if (cmpltr < 0) - { - s = save_s; - cmpltr = pa_parse_neg_cmpsub_cmpltr (&s, 1); - if (cmpltr < 0) + /* Handle a PROBE read/write completer. */ + case 'w': + flag = 0; + if (!strncasecmp (s, ",w", 2)) { - as_bad (_("Invalid Compare/Subtract Condition.")); - cmpltr = 0; + flag = 1; + s += 2; } - else + else if (!strncasecmp (s, ",r", 2)) { - /* Negated condition requires an opcode change. */ - opcode |= 1 << 27; + flag = 0; + s += 2; } - } - - INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13); - /* Handle non-negated add condition. */ - case '!': - cmpltr = pa_parse_nonneg_add_cmpltr (&s, 1); - if (cmpltr < 0) - { - as_bad (_("Invalid Compare/Subtract Condition: %c"), *s); - cmpltr = 0; - } - INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13); + INSERT_FIELD_AND_CONTINUE (opcode, flag, 6); - /* Handle a negated or non-negated add condition. */ - case '@': - save_s = s; - cmpltr = pa_parse_nonneg_add_cmpltr (&s, 1); - if (cmpltr < 0) - { - s = save_s; - cmpltr = pa_parse_neg_add_cmpltr (&s, 1); - if (cmpltr < 0) - { - as_bad (_("Invalid Compare/Subtract Condition")); - cmpltr = 0; - } - else - { - /* Negated condition requires an opcode change. */ - opcode |= 1 << 27; - } - } - INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13); + /* Handle MFCTL wide completer. */ + case 'W': + if (strncasecmp (s, ",w", 2) != 0) + break; + s += 2; + continue; - /* Handle a compare/subtract condition. */ - case 'a': - cmpltr = 0; - flag = 0; - if (*s == ',') - { - s++; - name = s; - while (*s != ',' && *s != ' ' && *s != '\t') - s += 1; - c = *s; - *s = 0x00; - if (strcmp (name, "=") == 0) - cmpltr = 1; - else if (strcmp (name, "<") == 0) - cmpltr = 2; - else if (strcmp (name, "<=") == 0) - cmpltr = 3; - else if (strcasecmp (name, "<<") == 0) - cmpltr = 4; - else if (strcasecmp (name, "<<=") == 0) - cmpltr = 5; - else if (strcasecmp (name, "sv") == 0) - cmpltr = 6; - else if (strcasecmp (name, "od") == 0) - cmpltr = 7; - else if (strcasecmp (name, "tr") == 0) - { - cmpltr = 0; - flag = 1; - } - else if (strcmp (name, "<>") == 0) - { - cmpltr = 1; - flag = 1; - } - else if (strcmp (name, ">=") == 0) - { - cmpltr = 2; - flag = 1; - } - else if (strcmp (name, ">") == 0) - { - cmpltr = 3; - flag = 1; - } - else if (strcasecmp (name, ">>=") == 0) - { - cmpltr = 4; - flag = 1; - } - else if (strcasecmp (name, ">>") == 0) + /* Handle an RFI restore completer. */ + case 'r': + flag = 0; + if (!strncasecmp (s, ",r", 2)) { - cmpltr = 5; - flag = 1; - } - else if (strcasecmp (name, "nsv") == 0) - { - cmpltr = 6; - flag = 1; + flag = 5; + s += 2; } - else if (strcasecmp (name, "ev") == 0) + + INSERT_FIELD_AND_CONTINUE (opcode, flag, 5); + + /* Handle a system control completer. */ + case 'Z': + if (*s == ',' && (*(s + 1) == 'm' || *(s + 1) == 'M')) { - cmpltr = 7; flag = 1; + s += 2; } else - as_bad (_("Invalid Add Condition: %s"), name); - *s = c; - } - opcode |= cmpltr << 13; - INSERT_FIELD_AND_CONTINUE (opcode, flag, 12); + flag = 0; - /* Handle a non-negated add condition. */ - case 'd': - cmpltr = 0; - flag = 0; - if (*s == ',') - { - s++; - name = s; - while (*s != ',' && *s != ' ' && *s != '\t') - s += 1; - c = *s; - *s = 0x00; - if (strcmp (name, "=") == 0) - cmpltr = 1; - else if (strcmp (name, "<") == 0) - cmpltr = 2; - else if (strcmp (name, "<=") == 0) - cmpltr = 3; - else if (strcasecmp (name, "nuv") == 0) - cmpltr = 4; - else if (strcasecmp (name, "znv") == 0) - cmpltr = 5; - else if (strcasecmp (name, "sv") == 0) - cmpltr = 6; - else if (strcasecmp (name, "od") == 0) - cmpltr = 7; - else if (strcasecmp (name, "tr") == 0) - { - cmpltr = 0; - flag = 1; - } - else if (strcmp (name, "<>") == 0) - { - cmpltr = 1; - flag = 1; - } - else if (strcmp (name, ">=") == 0) + INSERT_FIELD_AND_CONTINUE (opcode, flag, 5); + + /* Handle intermediate/final completer for DCOR. */ + case 'i': + flag = 0; + if (!strncasecmp (s, ",i", 2)) { - cmpltr = 2; flag = 1; + s += 2; } - else if (strcmp (name, ">") == 0) + + INSERT_FIELD_AND_CONTINUE (opcode, flag, 6); + + /* Handle zero/sign extension completer. */ + case 'z': + flag = 1; + if (!strncasecmp (s, ",z", 2)) { - cmpltr = 3; - flag = 1; + flag = 0; + s += 2; } - else if (strcasecmp (name, "uv") == 0) + + INSERT_FIELD_AND_CONTINUE (opcode, flag, 10); + + /* Handle add completer. */ + case 'a': + flag = 1; + if (!strncasecmp (s, ",l", 2)) { - cmpltr = 4; - flag = 1; + flag = 2; + s += 2; } - else if (strcasecmp (name, "vnz") == 0) + else if (!strncasecmp (s, ",tsv", 4)) { - cmpltr = 5; - flag = 1; + flag = 3; + s += 4; } - else if (strcasecmp (name, "nsv") == 0) + + INSERT_FIELD_AND_CONTINUE (opcode, flag, 10); + + /* Handle 64 bit carry for ADD. */ + case 'Y': + flag = 0; + if (!strncasecmp (s, ",dc,tsv", 7) || + !strncasecmp (s, ",tsv,dc", 7)) { - cmpltr = 6; flag = 1; + s += 7; } - else if (strcasecmp (name, "ev") == 0) + else if (!strncasecmp (s, ",dc", 3)) { - cmpltr = 7; - flag = 1; + flag = 0; + s += 3; } else - as_bad (_("Invalid Add Condition: %s"), name); - *s = c; - } - opcode |= cmpltr << 13; - INSERT_FIELD_AND_CONTINUE (opcode, flag, 12); + break; - /* HANDLE a logical instruction condition. */ - case '&': - cmpltr = 0; - flag = 0; - if (*s == ',') - { - s++; - name = s; - while (*s != ',' && *s != ' ' && *s != '\t') - s += 1; - c = *s; - *s = 0x00; - - - if (strcmp (name, "=") == 0) - cmpltr = 1; - else if (strcmp (name, "<") == 0) - cmpltr = 2; - else if (strcmp (name, "<=") == 0) - cmpltr = 3; - else if (strcasecmp (name, "od") == 0) - cmpltr = 7; - else if (strcasecmp (name, "tr") == 0) + INSERT_FIELD_AND_CONTINUE (opcode, flag, 11); + + /* Handle 32 bit carry for ADD. */ + case 'y': + flag = 0; + if (!strncasecmp (s, ",c,tsv", 6) || + !strncasecmp (s, ",tsv,c", 6)) { - cmpltr = 0; flag = 1; + s += 6; } - else if (strcmp (name, "<>") == 0) + else if (!strncasecmp (s, ",c", 2)) { - cmpltr = 1; - flag = 1; + flag = 0; + s += 2; } - else if (strcmp (name, ">=") == 0) + else + break; + + INSERT_FIELD_AND_CONTINUE (opcode, flag, 11); + + /* Handle trap on signed overflow. */ + case 'v': + flag = 0; + if (!strncasecmp (s, ",tsv", 4)) { - cmpltr = 2; flag = 1; + s += 4; } - else if (strcmp (name, ">") == 0) + + INSERT_FIELD_AND_CONTINUE (opcode, flag, 11); + + /* Handle trap on condition and overflow. */ + case 't': + flag = 0; + if (!strncasecmp (s, ",tc,tsv", 7) || + !strncasecmp (s, ",tsv,tc", 7)) { - cmpltr = 3; flag = 1; + s += 7; } - else if (strcasecmp (name, "ev") == 0) + else if (!strncasecmp (s, ",tc", 3)) { - cmpltr = 7; - flag = 1; + flag = 0; + s += 3; } else - as_bad (_("Invalid Logical Instruction Condition.")); - *s = c; - } - opcode |= cmpltr << 13; - INSERT_FIELD_AND_CONTINUE (opcode, flag, 12); - - /* Handle a unit instruction condition. */ - case 'U': - cmpltr = 0; - flag = 0; - if (*s == ',') - { - s++; + break; + INSERT_FIELD_AND_CONTINUE (opcode, flag, 11); - if (strncasecmp (s, "sbz", 3) == 0) - { - cmpltr = 2; - s += 3; - } - else if (strncasecmp (s, "shz", 3) == 0) + /* Handle 64 bit borrow for SUB. */ + case 'B': + flag = 0; + if (!strncasecmp (s, ",db,tsv", 7) || + !strncasecmp (s, ",tsv,db", 7)) { - cmpltr = 3; - s += 3; - } - else if (strncasecmp (s, "sdc", 3) == 0) - { - cmpltr = 4; - s += 3; - } - else if (strncasecmp (s, "sbc", 3) == 0) - { - cmpltr = 6; - s += 3; - } - else if (strncasecmp (s, "shc", 3) == 0) - { - cmpltr = 7; - s += 3; - } - else if (strncasecmp (s, "tr", 2) == 0) - { - cmpltr = 0; flag = 1; - s += 2; + s += 7; } - else if (strncasecmp (s, "nbz", 3) == 0) + else if (!strncasecmp (s, ",db", 3)) { - cmpltr = 2; - flag = 1; + flag = 0; s += 3; } - else if (strncasecmp (s, "nhz", 3) == 0) + else + break; + + INSERT_FIELD_AND_CONTINUE (opcode, flag, 11); + + /* Handle 32 bit borrow for SUB. */ + case 'b': + flag = 0; + if (!strncasecmp (s, ",b,tsv", 6) || + !strncasecmp (s, ",tsv,b", 6)) { - cmpltr = 3; flag = 1; - s += 3; + s += 6; } - else if (strncasecmp (s, "ndc", 3) == 0) + else if (!strncasecmp (s, ",b", 2)) { - cmpltr = 4; - flag = 1; - s += 3; + flag = 0; + s += 2; } - else if (strncasecmp (s, "nbc", 3) == 0) + else + break; + + INSERT_FIELD_AND_CONTINUE (opcode, flag, 11); + + /* Handle trap condition completer for UADDCM. */ + case 'T': + flag = 0; + if (!strncasecmp (s, ",tc", 3)) { - cmpltr = 6; flag = 1; s += 3; } - else if (strncasecmp (s, "nhc", 3) == 0) + + INSERT_FIELD_AND_CONTINUE (opcode, flag, 6); + + /* Handle signed/unsigned at 21. */ + case 'S': + { + int sign = 1; + if (strncasecmp (s, ",s", 2) == 0) + { + sign = 1; + s += 2; + } + else if (strncasecmp (s, ",u", 2) == 0) + { + sign = 0; + s += 2; + } + + INSERT_FIELD_AND_CONTINUE (opcode, sign, 10); + } + + /* Handle left/right combination at 17:18. */ + case 'h': + if (*s++ == ',') { - cmpltr = 7; - flag = 1; - s += 3; + int lr = 0; + if (*s == 'r') + lr = 2; + else if (*s == 'l') + lr = 0; + else + as_bad(_("Invalid left/right combination completer")); + + s++; + INSERT_FIELD_AND_CONTINUE (opcode, lr, 13); } else - as_bad (_("Invalid Logical Instruction Condition.")); - } - opcode |= cmpltr << 13; - INSERT_FIELD_AND_CONTINUE (opcode, flag, 12); + as_bad(_("Invalid left/right combination completer")); + break; - /* Handle a shift/extract/deposit condition. */ - case '|': - case '>': - cmpltr = 0; - if (*s == ',') - { - save_s = s++; - - - name = s; - while (*s != ',' && *s != ' ' && *s != '\t') - s += 1; - c = *s; - *s = 0x00; - if (strcmp (name, "=") == 0) - cmpltr = 1; - else if (strcmp (name, "<") == 0) - cmpltr = 2; - else if (strcasecmp (name, "od") == 0) - cmpltr = 3; - else if (strcasecmp (name, "tr") == 0) - cmpltr = 4; - else if (strcmp (name, "<>") == 0) - cmpltr = 5; - else if (strcmp (name, ">=") == 0) - cmpltr = 6; - else if (strcasecmp (name, "ev") == 0) - cmpltr = 7; - /* Handle movb,n. Put things back the way they were. - This includes moving s back to where it started. */ - else if (strcasecmp (name, "n") == 0 && *args == '|') + /* Handle saturation at 24:25. */ + case 'H': + { + int sat = 3; + if (strncasecmp (s, ",ss", 3) == 0) + { + sat = 1; + s += 3; + } + else if (strncasecmp (s, ",us", 3) == 0) + { + sat = 0; + s += 3; + } + + INSERT_FIELD_AND_CONTINUE (opcode, sat, 6); + } + + /* Handle permutation completer. */ + case '*': + if (*s++ == ',') { - *s = c; - s = save_s; + int permloc[4] = {13,10,8,6}; + int perm = 0; + int i = 0; + for (; i < 4; i++) + { + switch (*s++) + { + case '0': + perm = 0; + break; + case '1': + perm = 1; + break; + case '2': + perm = 2; + break; + case '3': + perm = 3; + break; + default: + as_bad(_("Invalid permutation completer")); + } + opcode |= perm << permloc[i]; + } continue; } else - as_bad (_("Invalid Shift/Extract/Deposit Condition.")); - *s = c; - } - INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13); + as_bad(_("Invalid permutation completer")); + break; - /* Handle bvb and bb conditions. */ - case '~': - cmpltr = 0; - if (*s == ',') - { - s++; - if (strncmp (s, "<", 1) == 0) - { - cmpltr = 0; - s++; - } - else if (strncmp (s, ">=", 2) == 0) - { - cmpltr = 1; - s += 2; - } - else - as_bad (_("Invalid Bit Branch Condition: %c"), *s); + default: + abort (); } - INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 15); + break; - /* Handle a system control completer. */ - case 'Z': - if (*s == ',' && (*(s + 1) == 'm' || *(s + 1) == 'M')) - { - flag = 1; - s += 2; - } - else - flag = 0; + /* Handle all conditions. */ + case '?': + { + args++; + switch (*args) + { + /* Handle FP compare conditions. */ + case 'f': + cond = pa_parse_fp_cmp_cond (&s); + INSERT_FIELD_AND_CONTINUE (opcode, cond, 0); + + /* Handle an add condition. */ + case 'A': + case 'a': + cmpltr = 0; + flag = 0; + if (*s == ',') + { + s++; + + /* 64 bit conditions. */ + if (*args == 'A') + { + if (*s == '*') + s++; + else + break; + } + else if (*s == '*') + break; + name = s; + + name = s; + while (*s != ',' && *s != ' ' && *s != '\t') + s += 1; + c = *s; + *s = 0x00; + if (strcmp (name, "=") == 0) + cmpltr = 1; + else if (strcmp (name, "<") == 0) + cmpltr = 2; + else if (strcmp (name, "<=") == 0) + cmpltr = 3; + else if (strcasecmp (name, "nuv") == 0) + cmpltr = 4; + else if (strcasecmp (name, "znv") == 0) + cmpltr = 5; + else if (strcasecmp (name, "sv") == 0) + cmpltr = 6; + else if (strcasecmp (name, "od") == 0) + cmpltr = 7; + else if (strcasecmp (name, "tr") == 0) + { + cmpltr = 0; + flag = 1; + } + else if (strcmp (name, "<>") == 0) + { + cmpltr = 1; + flag = 1; + } + else if (strcmp (name, ">=") == 0) + { + cmpltr = 2; + flag = 1; + } + else if (strcmp (name, ">") == 0) + { + cmpltr = 3; + flag = 1; + } + else if (strcasecmp (name, "uv") == 0) + { + cmpltr = 4; + flag = 1; + } + else if (strcasecmp (name, "vnz") == 0) + { + cmpltr = 5; + flag = 1; + } + else if (strcasecmp (name, "nsv") == 0) + { + cmpltr = 6; + flag = 1; + } + else if (strcasecmp (name, "ev") == 0) + { + cmpltr = 7; + flag = 1; + } + /* ",*" is a valid condition. */ + else if (*args == 'a') + as_bad (_("Invalid Add Condition: %s"), name); + *s = c; + } + opcode |= cmpltr << 13; + INSERT_FIELD_AND_CONTINUE (opcode, flag, 12); + + /* Handle non-negated add and branch condition. */ + case 'd': + cmpltr = pa_parse_nonneg_add_cmpltr (&s, 1); + if (cmpltr < 0) + { + as_bad (_("Invalid Compare/Subtract Condition: %c"), *s); + cmpltr = 0; + } + INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13); + + /* Handle negated add and branch condition. */ + case 'D': + abort (); + + /* Handle wide-mode non-negated add and branch condition. */ + case 'w': + abort (); + + /* Handle wide-mode negated add and branch condition. */ + case 'W': + abort(); + + /* Handle a negated or non-negated add and branch + condition. */ + case '@': + save_s = s; + cmpltr = pa_parse_nonneg_add_cmpltr (&s, 1); + if (cmpltr < 0) + { + s = save_s; + cmpltr = pa_parse_neg_add_cmpltr (&s, 1); + if (cmpltr < 0) + { + as_bad (_("Invalid Compare/Subtract Condition")); + cmpltr = 0; + } + else + { + /* Negated condition requires an opcode change. */ + opcode |= 1 << 27; + } + } + INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13); + + /* Handle branch on bit conditions. */ + case 'B': + case 'b': + cmpltr = 0; + if (*s == ',') + { + s++; + + if (*args == 'B') + { + if (*s == '*') + s++; + else + break; + } + else if (*s == '*') + break; + + if (strncmp (s, "<", 1) == 0) + { + cmpltr = 0; + s++; + } + else if (strncmp (s, ">=", 2) == 0) + { + cmpltr = 1; + s += 2; + } + else + as_bad (_("Invalid Bit Branch Condition: %c"), *s); + } + INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 15); + + /* Handle a compare/subtract condition. */ + case 'S': + case 's': + cmpltr = 0; + flag = 0; + if (*s == ',') + { + s++; - INSERT_FIELD_AND_CONTINUE (opcode, flag, 5); + /* 64 bit conditions. */ + if (*args == 'S') + { + if (*s == '*') + s++; + else + break; + } + else if (*s == '*') + break; + name = s; + + name = s; + while (*s != ',' && *s != ' ' && *s != '\t') + s += 1; + c = *s; + *s = 0x00; + if (strcmp (name, "=") == 0) + cmpltr = 1; + else if (strcmp (name, "<") == 0) + cmpltr = 2; + else if (strcmp (name, "<=") == 0) + cmpltr = 3; + else if (strcasecmp (name, "<<") == 0) + cmpltr = 4; + else if (strcasecmp (name, "<<=") == 0) + cmpltr = 5; + else if (strcasecmp (name, "sv") == 0) + cmpltr = 6; + else if (strcasecmp (name, "od") == 0) + cmpltr = 7; + else if (strcasecmp (name, "tr") == 0) + { + cmpltr = 0; + flag = 1; + } + else if (strcmp (name, "<>") == 0) + { + cmpltr = 1; + flag = 1; + } + else if (strcmp (name, ">=") == 0) + { + cmpltr = 2; + flag = 1; + } + else if (strcmp (name, ">") == 0) + { + cmpltr = 3; + flag = 1; + } + else if (strcasecmp (name, ">>=") == 0) + { + cmpltr = 4; + flag = 1; + } + else if (strcasecmp (name, ">>") == 0) + { + cmpltr = 5; + flag = 1; + } + else if (strcasecmp (name, "nsv") == 0) + { + cmpltr = 6; + flag = 1; + } + else if (strcasecmp (name, "ev") == 0) + { + cmpltr = 7; + flag = 1; + } + /* ",*" is a valid condition. */ + else if (*args != 'S') + as_bad (_("Invalid Compare/Subtract Condition: %s"), + name); + *s = c; + } + opcode |= cmpltr << 13; + INSERT_FIELD_AND_CONTINUE (opcode, flag, 12); + + /* Handle a non-negated compare condition. */ + case 't': + cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s, 1); + if (cmpltr < 0) + { + as_bad (_("Invalid Compare/Subtract Condition: %c"), *s); + cmpltr = 0; + } + INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13); + + /* Handle a negated compare condition. */ + case 'T': + abort (); + + /* Handle a 64 bit non-negated compare condition. */ + case 'r': + abort (); + + /* Handle a 64 bit negated compare condition. */ + case 'R': + abort (); + + /* Handle a 64 bit cmpib condition. */ + case 'Q': + abort (); + + /* Handle a negated or non-negated compare/subtract + condition. */ + case 'n': + save_s = s; + cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s, 1); + if (cmpltr < 0) + { + s = save_s; + cmpltr = pa_parse_neg_cmpsub_cmpltr (&s, 1); + if (cmpltr < 0) + { + as_bad (_("Invalid Compare/Subtract Condition.")); + cmpltr = 0; + } + else + { + /* Negated condition requires an opcode change. */ + opcode |= 1 << 27; + } + } + + INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13); + + /* Handle a logical instruction condition. */ + case 'L': + case 'l': + cmpltr = 0; + flag = 0; + if (*s == ',') + { + s++; + + /* 64 bit conditions. */ + if (*args == 'L') + { + if (*s == '*') + s++; + else + break; + } + else if (*s == '*') + break; + name = s; + + name = s; + while (*s != ',' && *s != ' ' && *s != '\t') + s += 1; + c = *s; + *s = 0x00; + + + if (strcmp (name, "=") == 0) + cmpltr = 1; + else if (strcmp (name, "<") == 0) + cmpltr = 2; + else if (strcmp (name, "<=") == 0) + cmpltr = 3; + else if (strcasecmp (name, "od") == 0) + cmpltr = 7; + else if (strcasecmp (name, "tr") == 0) + { + cmpltr = 0; + flag = 1; + } + else if (strcmp (name, "<>") == 0) + { + cmpltr = 1; + flag = 1; + } + else if (strcmp (name, ">=") == 0) + { + cmpltr = 2; + flag = 1; + } + else if (strcmp (name, ">") == 0) + { + cmpltr = 3; + flag = 1; + } + else if (strcasecmp (name, "ev") == 0) + { + cmpltr = 7; + flag = 1; + } + /* ",*" is a valid condition. */ + else if (*args != 'L') + as_bad (_("Invalid Logical Instruction Condition.")); + *s = c; + } + opcode |= cmpltr << 13; + INSERT_FIELD_AND_CONTINUE (opcode, flag, 12); + + /* Handle a shift/extract/deposit condition. */ + case 'X': + case 'x': + case 'y': + cmpltr = 0; + if (*s == ',') + { + save_s = s++; + + /* 64 bit conditions. */ + if (*args == 'X') + { + if (*s == '*') + s++; + else + break; + } + else if (*s == '*') + break; + name = s; + + name = s; + while (*s != ',' && *s != ' ' && *s != '\t') + s += 1; + c = *s; + *s = 0x00; + if (strcmp (name, "=") == 0) + cmpltr = 1; + else if (strcmp (name, "<") == 0) + cmpltr = 2; + else if (strcasecmp (name, "od") == 0) + cmpltr = 3; + else if (strcasecmp (name, "tr") == 0) + cmpltr = 4; + else if (strcmp (name, "<>") == 0) + cmpltr = 5; + else if (strcmp (name, ">=") == 0) + cmpltr = 6; + else if (strcasecmp (name, "ev") == 0) + cmpltr = 7; + /* Handle movb,n. Put things back the way they were. + This includes moving s back to where it started. */ + else if (strcasecmp (name, "n") == 0 && *args == 'y') + { + *s = c; + s = save_s; + continue; + } + /* ",*" is a valid condition. */ + else if (*args != 'X') + as_bad (_("Invalid Shift/Extract/Deposit Condition.")); + *s = c; + } + INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13); + + /* Handle a unit instruction condition. */ + case 'U': + case 'u': + cmpltr = 0; + flag = 0; + if (*s == ',') + { + s++; + + /* 64 bit conditions. */ + if (*args == 'U') + { + if (*s == '*') + s++; + else + break; + } + else if (*s == '*') + break; + + if (strncasecmp (s, "sbz", 3) == 0) + { + cmpltr = 2; + s += 3; + } + else if (strncasecmp (s, "shz", 3) == 0) + { + cmpltr = 3; + s += 3; + } + else if (strncasecmp (s, "sdc", 3) == 0) + { + cmpltr = 4; + s += 3; + } + else if (strncasecmp (s, "sbc", 3) == 0) + { + cmpltr = 6; + s += 3; + } + else if (strncasecmp (s, "shc", 3) == 0) + { + cmpltr = 7; + s += 3; + } + else if (strncasecmp (s, "tr", 2) == 0) + { + cmpltr = 0; + flag = 1; + s += 2; + } + else if (strncasecmp (s, "nbz", 3) == 0) + { + cmpltr = 2; + flag = 1; + s += 3; + } + else if (strncasecmp (s, "nhz", 3) == 0) + { + cmpltr = 3; + flag = 1; + s += 3; + } + else if (strncasecmp (s, "ndc", 3) == 0) + { + cmpltr = 4; + flag = 1; + s += 3; + } + else if (strncasecmp (s, "nbc", 3) == 0) + { + cmpltr = 6; + flag = 1; + s += 3; + } + else if (strncasecmp (s, "nhc", 3) == 0) + { + cmpltr = 7; + flag = 1; + s += 3; + } + /* ",*" is a valid condition. */ + else if (*args != 'U') + as_bad (_("Invalid Unit Instruction Condition.")); + } + opcode |= cmpltr << 13; + INSERT_FIELD_AND_CONTINUE (opcode, flag, 12); + + default: + abort (); + } + break; + } /* Handle a nullification completer for branch instructions. */ case 'n': @@ -2290,81 +2830,173 @@ pa_ip (str) continue; } + /* Handle a 2 bit shift count at 25. */ + case '.': + num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; + s = expr_end; + CHECK_FIELD (num, 3, 1, strict); + INSERT_FIELD_AND_CONTINUE (opcode, num, 6); + + /* Handle a 4 bit shift count at 25. */ + case '*': + num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; + s = expr_end; + CHECK_FIELD (num, 15, 0, strict); + INSERT_FIELD_AND_CONTINUE (opcode, num, 6); + /* Handle a 5 bit shift count at 26. */ case 'p': num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; s = expr_end; - CHECK_FIELD (num, 31, 0, 0); + CHECK_FIELD (num, 31, 0, strict); INSERT_FIELD_AND_CONTINUE (opcode, 31 - num, 5); + /* Handle a 6 bit shift count at 20,22:26. */ + case '~': + num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; + s = expr_end; + CHECK_FIELD (num, 63, 0, strict); + num = 63 - num; + opcode |= (num & 0x20) << 6; + INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 5); + + /* Handle a 6 bit field length at 23,27:31. */ + case '%': + flag = 0; + num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; + s = expr_end; + CHECK_FIELD (num, 64, 1, strict); + num--; + opcode |= (num & 0x20) << 3; + num = 31 - (num & 0x1f); + INSERT_FIELD_AND_CONTINUE (opcode, num, 0); + + /* Handle a 6 bit field length at 19,27:31. */ + case '|': + num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; + s = expr_end; + CHECK_FIELD (num, 64, 1, strict); + num--; + opcode |= (num & 0x20) << 7; + num = 31 - (num & 0x1f); + INSERT_FIELD_AND_CONTINUE (opcode, num, 0); + /* Handle a 5 bit bit position at 26. */ case 'P': num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; s = expr_end; - CHECK_FIELD (num, 31, 0, 0); + CHECK_FIELD (num, 31, 0, strict); INSERT_FIELD_AND_CONTINUE (opcode, num, 5); + /* Handle a 6 bit bit position at 20,22:26. */ + case 'q': + num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; + s = expr_end; + CHECK_FIELD (num, 63, 0, strict); + opcode |= (num & 0x20) << 6; + INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 5); + /* Handle a 5 bit immediate at 10. */ case 'Q': - num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; if (the_insn.exp.X_op != O_constant) break; s = expr_end; - CHECK_FIELD (num, 31, 0, 0); + CHECK_FIELD (num, 31, 0, strict); INSERT_FIELD_AND_CONTINUE (opcode, num, 21); + /* Handle a 9 bit immediate at 28. */ + case '$': + num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; + s = expr_end; + CHECK_FIELD (num, 511, 1, strict); + INSERT_FIELD_AND_CONTINUE (opcode, num, 3); + /* Handle a 13 bit immediate at 18. */ case 'A': num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; s = expr_end; - CHECK_FIELD (num, 8191, 0, 0); + CHECK_FIELD (num, 8191, 0, strict); INSERT_FIELD_AND_CONTINUE (opcode, num, 13); /* Handle a 26 bit immediate at 31. */ case 'D': num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; s = expr_end; - CHECK_FIELD (num, 671108864, 0, 0); + CHECK_FIELD (num, 671108864, 0, strict); INSERT_FIELD_AND_CONTINUE (opcode, num, 0); /* Handle a 3 bit SFU identifier at 25. */ - case 'f': + case 'v': if (*s++ != ',') as_bad (_("Invalid SFU identifier")); num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; s = expr_end; - CHECK_FIELD (num, 7, 0, 0); + CHECK_FIELD (num, 7, 0, strict); INSERT_FIELD_AND_CONTINUE (opcode, num, 6); /* Handle a 20 bit SOP field for spop0. */ case 'O': num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; s = expr_end; - CHECK_FIELD (num, 1048575, 0, 0); + CHECK_FIELD (num, 1048575, 0, strict); num = (num & 0x1f) | ((num & 0x000fffe0) << 6); INSERT_FIELD_AND_CONTINUE (opcode, num, 0); /* Handle a 15bit SOP field for spop1. */ case 'o': num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; s = expr_end; - CHECK_FIELD (num, 32767, 0, 0); + CHECK_FIELD (num, 32767, 0, strict); INSERT_FIELD_AND_CONTINUE (opcode, num, 11); /* Handle a 10bit SOP field for spop3. */ case '0': num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; s = expr_end; - CHECK_FIELD (num, 1023, 0, 0); + CHECK_FIELD (num, 1023, 0, strict); num = (num & 0x1f) | ((num & 0x000003e0) << 6); INSERT_FIELD_AND_CONTINUE (opcode, num, 0); /* Handle a 15 bit SOP field for spop2. */ case '1': num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; s = expr_end; - CHECK_FIELD (num, 32767, 0, 0); + CHECK_FIELD (num, 32767, 0, strict); num = (num & 0x1f) | ((num & 0x00007fe0) << 6); INSERT_FIELD_AND_CONTINUE (opcode, num, 0); @@ -2373,15 +3005,19 @@ pa_ip (str) if (*s++ != ',') as_bad (_("Invalid COPR identifier")); num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; s = expr_end; - CHECK_FIELD (num, 7, 0, 0); + CHECK_FIELD (num, 7, 0, strict); INSERT_FIELD_AND_CONTINUE (opcode, num, 6); /* Handle a 22bit SOP field for copr. */ case '2': num = pa_get_absolute_expression (&the_insn, &s); + if (strict && the_insn.exp.X_op != O_constant) + break; s = expr_end; - CHECK_FIELD (num, 4194303, 0, 0); + CHECK_FIELD (num, 4194303, 0, strict); num = (num & 0x1f) | ((num & 0x003fffe0) << 4); INSERT_FIELD_AND_CONTINUE (opcode, num, 0); @@ -2400,211 +3036,290 @@ pa_ip (str) the_insn.fpof2 = flag; INSERT_FIELD_AND_CONTINUE (opcode, flag, 13); - /* Handle FP compare conditions. */ - case 'M': - cond = pa_parse_fp_cmp_cond (&s); - INSERT_FIELD_AND_CONTINUE (opcode, cond, 0); + /* Handle a source FP operand format completer at 20. */ + case 'I': + flag = pa_parse_fp_format (&s); + the_insn.fpof1 = flag; + INSERT_FIELD_AND_CONTINUE (opcode, flag, 11); - /* Handle L/R register halves like 't'. */ - case 'v': - { - struct pa_11_fp_reg_struct result; + /* Handle a floating point operand format at 26. + Only allows single and double precision. */ + case 'H': + flag = pa_parse_fp_format (&s); + switch (flag) + { + case SGL: + opcode |= 0x20; + case DBL: + the_insn.fpof1 = flag; + continue; - pa_parse_number (&s, &result); - CHECK_FIELD (result.number_part, 31, 0, 0); - opcode |= result.number_part; + case QUAD: + case ILLEGAL_FMT: + default: + as_bad (_("Invalid Floating Point Operand Format.")); + } + break; + + /* Handle all floating point registers. */ + case 'f': + switch (*++args) + { + /* Float target register. */ + case 't': + /* This should be more strict. Small steps. */ + if (strict && *s != '%') + break; + num = pa_parse_number (&s, 0); + CHECK_FIELD (num, 31, 0, 0); + INSERT_FIELD_AND_CONTINUE (opcode, num, 0); - /* 0x30 opcodes are FP arithmetic operation opcodes - and need to be turned into 0x38 opcodes. This - is not necessary for loads/stores. */ - if (need_pa11_opcode (&the_insn, &result) - && ((opcode & 0xfc000000) == 0x30000000)) - opcode |= 1 << 27; + /* Float target register with L/R selection. */ + case 'T': + { + struct pa_11_fp_reg_struct result; - INSERT_FIELD_AND_CONTINUE (opcode, result.l_r_select & 1, 6); - } + /* This should be more strict. Small steps. */ + if (strict && *s != '%') + break; + pa_parse_number (&s, &result); + CHECK_FIELD (result.number_part, 31, 0, 0); + opcode |= result.number_part; + + /* 0x30 opcodes are FP arithmetic operation opcodes + and need to be turned into 0x38 opcodes. This + is not necessary for loads/stores. */ + if (need_pa11_opcode (&the_insn, &result) + && ((opcode & 0xfc000000) == 0x30000000)) + opcode |= 1 << 27; - /* Handle L/R register halves like 'b'. */ - case 'E': - { - struct pa_11_fp_reg_struct result; + INSERT_FIELD_AND_CONTINUE (opcode, result.l_r_select & 1, 6); + } - pa_parse_number (&s, &result); - CHECK_FIELD (result.number_part, 31, 0, 0); - opcode |= result.number_part << 21; - if (need_pa11_opcode (&the_insn, &result)) + /* Float operand 1. */ + case 'a': { - opcode |= (result.l_r_select & 1) << 7; - opcode |= 1 << 27; - } - continue; - } + struct pa_11_fp_reg_struct result; - /* Handle L/R register halves like 'b'. */ - case '3': - { - struct pa_11_fp_reg_struct result; - int regnum; + /* This should be more strict. Small steps. */ + if (strict && *s != '%') + break; + pa_parse_number (&s, &result); + CHECK_FIELD (result.number_part, 31, 0, 0); + opcode |= result.number_part << 21; + if (need_pa11_opcode (&the_insn, &result)) + { + opcode |= (result.l_r_select & 1) << 7; + opcode |= 1 << 27; + } + continue; + } - pa_parse_number (&s, &result); - CHECK_FIELD (result.number_part, 31, 0, 0); - opcode |= (result.number_part & 0x1c) << 11; - opcode |= (result.number_part & 0x3) << 9; - opcode |= (result.l_r_select & 1) << 8; - continue; - } + /* Float operand 1 with L/R selection. */ + case 'A': + { + struct pa_11_fp_reg_struct result; - /* Handle L/R register halves like 'x'. */ - case 'e': - { - struct pa_11_fp_reg_struct result; + /* This should be more strict. Small steps. */ + if (strict && *s != '%') + break; + pa_parse_number (&s, &result); + CHECK_FIELD (result.number_part, 31, 0, 0); + opcode |= result.number_part << 21; + opcode |= (result.l_r_select & 1) << 7; + continue; + } - pa_parse_number (&s, &result); - CHECK_FIELD (result.number_part, 31, 0, 0); - opcode |= (result.number_part & 0x1f) << 16; - if (need_pa11_opcode (&the_insn, &result)) + /* Float operand 2. */ + case 'b': { - opcode |= (result.l_r_select & 1) << 1; - } - continue; - } + struct pa_11_fp_reg_struct result; - /* Handle L/R register halves like 'x'. */ - case 'X': - { - struct pa_11_fp_reg_struct result; + /* This should be more strict. Small steps. */ + if (strict && *s != '%') + break; + pa_parse_number (&s, &result); + CHECK_FIELD (result.number_part, 31, 0, 0); + opcode |= (result.number_part & 0x1f) << 16; + if (need_pa11_opcode (&the_insn, &result)) + { + opcode |= (result.l_r_select & 1) << 12; + opcode |= 1 << 27; + } + continue; + } - pa_parse_number (&s, &result); - CHECK_FIELD (result.number_part, 31, 0, 0); - opcode |= (result.number_part & 0x1f) << 16; - if (need_pa11_opcode (&the_insn, &result)) + /* Float operand 2 with L/R selection. */ + case 'B': { + struct pa_11_fp_reg_struct result; + + /* This should be more strict. Small steps. */ + if (strict && *s != '%') + break; + pa_parse_number (&s, &result); + CHECK_FIELD (result.number_part, 31, 0, 0); + opcode |= (result.number_part & 0x1f) << 16; opcode |= (result.l_r_select & 1) << 12; - opcode |= 1 << 27; + continue; } - continue; - } - /* Handle a 5 bit register field at 10. */ - case '4': - { - struct pa_11_fp_reg_struct result; + /* Float operand 3 for fmpyfadd, fmpynfadd. */ + case 'C': + { + struct pa_11_fp_reg_struct result; + int regnum; - pa_parse_number (&s, &result); - CHECK_FIELD (result.number_part, 31, 0, 0); - if (the_insn.fpof1 == SGL) + /* This should be more strict. Small steps. */ + if (strict && *s != '%') + break; + pa_parse_number (&s, &result); + CHECK_FIELD (result.number_part, 31, 0, 0); + opcode |= (result.number_part & 0x1c) << 11; + opcode |= (result.number_part & 0x3) << 9; + opcode |= (result.l_r_select & 1) << 8; + continue; + } + + /* Float mult operand 1 for fmpyadd, fmpysub */ + case 'i': { - if (result.number_part < 16) + struct pa_11_fp_reg_struct result; + + /* This should be more strict. Small steps. */ + if (strict && *s != '%') + break; + pa_parse_number (&s, &result); + CHECK_FIELD (result.number_part, 31, 0, 0); + if (the_insn.fpof1 == SGL) { - as_bad (_("Invalid register for single precision fmpyadd or fmpysub")); - break; + if (result.number_part < 16) + { + as_bad (_("Invalid register for single precision fmpyadd or fmpysub")); + break; + } + + result.number_part &= 0xF; + result.number_part |= (result.l_r_select & 1) << 4; } - - result.number_part &= 0xF; - result.number_part |= (result.l_r_select & 1) << 4; + INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 21); } - INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 21); - } - - /* Handle a 5 bit register field at 15. */ - case '6': - { - struct pa_11_fp_reg_struct result; - pa_parse_number (&s, &result); - CHECK_FIELD (result.number_part, 31, 0, 0); - if (the_insn.fpof1 == SGL) + /* Float mult operand 2 for fmpyadd, fmpysub */ + case 'j': { - if (result.number_part < 16) + struct pa_11_fp_reg_struct result; + + /* This should be more strict. Small steps. */ + if (strict && *s != '%') + break; + pa_parse_number (&s, &result); + CHECK_FIELD (result.number_part, 31, 0, 0); + if (the_insn.fpof1 == SGL) { - as_bad (_("Invalid register for single precision fmpyadd or fmpysub")); - break; + if (result.number_part < 16) + { + as_bad (_("Invalid register for single precision fmpyadd or fmpysub")); + break; + } + result.number_part &= 0xF; + result.number_part |= (result.l_r_select & 1) << 4; } - result.number_part &= 0xF; - result.number_part |= (result.l_r_select & 1) << 4; + INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 16); } - INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 16); - } - - /* Handle a 5 bit register field at 31. */ - case '7': - { - struct pa_11_fp_reg_struct result; - pa_parse_number (&s, &result); - CHECK_FIELD (result.number_part, 31, 0, 0); - if (the_insn.fpof1 == SGL) + /* Float mult target for fmpyadd, fmpysub */ + case 'k': { - if (result.number_part < 16) + struct pa_11_fp_reg_struct result; + + /* This should be more strict. Small steps. */ + if (strict && *s != '%') + break; + pa_parse_number (&s, &result); + CHECK_FIELD (result.number_part, 31, 0, 0); + if (the_insn.fpof1 == SGL) { - as_bad (_("Invalid register for single precision fmpyadd or fmpysub")); - break; + if (result.number_part < 16) + { + as_bad (_("Invalid register for single precision fmpyadd or fmpysub")); + break; + } + result.number_part &= 0xF; + result.number_part |= (result.l_r_select & 1) << 4; } - result.number_part &= 0xF; - result.number_part |= (result.l_r_select & 1) << 4; + INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 0); } - INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 0); - } - /* Handle a 5 bit register field at 20. */ - case '8': - { - struct pa_11_fp_reg_struct result; + /* Float add operand 1 for fmpyadd, fmpysub */ + case 'l': + { + struct pa_11_fp_reg_struct result; + + /* This should be more strict. Small steps. */ + if (strict && *s != '%') + break; + pa_parse_number (&s, &result); + CHECK_FIELD (result.number_part, 31, 0, 0); + if (the_insn.fpof1 == SGL) + { + if (result.number_part < 16) + { + as_bad (_("Invalid register for single precision fmpyadd or fmpysub")); + break; + } + result.number_part &= 0xF; + result.number_part |= (result.l_r_select & 1) << 4; + } + INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 6); + } - pa_parse_number (&s, &result); - CHECK_FIELD (result.number_part, 31, 0, 0); - if (the_insn.fpof1 == SGL) + /* Float add target for fmpyadd, fmpysub */ + case 'm': { - if (result.number_part < 16) + struct pa_11_fp_reg_struct result; + + /* This should be more strict. Small steps. */ + if (strict && *s != '%') + break; + pa_parse_number (&s, &result); + CHECK_FIELD (result.number_part, 31, 0, 0); + if (the_insn.fpof1 == SGL) { - as_bad (_("Invalid register for single precision fmpyadd or fmpysub")); - break; + if (result.number_part < 16) + { + as_bad (_("Invalid register for single precision fmpyadd or fmpysub")); + break; + } + result.number_part &= 0xF; + result.number_part |= (result.l_r_select & 1) << 4; } - result.number_part &= 0xF; - result.number_part |= (result.l_r_select & 1) << 4; + INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 11); } - INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 11); - } - /* Handle a 5 bit register field at 25. */ - case '9': + default: + abort (); + } + break; + + /* Handle L/R register halves like 'x'. */ + case 'e': { struct pa_11_fp_reg_struct result; + /* This should be more strict. Small steps. */ + if (strict && *s != '%') + break; pa_parse_number (&s, &result); CHECK_FIELD (result.number_part, 31, 0, 0); - if (the_insn.fpof1 == SGL) + opcode |= (result.number_part & 0x1f) << 16; + if (need_pa11_opcode (&the_insn, &result)) { - if (result.number_part < 16) - { - as_bad (_("Invalid register for single precision fmpyadd or fmpysub")); - break; - } - result.number_part &= 0xF; - result.number_part |= (result.l_r_select & 1) << 4; + opcode |= (result.l_r_select & 1) << 1; } - INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 6); + continue; } - /* Handle a floating point operand format at 26. - Only allows single and double precision. */ - case 'H': - flag = pa_parse_fp_format (&s); - switch (flag) - { - case SGL: - opcode |= 0x20; - case DBL: - the_insn.fpof1 = flag; - continue; - - case QUAD: - case ILLEGAL_FMT: - default: - as_bad (_("Invalid Floating Point Operand Format.")); - } - break; - default: abort (); } @@ -2730,13 +3445,14 @@ tc_gen_reloc (section, fixp) reloc = (arelent *) xmalloc (sizeof (arelent)); - reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym; + reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); codes = (bfd_reloc_code_real_type **) hppa_gen_reloc_type (stdoutput, fixp->fx_r_type, hppa_fixp->fx_r_format, hppa_fixp->fx_r_field, fixp->fx_subsy != NULL, - fixp->fx_addsy->bsym); + symbol_get_bfdsym (fixp->fx_addsy)); if (codes == NULL) abort (); @@ -2759,7 +3475,8 @@ tc_gen_reloc (section, fixp) code = *codes[0]; - reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym; + reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); reloc->howto = bfd_reloc_type_lookup (stdoutput, code); reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; reloc->addend = 0; /* default */ @@ -2809,7 +3526,8 @@ tc_gen_reloc (section, fixp) { code = *codes[i]; - relocs[i]->sym_ptr_ptr = &fixp->fx_addsy->bsym; + relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); relocs[i]->howto = bfd_reloc_type_lookup (stdoutput, code); relocs[i]->address = fixp->fx_frag->fr_address + fixp->fx_where; @@ -2820,23 +3538,25 @@ tc_gen_reloc (section, fixp) of two symbols. With that in mind we fill in all four relocs now and break out of the loop. */ assert (i == 1); - relocs[0]->sym_ptr_ptr = (asymbol **) &bfd_abs_symbol; + relocs[0]->sym_ptr_ptr = (asymbol **) &(bfd_abs_symbol); relocs[0]->howto = bfd_reloc_type_lookup (stdoutput, *codes[0]); relocs[0]->address = fixp->fx_frag->fr_address + fixp->fx_where; relocs[0]->addend = 0; - relocs[1]->sym_ptr_ptr = &fixp->fx_addsy->bsym; + relocs[1]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + *relocs[1]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); relocs[1]->howto = bfd_reloc_type_lookup (stdoutput, *codes[1]); relocs[1]->address = fixp->fx_frag->fr_address + fixp->fx_where; relocs[1]->addend = 0; - relocs[2]->sym_ptr_ptr = &fixp->fx_subsy->bsym; + relocs[2]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + *relocs[2]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy); relocs[2]->howto = bfd_reloc_type_lookup (stdoutput, *codes[2]); relocs[2]->address = fixp->fx_frag->fr_address + fixp->fx_where; relocs[2]->addend = 0; - relocs[3]->sym_ptr_ptr = (asymbol **) &bfd_abs_symbol; + relocs[3]->sym_ptr_ptr = (asymbol **) &(bfd_abs_symbol); relocs[3]->howto = bfd_reloc_type_lookup (stdoutput, *codes[3]); relocs[3]->address = fixp->fx_frag->fr_address + fixp->fx_where; relocs[3]->addend = 0; - relocs[4]->sym_ptr_ptr = (asymbol **) &bfd_abs_symbol; + relocs[4]->sym_ptr_ptr = (asymbol **) &(bfd_abs_symbol); relocs[4]->howto = bfd_reloc_type_lookup (stdoutput, *codes[4]); relocs[4]->address = fixp->fx_frag->fr_address + fixp->fx_where; relocs[4]->addend = 0; @@ -2874,7 +3594,8 @@ tc_gen_reloc (section, fixp) case R_N0SEL: case R_N1SEL: /* There is no symbol or addend associated with these fixups. */ - relocs[i]->sym_ptr_ptr = &dummy_symbol->bsym; + relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol); relocs[i]->addend = 0; break; @@ -2882,7 +3603,8 @@ tc_gen_reloc (section, fixp) case R_ENTRY: case R_EXIT: /* There is no symbol associated with these fixups. */ - relocs[i]->sym_ptr_ptr = &dummy_symbol->bsym; + relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol); relocs[i]->addend = fixp->fx_offset; break; @@ -3066,9 +3788,11 @@ md_apply_fix (fixP, valp) if ((fmt == 12 || fmt == 17 || fmt == 22) && fixP->fx_addsy && fixP->fx_pcrel +#ifdef OBJ_SOM && !arg_reloc_stub_needed ((long) ((obj_symbol_type *) - fixP->fx_addsy->bsym)->tc_data.ap.hppa_arg_reloc, - hppa_fixP->fx_arg_reloc) + symbol_get_bfdsym (fixP->fx_addsy))->tc_data.ap.hppa_arg_reloc, + hppa_fixP->fx_arg_reloc) +#endif && (((int)(*valp) > -262144 && (int)(*valp) < 262143) && fmt != 22) && S_GET_SEGMENT (fixP->fx_addsy) == hppa_fixP->segment && !(fixP->fx_subsy @@ -3568,13 +4292,11 @@ pa_chk_field_selector (str) name[0] = tolower ((*str)[0]), name[1] = tolower ((*str)[1]), name[2] = 0; -#ifdef OBJ_SOM else if ((*str)[3] == '\'' || (*str)[3] == '%') name[0] = tolower ((*str)[0]), name[1] = tolower ((*str)[1]), name[2] = tolower ((*str)[2]), name[3] = 0; -#endif else return e_fsel; @@ -3669,6 +4391,14 @@ pa_get_absolute_expression (insn, strp) *s = c; return evaluate_absolute (insn); } + /* When in strict mode we have a non-match, fix up the pointers + and return to our caller. */ + if (insn->exp.X_op != O_constant && strict) + { + expr_end = input_line_pointer; + input_line_pointer = save_in; + return 0; + } if (insn->exp.X_op != O_constant) { as_bad (_("Bad segment (should be absolute).")); @@ -4144,6 +4874,7 @@ pa_parse_neg_add_cmpltr (s, isbranch) return cmpltr; } +#ifdef OBJ_SOM /* Handle an alignment directive. Special so that we can update the alignment of the subspace if necessary. */ static void @@ -4160,6 +4891,7 @@ pa_align (bytes) if (log2 (bytes) != -1) record_alignment (current_subspace->ssd_seg, log2 (bytes)); } +#endif /* Handle a .BLOCK type pseudo-op. */ @@ -4172,8 +4904,10 @@ pa_block (z) unsigned int temp_size; unsigned int i; +#ifdef OBJ_SOM /* We must have a valid space and subspace. */ pa_check_current_space_and_subspace (); +#endif temp_size = get_absolute_expression (); @@ -4251,8 +4985,10 @@ static void pa_call (unused) int unused; { +#ifdef OBJ_SOM /* We must have a valid space and subspace. */ pa_check_current_space_and_subspace (); +#endif pa_call_args (&last_call_desc); demand_empty_rest_of_line (); @@ -4338,26 +5074,32 @@ pa_build_unwind_subspace (call_info) { char *unwind; asection *seg, *save_seg; + asymbol *sym; subsegT subseg, save_subseg; - int i; + int i, reloc; char c, *p; + if (bfd_get_arch_info (stdoutput)->bits_per_address == 32) + reloc = R_PARISC_DIR32; + else + reloc = R_PARISC_SEGREL32; + /* Get into the right seg/subseg. This may involve creating the seg the first time through. Make sure to have the old seg/subseg so that we can reset things when we are done. */ - subseg = SUBSEG_UNWIND; seg = bfd_get_section_by_name (stdoutput, UNWIND_SECTION_NAME); if (seg == ASEC_NULL) { seg = bfd_make_section_old_way (stdoutput, UNWIND_SECTION_NAME); bfd_set_section_flags (stdoutput, seg, SEC_READONLY | SEC_HAS_CONTENTS - | SEC_LOAD | SEC_RELOC); + | SEC_LOAD | SEC_RELOC | SEC_ALLOC | SEC_DATA); + bfd_set_section_alignment (stdoutput, seg, 2); } save_seg = now_seg; save_subseg = now_subseg; - subseg_set (seg, subseg); + subseg_set (seg, 0); /* Get some space to hold relocation information for the unwind @@ -4368,7 +5110,8 @@ pa_build_unwind_subspace (call_info) /* Relocation info. for start offset of the function. */ fix_new_hppa (frag_now, p - frag_now->fr_literal, 4, call_info->start_symbol, (offsetT) 0, - (expressionS *) NULL, 0, R_PARISC_DIR32, e_fsel, 32, 0, NULL); + (expressionS *) NULL, 0, reloc, + e_fsel, 32, 0, NULL); p = frag_more (4); md_number_to_chars (p, 0, 4); @@ -4383,7 +5126,8 @@ pa_build_unwind_subspace (call_info) fix_new_hppa (frag_now, p - frag_now->fr_literal, 4, call_info->end_symbol, (offsetT) 0, - (expressionS *) NULL, 0, R_PARISC_DIR32, e_fsel, 32, 0, NULL); + (expressionS *) NULL, 0, reloc, + e_fsel, 32, 0, NULL); /* Dump it. */ unwind = (char *) &call_info->ci_unwind; @@ -4411,8 +5155,10 @@ pa_callinfo (unused) char *name, c, *p; int temp; +#ifdef OBJ_SOM /* We must have a valid space and subspace. */ pa_check_current_space_and_subspace (); +#endif /* .CALLINFO must appear within a procedure definition. */ if (!within_procedure) @@ -4549,9 +5295,11 @@ static void pa_code (unused) int unused; { +#ifdef OBJ_SOM current_space = is_defined_space ("$TEXT$"); current_subspace = pa_subsegment_to_subspace (current_space->sd_seg, 0); +#endif s_text (0); pa_undefine_label (); } @@ -4601,7 +5349,7 @@ pa_comm (unused) /* colon() has already set the frag to the current location in the current subspace; we need to reset the fragment to the zero address fragment. We also need to reset the segment pointer. */ - symbol->sy_frag = &zero_address_frag; + symbol_set_frag (symbol, &zero_address_frag); } demand_empty_rest_of_line (); } @@ -4620,8 +5368,10 @@ static void pa_enter (unused) int unused; { +#ifdef OBJ_SOM /* We must have a valid space and subspace. */ pa_check_current_space_and_subspace (); +#endif as_bad (_("The .ENTER pseudo-op is not supported")); demand_empty_rest_of_line (); @@ -4633,8 +5383,10 @@ static void pa_entry (unused) int unused; { +#ifdef OBJ_SOM /* We must have a valid space and subspace. */ pa_check_current_space_and_subspace (); +#endif if (!within_procedure) as_bad (_("Misplaced .entry. Ignored.")); @@ -4738,8 +5490,10 @@ static void pa_exit (unused) int unused; { +#ifdef OBJ_SOM /* We must have a valid space and subspace. */ pa_check_current_space_and_subspace (); +#endif if (!within_procedure) as_bad (_(".EXIT must appear within a procedure")); @@ -4808,13 +5562,13 @@ pa_type_args (symbolP, is_export) char *name, c, *p; unsigned int temp, arg_reloc; pa_symbol_type type = SYMBOL_TYPE_UNKNOWN; - obj_symbol_type *symbol = (obj_symbol_type *) symbolP->bsym; + obj_symbol_type *symbol = (obj_symbol_type *) symbol_get_bfdsym (symbolP); if (strncasecmp (input_line_pointer, "absolute", 8) == 0) { input_line_pointer += 8; - symbolP->bsym->flags &= ~BSF_FUNCTION; + symbol_get_bfdsym (symbolP)->flags &= ~BSF_FUNCTION; S_SET_SEGMENT (symbolP, bfd_abs_section_ptr); type = SYMBOL_TYPE_ABSOLUTE; } @@ -4827,54 +5581,55 @@ pa_type_args (symbolP, is_export) Complain if one tries to EXPORT a CODE type since that's never done. Both GCC and HP C still try to IMPORT CODE types, so silently fix them to be ENTRY types. */ - if (symbolP->bsym->flags & BSF_FUNCTION) + if (S_IS_FUNCTION (symbolP)) { if (is_export) - as_tsktsk (_("Using ENTRY rather than CODE in export directive for %s"), symbolP->bsym->name); + as_tsktsk (_("Using ENTRY rather than CODE in export directive for %s"), + S_GET_NAME (symbolP)); - symbolP->bsym->flags |= BSF_FUNCTION; + symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION; type = SYMBOL_TYPE_ENTRY; } else { - symbolP->bsym->flags &= ~BSF_FUNCTION; + symbol_get_bfdsym (symbolP)->flags &= ~BSF_FUNCTION; type = SYMBOL_TYPE_CODE; } } else if (strncasecmp (input_line_pointer, "data", 4) == 0) { input_line_pointer += 4; - symbolP->bsym->flags &= ~BSF_FUNCTION; + symbol_get_bfdsym (symbolP)->flags &= ~BSF_FUNCTION; type = SYMBOL_TYPE_DATA; } else if ((strncasecmp (input_line_pointer, "entry", 5) == 0)) { input_line_pointer += 5; - symbolP->bsym->flags |= BSF_FUNCTION; + symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION; type = SYMBOL_TYPE_ENTRY; } else if (strncasecmp (input_line_pointer, "millicode", 9) == 0) { input_line_pointer += 9; - symbolP->bsym->flags |= BSF_FUNCTION; + symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION; type = SYMBOL_TYPE_MILLICODE; } else if (strncasecmp (input_line_pointer, "plabel", 6) == 0) { input_line_pointer += 6; - symbolP->bsym->flags &= ~BSF_FUNCTION; + symbol_get_bfdsym (symbolP)->flags &= ~BSF_FUNCTION; type = SYMBOL_TYPE_PLABEL; } else if (strncasecmp (input_line_pointer, "pri_prog", 8) == 0) { input_line_pointer += 8; - symbolP->bsym->flags |= BSF_FUNCTION; + symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION; type = SYMBOL_TYPE_PRI_PROG; } else if (strncasecmp (input_line_pointer, "sec_prog", 8) == 0) { input_line_pointer += 8; - symbolP->bsym->flags |= BSF_FUNCTION; + symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION; type = SYMBOL_TYPE_SEC_PROG; } @@ -4882,7 +5637,7 @@ pa_type_args (symbolP, is_export) than BFD understands. This is how we get this information to the SOM BFD backend. */ #ifdef obj_set_symbol_type - obj_set_symbol_type (symbolP->bsym, (int) type); + obj_set_symbol_type (symbol_get_bfdsym (symbolP), (int) type); #endif /* Now that the type of the exported symbol has been handled, @@ -4903,7 +5658,9 @@ pa_type_args (symbolP, is_export) name = input_line_pointer; c = get_symbol_end (); arg_reloc = pa_align_arg_reloc (temp, pa_build_arg_reloc (name)); +#ifdef OBJ_SOM symbol->tc_data.ap.hppa_arg_reloc |= arg_reloc; +#endif *input_line_pointer = c; } /* The return value. */ @@ -4915,7 +5672,9 @@ pa_type_args (symbolP, is_export) name = input_line_pointer; c = get_symbol_end (); arg_reloc = pa_build_arg_reloc (name); +#ifdef OBJ_SOM symbol->tc_data.ap.hppa_arg_reloc |= arg_reloc; +#endif *input_line_pointer = c; } /* Privelege level. */ @@ -4925,7 +5684,9 @@ pa_type_args (symbolP, is_export) *p = c; input_line_pointer++; temp = atoi (input_line_pointer); +#ifdef OBJ_SOM symbol->tc_data.ap.hppa_priv_level = temp; +#endif c = get_symbol_end (); *input_line_pointer = c; } @@ -4976,7 +5737,7 @@ pa_import (unused) the the current segment. Note only BSF_FUNCTION really matters, we do not need to set the full SYMBOL_TYPE_* info. */ if (now_seg == text_section) - symbol->bsym->flags |= BSF_FUNCTION; + symbol_get_bfdsym (symbol)->flags |= BSF_FUNCTION; /* If the section is undefined, then the symbol is undefined Since this is an import, leave the section undefined. */ @@ -5030,8 +5791,10 @@ static void pa_leave (unused) int unused; { +#ifdef OBJ_SOM /* We must have a valid space and subspace. */ pa_check_current_space_and_subspace (); +#endif as_bad (_("The .LEAVE pseudo-op is not supported")); demand_empty_rest_of_line (); @@ -5058,6 +5821,12 @@ pa_level (unused) if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 11)) as_warn (_("could not set architecture and machine")); } + else if (strncmp (level, "2.0w", 4) == 0) + { + input_line_pointer += 4; + if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 25)) + as_warn (_("could not set architecture and machine")); + } else if (strncmp (level, "2.0", 3) == 0) { input_line_pointer += 3; @@ -5078,8 +5847,10 @@ static void pa_origin (unused) int unused; { +#ifdef OBJ_SOM /* We must have a valid space and subspace. */ pa_check_current_space_and_subspace (); +#endif s_org (0); pa_undefine_label (); @@ -5129,8 +5900,10 @@ pa_proc (unused) { struct call_info *call_info; +#ifdef OBJ_SOM /* We must have a valid space and subspace. */ pa_check_current_space_and_subspace (); +#endif if (within_procedure) as_fatal (_("Nested procedures")); @@ -5176,7 +5949,7 @@ pa_proc (unused) if (label_symbol->lss_label) { last_call_info->start_symbol = label_symbol->lss_label; - label_symbol->lss_label->bsym->flags |= BSF_FUNCTION; + symbol_get_bfdsym (label_symbol->lss_label)->flags |= BSF_FUNCTION; } else as_bad (_("Missing function name for .PROC (corrupted label chain)")); @@ -5196,8 +5969,10 @@ pa_procend (unused) int unused; { +#ifdef OBJ_SOM /* We must have a valid space and subspace. */ pa_check_current_space_and_subspace (); +#endif /* If we are within a procedure definition, make sure we've defined a label for the procedure; handle case where the @@ -5215,7 +5990,8 @@ pa_procend (unused) if (label_symbol->lss_label) { last_call_info->start_symbol = label_symbol->lss_label; - label_symbol->lss_label->bsym->flags |= BSF_FUNCTION; + symbol_get_bfdsym (label_symbol->lss_label)->flags + |= BSF_FUNCTION; #ifdef OBJ_SOM /* Also handle allocation of a fixup to hold the unwind information when the label appears after the proc/procend. */ @@ -5257,6 +6033,38 @@ pa_procend (unused) pa_undefine_label (); } +/* If VALUE is an exact power of two between zero and 2^31, then + return log2 (VALUE). Else return -1. */ + +static int +log2 (value) + int value; +{ + int shift = 0; + + while ((1 << shift) != value && shift < 32) + shift++; + + if (shift >= 32) + return -1; + else + return shift; +} + + +#ifdef OBJ_SOM +/* Check to make sure we have a valid space and subspace. */ + +static void +pa_check_current_space_and_subspace () +{ + if (current_space == NULL) + as_fatal (_("Not in a space.\n")); + + if (current_subspace == NULL) + as_fatal (_("Not in a subspace.\n")); +} + /* Parse the parameters to a .SPACE directive; if CREATE_FLAG is nonzero, then create a new space entry to hold the information specified by the parameters to the .SPACE directive. */ @@ -5525,24 +6333,6 @@ pa_spnum (unused) demand_empty_rest_of_line (); } -/* If VALUE is an exact power of two between zero and 2^31, then - return log2 (VALUE). Else return -1. */ - -static int -log2 (value) - int value; -{ - int shift = 0; - - while ((1 << shift) != value && shift < 32) - shift++; - - if (shift >= 32) - return -1; - else - return shift; -} - /* Handle a .SUBSPACE pseudo-op; this switches the current subspace to the given subspace, creating the new subspace if necessary. @@ -5553,7 +6343,7 @@ static void pa_subspace (create_new) int create_new; { - char *name, *ss_name, *alias, c; + char *name, *ss_name, c; char loadable, code_only, common, dup_common, zero, sort; int i, access, space_index, alignment, quadrant, applicable, flags; sd_chain_struct *space; @@ -5587,7 +6377,6 @@ pa_subspace (create_new) space_index = ~0; alignment = 1; quadrant = 0; - alias = NULL; space = current_space; if (create_new) @@ -5624,8 +6413,6 @@ pa_subspace (create_new) quadrant = pa_def_subspaces[i].quadrant; access = pa_def_subspaces[i].access; sort = pa_def_subspaces[i].sort; - if (USE_ALIASES && pa_def_subspaces[i].alias) - alias = pa_def_subspaces[i].alias; break; } i++; @@ -5734,14 +6521,6 @@ pa_subspace (create_new) section = subseg_force_new (ss_name, 0); else if (ssd) section = ssd->ssd_seg; - else if (alias) - section = subseg_new (alias, 0); - else if (!alias && USE_ALIASES) - { - as_warn (_("Ignoring subspace decl due to ELF BFD bugs.")); - demand_empty_rest_of_line (); - return; - } else section = subseg_new (ss_name, 0); @@ -5798,10 +6577,7 @@ pa_spaces_begin () char *name; /* Pick the right name to use for the new section. */ - if (pa_def_spaces[i].alias && USE_ALIASES) - name = pa_def_spaces[i].alias; - else - name = pa_def_spaces[i].name; + name = pa_def_spaces[i].name; pa_def_spaces[i].segment = subseg_new (name, 0); create_new_space (pa_def_spaces[i].name, pa_def_spaces[i].spnum, @@ -5821,16 +6597,8 @@ pa_spaces_begin () /* Pick the right name for the new section and pick the right subsegment number. */ - if (pa_def_subspaces[i].alias && USE_ALIASES) - { - name = pa_def_subspaces[i].alias; - subsegment = pa_def_subspaces[i].subsegment; - } - else - { - name = pa_def_subspaces[i].name; - subsegment = 0; - } + name = pa_def_subspaces[i].name; + subsegment = 0; /* Create the new section. */ segment = subseg_new (name, subsegment); @@ -5839,7 +6607,7 @@ pa_spaces_begin () /* For SOM we want to replace the standard .text, .data, and .bss sections with our own. We also want to set BFD flags for all the built-in subspaces. */ - if (!strcmp (pa_def_subspaces[i].name, "$CODE$") && !USE_ALIASES) + if (!strcmp (pa_def_subspaces[i].name, "$CODE$")) { text_section = segment; applicable = bfd_applicable_section_flags (stdoutput); @@ -5849,7 +6617,7 @@ pa_spaces_begin () | SEC_READONLY | SEC_HAS_CONTENTS)); } - else if (!strcmp (pa_def_subspaces[i].name, "$DATA$") && !USE_ALIASES) + else if (!strcmp (pa_def_subspaces[i].name, "$DATA$")) { data_section = segment; applicable = bfd_applicable_section_flags (stdoutput); @@ -5860,14 +6628,14 @@ pa_spaces_begin () } - else if (!strcmp (pa_def_subspaces[i].name, "$BSS$") && !USE_ALIASES) + else if (!strcmp (pa_def_subspaces[i].name, "$BSS$")) { bss_section = segment; applicable = bfd_applicable_section_flags (stdoutput); bfd_set_section_flags (stdoutput, segment, applicable & SEC_ALLOC); } - else if (!strcmp (pa_def_subspaces[i].name, "$LIT$") && !USE_ALIASES) + else if (!strcmp (pa_def_subspaces[i].name, "$LIT$")) { applicable = bfd_applicable_section_flags (stdoutput); bfd_set_section_flags (stdoutput, segment, @@ -5876,8 +6644,7 @@ pa_spaces_begin () | SEC_READONLY | SEC_HAS_CONTENTS)); } - else if (!strcmp (pa_def_subspaces[i].name, "$MILLICODE$") - && !USE_ALIASES) + else if (!strcmp (pa_def_subspaces[i].name, "$MILLICODE$")) { applicable = bfd_applicable_section_flags (stdoutput); bfd_set_section_flags (stdoutput, segment, @@ -5886,7 +6653,7 @@ pa_spaces_begin () | SEC_READONLY | SEC_HAS_CONTENTS)); } - else if (!strcmp (pa_def_subspaces[i].name, "$UNWIND$") && !USE_ALIASES) + else if (!strcmp (pa_def_subspaces[i].name, "$UNWIND$")) { applicable = bfd_applicable_section_flags (stdoutput); bfd_set_section_flags (stdoutput, segment, @@ -6037,7 +6804,7 @@ create_new_subspace (space, name, loadable, code_only, common, we'll set it to 1 which "locks-in" the subspace attributes. */ SUBSPACE_DEFINED (chain_entry) = 0; - chain_entry->ssd_subseg = USE_ALIASES ? pa_next_subseg (space) : 0; + chain_entry->ssd_subseg = 0; chain_entry->ssd_seg = seg; chain_entry->ssd_next = NULL; @@ -6256,7 +7023,6 @@ pa_subspace_start (space, quadrant) sd_chain_struct *space; int quadrant; { -#ifdef OBJ_SOM /* FIXME. Assumes everyone puts read/write data at 0x4000000, this is not correct for the PA OSF1 port. */ if ((strcmp (SPACE_NAME (space), "$PRIVATE$") == 0) && quadrant == 1) @@ -6265,7 +7031,6 @@ pa_subspace_start (space, quadrant) return 0x40000000; else return 0; -#endif return 0; } @@ -6278,6 +7043,7 @@ pa_next_subseg (space) space->sd_last_subseg++; return space->sd_last_subseg; } +#endif /* Helper function for pa_stringer. Used to find the end of a string. */ @@ -6288,8 +7054,10 @@ pa_stringer_aux (s) { unsigned int c = *s & CHAR_MASK; +#ifdef OBJ_SOM /* We must have a valid space and subspace. */ pa_check_current_space_and_subspace (); +#endif switch (c) { @@ -6430,9 +7198,11 @@ static void pa_data (unused) int unused; { +#ifdef OBJ_SOM current_space = is_defined_space ("$PRIVATE$"); current_subspace = pa_subsegment_to_subspace (current_space->sd_seg, 0); +#endif s_data (0); pa_undefine_label (); } @@ -6453,8 +7223,10 @@ static void pa_fill (unused) int unused; { +#ifdef OBJ_SOM /* We must have a valid space and subspace. */ pa_check_current_space_and_subspace (); +#endif s_fill (0); pa_undefine_label (); @@ -6466,8 +7238,10 @@ static void pa_lcomm (needs_align) int needs_align; { +#ifdef OBJ_SOM /* We must have a valid space and subspace. */ pa_check_current_space_and_subspace (); +#endif s_lcomm (needs_align); pa_undefine_label (); @@ -6479,8 +7253,10 @@ static void pa_lsym (unused) int unused; { +#ifdef OBJ_SOM /* We must have a valid space and subspace. */ pa_check_current_space_and_subspace (); +#endif s_lsym (0); pa_undefine_label (); @@ -6492,9 +7268,11 @@ static void pa_text (unused) int unused; { +#ifdef OBJ_SOM current_space = is_defined_space ("$TEXT$"); current_subspace = pa_subsegment_to_subspace (current_space->sd_seg, 0); +#endif s_text (0); pa_undefine_label (); @@ -6549,7 +7327,7 @@ hppa_fix_adjustable (fixp) && (hppa_fix->segment->flags & SEC_CODE)) { /* Apparently sy_used_in_reloc never gets set for sub symbols. */ - fixp->fx_subsy->sy_used_in_reloc = 1; + symbol_mark_used_in_reloc (fixp->fx_subsy); return 0; } @@ -6571,7 +7349,7 @@ hppa_fix_adjustable (fixp) || hppa_fix->fx_r_field == e_lpsel) return 0; - if (fixp->fx_addsy && fixp->fx_addsy->bsym->flags & BSF_GLOBAL) + if (fixp->fx_addsy && S_IS_EXTERNAL (fixp->fx_addsy)) return 0; /* Reject absolute calls (jumps). */ @@ -6579,8 +7357,7 @@ hppa_fix_adjustable (fixp) return 0; /* Reject reductions of function symbols. */ - if (fixp->fx_addsy == 0 - || (fixp->fx_addsy->bsym->flags & BSF_FUNCTION) == 0) + if (fixp->fx_addsy == 0 || ! S_IS_FUNCTION (fixp->fx_addsy)) return 1; return 0; @@ -6612,15 +7389,16 @@ hppa_force_relocation (fixp) #define arg_reloc_stub_needed(CALLER, CALLEE) \ ((CALLEE) && (CALLER) && ((CALLEE) != (CALLER))) +#ifdef OBJ_SOM /* It is necessary to force PC-relative calls/jumps to have a relocation entry if they're going to need either a argument relocation or long call stub. FIXME. Can't we need the same for absolute calls? */ if (fixp->fx_pcrel && fixp->fx_addsy && (arg_reloc_stub_needed ((long) ((obj_symbol_type *) - fixp->fx_addsy->bsym)->tc_data.ap.hppa_arg_reloc, - - hppa_fixp->fx_arg_reloc))) + symbol_get_bfdsym (fixp->fx_addsy))->tc_data.ap.hppa_arg_reloc, + hppa_fixp->fx_arg_reloc))) return 1; +#endif distance = (fixp->fx_offset + S_GET_VALUE (fixp->fx_addsy) - md_pcrel_from (fixp)); /* Now check and see if we're going to need a long-branch stub. */ @@ -6677,7 +7455,7 @@ hppa_elf_mark_end_of_function () frag_now); assert (symbolP); - symbolP->bsym->flags = BSF_LOCAL; + S_CLEAR_EXTERNAL (symbolP); symbol_table_insert (symbolP); } @@ -6707,7 +7485,8 @@ elf_hppa_final_processing () call_info_pointer = call_info_pointer->ci_next) { elf_symbol_type *esym - = (elf_symbol_type *) call_info_pointer->start_symbol->bsym; + = ((elf_symbol_type *) + symbol_get_bfdsym (call_info_pointer->start_symbol)); esym->internal_elf_sym.st_size = S_GET_VALUE (call_info_pointer->end_symbol) - S_GET_VALUE (call_info_pointer->start_symbol) + 4;