X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-hppa.c;h=5f938c5df44c91a029a8af59757326094cdc76dc;hb=e7c1f43c29d3e1d681c2dbc7aacf33d78af2b929;hp=7539f036e9bc0b8fb1d314c01af2ca3a4b0096a2;hpb=fb338f1d79bf2e003a78c8bc6003c409512ca1ed;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-hppa.c b/gas/config/tc-hppa.c index 7539f036e9..5f938c5df4 100644 --- a/gas/config/tc-hppa.c +++ b/gas/config/tc-hppa.c @@ -1,11 +1,12 @@ /* tc-hppa.c -- Assemble for the PA - Copyright (C) 1989 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. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 1, or (at your option) + the Free Software Foundation; either version 2, or (at your option) any later version. GAS is distributed in the hope that it will be useful, @@ -14,8 +15,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with GAS; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ /* HP PA-RISC support was contributed by the Center for Software Science @@ -27,38 +29,38 @@ #include "as.h" #include "subsegs.h" -#include "../bfd/libhppa.h" -#include "../bfd/libbfd.h" +#include "bfd/libhppa.h" +#include "bfd/libbfd.h" /* 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 ".hppa_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 @@ -75,14 +77,24 @@ 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 /* Object file formats specify BFD symbol types. */ typedef som_symbol_type obj_symbol_type; + +/* This apparently isn't in older versions of hpux reloc.h. */ +#ifndef R_DLT_REL +#define R_DLT_REL 0x78 +#endif +#endif + +#ifndef R_N0SEL +#define R_N0SEL 0xd8 +#endif + +#ifndef R_N1SEL +#define R_N1SEL 0xd9 #endif /* Various structures and types used internally in tc-hppa.c. */ @@ -152,7 +164,7 @@ struct call_info SGL and DBL). */ typedef enum { - SGL, DBL, ILLEGAL_FMT, QUAD + SGL, DBL, ILLEGAL_FMT, QUAD, W, UW, DW, UDW, QW, UQW } fp_operand_format; @@ -173,7 +185,7 @@ typedef enum } pa_symbol_type; -/* This structure contains information needed to assemble +/* This structure contains information needed to assemble individual instructions. */ struct pa_it { @@ -190,6 +202,7 @@ struct pa_it fp_operand_format fpof1; fp_operand_format fpof2; + /* Holds the field selector for this instruction (for example L%, LR%, etc). */ long field_selector; @@ -231,9 +244,9 @@ struct pa_it handles the L/R notation and returns the correct value to put into the instruction register field. The correct value to put into the instruction is - encoded in the structure 'pa_89_fp_reg_struct'. */ + encoded in the structure 'pa_11_fp_reg_struct'. */ -struct pa_89_fp_reg_struct +struct pa_11_fp_reg_struct { /* The register number. */ char number_part; @@ -252,6 +265,7 @@ struct call_desc unsigned int arg_count; }; +#ifdef OBJ_SOM /* This structure defines an entry in the subspace dictionary chain. */ @@ -278,7 +292,7 @@ typedef struct subspace_dictionary_chain ssd_chain_struct; struct space_dictionary_chain { - /* Nonzero if this space has been defined by the user code or + /* Nonzero if this space has been defined by the user code or as a default space. */ unsigned int sd_defined; @@ -306,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. */ @@ -363,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; }; @@ -396,16 +396,30 @@ 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 { /* The field selector. */ - enum hppa_reloc_field_selector_type fx_r_field; + enum hppa_reloc_field_selector_type_alt fx_r_field; /* Type of fixup. */ int fx_r_type; @@ -416,9 +430,6 @@ struct hppa_fix_struct /* Argument relocation bits. */ long fx_arg_reloc; - /* The unwind descriptor associated with this fixup. */ - char fx_unwind[8]; - /* The segment this fixup appears in. */ segT segment; }; @@ -449,6 +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)); @@ -471,6 +486,8 @@ 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_block PARAMS ((int)); +static void pa_brtab PARAMS ((int)); +static void pa_try PARAMS ((int)); static void pa_call PARAMS ((int)); static void pa_call_args PARAMS ((struct call_desc *)); static void pa_callinfo PARAMS ((int)); @@ -487,29 +504,33 @@ static void pa_type_args PARAMS ((symbolS *, int)); static void pa_import PARAMS ((int)); static void pa_label PARAMS ((int)); static void pa_leave PARAMS ((int)); +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_89_opcode PARAMS ((struct pa_it *, - struct pa_89_fp_reg_struct *)); -static int pa_parse_number PARAMS ((char **, struct pa_89_fp_reg_struct *)); +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)); -static sd_chain_struct *create_new_space PARAMS ((char *, int, char, - char, char, char, +#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)); static ssd_chain_struct *create_new_subspace PARAMS ((sd_chain_struct *, - char *, char, char, - char, char, char, - char, int, int, int, + char *, int, int, + int, int, int, + int, int, int, int, int, asection *)); static ssd_chain_struct *update_subspace PARAMS ((sd_chain_struct *, - char *, char, char, char, - char, char, char, int, + char *, int, int, int, + int, int, int, int, int, int, int, asection *)); static sd_chain_struct *is_defined_space PARAMS ((char *)); @@ -519,27 +540,32 @@ 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, short int, symbolS *, +static void fix_new_hppa PARAMS ((fragS *, int, int, symbolS *, long, expressionS *, int, bfd_reloc_code_real_type, - enum hppa_reloc_field_selector_type, - int, long, char *)); + enum hppa_reloc_field_selector_type_alt, + int, long, int *)); static int is_end_of_statement PARAMS ((void)); 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 pa_build_unwind_subspace PARAMS ((struct call_info *)); 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)); +static void pa_build_unwind_subspace PARAMS ((struct call_info *)); +#endif /* 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; @@ -547,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; @@ -559,14 +586,6 @@ static struct call_info *last_call_info; /* The last call description (for actual calls). */ static struct call_desc last_call_desc; -/* Relaxation isn't supported for the PA yet. */ -const relax_typeS md_relax_table[] = -{0}; - -/* Jumps are always the same size -- one instruction. */ -int md_short_jump_size = 4; -int md_long_jump_size = 4; - /* handle of the OPCODE hash table */ static struct hash_control *op_hash = NULL; @@ -581,96 +600,72 @@ 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}, - {"ALIGN", s_align_bytes, 8}, +#endif + {"begin_brtab", pa_brtab, 1}, + {"begin_try", pa_try, 1}, {"block", pa_block, 1}, - {"BLOCK", pa_block, 1}, {"blockz", pa_block, 0}, - {"BLOCKZ", pa_block, 0}, {"byte", pa_cons, 1}, - {"BYTE", pa_cons, 1}, {"call", pa_call, 0}, - {"CALL", pa_call, 0}, {"callinfo", pa_callinfo, 0}, - {"CALLINFO", pa_callinfo, 0}, {"code", pa_code, 0}, - {"CODE", pa_code, 0}, {"comm", pa_comm, 0}, - {"COMM", pa_comm, 0}, +#ifdef OBJ_SOM + {"compiler", pa_compiler, 0}, +#endif {"copyright", pa_copyright, 0}, - {"COPYRIGHT", pa_copyright, 0}, {"data", pa_data, 0}, - {"DATA", pa_data, 0}, {"double", pa_float_cons, 'd'}, - {"DOUBLE", pa_float_cons, 'd'}, + {"dword", pa_cons, 8}, {"end", pa_end, 0}, - {"END", pa_end, 0}, + {"end_brtab", pa_brtab, 0}, + {"end_try", pa_try, 0}, {"enter", pa_enter, 0}, - {"ENTER", pa_enter, 0}, {"entry", pa_entry, 0}, - {"ENTRY", pa_entry, 0}, {"equ", pa_equ, 0}, - {"EQU", pa_equ, 0}, {"exit", pa_exit, 0}, - {"EXIT", pa_exit, 0}, {"export", pa_export, 0}, - {"EXPORT", pa_export, 0}, {"fill", pa_fill, 0}, - {"FILL", pa_fill, 0}, {"float", pa_float_cons, 'f'}, - {"FLOAT", pa_float_cons, 'f'}, {"half", pa_cons, 2}, - {"HALF", pa_cons, 2}, {"import", pa_import, 0}, - {"IMPORT", pa_import, 0}, {"int", pa_cons, 4}, - {"INT", pa_cons, 4}, {"label", pa_label, 0}, - {"LABEL", pa_label, 0}, {"lcomm", pa_lcomm, 0}, - {"LCOMM", pa_lcomm, 0}, {"leave", pa_leave, 0}, - {"LEAVE", pa_leave, 0}, + {"level", pa_level, 0}, {"long", pa_cons, 4}, - {"LONG", pa_cons, 4}, {"lsym", pa_lsym, 0}, - {"LSYM", pa_lsym, 0}, +#ifdef OBJ_SOM + {"nsubspa", pa_subspace, 1}, +#endif {"octa", pa_cons, 16}, - {"OCTA", pa_cons, 16}, {"org", pa_origin, 0}, - {"ORG", pa_origin, 0}, {"origin", pa_origin, 0}, - {"ORIGIN", pa_origin, 0}, {"param", pa_param, 0}, - {"PARAM", pa_param, 0}, {"proc", pa_proc, 0}, - {"PROC", pa_proc, 0}, {"procend", pa_procend, 0}, - {"PROCEND", pa_procend, 0}, {"quad", pa_cons, 8}, - {"QUAD", pa_cons, 8}, {"reg", pa_equ, 1}, - {"REG", pa_equ, 1}, {"short", pa_cons, 2}, - {"SHORT", pa_cons, 2}, {"single", pa_float_cons, 'f'}, - {"SINGLE", pa_float_cons, 'f'}, +#ifdef OBJ_SOM {"space", pa_space, 0}, - {"SPACE", pa_space, 0}, {"spnum", pa_spnum, 0}, - {"SPNUM", pa_spnum, 0}, +#endif {"string", pa_stringer, 0}, - {"STRING", pa_stringer, 0}, {"stringz", pa_stringer, 1}, - {"STRINGZ", pa_stringer, 1}, +#ifdef OBJ_SOM {"subspa", pa_subspace, 0}, - {"SUBSPA", pa_subspace, 0}, +#endif {"text", pa_text, 0}, - {"TEXT", pa_text, 0}, {"version", pa_version, 0}, - {"VERSION", pa_version, 0}, {"word", pa_cons, 4}, - {"WORD", pa_cons, 4}, {NULL, 0, 0} }; @@ -682,7 +677,7 @@ const pseudo_typeS md_pseudo_table[] = first line of the input file. This is because the compiler outputs #NO_APP at the beginning of its output. - Also note that '/*' will always start a comment. */ + Also note that C style comments will always work. */ const char line_comment_chars[] = "#"; /* This array holds the characters which act as line separators. */ @@ -692,9 +687,9 @@ const char line_separator_chars[] = "!"; const char EXP_CHARS[] = "eE"; /* Chars that mean this number is a floating point constant. - As in 0f12.456 or 0d1.2345e12. + As in 0f12.456 or 0d1.2345e12. - Be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be + Be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be changed in read.c. Ideally it shouldn't hae to know abou it at all, but nothing is ideal around here. */ const char FLT_CHARS[] = "rRsSfFdDxXpP"; @@ -722,8 +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; @@ -731,10 +734,10 @@ static int print_errors = 1; /* List of registers that are pre-defined: Each general register has one predefined name of the form - %r which has the value . + %r which has the value . Space and control registers are handled in a similar manner, - but use %sr and %cr as their predefined names. + but use %sr and %cr as their predefined names. Likewise for the floating point registers, but of the form %fr. Floating point registers have additional predefined @@ -750,7 +753,7 @@ static int print_errors = 1; %r2 has %rp as a synonym Almost every control register has a synonym; they are not listed - here for brevity. + here for brevity. The table is sorted. Suitable for searching by a binary search. */ @@ -955,7 +958,7 @@ static const struct pd_reg pre_defined_registers[] = }; /* This table is sorted by order of the length of the string. This is - so we check for <> before we check for <. If we had a <> and checked + so we check for <> before we check for <. If we had a <> and checked for < first, we would get a false match. */ static const struct fp_cond_map fp_cond_map[] = { @@ -1002,6 +1005,10 @@ 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}, {"p", e_psel}, {"r", e_rsel}, {"rd", e_rdsel}, @@ -1009,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 @@ -1019,8 +1028,9 @@ static const struct selector_entry selector_table[] = /* pre-defined subsegments (subspaces) for the HPPA. */ #define SUBSEG_CODE 0 -#define SUBSEG_DATA 0 #define SUBSEG_LIT 1 +#define SUBSEG_MILLI 2 +#define SUBSEG_DATA 0 #define SUBSEG_BSS 2 #define SUBSEG_UNWIND 3 #define SUBSEG_GDB_STRINGS 0 @@ -1028,30 +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}, - {"$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, ".hppa_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 @@ -1060,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. */ @@ -1070,7 +1079,7 @@ static struct default_space_dict pa_def_spaces[] = continue; \ } -/* Simple range checking for FIELD againt HIGH and LOW bounds. +/* Simple range checking for FIELD againt HIGH and LOW bounds. IGNORE is used to suppress the error message. */ #define CHECK_FIELD(FIELD, HIGH, LOW, IGNORE) \ @@ -1078,7 +1087,7 @@ static struct default_space_dict pa_def_spaces[] = if ((FIELD) > (HIGH) || (FIELD) < (LOW)) \ { \ if (! IGNORE) \ - as_bad ("Field out of range [%d..%d] (%d).", (LOW), (HIGH), \ + as_bad (_("Field out of range [%d..%d] (%d)."), (LOW), (HIGH), \ (int) (FIELD));\ break; \ } \ @@ -1086,17 +1095,33 @@ 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 + need real complex handling yet. */ #define is_complex(exp) \ ((exp).X_op != O_constant && (exp).X_op != O_symbol) /* Actual functions to implement the PA specific code for the assembler. */ +/* Called before writing the object file. Make sure entry/exit and + proc/procend pairs match. */ + +void +pa_check_eof () +{ + if (within_entry_exit) + as_fatal (_("Missing .exit\n")); + + if (within_procedure) + as_fatal (_("Missing .procend\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. */ @@ -1104,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; } @@ -1123,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; @@ -1133,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) @@ -1151,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) @@ -1177,24 +1219,24 @@ pa_undefine_label () code needs to keep track of some extra stuff. Each call to fix_new_hppa results in the creation of an instance of an hppa_fix_struct. An hppa_fix_struct stores the extra information along with a pointer to the - original fixS. This is attached to the original fixup via the + original fixS. This is attached to the original fixup via the tc_fix_data field. */ static void fix_new_hppa (frag, where, size, add_symbol, offset, exp, pcrel, - r_type, r_field, r_format, arg_reloc, unwind_desc) + r_type, r_field, r_format, arg_reloc, unwind_bits) fragS *frag; int where; - short int size; + int size; symbolS *add_symbol; long offset; expressionS *exp; int pcrel; bfd_reloc_code_real_type r_type; - enum hppa_reloc_field_selector_type r_field; + enum hppa_reloc_field_selector_type_alt r_field; int r_format; long arg_reloc; - char *unwind_desc; + int* unwind_bits; { fixS *new_fix; @@ -1211,17 +1253,10 @@ fix_new_hppa (frag, where, size, add_symbol, offset, exp, pcrel, hppa_fix->fx_r_format = r_format; hppa_fix->fx_arg_reloc = arg_reloc; hppa_fix->segment = now_seg; - if (unwind_desc) - { - bcopy (unwind_desc, hppa_fix->fx_unwind, 8); - - /* If necessary call BFD backend function to attach the - unwind bits to the target dependent parts of a BFD symbol. - Yuk. */ -#ifdef obj_attach_unwind_info - obj_attach_unwind_info (add_symbol->bsym, unwind_desc); +#ifdef OBJ_SOM + if (r_type == R_ENTRY || r_type == R_EXIT) + new_fix->fx_offset = *unwind_bits; #endif - } /* foo-$global$ is used to access non-automatic storage. $global$ is really just a marker and has served its purpose, so eliminate @@ -1254,6 +1289,7 @@ cons_fix_new_hppa (frag, where, size, exp) { unsigned int rel_type; + /* Get a base relocation type. */ if (is_DP_relative (*exp)) rel_type = R_HPPA_GOTOFF; else if (is_complex (*exp)) @@ -1262,11 +1298,11 @@ cons_fix_new_hppa (frag, where, size, exp) rel_type = R_HPPA; if (hppa_field_selector != e_psel && hppa_field_selector != e_fsel) - as_warn ("Invalid field selector. Assuming F%%."); + as_warn (_("Invalid field selector. Assuming F%%.")); fix_new_hppa (frag, where, size, (symbolS *) NULL, (offsetT) 0, exp, 0, rel_type, - hppa_field_selector, 32, 0, (char *) 0); + hppa_field_selector, size * 8, 0, NULL); /* Reset field selector to its default state. */ hppa_field_selector = 0; @@ -1285,16 +1321,21 @@ md_begin () last_call_info = NULL; call_info_root = NULL; + /* Set the default machine type. */ + if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 10)) + as_warn (_("could not set architecture and machine")); + /* Folding of text and data segments fails miserably on the PA. Warn user and disable "-R" option. */ - if (flagseen['R']) + if (flag_readonly_data_in_text) { - as_warn ("-R option not supported on this target."); + as_warn (_("-R option not supported on this target.")); flag_readonly_data_in_text = 0; - flagseen['R'] = 0; } +#ifdef OBJ_SOM pa_spaces_begin (); +#endif op_hash = hash_new (); @@ -1304,7 +1345,7 @@ md_begin () retval = hash_insert (op_hash, name, (struct pa_opcode *) &pa_opcodes[i]); if (retval != NULL && *retval != '\0') { - as_fatal ("Internal error: can't hash `%s': %s\n", name, retval); + as_fatal (_("Internal error: can't hash `%s': %s\n"), name, retval); lose = 1; } do @@ -1312,7 +1353,7 @@ md_begin () if ((pa_opcodes[i].match & pa_opcodes[i].mask) != pa_opcodes[i].match) { - fprintf (stderr, "internal error: losing opcode: `%s' \"%s\"\n", + fprintf (stderr, _("internal error: losing opcode: `%s' \"%s\"\n"), pa_opcodes[i].name, pa_opcodes[i].args); lose = 1; } @@ -1322,14 +1363,20 @@ md_begin () } if (lose) - as_fatal ("Broken assembler. No assembly attempted."); + 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. */ @@ -1344,7 +1391,7 @@ md_assemble (str) /* If we are within a procedure definition, make sure we've defined a label for the procedure; handle case where the - label was defined after the .PROC directive. + label was defined after the .PROC directive. Note there's not need to diddle with the segment or fragment for the label symbol in this case. We have already switched @@ -1358,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. */ @@ -1367,17 +1415,17 @@ md_assemble (str) char *where = frag_more (0); fix_new_hppa (frag_now, where - frag_now->fr_literal, 0, - last_call_info->start_symbol, (offsetT) 0, NULL, + NULL, (offsetT) 0, NULL, 0, R_HPPA_ENTRY, e_fsel, 0, 0, - (char *) &last_call_info->ci_unwind.descriptor); + (int *)&last_call_info->ci_unwind.descriptor); } #endif } else - as_bad ("Missing function name for .PROC (corrupted label chain)"); + as_bad (_("Missing function name for .PROC (corrupted label chain)")); } else - as_bad ("Missing function name for .PROC"); + as_bad (_("Missing function name for .PROC")); } /* Assemble the instruction. Results are saved into "the_insn". */ @@ -1413,6 +1461,17 @@ 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) ; @@ -1433,20 +1492,11 @@ pa_ip (str) break; default: - as_bad ("Unknown opcode: `%s'", str); - exit (1); + as_fatal (_("Unknown opcode: `%s'"), 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) { @@ -1466,14 +1516,35 @@ pa_ip (str) { /* Do some initialization. */ opcode = insn->match; - bzero (&the_insn, sizeof (the_insn)); + strict = (insn->flags & FLAG_STRICT); + memset (&the_insn, 0, sizeof (the_insn)); the_insn.reloc = R_HPPA_NONE; + /* If this instruction is specific to a particular architecture, + then set a new architecture. */ + /* But do not automatically promote to pa2.0. The automatic promotion + crud is for compatability with HP's old assemblers only. */ + if (insn->arch < 20 + && bfd_get_mach (stdoutput) < insn->arch) + { + if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, insn->arch)) + as_warn (_("could not update architecture and machine")); + } + else if (bfd_get_mach (stdoutput) < insn->arch) + { + match = FALSE; + goto failed; + } + /* Build the opcode, checking as we go to make sure that the operands match. */ for (args = insn->args;; ++args) { + /* Absorb white space in instruction. */ + while (*s == ' ' || *s == '\t') + s++; + switch (*args) { @@ -1505,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); @@ -1532,489 +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) - low_sign_unext (num, 5, &num); + /* 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; + + opcode |= m << 5; + INSERT_FIELD_AND_CONTINUE (opcode, a, 13); } - 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 - as_bad ("Invalid Store Bytes Short Completer"); - s++; - i++; + 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")); + 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 + /* Handle MFCTL wide completer. */ + case 'W': + if (strncasecmp (s, ",w", 2) != 0) + break; + s += 2; + continue; + + /* Handle an RFI restore completer. */ + case 'r': + flag = 0; + if (!strncasecmp (s, ",r", 2)) { - /* Negated condition requires an opcode change. */ - opcode |= 1 << 27; + flag = 5; + s += 2; } - } - INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13); - /* Handle a compare/subtract condition. */ - case 'a': - cmpltr = 0; - flag = 0; - save_s = s; - if (*s == ',') - { - cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s, 0); - if (cmpltr < 0) + INSERT_FIELD_AND_CONTINUE (opcode, flag, 5); + + /* Handle a system control completer. */ + case 'Z': + if (*s == ',' && (*(s + 1) == 'm' || *(s + 1) == 'M')) { flag = 1; - s = save_s; - cmpltr = pa_parse_neg_cmpsub_cmpltr (&s, 0); - if (cmpltr < 0) - { - as_bad ("Invalid Compare/Subtract Condition"); - } + s += 2; } - } - opcode |= cmpltr << 13; - INSERT_FIELD_AND_CONTINUE (opcode, flag, 12); + else + flag = 0; - /* Handle a non-negated add condition. */ - case 'd': - cmpltr = 0; - nullif = 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, "n") == 0) - nullif = 1; - else if (strcasecmp (name, "tr") == 0) + INSERT_FIELD_AND_CONTINUE (opcode, flag, 5); + + /* Handle intermediate/final completer for DCOR. */ + case 'i': + flag = 0; + if (!strncasecmp (s, ",i", 2)) { - cmpltr = 0; 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 = 1; - flag = 1; + flag = 0; + s += 2; } - else if (strcmp (name, ">=") == 0) - { - cmpltr = 2; - flag = 1; - } - else if (strcmp (name, ">") == 0) - { - cmpltr = 3; - flag = 1; - } - 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; - } - nullif = pa_parse_nullif (&s); - opcode |= nullif << 1; - 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); + break; - /* Handle a unit instruction condition. */ - case 'U': - cmpltr = 0; - flag = 0; - if (*s == ',') - { - s++; - 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) + INSERT_FIELD_AND_CONTINUE (opcode, flag, 11); + + /* Handle 64 bit borrow for SUB. */ + case 'B': + flag = 0; + if (!strncasecmp (s, ",db,tsv", 7) || + !strncasecmp (s, ",tsv,db", 7)) { - 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 = 2; - s++; - } - else if (strncmp (s, ">=", 2) == 0) - { - cmpltr = 6; - s += 2; - } - else - as_bad ("Invalid Bit Branch Condition: %c", *s); + default: + abort (); } - INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13); + 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); - INSERT_FIELD_AND_CONTINUE (opcode, flag, 5); + /* 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++; + + /* 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': @@ -2026,6 +2651,7 @@ pa_ip (str) nullif = pa_parse_nullif (&s); INSERT_FIELD_AND_CONTINUE (opcode, nullif, 5); + /* Handle a 11 bit immediate at 31. */ case 'i': the_insn.field_selector = pa_chk_field_selector (&s); @@ -2044,14 +2670,13 @@ pa_ip (str) the_insn.reloc = R_HPPA_GOTOFF; else if (is_PC_relative (the_insn.exp)) the_insn.reloc = R_HPPA_PCREL_CALL; - else if (is_complex (the_insn.exp)) - the_insn.reloc = R_HPPA_COMPLEX; else the_insn.reloc = R_HPPA; the_insn.format = 11; continue; } + /* Handle a 14 bit immediate at 31. */ case 'j': the_insn.field_selector = pa_chk_field_selector (&s); @@ -2070,8 +2695,6 @@ pa_ip (str) the_insn.reloc = R_HPPA_GOTOFF; else if (is_PC_relative (the_insn.exp)) the_insn.reloc = R_HPPA_PCREL_CALL; - else if (is_complex (the_insn.exp)) - the_insn.reloc = R_HPPA_COMPLEX; else the_insn.reloc = R_HPPA; the_insn.format = 14; @@ -2096,8 +2719,6 @@ pa_ip (str) the_insn.reloc = R_HPPA_GOTOFF; else if (is_PC_relative (the_insn.exp)) the_insn.reloc = R_HPPA_PCREL_CALL; - else if (is_complex (the_insn.exp)) - the_insn.reloc = R_HPPA_COMPLEX; else the_insn.reloc = R_HPPA; the_insn.format = 21; @@ -2117,23 +2738,20 @@ pa_ip (str) num = evaluate_absolute (&the_insn); if (num % 4) { - as_bad ("Branch to unaligned address"); + as_bad (_("Branch to unaligned address")); break; } - CHECK_FIELD (num, 8191, -8192, 0); + CHECK_FIELD (num, 8199, -8184, 0); sign_unext ((num - 8) >> 2, 12, &result); dis_assemble_12 (result, &w1, &w); INSERT_FIELD_AND_CONTINUE (opcode, ((w1 << 2) | w), 0); } else { - if (is_complex (the_insn.exp)) - the_insn.reloc = R_HPPA_COMPLEX_PCREL_CALL; - else - the_insn.reloc = R_HPPA_PCREL_CALL; + the_insn.reloc = R_HPPA_PCREL_CALL; the_insn.format = 12; the_insn.arg_reloc = last_call_desc.arg_reloc; - bzero (&last_call_desc, sizeof (struct call_desc)); + memset (&last_call_desc, 0, sizeof (struct call_desc)); s = expr_end; continue; } @@ -2153,7 +2771,7 @@ pa_ip (str) num = evaluate_absolute (&the_insn); if (num % 4) { - as_bad ("Branch to unaligned address"); + as_bad (_("Branch to unaligned address")); break; } CHECK_FIELD (num, 262143, -262144, 0); @@ -2168,13 +2786,10 @@ pa_ip (str) } else { - if (is_complex (the_insn.exp)) - the_insn.reloc = R_HPPA_COMPLEX_PCREL_CALL; - else - the_insn.reloc = R_HPPA_PCREL_CALL; + the_insn.reloc = R_HPPA_PCREL_CALL; the_insn.format = 17; the_insn.arg_reloc = last_call_desc.arg_reloc; - bzero (&last_call_desc, sizeof (struct call_desc)); + memset (&last_call_desc, 0, sizeof (struct call_desc)); continue; } @@ -2193,7 +2808,7 @@ pa_ip (str) num = evaluate_absolute (&the_insn); if (num % 4) { - as_bad ("Branch to unaligned address"); + as_bad (_("Branch to unaligned address")); break; } CHECK_FIELD (num, 262143, -262144, 0); @@ -2208,106 +2823,205 @@ pa_ip (str) } else { - if (is_complex (the_insn.exp)) - the_insn.reloc = R_HPPA_COMPLEX_ABS_CALL; - else - the_insn.reloc = R_HPPA_ABS_CALL; + the_insn.reloc = R_HPPA_ABS_CALL; the_insn.format = 17; + the_insn.arg_reloc = last_call_desc.arg_reloc; + memset (&last_call_desc, 0, sizeof (struct call_desc)); 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, 4095, -4096, 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); - INSERT_FIELD_AND_CONTINUE (opcode, num, 1); + 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"); + 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); /* Handle a 3-bit co-processor ID field. */ case 'u': if (*s++ != ',') - as_bad ("Invalid COPR identifier"); + 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); + /* Handle a source FP operand format completer. */ case 'F': flag = pa_parse_fp_format (&s); @@ -2322,166 +3036,301 @@ 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_89_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; - /* 0x30 opcodes are FP arithmetic operation opcodes - and need to be turned into 0x38 opcodes. This - is not necessary for loads/stores. */ - if (need_89_opcode (&the_insn, &result) - && ((opcode & 0xfc000000) == 0x30000000)) - opcode |= 1 << 27; + /* 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); - INSERT_FIELD_AND_CONTINUE (opcode, result.l_r_select & 1, 6); - } + /* Float target register with L/R selection. */ + case 'T': + { + struct pa_11_fp_reg_struct result; - /* Handle L/R register halves like 'b'. */ - case 'E': - { - struct pa_89_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; + + /* 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; - pa_parse_number (&s, &result); - CHECK_FIELD (result.number_part, 31, 0, 0); - opcode |= result.number_part << 21; - if (need_89_opcode (&the_insn, &result)) + INSERT_FIELD_AND_CONTINUE (opcode, result.l_r_select & 1, 6); + } + + /* Float operand 1. */ + case 'a': { + 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; + if (need_pa11_opcode (&the_insn, &result)) + { + opcode |= (result.l_r_select & 1) << 7; + opcode |= 1 << 27; + } + continue; + } + + /* Float operand 1 with L/R selection. */ + case 'A': + { + 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; - opcode |= 1 << 27; + continue; } - continue; - } - /* Handle L/R register halves like 'x'. */ - case 'X': - { - struct pa_89_fp_reg_struct result; + /* Float operand 2. */ + case 'b': + { + struct pa_11_fp_reg_struct result; - pa_parse_number (&s, &result); - CHECK_FIELD (result.number_part, 31, 0, 0); - opcode |= (result.number_part & 0x1f) << 16; - if (need_89_opcode (&the_insn, &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; + } + + /* 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_89_fp_reg_struct result; - - pa_parse_number (&s, &result); - CHECK_FIELD (result.number_part, 31, 0, 0); - if (the_insn.fpof1 == SGL) + /* Float operand 3 for fmpyfadd, fmpynfadd. */ + case 'C': { - result.number_part &= 0xF; - result.number_part |= (result.l_r_select & 1) << 4; - } - INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 21); - } + struct pa_11_fp_reg_struct result; + int regnum; - /* Handle a 5 bit register field at 15. */ - case '6': - { - struct pa_89_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 & 0x1c) << 11; + opcode |= (result.number_part & 0x3) << 9; + opcode |= (result.l_r_select & 1) << 8; + continue; + } - pa_parse_number (&s, &result); - CHECK_FIELD (result.number_part, 31, 0, 0); - if (the_insn.fpof1 == SGL) + /* Float mult operand 1 for fmpyadd, fmpysub */ + case 'i': { - result.number_part &= 0xF; - result.number_part |= (result.l_r_select & 1) << 4; + 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, 21); } - INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 16); - } - /* Handle a 5 bit register field at 31. */ - case '7': - { - struct pa_89_fp_reg_struct result; + /* Float mult operand 2 for fmpyadd, fmpysub */ + case 'j': + { + 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, 16); + } - 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': { - result.number_part &= 0xF; - result.number_part |= (result.l_r_select & 1) << 4; + 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, 0); } - INSERT_FIELD_AND_CONTINUE (opcode, result.number_part, 0); - } - /* Handle a 5 bit register field at 20. */ - case '8': - { - struct pa_89_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': { - result.number_part &= 0xF; - result.number_part |= (result.l_r_select & 1) << 4; + 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, 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_89_fp_reg_struct result; + 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)) { - 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 (); } break; } + failed: /* Check if the args matched. */ if (match == FALSE) { - if (&insn[1] - pa_opcodes < NUMOPCODES + if (&insn[1] - pa_opcodes < (int) NUMOPCODES && !strcmp (insn->name, insn[1].name)) { ++insn; @@ -2490,7 +3339,7 @@ pa_ip (str) } else { - as_bad ("Invalid operands %s", error_message); + as_bad (_("Invalid operands %s"), error_message); return; } } @@ -2546,7 +3395,7 @@ md_atof (type, litP, sizeP) default: *sizeP = 0; - return "Bad call to MD_ATOF()"; + return _("Bad call to MD_ATOF()"); } t = atof_ieee (input_line_pointer, type, words); if (t) @@ -2582,8 +3431,6 @@ tc_gen_reloc (section, fixp) arelent *reloc; struct hppa_fix_struct *hppa_fixp; bfd_reloc_code_real_type code; - static int unwind_reloc_fixp_cnt = 0; - static arelent *unwind_reloc_entryP = NULL; static arelent *no_relocs = NULL; arelent **relocs; bfd_reloc_code_real_type **codes; @@ -2596,79 +3443,25 @@ tc_gen_reloc (section, fixp) assert (hppa_fixp != 0); assert (section != 0); -#ifdef OBJ_ELF - /* Yuk. I would really like to push all this ELF specific unwind - crud into BFD and the linker. That's how SOM does it -- and - if we could make ELF emulate that then we could share more code - in GAS (and potentially a gnu-linker later). - - Unwind section relocations are handled in a special way. - The relocations for the .unwind section are originally - built in the usual way. That is, for each unwind table - entry there are two relocations: one for the beginning of - the function and one for the end. - - The first time we enter this function we create a - relocation of the type R_HPPA_UNWIND_ENTRIES. The addend - of the relocation is initialized to 0. Each additional - pair of times this function is called for the unwind - section represents an additional unwind table entry. Thus, - the addend of the relocation should end up to be the number - of unwind table entries. */ - if (strcmp (UNWIND_SECTION_NAME, section->name) == 0) - { - if (unwind_reloc_entryP == NULL) - { - reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, - sizeof (arelent)); - assert (reloc != 0); - unwind_reloc_entryP = reloc; - unwind_reloc_fixp_cnt++; - unwind_reloc_entryP->address - = fixp->fx_frag->fr_address + fixp->fx_where; - /* A pointer to any function will do. We only - need one to tell us what section the unwind - relocations are for. */ - unwind_reloc_entryP->sym_ptr_ptr = &fixp->fx_addsy->bsym; - hppa_fixp->fx_r_type = code = R_HPPA_UNWIND_ENTRIES; - fixp->fx_r_type = R_HPPA_UNWIND; - unwind_reloc_entryP->howto = bfd_reloc_type_lookup (stdoutput, code); - unwind_reloc_entryP->addend = unwind_reloc_fixp_cnt / 2; - relocs = (arelent **) bfd_alloc_by_size_t (stdoutput, - sizeof (arelent *) * 2); - assert (relocs != 0); - relocs[0] = unwind_reloc_entryP; - relocs[1] = NULL; - return relocs; - } - unwind_reloc_fixp_cnt++; - unwind_reloc_entryP->addend = unwind_reloc_fixp_cnt / 2; - - return &no_relocs; - } -#endif - - reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent)); - assert (reloc != 0); + reloc = (arelent *) xmalloc (sizeof (arelent)); - reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym; - codes = hppa_gen_reloc_type (stdoutput, + 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); + hppa_fixp->fx_r_field, + fixp->fx_subsy != NULL, + symbol_get_bfdsym (fixp->fx_addsy)); + + if (codes == NULL) + abort (); for (n_relocs = 0; codes[n_relocs]; n_relocs++) ; - relocs = (arelent **) - bfd_alloc_by_size_t (stdoutput, sizeof (arelent *) * n_relocs + 1); - assert (relocs != 0); - - reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, - sizeof (arelent) * n_relocs); - if (n_relocs > 0) - assert (reloc != 0); - + relocs = (arelent **) xmalloc (sizeof (arelent *) * n_relocs + 1); + reloc = (arelent *) xmalloc (sizeof (arelent) * n_relocs); for (i = 0; i < n_relocs; i++) relocs[i] = &reloc[i]; @@ -2677,38 +3470,13 @@ tc_gen_reloc (section, fixp) #ifdef OBJ_ELF switch (fixp->fx_r_type) { - case R_HPPA_COMPLEX: - case R_HPPA_COMPLEX_PCREL_CALL: - case R_HPPA_COMPLEX_ABS_CALL: - assert (n_relocs == 5); - - for (i = 0; i < n_relocs; i++) - { - reloc[i].sym_ptr_ptr = NULL; - reloc[i].address = 0; - reloc[i].addend = 0; - reloc[i].howto = bfd_reloc_type_lookup (stdoutput, *codes[i]); - assert (reloc[i].howto && *codes[i] == reloc[i].howto->type); - } - - reloc[0].sym_ptr_ptr = &fixp->fx_addsy->bsym; - reloc[1].sym_ptr_ptr = &fixp->fx_subsy->bsym; - reloc[4].address = fixp->fx_frag->fr_address + fixp->fx_where; - - if (fixp->fx_r_type == R_HPPA_COMPLEX) - reloc[3].addend = fixp->fx_addnumber; - else if (fixp->fx_r_type == R_HPPA_COMPLEX_PCREL_CALL || - fixp->fx_r_type == R_HPPA_COMPLEX_ABS_CALL) - reloc[1].addend = fixp->fx_addnumber; - - break; - default: assert (n_relocs == 1); 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 */ @@ -2718,62 +3486,35 @@ tc_gen_reloc (section, fixp) /* Now, do any processing that is dependent on the relocation type. */ switch (code) { - case R_HPPA_PLABEL_32: - case R_HPPA_PLABEL_11: - case R_HPPA_PLABEL_14: - case R_HPPA_PLABEL_L21: - case R_HPPA_PLABEL_R11: - case R_HPPA_PLABEL_R14: + case R_PARISC_DLTREL21L: + case R_PARISC_DLTREL14R: + case R_PARISC_DLTREL14F: + case R_PARISC_PLABEL32: + case R_PARISC_PLABEL21L: + case R_PARISC_PLABEL14R: /* For plabel relocations, the addend of the relocation should be either 0 (no static link) or 2 (static link required). - FIXME: We always assume no static link! */ + FIXME: We always assume no static link! + + We also slam a zero addend into the DLT relative relocs; + it doesn't make a lot of sense to use any addend since + it gets you a different (eg unknown) DLT entry. */ reloc->addend = 0; break; - case R_HPPA_ABS_CALL_11: - case R_HPPA_ABS_CALL_14: - case R_HPPA_ABS_CALL_17: - case R_HPPA_ABS_CALL_L21: - case R_HPPA_ABS_CALL_R11: - case R_HPPA_ABS_CALL_R14: - case R_HPPA_ABS_CALL_R17: - case R_HPPA_ABS_CALL_LS21: - case R_HPPA_ABS_CALL_RS11: - case R_HPPA_ABS_CALL_RS14: - case R_HPPA_ABS_CALL_RS17: - case R_HPPA_ABS_CALL_LD21: - case R_HPPA_ABS_CALL_RD11: - case R_HPPA_ABS_CALL_RD14: - case R_HPPA_ABS_CALL_RD17: - case R_HPPA_ABS_CALL_LR21: - case R_HPPA_ABS_CALL_RR14: - case R_HPPA_ABS_CALL_RR17: - - case R_HPPA_PCREL_CALL_11: - case R_HPPA_PCREL_CALL_14: - case R_HPPA_PCREL_CALL_17: - case R_HPPA_PCREL_CALL_L21: - case R_HPPA_PCREL_CALL_R11: - case R_HPPA_PCREL_CALL_R14: - case R_HPPA_PCREL_CALL_R17: - case R_HPPA_PCREL_CALL_LS21: - case R_HPPA_PCREL_CALL_RS11: - case R_HPPA_PCREL_CALL_RS14: - case R_HPPA_PCREL_CALL_RS17: - case R_HPPA_PCREL_CALL_LD21: - case R_HPPA_PCREL_CALL_RD11: - case R_HPPA_PCREL_CALL_RD14: - case R_HPPA_PCREL_CALL_RD17: - case R_HPPA_PCREL_CALL_LR21: - case R_HPPA_PCREL_CALL_RR14: - case R_HPPA_PCREL_CALL_RR17: + case R_PARISC_PCREL21L: + case R_PARISC_PCREL17R: + case R_PARISC_PCREL17F: + case R_PARISC_PCREL17C: + case R_PARISC_PCREL14R: + case R_PARISC_PCREL14F: /* The constant is stored in the instruction. */ reloc->addend = HPPA_R_ADDEND (hppa_fixp->fx_arg_reloc, 0); break; default: - reloc->addend = fixp->fx_addnumber; + reloc->addend = fixp->fx_offset; break; } break; @@ -2785,24 +3526,58 @@ 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; switch (code) { + case R_COMP2: + /* The only time we ever use a R_COMP2 fixup is for the difference + 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]->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 = (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 = (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]->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]->howto = bfd_reloc_type_lookup (stdoutput, *codes[4]); + relocs[4]->address = fixp->fx_frag->fr_address + fixp->fx_where; + relocs[4]->addend = 0; + goto done; case R_PCREL_CALL: case R_ABS_CALL: relocs[i]->addend = HPPA_R_ADDEND (hppa_fixp->fx_arg_reloc, 0); break; + case R_DLT_REL: case R_DATA_PLABEL: case R_CODE_PLABEL: /* For plabel relocations, the addend of the relocation should be either 0 (no static link) or 2 (static link required). - FIXME: We always assume no static link! */ + FIXME: We always assume no static link! + + We also slam a zero addend into the DLT relative relocs; + it doesn't make a lot of sense to use any addend since + it gets you a different (eg unknown) DLT entry. */ relocs[i]->addend = 0; break; @@ -2810,20 +3585,35 @@ tc_gen_reloc (section, fixp) case R_S_MODE: case R_D_MODE: case R_R_MODE: - case R_EXIT: case R_FSEL: case R_LSEL: case R_RSEL: + case R_BEGIN_BRTAB: + case R_END_BRTAB: + case R_BEGIN_TRY: + 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; - default: - relocs[i]->addend = fixp->fx_addnumber; + case R_END_TRY: + case R_ENTRY: + case R_EXIT: + /* There is no symbol associated with these fixups. */ + 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; + + default: + relocs[i]->addend = fixp->fx_offset; } } + + done: #endif return relocs; @@ -2875,30 +3665,6 @@ md_section_align (segment, size) return (size + align2) & ~align2; } -/* Create a short jump from FROM_ADDR to TO_ADDR. Not used on the PA. */ -void -md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol) - char *ptr; - addressT from_addr, to_addr; - fragS *frag; - symbolS *to_symbol; -{ - fprintf (stderr, "pa_create_short_jmp\n"); - abort (); -} - -/* Create a long jump from FROM_ADDR to TO_ADDR. Not used on the PA. */ -void -md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol) - char *ptr; - addressT from_addr, to_addr; - fragS *frag; - symbolS *to_symbol; -{ - fprintf (stderr, "pa_create_long_jump\n"); - abort (); -} - /* Return the approximate size of a frag before relaxation has occurred. */ int md_estimate_size_before_relax (fragP, segment) @@ -2914,17 +3680,27 @@ md_estimate_size_before_relax (fragP, segment) return size; } + +CONST char *md_shortopts = ""; +struct option md_longopts[] = { + {NULL, no_argument, NULL, 0} +}; +size_t md_longopts_size = sizeof(md_longopts); -/* Parse machine dependent options. There are none on the PA. */ int -md_parse_option (argP, cntP, vecP) - char **argP; - int *cntP; - char ***vecP; +md_parse_option (c, arg) + int c; + char *arg; { - return 1; + return 0; } +void +md_show_usage (stream) + FILE *stream; +{ +} + /* We have no need to default values of symbols. */ symbolS * @@ -2934,16 +3710,6 @@ md_undefined_symbol (name) return 0; } -/* Parse an operand that is machine-specific. - We just return without modifying the expression as we have nothing - to do on the PA. */ - -void -md_operand (expressionP) - expressionS *expressionP; -{ -} - /* Apply a fixup to an instruction. */ int @@ -2953,17 +3719,29 @@ md_apply_fix (fixP, valp) { char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; struct hppa_fix_struct *hppa_fixP; - long new_val, result; - unsigned int w1, w2, w; - valueT val = *valp; + long new_val, result = 0; + unsigned int w1, w2, w, resulti; hppa_fixP = (struct hppa_fix_struct *) fixP->tc_fix_data; - /* SOM uses R_HPPA_ENTRY and R_HPPA_EXIT relocations which can - never be "applied" (they are just markers). */ + /* SOM uses R_HPPA_ENTRY and R_HPPA_EXIT relocations which can + never be "applied" (they are just markers). Likewise for + R_HPPA_BEGIN_BRTAB and R_HPPA_END_BRTAB. */ #ifdef OBJ_SOM if (fixP->fx_r_type == R_HPPA_ENTRY - || fixP->fx_r_type == R_HPPA_EXIT) + || fixP->fx_r_type == R_HPPA_EXIT + || fixP->fx_r_type == R_HPPA_BEGIN_BRTAB + || fixP->fx_r_type == R_HPPA_END_BRTAB + || fixP->fx_r_type == R_HPPA_BEGIN_TRY) return 1; + + /* Disgusting. We must set fx_offset ourselves -- R_HPPA_END_TRY + fixups are considered not adjustable, which in turn causes + adjust_reloc_syms to not set fx_offset. Ugh. */ + if (fixP->fx_r_type == R_HPPA_END_TRY) + { + fixP->fx_offset = *valp; + return 1; + } #endif /* There should have been an HPPA specific fixup associated @@ -2973,40 +3751,56 @@ md_apply_fix (fixP, valp) unsigned long buf_wd = bfd_get_32 (stdoutput, buf); unsigned char fmt = bfd_hppa_insn2fmt (buf_wd); - if (fixP->fx_r_type == R_HPPA_NONE) - fmt = 0; - - /* Remember this value for emit_reloc. FIXME, is this braindamage - documented anywhere!?! */ - fixP->fx_addnumber = val; - - /* Check if this is an undefined symbol. No relocation can - possibly be performed in this case. - - Also avoid doing anything for pc-relative fixups in which the - fixup is in a different space than the symbol it references. */ - if ((fixP->fx_addsy && fixP->fx_addsy->bsym->section == &bfd_und_section) - || (fixP->fx_subsy - && fixP->fx_subsy->bsym->section == &bfd_und_section) - || (fixP->fx_pcrel - && fixP->fx_addsy - && S_GET_SEGMENT (fixP->fx_addsy) != hppa_fixP->segment) - || (fixP->fx_pcrel - && fixP->fx_subsy - && S_GET_SEGMENT (fixP->fx_subsy) != hppa_fixP->segment)) - return 1; - - /* PLABEL field selectors should not be passed to hppa_field_adjust. */ - if (fmt != 0 && hppa_fixP->fx_r_field != R_HPPA_PSEL - && hppa_fixP->fx_r_field != R_HPPA_LPSEL - && hppa_fixP->fx_r_field != R_HPPA_RPSEL - && hppa_fixP->fx_r_field != R_HPPA_TSEL - && hppa_fixP->fx_r_field != R_HPPA_LTSEL - && hppa_fixP->fx_r_field != R_HPPA_RTSEL) - new_val = hppa_field_adjust (val, 0, hppa_fixP->fx_r_field); + /* If there is a symbol associated with this fixup, then it's something + which will need a SOM relocation (except for some PC-relative relocs). + In such cases we should treat the "val" or "addend" as zero since it + will be added in as needed from fx_offset in tc_gen_reloc. */ + if ((fixP->fx_addsy != NULL + || fixP->fx_r_type == R_HPPA_NONE) +#ifdef OBJ_SOM + && fmt != 32 +#endif + ) + new_val = ((fmt == 12 || fmt == 17 || fmt == 22) ? 8 : 0); +#ifdef OBJ_SOM + /* These field selectors imply that we do not want an addend. */ + else if (hppa_fixP->fx_r_field == e_psel + || hppa_fixP->fx_r_field == e_rpsel + || hppa_fixP->fx_r_field == e_lpsel + || hppa_fixP->fx_r_field == e_tsel + || hppa_fixP->fx_r_field == e_rtsel + || hppa_fixP->fx_r_field == e_ltsel) + new_val = ((fmt == 12 || fmt == 17 || fmt == 22) ? 8 : 0); + /* This is truely disgusting. The machine independent code blindly + adds in the value of the symbol being relocated against. Damn! */ + else if (fmt == 32 + && fixP->fx_addsy != NULL + && S_GET_SEGMENT (fixP->fx_addsy) != bfd_com_section_ptr) + new_val = hppa_field_adjust (*valp - S_GET_VALUE (fixP->fx_addsy), + 0, hppa_fixP->fx_r_field); +#endif else - new_val = 0; + new_val = hppa_field_adjust (*valp, 0, hppa_fixP->fx_r_field); + /* Handle pc-relative exceptions from above. */ +#define arg_reloc_stub_needed(CALLER, CALLEE) \ + ((CALLEE) && (CALLER) && ((CALLEE) != (CALLER))) + if ((fmt == 12 || fmt == 17 || fmt == 22) + && fixP->fx_addsy + && fixP->fx_pcrel +#ifdef OBJ_SOM + && !arg_reloc_stub_needed ((long) ((obj_symbol_type *) + 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 + && S_GET_SEGMENT (fixP->fx_subsy) != hppa_fixP->segment)) + + new_val = hppa_field_adjust (*valp, 0, hppa_fixP->fx_r_field); +#undef arg_reloc_stub_needed + switch (fmt) { /* Handle all opcodes with the 'j' operand type. */ @@ -3017,7 +3811,8 @@ md_apply_fix (fixP, valp) bfd_put_32 (stdoutput, bfd_get_32 (stdoutput, buf) & 0xffffc000, buf); - low_sign_unext (new_val, 14, &result); + low_sign_unext (new_val, 14, &resulti); + result = resulti; break; /* Handle all opcodes with the 'k' operand type. */ @@ -3028,7 +3823,8 @@ md_apply_fix (fixP, valp) bfd_put_32 (stdoutput, bfd_get_32 (stdoutput, buf) & 0xffe00000, buf); - dis_assemble_21 (new_val, &result); + dis_assemble_21 (new_val, &resulti); + result = resulti; break; /* Handle all the opcodes with the 'i' operand type. */ @@ -3039,80 +3835,56 @@ md_apply_fix (fixP, valp) bfd_put_32 (stdoutput, bfd_get_32 (stdoutput, buf) & 0xffff800, buf); - low_sign_unext (new_val, 11, &result); + low_sign_unext (new_val, 11, &resulti); + result = resulti; break; /* Handle all the opcodes with the 'w' operand type. */ case 12: - CHECK_FIELD (new_val, 8191, -8192, 0) + CHECK_FIELD (new_val, 8199, -8184, 0); /* Mask off 11 bits to be changed. */ - sign_unext ((new_val - 8) >> 2, 12, &result); + sign_unext ((new_val - 8) >> 2, 12, &resulti); bfd_put_32 (stdoutput, bfd_get_32 (stdoutput, buf) & 0xffffe002, buf); - dis_assemble_12 (result, &w1, &w); + dis_assemble_12 (resulti, &w1, &w); result = ((w1 << 2) | w); break; /* Handle some of the opcodes with the 'W' operand type. */ case 17: - -#define stub_needed(CALLER, CALLEE) \ - ((CALLEE) && (CALLER) && ((CALLEE) != (CALLER))) - /* 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_addsy - && (stub_needed (((obj_symbol_type *) - fixP->fx_addsy->bsym)->tc_data.hppa_arg_reloc, - hppa_fixP->fx_arg_reloc))) - return 1; -#undef stub_needed - - CHECK_FIELD (new_val, 262143, -262144, 0); - - /* Mask off 17 bits to be changed. */ - bfd_put_32 (stdoutput, - bfd_get_32 (stdoutput, buf) & 0xffe0e002, - buf); - sign_unext ((new_val - 8) >> 2, 17, &result); - dis_assemble_17 (result, &w1, &w2, &w); - result = ((w2 << 2) | (w1 << 16) | w); - break; + { + int distance = *valp; + + CHECK_FIELD (new_val, 262143, -262144, 0); + + /* If this is an absolute branch (ie no link) with an out of + range target, then we want to complain. */ + if (fixP->fx_r_type == R_HPPA_PCREL_CALL + && (distance > 262143 || distance < -262144) + && (bfd_get_32 (stdoutput, buf) & 0xffe00000) == 0xe8000000) + CHECK_FIELD (distance, 262143, -262144, 0); + + /* Mask off 17 bits to be changed. */ + bfd_put_32 (stdoutput, + bfd_get_32 (stdoutput, buf) & 0xffe0e002, + buf); + sign_unext ((new_val - 8) >> 2, 17, &resulti); + dis_assemble_17 (resulti, &w1, &w2, &w); + result = ((w2 << 2) | (w1 << 16) | w); + break; + } case 32: -#ifdef OBJ_ELF - /* These are ELF specific relocations. ELF unfortunately - handles unwinds in a completely different manner. */ - if (hppa_fixP->fx_r_type == R_HPPA_UNWIND_ENTRY - || hppa_fixP->fx_r_type == R_HPPA_UNWIND_ENTRIES) - result = fixP->fx_addnumber; - else -#endif - { - result = 0; - fixP->fx_addnumber = fixP->fx_offset; - /* If we have a real relocation, then we want zero to - be stored in the object file. If no relocation is going - to be emitted, then we need to store new_val into the - object file. */ - if (fixP->fx_addsy) - bfd_put_32 (stdoutput, 0, buf); - else - bfd_put_32 (stdoutput, new_val, buf); - return 1; - } + result = 0; + bfd_put_32 (stdoutput, new_val, buf); break; - case 0: - return 1; - default: - as_bad ("Unknown relocation encountered in md_apply_fix."); - return 1; + as_bad (_("Unknown relocation encountered in md_apply_fix.")); + return 0; } /* Insert the relocation. */ @@ -3121,7 +3893,7 @@ md_apply_fix (fixP, valp) } else { - printf ("no hppa_fixup entry for this fixup (fixP = 0x%x, type = 0x%x)\n", + printf (_("no hppa_fixup entry for this fixup (fixP = 0x%x, type = 0x%x)\n"), (unsigned int) fixP, fixP->fx_r_type); return 0; } @@ -3137,7 +3909,7 @@ md_pcrel_from (fixP) return fixP->fx_where + fixP->fx_frag->fr_address; } -/* Return nonzero if the input line pointer is at the end of +/* Return nonzero if the input line pointer is at the end of a statement. */ static int @@ -3164,7 +3936,7 @@ is_end_of_statement () static int pa_parse_number (s, result) char **s; - struct pa_89_fp_reg_struct *result; + struct pa_11_fp_reg_struct *result; { int num; char *name; @@ -3243,7 +4015,7 @@ pa_parse_number (s, result) p++; c = *p; /* Tege hack: Special case for general registers as the general - code makes a binary search with case translation, and is VERY + code makes a binary search with case translation, and is VERY slow. */ if (c == 'r') { @@ -3263,7 +4035,7 @@ pa_parse_number (s, result) else if (!isdigit (*p)) { if (print_errors) - as_bad ("Undefined register: '%s'.", name); + as_bad (_("Undefined register: '%s'."), name); num = -1; } else @@ -3288,7 +4060,7 @@ pa_parse_number (s, result) else { if (print_errors) - as_bad ("Undefined register: '%s'.", name); + as_bad (_("Undefined register: '%s'."), name); num = -1; } *p = c; @@ -3326,7 +4098,7 @@ pa_parse_number (s, result) else { if (print_errors) - as_bad ("Non-absolute symbol: '%s'.", name); + as_bad (_("Non-absolute symbol: '%s'."), name); num = -1; } } @@ -3341,7 +4113,7 @@ pa_parse_number (s, result) else { if (print_errors) - as_bad ("Undefined absolute constant: '%s'.", name); + as_bad (_("Undefined absolute constant: '%s'."), name); num = -1; } } @@ -3397,15 +4169,24 @@ reg_name_search (name) /* Return nonzero if the given INSN and L/R information will require - a new PA-89 opcode. */ + a new PA-1.1 opcode. */ static int -need_89_opcode (insn, result) +need_pa11_opcode (insn, result) struct pa_it *insn; - struct pa_89_fp_reg_struct *result; + struct pa_11_fp_reg_struct *result; { if (result->l_r_select == 1 && !(insn->fpof1 == DBL && insn->fpof2 == DBL)) - return TRUE; + { + /* If this instruction is specific to a particular architecture, + then set a new architecture. */ + if (bfd_get_mach (stdoutput) < pa11) + { + if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, pa11)) + as_warn (_("could not update architecture and machine")); + } + return TRUE; + } else return FALSE; } @@ -3428,16 +4209,29 @@ pa_parse_fp_cmp_cond (s) { cond = fp_cond_map[i].cond; *s += strlen (fp_cond_map[i].string); + /* If not a complete match, back up the input string and + report an error. */ + if (**s != ' ' && **s != '\t') + { + *s -= strlen (fp_cond_map[i].string); + break; + } while (**s == ' ' || **s == '\t') *s = *s + 1; return cond; } } - as_bad ("Invalid FP Compare Condition: %c", **s); + as_bad (_("Invalid FP Compare Condition: %s"), *s); + + /* Advance over the bogus completer. */ + while (**s != ',' && **s != ' ' && **s != '\t') + *s += 1; + return 0; } + /* Parse an FP operand format completer returning the completer type. */ @@ -3469,7 +4263,7 @@ pa_parse_fp_format (s) else { format = ILLEGAL_FMT; - as_bad ("Invalid FP Operand Format: %3s", *s); + as_bad (_("Invalid FP Operand Format: %3s"), *s); } } @@ -3484,7 +4278,7 @@ pa_chk_field_selector (str) { int middle, low, high; int cmp; - char name[3]; + char name[4]; /* Read past any whitespace. */ /* FIXME: should we read past newlines and formfeeds??? */ @@ -3498,6 +4292,11 @@ pa_chk_field_selector (str) name[0] = tolower ((*str)[0]), name[1] = tolower ((*str)[1]), name[2] = 0; + else if ((*str)[3] == '\'' || (*str)[3] == '%') + name[0] = tolower ((*str)[0]), + name[1] = tolower ((*str)[1]), + name[2] = tolower ((*str)[2]), + name[3] = 0; else return e_fsel; @@ -3515,6 +4314,10 @@ pa_chk_field_selector (str) else { *str += strlen (name) + 1; +#ifndef OBJ_SOM + if (selector_table[middle].field_selector == e_nsel) + return e_fsel; +#endif return selector_table[middle].field_selector; } } @@ -3539,7 +4342,7 @@ get_expression (str) || seg == undefined_section || SEG_NORMAL (seg))) { - as_warn ("Bad segment in expression."); + as_warn (_("Bad segment in expression.")); expr_end = input_line_pointer; input_line_pointer = save_in; return 1; @@ -3561,9 +4364,44 @@ pa_get_absolute_expression (insn, strp) save_in = input_line_pointer; input_line_pointer = *strp; expression (&insn->exp); + /* This is not perfect, but is a huge improvement over doing nothing. + + The PA assembly syntax is ambigious in a variety of ways. Consider + this string "4 %r5" Is that the number 4 followed by the register + r5, or is that 4 MOD 5? + + If we get a modulo expresion When looking for an absolute, we try + again cutting off the input string at the first whitespace character. */ + if (insn->exp.X_op == O_modulus) + { + char *s, c; + int retval; + + input_line_pointer = *strp; + s = *strp; + while (*s != ',' && *s != ' ' && *s != '\t') + s++; + + c = *s; + *s = 0; + + retval = pa_get_absolute_expression (insn, strp); + + input_line_pointer = save_in; + *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)."); + as_bad (_("Bad segment (should be absolute).")); expr_end = input_line_pointer; input_line_pointer = save_in; return 0; @@ -3573,7 +4411,7 @@ pa_get_absolute_expression (insn, strp) return evaluate_absolute (insn); } -/* Evaluate an absolute expression EXP which may be modified by +/* Evaluate an absolute expression EXP which may be modified by the selector FIELD_SELECTOR. Return the value of the expression. */ static int evaluate_absolute (insn) @@ -3662,7 +4500,7 @@ pa_build_arg_reloc (type_name) else if (strncasecmp (type_name, "fu", 2) == 0) return 3; else - as_bad ("Invalid argument location: %s\n", type_name); + as_bad (_("Invalid argument location: %s\n"), type_name); return 0; } @@ -3693,7 +4531,7 @@ pa_align_arg_reloc (reg, arg_reloc) new_reloc <<= 2; break; default: - as_bad ("Invalid argument description: %d", reg); + as_bad (_("Invalid argument description: %d"), reg); } return new_reloc; @@ -3716,7 +4554,7 @@ pa_parse_nullif (s) nullif = 1; else { - as_bad ("Invalid Nullification: (%c)", **s); + as_bad (_("Invalid Nullification: (%c)"), **s); nullif = 0; } *s = *s + 1; @@ -3741,6 +4579,7 @@ pa_parse_nonneg_cmpsub_cmpltr (s, isbranch) char *name = *s + 1; char c; char *save_s = *s; + int nullify = 0; cmpltr = 0; if (**s == ',') @@ -3750,6 +4589,8 @@ pa_parse_nonneg_cmpsub_cmpltr (s, isbranch) *s += 1; c = **s; **s = 0x00; + + if (strcmp (name, "=") == 0) { cmpltr = 1; @@ -3783,6 +4624,7 @@ pa_parse_nonneg_cmpsub_cmpltr (s, isbranch) else if (strcasecmp (name, "n") == 0 && isbranch) { cmpltr = 0; + nullify = 1; } else { @@ -3792,9 +4634,10 @@ pa_parse_nonneg_cmpsub_cmpltr (s, isbranch) } /* Reset pointers if this was really a ,n for a branch instruction. */ - if (cmpltr == 0 && *name == 'n' && isbranch) + if (nullify) *s = save_s; + return cmpltr; } @@ -3814,6 +4657,7 @@ pa_parse_neg_cmpsub_cmpltr (s, isbranch) char *name = *s + 1; char c; char *save_s = *s; + int nullify = 0; cmpltr = 0; if (**s == ',') @@ -3823,6 +4667,8 @@ pa_parse_neg_cmpsub_cmpltr (s, isbranch) *s += 1; c = **s; **s = 0x00; + + if (strcasecmp (name, "tr") == 0) { cmpltr = 0; @@ -3860,6 +4706,7 @@ pa_parse_neg_cmpsub_cmpltr (s, isbranch) else if (strcasecmp (name, "n") == 0 && isbranch) { cmpltr = 0; + nullify = 1; } else { @@ -3869,12 +4716,14 @@ pa_parse_neg_cmpsub_cmpltr (s, isbranch) } /* Reset pointers if this was really a ,n for a branch instruction. */ - if (cmpltr == 0 && *name == 'n' && isbranch) + if (nullify) *s = save_s; + return cmpltr; } + /* Parse a non-negated addition completer returning the number (for encoding in instrutions) of the given completer. @@ -3953,7 +4802,7 @@ pa_parse_nonneg_add_cmpltr (s, isbranch) ISBRANCH specifies whether or not this is parsing a condition completer for a branch (vs a nullification completer for a - computational instruction. */ + computational instruction). */ static int pa_parse_neg_add_cmpltr (s, isbranch) @@ -4025,6 +4874,25 @@ 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 +pa_align (bytes) +{ + /* We must have a valid space and subspace. */ + pa_check_current_space_and_subspace (); + + /* Let the generic gas code do most of the work. */ + s_align_bytes (bytes); + + /* If bytes is a power of 2, then update the current subspace's + alignment if necessary. */ + if (log2 (bytes) != -1) + record_alignment (current_subspace->ssd_seg, log2 (bytes)); +} +#endif + /* Handle a .BLOCK type pseudo-op. */ static void @@ -4034,7 +4902,12 @@ pa_block (z) char *p; long int temp_fill; unsigned int temp_size; - int i; + 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 (); @@ -4042,8 +4915,8 @@ pa_block (z) temp_fill = 0; p = frag_var (rs_fill, (int) temp_size, (int) temp_size, - (relax_substateT) 0, (symbolS *) 0, 1, NULL); - bzero (p, temp_size); + (relax_substateT) 0, (symbolS *) 0, (offsetT) 1, NULL); + memset (p, 0, temp_size); /* Convert 2 bytes at a time. */ @@ -4058,6 +4931,52 @@ pa_block (z) demand_empty_rest_of_line (); } +/* Handle a .begin_brtab and .end_brtab pseudo-op. */ + +static void +pa_brtab (begin) + int begin; +{ + +#ifdef OBJ_SOM + /* The BRTAB relocations are only availble in SOM (to denote + the beginning and end of branch tables). */ + char *where = frag_more (0); + + fix_new_hppa (frag_now, where - frag_now->fr_literal, 0, + NULL, (offsetT) 0, NULL, + 0, begin ? R_HPPA_BEGIN_BRTAB : R_HPPA_END_BRTAB, + e_fsel, 0, 0, NULL); +#endif + + demand_empty_rest_of_line (); +} + +/* Handle a .begin_try and .end_try pseudo-op. */ + +static void +pa_try (begin) + int begin; +{ +#ifdef OBJ_SOM + expressionS exp; + char *where = frag_more (0); + + if (! begin) + expression (&exp); + + /* The TRY relocations are only availble in SOM (to denote + the beginning and end of exception handling regions). */ + + fix_new_hppa (frag_now, where - frag_now->fr_literal, 0, + NULL, (offsetT) 0, begin ? NULL : &exp, + 0, begin ? R_HPPA_BEGIN_TRY : R_HPPA_END_TRY, + e_fsel, 0, 0, NULL); +#endif + + demand_empty_rest_of_line (); +} + /* Handle a .CALL pseudo-op. This involves storing away information about where arguments are to be found so the linker can detect (and correct) argument location mismatches between caller and callee. */ @@ -4066,6 +4985,11 @@ 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 (); } @@ -4109,7 +5033,7 @@ pa_call_args (call_desc) } else { - as_bad ("Invalid .CALL argument: %s", name); + as_bad (_("Invalid .CALL argument: %s"), name); } p = input_line_pointer; *p = c; @@ -4139,7 +5063,7 @@ is_same_frag (frag1, frag2) } #ifdef OBJ_ELF -/* Build an entry in the UNWIND subspace from the given function +/* Build an entry in the UNWIND subspace from the given function attributes in CALL_INFO. This is not needed for SOM as using R_ENTRY and R_EXIT relocations allow the linker to handle building of the unwind spaces. */ @@ -4150,45 +5074,60 @@ 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 descriptor. */ p = frag_more (4); + md_number_to_chars (p, 0, 4); /* 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_HPPA_UNWIND, e_fsel, 32, 0, - (char *) 0); + (expressionS *) NULL, 0, reloc, + e_fsel, 32, 0, NULL); p = frag_more (4); + md_number_to_chars (p, 0, 4); + + /* Relocation info. for end offset of the function. + + Because we allow reductions of 32bit relocations for ELF, this will be + reduced to section_sym + offset which avoids putting the temporary + symbol into the symbol table. It (should) end up giving the same + value as call_info->start_symbol + function size once the linker is + finished with its work. */ - /* Relocation info. for end offset of the function. */ fix_new_hppa (frag_now, p - frag_now->fr_literal, 4, call_info->end_symbol, (offsetT) 0, - (expressionS *) NULL, 0, R_HPPA_UNWIND, e_fsel, 32, 0, - (char *) 0); + (expressionS *) NULL, 0, reloc, + e_fsel, 32, 0, NULL); /* Dump it. */ unwind = (char *) &call_info->ci_unwind; @@ -4216,9 +5155,14 @@ 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) - as_bad (".callinfo is not within a procedure definition"); + as_bad (_(".callinfo is not within a procedure definition")); /* Mark the fact that we found the .CALLINFO for the current procedure. */ @@ -4238,7 +5182,7 @@ pa_callinfo (unused) temp = get_absolute_expression (); if ((temp & 0x3) != 0) { - as_bad ("FRAME parameter must be a multiple of 8: %d\n", temp); + as_bad (_("FRAME parameter must be a multiple of 8: %d\n"), temp); temp = 0; } @@ -4254,10 +5198,10 @@ pa_callinfo (unused) input_line_pointer++; temp = get_absolute_expression (); /* The HP assembler accepts 19 as the high bound for ENTRY_GR - even though %r19 is caller saved. I think this is a bug in + even though %r19 is caller saved. I think this is a bug in the HP assembler, and we are not going to emulate it. */ if (temp < 3 || temp > 18) - as_bad ("Value for ENTRY_GR must be in the range 3..18\n"); + as_bad (_("Value for ENTRY_GR must be in the range 3..18\n")); last_call_info->ci_unwind.descriptor.entry_gr = temp - 2; } else if ((strncasecmp (name, "entry_fr", 8) == 0)) @@ -4266,10 +5210,10 @@ pa_callinfo (unused) *p = c; input_line_pointer++; temp = get_absolute_expression (); - /* Similarly the HP assembler takes 31 as the high bound even + /* Similarly the HP assembler takes 31 as the high bound even though %fr21 is the last callee saved floating point register. */ if (temp < 12 || temp > 21) - as_bad ("Value for ENTRY_FR must be in the range 12..21\n"); + as_bad (_("Value for ENTRY_FR must be in the range 12..21\n")); last_call_info->ci_unwind.descriptor.entry_fr = temp - 11; } else if ((strncasecmp (name, "entry_sr", 8) == 0)) @@ -4279,7 +5223,7 @@ pa_callinfo (unused) input_line_pointer++; temp = get_absolute_expression (); if (temp != 3) - as_bad ("Value for ENTRY_SR must be 3\n"); + as_bad (_("Value for ENTRY_SR must be 3\n")); } /* Note whether or not this function performs any calls. */ else if ((strncasecmp (name, "calls", 5) == 0) || @@ -4323,9 +5267,20 @@ pa_callinfo (unused) *p = c; last_call_info->ci_unwind.descriptor.hpux_interrupt_marker = 1; } + /* Is this a millicode routine. "millicode" isn't in my + assembler manual, but my copy is old. The HP assembler + accepts it, and there's a place in the unwind descriptor + to drop the information, so we'll accept it too. */ + else if ((strncasecmp (name, "millicode", 9) == 0)) + { + p = input_line_pointer; + *p = c; + last_call_info->ci_unwind.descriptor.millicode = 1; + } else { - as_bad ("Invalid .CALLINFO argument: %s", name); + as_bad (_("Invalid .CALLINFO argument: %s"), name); + *input_line_pointer = c; } if (!is_end_of_statement ()) input_line_pointer++; @@ -4340,24 +5295,13 @@ static void pa_code (unused) int unused; { - sd_chain_struct *sdchain; - - /* First time through it might be necessary to create the - $TEXT$ space. */ - if ((sdchain = is_defined_space ("$TEXT$")) == NULL) - { - sdchain = create_new_space (pa_def_spaces[0].name, - pa_def_spaces[0].spnum, - pa_def_spaces[0].loadable, - pa_def_spaces[0].defined, - pa_def_spaces[0].private, - pa_def_spaces[0].sort, - pa_def_spaces[0].segment, 0); - } - - SPACE_DEFINED (sdchain) = 1; - subseg_set (text_section, SUBSEG_CODE); - demand_empty_rest_of_line (); +#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 (); } /* This is different than the standard GAS s_comm(). On HP9000/800 machines, @@ -4368,7 +5312,17 @@ pa_code (unused) where