X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-hppa.c;h=8ae5a57e9039756f9a8c295f7f5b44baa72ad48e;hb=7f3dfb9cf74da197cfe71fb0490a90613269ca0f;hp=dcaae9bdad285f6ad12d1e2455d6b765ec6517cf;hpb=9e75421134a05366b5d987f1b6921d7afcf9325d;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-hppa.c b/gas/config/tc-hppa.c index dcaae9bdad..8ae5a57e90 100644 --- a/gas/config/tc-hppa.c +++ b/gas/config/tc-hppa.c @@ -1,6 +1,6 @@ /* tc-hppa.c -- Assemble for the PA - Copyright (C) 1989, 93, 94, 95, 96, 97, 98, 99, 2000 - Free Software Foundation, Inc. + Copyright 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -16,16 +16,16 @@ 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, 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ + Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ /* HP PA-RISC support was contributed by the Center for Software Science at the University of Utah. */ #include -#include #include "as.h" +#include "safe-ctype.h" #include "subsegs.h" #include "bfd/libhppa.h" @@ -42,9 +42,8 @@ error only one of OBJ_ELF and OBJ_SOM can be defined then we want to use the assembler support for compact line numbers. */ #ifdef OBJ_ELF #include "dwarf2dbg.h" -struct dwarf2_line_info debug_line; -/* A "convient" place to put object file dependencies which do +/* A "convenient" place to put object file dependencies which do not need to be seen outside of tc-hppa.c. */ /* Object file formats specify relocation types. */ @@ -58,8 +57,10 @@ typedef elf_symbol_type obj_symbol_type; #if TARGET_ARCH_SIZE == 64 /* How to generate a relocation. */ #define hppa_gen_reloc_type _bfd_elf64_hppa_gen_reloc_type +#define elf_hppa_reloc_final_type elf64_hppa_reloc_final_type #else #define hppa_gen_reloc_type _bfd_elf32_hppa_gen_reloc_type +#define elf_hppa_reloc_final_type elf32_hppa_reloc_final_type #endif /* ELF objects can have versions, but apparently do not have anywhere @@ -106,6 +107,12 @@ typedef som_symbol_type obj_symbol_type; #endif #endif /* OBJ_SOM */ +#if TARGET_ARCH_SIZE == 64 +#define DEFAULT_LEVEL 25 +#else +#define DEFAULT_LEVEL 10 +#endif + /* Various structures and types used internally in tc-hppa.c. */ /* Unwind table and descriptor. FIXME: Sync this with GDB version. */ @@ -134,6 +141,31 @@ struct unwind_desc unsigned int frame_size:27; }; +/* We can't rely on compilers placing bitfields in any particular + place, so use these macros when dumping unwind descriptors to + object files. */ +#define UNWIND_LOW32(U) \ + (((U)->cannot_unwind << 31) \ + | ((U)->millicode << 30) \ + | ((U)->millicode_save_rest << 29) \ + | ((U)->region_desc << 27) \ + | ((U)->save_sr << 25) \ + | ((U)->entry_fr << 21) \ + | ((U)->entry_gr << 16) \ + | ((U)->args_stored << 15) \ + | ((U)->call_fr << 10) \ + | ((U)->call_gr << 5) \ + | ((U)->save_sp << 4) \ + | ((U)->save_rp << 3) \ + | ((U)->save_rp_in_frame << 2) \ + | ((U)->extn_ptr_defined << 1) \ + | ((U)->cleanup_defined << 0)) + +#define UNWIND_HIGH32(U) \ + (((U)->hpe_interrupt_marker << 31) \ + | ((U)->hpux_interrupt_marker << 30) \ + | ((U)->frame_size << 0)) + struct unwind_table { /* Starting and ending offsets of the region described by @@ -331,6 +363,9 @@ struct default_subspace_dict /* Nonzero if this subspace contains only code. */ char code_only; + /* Nonzero if this is a comdat subspace. */ + char comdat; + /* Nonzero if this is a common subspace. */ char common; @@ -458,7 +493,7 @@ struct selector_entry static void pa_check_current_space_and_subspace PARAMS ((void)); #endif -#if !(defined (OBJ_ELF) && defined (TE_LINUX)) +#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD))) static void pa_text PARAMS ((int)); static void pa_data PARAMS ((int)); static void pa_comm PARAMS ((int)); @@ -478,10 +513,10 @@ static int evaluate_absolute PARAMS ((struct pa_it *)); static unsigned int pa_build_arg_reloc PARAMS ((char *)); static unsigned int pa_align_arg_reloc PARAMS ((unsigned int, unsigned int)); static int pa_parse_nullif PARAMS ((char **)); -static int pa_parse_nonneg_cmpsub_cmpltr PARAMS ((char **, int)); -static int pa_parse_neg_cmpsub_cmpltr PARAMS ((char **, int)); -static int pa_parse_neg_add_cmpltr PARAMS ((char **, int)); -static int pa_parse_nonneg_add_cmpltr PARAMS ((char **, int)); +static int pa_parse_nonneg_cmpsub_cmpltr PARAMS ((char **)); +static int pa_parse_neg_cmpsub_cmpltr PARAMS ((char **)); +static int pa_parse_neg_add_cmpltr PARAMS ((char **)); +static int pa_parse_nonneg_add_cmpltr PARAMS ((char **)); static int pa_parse_cmpb_64_cmpltr PARAMS ((char **)); static int pa_parse_cmpib_64_cmpltr PARAMS ((char **)); static int pa_parse_addb_64_cmpltr PARAMS ((char **)); @@ -512,7 +547,7 @@ static int need_pa11_opcode PARAMS ((void)); static int pa_parse_number PARAMS ((char **, int)); static label_symbol_struct *pa_get_label PARAMS ((void)); #ifdef OBJ_SOM -static int log2 PARAMS ((int)); +static int exact_log2 PARAMS ((int)); static void pa_compiler PARAMS ((int)); static void pa_align PARAMS ((int)); static void pa_space PARAMS ((int)); @@ -523,13 +558,13 @@ static sd_chain_struct *create_new_space PARAMS ((char *, int, int, asection *, int)); static ssd_chain_struct *create_new_subspace PARAMS ((sd_chain_struct *, char *, int, int, - int, int, int, + int, int, int, int, int, int, int, int, int, asection *)); static ssd_chain_struct *update_subspace PARAMS ((sd_chain_struct *, char *, int, int, int, int, int, int, int, - int, int, int, + int, int, int, int, asection *)); static sd_chain_struct *is_defined_space PARAMS ((char *)); static ssd_chain_struct *is_defined_subspace PARAMS ((char *)); @@ -539,7 +574,6 @@ static ssd_chain_struct *pa_subsegment_to_subspace PARAMS ((asection *, 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 *)); @@ -547,7 +581,7 @@ static void fix_new_hppa PARAMS ((fragS *, int, int, symbolS *, offsetT, expressionS *, int, bfd_reloc_code_real_type, enum hppa_reloc_field_selector_type_alt, - int, unsigned int, int *)); + int, unsigned int, int)); static int is_end_of_statement PARAMS ((void)); static int reg_name_search PARAMS ((char *)); static int pa_chk_field_selector PARAMS ((char **)); @@ -564,7 +598,7 @@ static void pa_vtable_entry PARAMS ((int)); static void pa_vtable_inherit PARAMS ((int)); #endif -/* File and gloally scoped variable declarations. */ +/* File and globally scoped variable declarations. */ #ifdef OBJ_SOM /* Root and final entry in the space chain. */ @@ -590,6 +624,11 @@ static struct call_desc last_call_desc; /* handle of the OPCODE hash table */ static struct hash_control *op_hash = NULL; +/* These characters can be suffixes of opcode names and they may be + followed by meaningful whitespace. We don't include `,' and `!' + as they never appear followed by meaningful whitespace. */ +const char hppa_symbol_chars[] = "*?=<>"; + /* Table of pseudo ops for the PA. FIXME -- how many of these are now redundant with the overall GAS and the object file dependent tables? */ @@ -610,7 +649,7 @@ const pseudo_typeS md_pseudo_table[] = {"byte", pa_cons, 1}, {"call", pa_call, 0}, {"callinfo", pa_callinfo, 0}, -#if defined (OBJ_ELF) && defined (TE_LINUX) +#if defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)) {"code", obj_elf_text, 0}, #else {"code", pa_text, 0}, @@ -620,14 +659,14 @@ const pseudo_typeS md_pseudo_table[] = {"compiler", pa_compiler, 0}, #endif {"copyright", pa_copyright, 0}, -#if !(defined (OBJ_ELF) && defined (TE_LINUX)) +#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD))) {"data", pa_data, 0}, #endif {"double", pa_float_cons, 'd'}, {"dword", pa_cons, 8}, {"end", pa_end, 0}, {"end_brtab", pa_brtab, 0}, -#if !(defined (OBJ_ELF) && defined (TE_LINUX)) +#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD))) {"end_try", pa_try, 0}, #endif {"enter", pa_enter, 0}, @@ -635,9 +674,6 @@ const pseudo_typeS md_pseudo_table[] = {"equ", pa_equ, 0}, {"exit", pa_exit, 0}, {"export", pa_export, 0}, -#ifdef OBJ_ELF - {"file", dwarf2_directive_file, 0 }, -#endif {"fill", pa_fill, 0}, {"float", pa_float_cons, 'f'}, {"half", pa_cons, 2}, @@ -647,9 +683,6 @@ const pseudo_typeS md_pseudo_table[] = {"lcomm", pa_lcomm, 0}, {"leave", pa_leave, 0}, {"level", pa_level, 0}, -#ifdef OBJ_ELF - {"loc", dwarf2_directive_loc, 0 }, -#endif {"long", pa_cons, 4}, {"lsym", pa_lsym, 0}, #ifdef OBJ_SOM @@ -674,7 +707,7 @@ const pseudo_typeS md_pseudo_table[] = #ifdef OBJ_SOM {"subspa", pa_subspace, 0}, #endif -#if !(defined (OBJ_ELF) && defined (TE_LINUX)) +#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD))) {"text", pa_text, 0}, #endif {"version", pa_version, 0}, @@ -717,7 +750,7 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP"; static struct pa_it the_insn; -/* Points to the end of an expression just parsed by get_expressoin +/* Points to the end of an expression just parsed by get_expression and friends. FIXME. This shouldn't be handled with a file-global variable. */ static char *expr_end; @@ -738,11 +771,15 @@ 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. +/* Nonzero when strict matching is enabled. Zero otherwise. + + Each opcode in the table has a flag which indicates whether or + not strict matching should be enabled for that instruction. - 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; + Mainly, strict causes errors to be ignored when a match failure + occurs. However, it also affects the parsing of register fields + by pa_parse_number. */ +static int strict; /* pa_parse_number returns values in `pa_number'. Mostly pa_parse_number is used to return a register number, with floating @@ -778,6 +815,7 @@ static int print_errors = 1; %r26 - %r23 have %arg0 - %arg3 as synonyms %r28 - %r29 have %ret0 - %ret1 as synonyms + %fr4 - %fr7 have %farg0 - %farg3 as synonyms %r30 has %sp as a synonym %r27 has %dp as a synonym %r2 has %rp as a synonym @@ -821,6 +859,10 @@ static const struct pd_reg pre_defined_registers[] = {"%dp", 27}, {"%eiem", 15}, {"%eirr", 23}, + {"%farg0", 4 + FP_REG_BASE}, + {"%farg1", 5 + FP_REG_BASE}, + {"%farg2", 6 + FP_REG_BASE}, + {"%farg3", 7 + FP_REG_BASE}, {"%fr0", 0 + FP_REG_BASE}, {"%fr0l", 0 + FP_REG_BASE}, {"%fr0r", 0 + FP_REG_BASE + FP_REG_RSEL}, @@ -917,6 +959,7 @@ static const struct pd_reg pre_defined_registers[] = {"%fr9", 9 + FP_REG_BASE}, {"%fr9l", 9 + FP_REG_BASE}, {"%fr9r", 9 + FP_REG_BASE + FP_REG_RSEL}, + {"%fret", 4}, {"%hta", 25}, {"%iir", 19}, {"%ior", 21}, @@ -924,6 +967,11 @@ static const struct pd_reg pre_defined_registers[] = {"%isr", 20}, {"%itmr", 16}, {"%iva", 14}, +#if TARGET_ARCH_SIZE == 64 + {"%mrp", 2}, +#else + {"%mrp", 31}, +#endif {"%pcoq", 18}, {"%pcsq", 17}, {"%pidr1", 8}, @@ -977,6 +1025,14 @@ static const struct pd_reg pre_defined_registers[] = {"%sr5", 5}, {"%sr6", 6}, {"%sr7", 7}, + {"%t1", 22}, + {"%t2", 21}, + {"%t3", 20}, + {"%t4", 19}, + {"%tf1", 11}, + {"%tf2", 10}, + {"%tf3", 9}, + {"%tf4", 8}, {"%tr0", 24}, {"%tr1", 25}, {"%tr2", 26}, @@ -1068,12 +1124,12 @@ 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, 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} + {"$CODE$", 1, 1, 1, 0, 0, 0, 0, 24, 0x2c, 0, 8, 0, 0, SUBSEG_CODE}, + {"$DATA$", 1, 1, 0, 0, 0, 0, 0, 24, 0x1f, 1, 8, 1, 1, SUBSEG_DATA}, + {"$LIT$", 1, 1, 0, 0, 0, 0, 0, 16, 0x2c, 0, 8, 0, 0, SUBSEG_LIT}, + {"$MILLICODE$", 1, 1, 0, 0, 0, 0, 0, 8, 0x2c, 0, 8, 0, 0, SUBSEG_MILLI}, + {"$BSS$", 1, 1, 0, 0, 0, 0, 1, 80, 0x1f, 1, 8, 1, 1, SUBSEG_BSS}, + {NULL, 0, 1, 0, 0, 0, 0, 0, 255, 0x1f, 0, 4, 0, 0, 0} }; static struct default_space_dict pa_def_spaces[] = @@ -1109,7 +1165,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 against HIGH and LOW bounds. IGNORE is used to suppress the error message. */ #define CHECK_FIELD(FIELD, HIGH, LOW, IGNORE) \ @@ -1123,7 +1179,21 @@ static struct default_space_dict pa_def_spaces[] = } \ } -/* Simple alignment checking for FIELD againt ALIGN (a power of two). +/* Variant of CHECK_FIELD for use in md_apply_fix and other places where + the current file and line number are not valid. */ + +#define CHECK_FIELD_WHERE(FIELD, HIGH, LOW, FILENAME, LINE) \ + { \ + if ((FIELD) > (HIGH) || (FIELD) < (LOW)) \ + { \ + as_bad_where ((FILENAME), (LINE), \ + _("Field out of range [%d..%d] (%d)."), (LOW), (HIGH), \ + (int) (FIELD));\ + break; \ + } \ + } + +/* Simple alignment checking for FIELD against ALIGN (a power of two). IGNORE is used to suppress the error message. */ #define CHECK_ALIGN(FIELD, ALIGN, IGNORE) \ @@ -1221,6 +1291,10 @@ pa_define_label (symbol) label_symbols_rootp = label_chain; } + +#ifdef OBJ_ELF + dwarf2_emit_label (symbol); +#endif } /* Removes a label definition for the current space. @@ -1238,10 +1312,10 @@ pa_undefine_label () { if (1 #ifdef OBJ_SOM - && current_space == label_chain->lss_space && label_chain->lss_label + && current_space == label_chain->lss_space && label_chain->lss_label #endif #ifdef OBJ_ELF - && now_seg == label_chain->lss_segment && label_chain->lss_label + && now_seg == label_chain->lss_segment && label_chain->lss_label #endif ) { @@ -1279,7 +1353,7 @@ fix_new_hppa (frag, where, size, add_symbol, offset, exp, pcrel, enum hppa_reloc_field_selector_type_alt r_field; int r_format; unsigned int arg_reloc; - int* unwind_bits ATTRIBUTE_UNUSED; + int unwind_bits ATTRIBUTE_UNUSED; { fixS *new_fix; @@ -1298,7 +1372,7 @@ fix_new_hppa (frag, where, size, add_symbol, offset, exp, pcrel, hppa_fix->segment = now_seg; #ifdef OBJ_SOM if (r_type == R_ENTRY || r_type == R_EXIT) - new_fix->fx_offset = *unwind_bits; + new_fix->fx_offset = unwind_bits; #endif /* foo-$global$ is used to access non-automatic storage. $global$ @@ -1336,6 +1410,8 @@ cons_fix_new_hppa (frag, where, size, exp) /* Get a base relocation type. */ if (is_DP_relative (*exp)) rel_type = R_HPPA_GOTOFF; + else if (is_PC_relative (*exp)) + rel_type = R_HPPA_PCREL_CALL; else if (is_complex (*exp)) rel_type = R_HPPA_COMPLEX; else @@ -1349,7 +1425,7 @@ cons_fix_new_hppa (frag, where, size, exp) fix_new_hppa (frag, where, size, (symbolS *) NULL, (offsetT) 0, exp, 0, rel_type, - hppa_field_selector, size * 8, 0, NULL); + hppa_field_selector, size * 8, 0, 0); /* Reset field selector to its default state. */ hppa_field_selector = 0; @@ -1369,7 +1445,7 @@ md_begin () call_info_root = NULL; /* Set the default machine type. */ - if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 10)) + if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, DEFAULT_LEVEL)) as_warn (_("could not set architecture and machine")); /* Folding of text and data segments fails miserably on the PA. @@ -1459,12 +1535,14 @@ md_assemble (str) information when the label appears after the proc/procend. */ if (within_entry_exit) { - char *where = frag_more (0); + char *where; + unsigned int u; + where = frag_more (0); + u = UNWIND_LOW32 (&last_call_info->ci_unwind.descriptor); fix_new_hppa (frag_now, where - frag_now->fr_literal, 0, NULL, (offsetT) 0, NULL, - 0, R_HPPA_ENTRY, e_fsel, 0, 0, - (int *)&last_call_info->ci_unwind.descriptor); + 0, R_HPPA_ENTRY, e_fsel, 0, 0, u); } #endif } @@ -1478,7 +1556,7 @@ md_assemble (str) /* Assemble the instruction. Results are saved into "the_insn". */ pa_ip (str); - /* Get somewhere to put the assembled instrution. */ + /* Get somewhere to put the assembled instruction. */ to = frag_more (4); /* Output the opcode. */ @@ -1489,23 +1567,10 @@ md_assemble (str) fix_new_hppa (frag_now, (to - frag_now->fr_literal), 4, NULL, (offsetT) 0, &the_insn.exp, the_insn.pcrel, the_insn.reloc, the_insn.field_selector, - the_insn.format, the_insn.arg_reloc, NULL); + the_insn.format, the_insn.arg_reloc, 0); #ifdef OBJ_ELF - if (debug_type == DEBUG_DWARF2) - { - bfd_vma addr; - - /* First update the notion of the current source line. */ - dwarf2_where (&debug_line); - - /* We want the offset of the start of this instruction within the - the current frag. */ - addr = frag_now->fr_address + frag_now_fix () - 4; - - /* And record the information. */ - dwarf2_gen_line_info (addr, &debug_line); - } + dwarf2_emit_insn (4); #endif } @@ -1533,11 +1598,12 @@ pa_ip (str) /* 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); + *s = TOLOWER (*s); /* Skip to something interesting. */ - for (s = str; isupper (*s) || islower (*s) || (*s >= '0' && *s <= '3'); ++s) + for (s = str; + ISUPPER (*s) || ISLOWER (*s) || (*s >= '0' && *s <= '3'); + ++s) ; switch (*s) @@ -1556,11 +1622,10 @@ pa_ip (str) break; default: - as_fatal (_("Unknown opcode: `%s'"), str); + as_bad (_("Unknown opcode: `%s'"), str); + return; } - save_s = str; - /* Look up the opcode in the has table. */ if ((insn = (struct pa_opcode *) hash_find (op_hash, str)) == NULL) { @@ -1585,21 +1650,9 @@ pa_ip (str) 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 + if (insn->arch >= pa20 && 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; - } + goto failed; /* Build the opcode, checking as we go to make sure that the operands match. */ @@ -1653,12 +1706,12 @@ pa_ip (str) while (*s == ' ' || *s == '\t') s = s + 1; - if (!strncasecmp(s, "%sar", 4)) + if (!strncasecmp (s, "%sar", 4)) { s += 4; continue; } - else if (!strncasecmp(s, "%cr11", 5)) + else if (!strncasecmp (s, "%cr11", 5)) { s += 5; continue; @@ -1773,6 +1826,7 @@ pa_ip (str) { /* Handle a completer for an indexing load or store. */ + case 'X': case 'x': { int uu = 0; @@ -1793,9 +1847,9 @@ pa_ip (str) else if ((strncasecmp (s, "s ", 2) == 0) || (strncasecmp (s, "s,", 2) == 0)) uu = 1; - /* When in strict mode this is a match failure. */ else if (strict) { + /* This is a match failure. */ s--; break; } @@ -1811,6 +1865,7 @@ pa_ip (str) } /* Handle a short load/store completer. */ + case 'M': case 'm': case 'q': case 'J': @@ -1820,28 +1875,25 @@ pa_ip (str) int m = 0; if (*s == ',') { - int found = 0; s++; if (strncasecmp (s, "ma", 2) == 0) { a = 0; m = 1; - found = 1; + s += 2; } else if (strncasecmp (s, "mb", 2) == 0) { a = 1; m = 1; - found = 1; + s += 2; } - - /* When in strict mode, pass through for cache op. */ - if (!found && strict) + else if (strict) + /* This is a match failure. */ s--; else { - if (!found) - as_bad (_("Invalid Short Load/Store Completer.")); + as_bad (_("Invalid Short Load/Store Completer.")); s += 2; } } @@ -1850,9 +1902,9 @@ pa_ip (str) else if (*args == 'e') break; - /* 'J', 'm' and 'q' are the same, except for where they + /* 'J', 'm', 'M' and 'q' are the same, except for where they encode the before/after field. */ - if (*args == 'm') + if (*args == 'm' || *args == 'M') { opcode |= m << 5; INSERT_FIELD_AND_CONTINUE (opcode, a, 13); @@ -1869,15 +1921,16 @@ pa_ip (str) } else if (*args == 'e') { - /* Gross! Hide these values in the immediate field - of the instruction, then pull them out later. */ - opcode |= m << 8; - opcode |= a << 9; + /* Stash the ma/mb flag temporarily in the + instruction. We will use (and remove it) + later when handling 'J', 'K', '<' & '>'. */ + opcode |= a; continue; } } /* Handle a stbys completer. */ + case 'A': case 's': { int a = 0; @@ -1893,7 +1946,7 @@ pa_ip (str) a = 0; else if (strncasecmp (s, "e", 1) == 0) a = 1; - /* When in strict mode this is a match failure. */ + /* In strict mode, this is a match failure. */ else if (strict) { s--; @@ -1913,7 +1966,7 @@ pa_ip (str) /* Handle load cache hint completer. */ case 'c': cmpltr = 0; - if (!strncmp(s, ",sl", 3)) + if (!strncmp (s, ",sl", 3)) { s += 3; cmpltr = 2; @@ -1923,12 +1976,12 @@ pa_ip (str) /* Handle store cache hint completer. */ case 'C': cmpltr = 0; - if (!strncmp(s, ",sl", 3)) + if (!strncmp (s, ",sl", 3)) { s += 3; cmpltr = 2; } - else if (!strncmp(s, ",bc", 3)) + else if (!strncmp (s, ",bc", 3)) { s += 3; cmpltr = 1; @@ -1938,7 +1991,7 @@ pa_ip (str) /* Handle load and clear cache hint completer. */ case 'd': cmpltr = 0; - if (!strncmp(s, ",co", 3)) + if (!strncmp (s, ",co", 3)) { s += 3; cmpltr = 1; @@ -1947,7 +2000,7 @@ pa_ip (str) /* Handle load ordering completer. */ case 'o': - if (strncmp(s, ",o", 2) != 0) + if (strncmp (s, ",o", 2) != 0) break; s += 2; continue; @@ -2216,13 +2269,13 @@ pa_ip (str) else if (*s == 'l') lr = 0; else - as_bad(_("Invalid left/right combination completer")); + as_bad (_("Invalid left/right combination completer")); s++; INSERT_FIELD_AND_CONTINUE (opcode, lr, 13); } else - as_bad(_("Invalid left/right combination completer")); + as_bad (_("Invalid left/right combination completer")); break; /* Handle saturation at 24:25. */ @@ -2271,14 +2324,14 @@ pa_ip (str) perm = 3; break; default: - as_bad(_("Invalid permutation completer")); + as_bad (_("Invalid permutation completer")); } opcode |= perm << permloc[i]; } continue; } else - as_bad(_("Invalid permutation completer")); + as_bad (_("Invalid permutation completer")); break; default: @@ -2292,16 +2345,16 @@ pa_ip (str) args++; switch (*args) { - /* Handle FP compare conditions. */ - case 'f': - cond = pa_parse_fp_cmp_cond (&s); - INSERT_FIELD_AND_CONTINUE (opcode, cond, 0); + /* 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; + cmpltr = 0; + flag = 0; if (*s == ',') { s++; @@ -2316,7 +2369,6 @@ pa_ip (str) } else if (*s == '*') break; - name = s; name = s; while (*s != ',' && *s != ' ' && *s != '\t') @@ -2378,7 +2430,7 @@ pa_ip (str) flag = 1; } /* ",*" is a valid condition. */ - else if (*args == 'a') + else if (*args == 'a' || *name) as_bad (_("Invalid Add Condition: %s"), name); *s = c; } @@ -2387,10 +2439,10 @@ pa_ip (str) /* Handle non-negated add and branch condition. */ case 'd': - cmpltr = pa_parse_nonneg_add_cmpltr (&s, 1); + cmpltr = pa_parse_nonneg_add_cmpltr (&s); if (cmpltr < 0) { - as_bad (_("Invalid Add and Branch Condition: %c"), *s); + as_bad (_("Invalid Add and Branch Condition")); cmpltr = 0; } INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13); @@ -2400,7 +2452,7 @@ pa_ip (str) cmpltr = pa_parse_addb_64_cmpltr (&s); if (cmpltr < 0) { - as_bad (_("Invalid Add and Branch Condition: %c"), *s); + as_bad (_("Invalid Add and Branch Condition")); cmpltr = 0; } else @@ -2414,11 +2466,11 @@ pa_ip (str) condition. */ case '@': save_s = s; - cmpltr = pa_parse_nonneg_add_cmpltr (&s, 1); + cmpltr = pa_parse_nonneg_add_cmpltr (&s); if (cmpltr < 0) { s = save_s; - cmpltr = pa_parse_neg_add_cmpltr (&s, 1); + cmpltr = pa_parse_neg_add_cmpltr (&s); if (cmpltr < 0) { as_bad (_("Invalid Compare/Subtract Condition")); @@ -2484,7 +2536,6 @@ pa_ip (str) } else if (*s == '*') break; - name = s; name = s; while (*s != ',' && *s != ' ' && *s != '\t') @@ -2546,7 +2597,7 @@ pa_ip (str) flag = 1; } /* ",*" is a valid condition. */ - else if (*args != 'S') + else if (*args != 'S' || *name) as_bad (_("Invalid Compare/Subtract Condition: %s"), name); *s = c; @@ -2556,10 +2607,10 @@ pa_ip (str) /* Handle a non-negated compare condition. */ case 't': - cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s, 1); + cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s); if (cmpltr < 0) { - as_bad (_("Invalid Compare/Subtract Condition: %c"), *s); + as_bad (_("Invalid Compare/Subtract Condition")); cmpltr = 0; } INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13); @@ -2567,14 +2618,14 @@ pa_ip (str) /* Handle a 32 bit compare and branch condition. */ case 'n': save_s = s; - cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s, 1); + cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s); if (cmpltr < 0) { s = save_s; - cmpltr = pa_parse_neg_cmpsub_cmpltr (&s, 1); + cmpltr = pa_parse_neg_cmpsub_cmpltr (&s); if (cmpltr < 0) { - as_bad (_("Invalid Compare and Branch Condition.")); + as_bad (_("Invalid Compare and Branch Condition")); cmpltr = 0; } else @@ -2669,7 +2720,7 @@ pa_ip (str) flag = 1; } /* ",*" is a valid condition. */ - else if (*args != 'L') + else if (*args != 'L' || *name) as_bad (_("Invalid Logical Instruction Condition.")); *s = c; } @@ -2724,7 +2775,7 @@ pa_ip (str) continue; } /* ",*" is a valid condition. */ - else if (*args != 'X') + else if (*args != 'X' || *name) as_bad (_("Invalid Shift/Extract/Deposit Condition.")); *s = c; } @@ -2836,7 +2887,7 @@ pa_ip (str) s += 3; } /* ",*" is a valid condition. */ - else if (*args != 'U') + else if (*args != 'U' || (*s != ' ' && *s != '\t')) as_bad (_("Invalid Unit Instruction Condition.")); } opcode |= cmpltr << 13; @@ -2936,26 +2987,22 @@ pa_ip (str) s = expr_end; if (the_insn.exp.X_op == O_constant) { - int a, m; + int mb; - /* XXX the completer stored away tibits of information + /* XXX the completer stored away tidbits of information for us to extract. We need a cleaner way to do this. Now that we have lots of letters again, it would be good to rethink this. */ - m = (opcode & (1 << 8)) != 0; - a = (opcode & (1 << 9)) != 0; - opcode &= ~ (3 << 8); + mb = opcode & 1; + opcode -= mb; num = evaluate_absolute (&the_insn); - if ((a == 1 && num >= 0) || (a == 0 && num < 0)) + if (mb != (num < 0)) break; CHECK_FIELD (num, 8191, -8192, 0); num = low_sign_unext (num, 14); INSERT_FIELD_AND_CONTINUE (opcode, num, 0); } - else - { - break; - } + break; /* Handle a 14 bit immediate at 31. */ case 'K': @@ -2964,34 +3011,67 @@ pa_ip (str) s = expr_end; if (the_insn.exp.X_op == O_constant) { - int a, m; + int mb; - /* XXX the completer stored away tibits of information - for us to extract. We need a cleaner way to do this. - Now that we have lots of letters again, it would be - good to rethink this. */ - m = (opcode & (1 << 8)) != 0; - a = (opcode & (1 << 9)) != 0; - opcode &= ~ (3 << 8); + mb = opcode & 1; + opcode -= mb; num = evaluate_absolute (&the_insn); - if ((a == 1 && num < 0) || (a == 0 && num > 0)) + if (mb == (num < 0)) break; if (num % 4) break; CHECK_FIELD (num, 8191, -8192, 0); - if (num < 0) - opcode |= 1; - num &= 0x1fff; - num >>= 2; - INSERT_FIELD_AND_CONTINUE (opcode, num, 3); + num = low_sign_unext (num, 14); + INSERT_FIELD_AND_CONTINUE (opcode, num, 0); } - else + break; + + /* Handle a 16 bit immediate at 31. */ + case '<': + the_insn.field_selector = pa_chk_field_selector (&s); + get_expression (s); + s = expr_end; + if (the_insn.exp.X_op == O_constant) { - break; + int mb; + + mb = opcode & 1; + opcode -= mb; + num = evaluate_absolute (&the_insn); + if (mb != (num < 0)) + break; + CHECK_FIELD (num, 32767, -32768, 0); + num = re_assemble_16 (num); + INSERT_FIELD_AND_CONTINUE (opcode, num, 0); } + break; + + /* Handle a 16 bit immediate at 31. */ + case '>': + the_insn.field_selector = pa_chk_field_selector (&s); + get_expression (s); + s = expr_end; + if (the_insn.exp.X_op == O_constant) + { + int mb; + + mb = opcode & 1; + opcode -= mb; + num = evaluate_absolute (&the_insn); + if (mb == (num < 0)) + break; + if (num % 4) + break; + CHECK_FIELD (num, 32767, -32768, 0); + num = re_assemble_16 (num); + INSERT_FIELD_AND_CONTINUE (opcode, num, 0); + } + break; /* Handle 14 bit immediate, shifted left three times. */ case '#': + if (bfd_get_mach (stdoutput) != pa20) + break; the_insn.field_selector = pa_chk_field_selector (&s); get_expression (s); s = expr_end; @@ -3180,7 +3260,9 @@ pa_ip (str) get_expression (s); s = expr_end; the_insn.pcrel = 1; - if (!strcmp (S_GET_NAME (the_insn.exp.X_add_symbol), "L$0\001")) + if (!the_insn.exp.X_add_symbol + || !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol), + FAKE_LABEL_NAME)) { num = evaluate_absolute (&the_insn); if (num % 4) @@ -3188,9 +3270,10 @@ pa_ip (str) as_bad (_("Branch to unaligned address")); break; } - CHECK_FIELD (num, 8199, -8184, 0); - - opcode |= re_assemble_12 ((num - 8) >> 2); + if (the_insn.exp.X_add_symbol) + num -= 8; + CHECK_FIELD (num, 8191, -8192, 0); + opcode |= re_assemble_12 (num >> 2); continue; } else @@ -3211,7 +3294,7 @@ pa_ip (str) the_insn.pcrel = 1; if (!the_insn.exp.X_add_symbol || !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol), - "L$0\001")) + FAKE_LABEL_NAME)) { num = evaluate_absolute (&the_insn); if (num % 4) @@ -3219,11 +3302,9 @@ pa_ip (str) as_bad (_("Branch to unaligned address")); break; } - CHECK_FIELD (num, 262143, -262144, 0); - if (the_insn.exp.X_add_symbol) num -= 8; - + CHECK_FIELD (num, 262143, -262144, 0); opcode |= re_assemble_17 (num >> 2); continue; } @@ -3244,7 +3325,7 @@ pa_ip (str) the_insn.pcrel = 1; if (!the_insn.exp.X_add_symbol || !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol), - "L$0\001")) + FAKE_LABEL_NAME)) { num = evaluate_absolute (&the_insn); if (num % 4) @@ -3252,11 +3333,9 @@ pa_ip (str) as_bad (_("Branch to unaligned address")); break; } - CHECK_FIELD (num, 8388607, -8388608, 0); - if (the_insn.exp.X_add_symbol) num -= 8; - + CHECK_FIELD (num, 8388607, -8388608, 0); opcode |= re_assemble_22 (num >> 2); } else @@ -3276,7 +3355,7 @@ pa_ip (str) the_insn.pcrel = 0; if (!the_insn.exp.X_add_symbol || !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol), - "L$0\001")) + FAKE_LABEL_NAME)) { num = evaluate_absolute (&the_insn); if (num % 4) @@ -3284,11 +3363,9 @@ pa_ip (str) as_bad (_("Branch to unaligned address")); break; } - CHECK_FIELD (num, 262143, -262144, 0); - if (the_insn.exp.X_add_symbol) num -= 8; - + CHECK_FIELD (num, 262143, -262144, 0); opcode |= re_assemble_17 (num >> 2); continue; } @@ -3455,7 +3532,7 @@ pa_ip (str) if (strict && the_insn.exp.X_op != O_constant) break; s = expr_end; - CHECK_FIELD (num, 671108864, 0, strict); + CHECK_FIELD (num, 67108863, 0, strict); INSERT_FIELD_AND_CONTINUE (opcode, num, 0); /* Handle a 3 bit SFU identifier at 25. */ @@ -3881,9 +3958,20 @@ pa_ip (str) break; } + /* If this instruction is specific to a particular architecture, + then set a new architecture. This automatic promotion crud is + for compatibility with HP's old assemblers only. */ + if (match == TRUE + && bfd_get_mach (stdoutput) < insn->arch + && !bfd_set_arch_mach (stdoutput, bfd_arch_hppa, insn->arch)) + { + as_warn (_("could not update architecture and machine")); + match = FALSE; + } + failed: /* Check if the args matched. */ - if (match == FALSE) + if (!match) { if (&insn[1] - pa_opcodes < (int) NUMOPCODES && !strcmp (insn->name, insn[1].name)) @@ -4011,7 +4099,10 @@ tc_gen_reloc (section, fixp) symbol_get_bfdsym (fixp->fx_addsy)); if (codes == NULL) - abort (); + { + as_bad_where (fixp->fx_file, fixp->fx_line, _("Cannot handle fixup")); + abort (); + } for (n_relocs = 0; codes[n_relocs]; n_relocs++) ; @@ -4031,14 +4122,6 @@ tc_gen_reloc (section, fixp) code = *codes[0]; - 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, - (bfd_reloc_code_real_type) code); - reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; - - assert (reloc->howto && (unsigned int) code == reloc->howto->type); - /* Now, do any processing that is dependent on the relocation type. */ switch (code) { @@ -4072,10 +4155,24 @@ tc_gen_reloc (section, fixp) break; #endif + case R_PARISC_DIR32: + /* Facilitate hand-crafted unwind info. */ + if (strcmp (section->name, UNWIND_SECTION_NAME) == 0) + code = R_PARISC_SEGREL32; + /* Fall thru */ + default: reloc->addend = fixp->fx_offset; break; } + + 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, + (bfd_reloc_code_real_type) code); + reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; + + assert (reloc->howto && (unsigned int) code == reloc->howto->type); break; } #else /* OBJ_SOM */ @@ -4165,8 +4262,8 @@ tc_gen_reloc (section, fixp) case R_N0SEL: case R_N1SEL: /* There is no symbol or addend associated with these fixups. */ - relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); - *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol); + relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol); relocs[i]->addend = 0; break; @@ -4174,8 +4271,8 @@ tc_gen_reloc (section, fixp) case R_ENTRY: case R_EXIT: /* There is no symbol associated with these fixups. */ - relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); - *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol); + 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; @@ -4272,7 +4369,7 @@ struct option md_longopts[] = { #endif {NULL, no_argument, NULL, 0} }; -size_t md_longopts_size = sizeof(md_longopts); +size_t md_longopts_size = sizeof (md_longopts); int md_parse_option (c, arg) @@ -4323,25 +4420,27 @@ md_undefined_symbol (name) } #if defined (OBJ_SOM) || defined (ELF_ARG_RELOC) +#define nonzero_dibits(x) \ + ((x) | (((x) & 0x55555555) << 1) | (((x) & 0xAAAAAAAA) >> 1)) #define arg_reloc_stub_needed(CALLER, CALLEE) \ - ((CALLEE) && (CALLER) && ((CALLEE) != (CALLER))) + (((CALLER) ^ (CALLEE)) & nonzero_dibits (CALLER) & nonzero_dibits (CALLEE)) #else #define arg_reloc_stub_needed(CALLER, CALLEE) 0 #endif /* Apply a fixup to an instruction. */ -int -md_apply_fix (fixP, valp) +void +md_apply_fix (fixP, valP, seg) fixS *fixP; - valueT *valp; + valueT *valP; + segT seg ATTRIBUTE_UNUSED; { - char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; + char *fixpos; struct hppa_fix_struct *hppa_fixP; offsetT new_val; - int insn, val; + int insn, val, fmt; - 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). Likewise for R_HPPA_BEGIN_BRTAB and R_HPPA_END_BRTAB. */ @@ -4351,194 +4450,216 @@ md_apply_fix (fixP, valp) || 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; + return; /* 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; + fixP->fx_offset = * valP; + return; } #endif #ifdef OBJ_ELF if (fixP->fx_r_type == (int) R_PARISC_GNU_VTENTRY || fixP->fx_r_type == (int) R_PARISC_GNU_VTINHERIT) - return 1; + return; #endif - insn = bfd_get_32 (stdoutput, (unsigned char *) buf); - /* There should have been an HPPA specific fixup associated - with the GAS fixup. */ - if (hppa_fixP) + if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0) + fixP->fx_done = 1; + + /* There should be a HPPA specific fixup associated with the GAS fixup. */ + hppa_fixP = (struct hppa_fix_struct *) fixP->tc_fix_data; + if (hppa_fixP == NULL) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + _("no hppa_fixup entry for fixup type 0x%x"), + fixP->fx_r_type); + return; + } + + fixpos = fixP->fx_frag->fr_literal + fixP->fx_where; + + if (fixP->fx_size != 4 || hppa_fixP->fx_r_format == 32) { - int fmt = bfd_hppa_insn2fmt (stdoutput, insn); - - /* 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 == (int) R_HPPA_NONE) + /* Handle constant output. */ + number_to_chars_bigendian (fixpos, *valP, fixP->fx_size); + return; + } + + insn = bfd_get_32 (stdoutput, fixpos); + fmt = bfd_hppa_insn2fmt (stdoutput, insn); + + /* 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 == (int) R_HPPA_NONE) #ifdef OBJ_SOM - && fmt != 32 + && fmt != 32 #endif - ) - new_val = ((fmt == 12 || fmt == 17 || fmt == 22) ? 8 : 0); + ) + 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); + /* 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); #endif - else - new_val = hppa_field_adjust (*valp, 0, hppa_fixP->fx_r_field); - - /* Handle pc-relative exceptions from above. */ - if ((fmt == 12 || fmt == 17 || fmt == 22) - && fixP->fx_addsy - && fixP->fx_pcrel - && !arg_reloc_stub_needed (symbol_arg_reloc_info (fixP->fx_addsy), - hppa_fixP->fx_arg_reloc) - && ((*valp + 8192) < 16384 - || (fmt == 17 && (*valp + 262144) < 524288) - || (fmt == 22 && (*valp + 8388608) < 16777216)) - && 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); - } - - switch (fmt) - { - case 10: - CHECK_FIELD (new_val, 8191, -8192, 0); - val = new_val; + else + new_val = hppa_field_adjust (* valP, 0, hppa_fixP->fx_r_field); + + /* Handle pc-relative exceptions from above. */ + if ((fmt == 12 || fmt == 17 || fmt == 22) + && fixP->fx_addsy + && fixP->fx_pcrel + && !arg_reloc_stub_needed (symbol_arg_reloc_info (fixP->fx_addsy), + hppa_fixP->fx_arg_reloc) +#ifdef OBJ_ELF + && (* valP - 8 + 8192 < 16384 + || (fmt == 17 && * valP - 8 + 262144 < 524288) + || (fmt == 22 && * valP - 8 + 8388608 < 16777216)) +#endif +#ifdef OBJ_SOM + && (* valP - 8 + 262144 < 524288 + || (fmt == 22 && * valP - 8 + 8388608 < 16777216)) +#endif + && !S_IS_EXTERNAL (fixP->fx_addsy) + && !S_IS_WEAK (fixP->fx_addsy) + && 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); + } - insn = (insn & ~ 0x3ff1) | (((val & 0x1ff8) << 1) - | ((val & 0x2000) >> 13)); - break; - case -11: - CHECK_FIELD (new_val, 8191, -8192, 0); - val = new_val; + switch (fmt) + { + case 10: + CHECK_FIELD_WHERE (new_val, 8191, -8192, + fixP->fx_file, fixP->fx_line); + val = new_val; - insn = (insn & ~ 0x3ff9) | (((val & 0x1ffc) << 1) - | ((val & 0x2000) >> 13)); - break; - /* Handle all opcodes with the 'j' operand type. */ - case 14: - CHECK_FIELD (new_val, 8191, -8192, 0); - val = new_val; + insn = (insn & ~ 0x3ff1) | (((val & 0x1ff8) << 1) + | ((val & 0x2000) >> 13)); + break; + case -11: + CHECK_FIELD_WHERE (new_val, 8191, -8192, + fixP->fx_file, fixP->fx_line); + val = new_val; - insn = ((insn & ~ 0x3fff) | low_sign_unext (val, 14)); - break; + insn = (insn & ~ 0x3ff9) | (((val & 0x1ffc) << 1) + | ((val & 0x2000) >> 13)); + break; + /* Handle all opcodes with the 'j' operand type. */ + case 14: + CHECK_FIELD_WHERE (new_val, 8191, -8192, + fixP->fx_file, fixP->fx_line); + val = new_val; - /* Handle all opcodes with the 'k' operand type. */ - case 21: - CHECK_FIELD (new_val, 1048575, -1048576, 0); - val = new_val; + insn = ((insn & ~ 0x3fff) | low_sign_unext (val, 14)); + break; - insn = (insn & ~ 0x1fffff) | re_assemble_21 (val); - break; + /* Handle all opcodes with the 'k' operand type. */ + case 21: + CHECK_FIELD_WHERE (new_val, 1048575, -1048576, + fixP->fx_file, fixP->fx_line); + val = new_val; - /* Handle all the opcodes with the 'i' operand type. */ - case 11: - CHECK_FIELD (new_val, 1023, -1023, 0); - val = new_val; + insn = (insn & ~ 0x1fffff) | re_assemble_21 (val); + break; - insn = (insn & ~ 0x7ff) | low_sign_unext (val, 11); - break; + /* Handle all the opcodes with the 'i' operand type. */ + case 11: + CHECK_FIELD_WHERE (new_val, 1023, -1024, + fixP->fx_file, fixP->fx_line); + val = new_val; - /* Handle all the opcodes with the 'w' operand type. */ - case 12: - CHECK_FIELD (new_val, 8199, -8184, 0); - val = new_val; + insn = (insn & ~ 0x7ff) | low_sign_unext (val, 11); + break; - insn = (insn & ~ 0x1ffd) | re_assemble_12 ((val - 8) >> 2); - break; + /* Handle all the opcodes with the 'w' operand type. */ + case 12: + CHECK_FIELD_WHERE (new_val - 8, 8191, -8192, + fixP->fx_file, fixP->fx_line); + val = new_val - 8; - /* Handle some of the opcodes with the 'W' operand type. */ - case 17: - { - offsetT distance = *valp; + insn = (insn & ~ 0x1ffd) | re_assemble_12 (val >> 2); + break; - /* 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 == (int) R_HPPA_PCREL_CALL - && (insn & 0xffe00000) == 0xe8000000) - CHECK_FIELD (distance, 262143, -262144, 0); + /* Handle some of the opcodes with the 'W' operand type. */ + case 17: + { + offsetT distance = * valP; - CHECK_FIELD (new_val, 262143, -262144, 0); - val = new_val; + /* 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 == (int) R_HPPA_PCREL_CALL + && (insn & 0xffe00000) == 0xe8000000) + CHECK_FIELD_WHERE (distance - 8, 262143, -262144, + fixP->fx_file, fixP->fx_line); - insn = (insn & ~ 0x1f1ffd) | re_assemble_17 ((val - 8) >> 2); - break; - } + CHECK_FIELD_WHERE (new_val - 8, 262143, -262144, + fixP->fx_file, fixP->fx_line); + val = new_val - 8; - case 22: - { - offsetT distance = *valp; + insn = (insn & ~ 0x1f1ffd) | re_assemble_17 (val >> 2); + break; + } - /* 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 == (int) R_HPPA_PCREL_CALL - && (insn & 0xffe00000) == 0xe8000000) - CHECK_FIELD (distance, 8388607, -8388608, 0); + case 22: + { + offsetT distance = * valP; - CHECK_FIELD (new_val, 8388607, -8388608, 0); - val = new_val; + /* 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 == (int) R_HPPA_PCREL_CALL + && (insn & 0xffe00000) == 0xe8000000) + CHECK_FIELD_WHERE (distance - 8, 8388607, -8388608, + fixP->fx_file, fixP->fx_line); - insn = (insn & ~ 0x3ff1ffd) | re_assemble_22 ((val - 8) >> 2); - break; - } + CHECK_FIELD_WHERE (new_val - 8, 8388607, -8388608, + fixP->fx_file, fixP->fx_line); + val = new_val - 8; - case -10: - val = new_val; - insn = (insn & ~ 0xfff1) | re_assemble_16 (val & -8); - break; + insn = (insn & ~ 0x3ff1ffd) | re_assemble_22 (val >> 2); + break; + } - case -16: - val = new_val; - insn = (insn & ~ 0xfff9) | re_assemble_16 (val & -4); - break; + case -10: + val = new_val; + insn = (insn & ~ 0xfff1) | re_assemble_16 (val & -8); + break; - case 16: - val = new_val; - insn = (insn & ~ 0xffff) | re_assemble_16 (val); - break; + case -16: + val = new_val; + insn = (insn & ~ 0xfff9) | re_assemble_16 (val & -4); + break; - case 32: - insn = new_val; - break; + case 16: + val = new_val; + insn = (insn & ~ 0xffff) | re_assemble_16 (val); + break; - default: - as_bad (_("Unknown relocation encountered in md_apply_fix.")); - return 0; - } + case 32: + insn = new_val; + break; - /* Insert the relocation. */ - bfd_put_32 (stdoutput, insn, (unsigned char *) buf); - return 1; - } - else - { - printf (_("no hppa_fixup entry for this fixup (fixP = 0x%x, type = 0x%x)\n"), - (unsigned int) fixP, fixP->fx_r_type); - return 0; + default: + as_bad_where (fixP->fx_file, fixP->fx_line, + _("Unknown relocation encountered in md_apply_fix.")); + return; } + + /* Insert the relocation. */ + bfd_put_32 (stdoutput, insn, fixpos); } /* Exactly what point is a PC-relative offset relative TO? @@ -4588,7 +4709,7 @@ pa_parse_number (s, is_float) symbolS *sym; int status; char *p = *s; - boolean have_prefix; + bfd_boolean have_prefix; /* Skip whitespace before the number. */ while (*p == ' ' || *p == '\t') @@ -4597,7 +4718,7 @@ pa_parse_number (s, is_float) pa_number = -1; have_prefix = 0; num = 0; - if (!strict && isdigit (*p)) + if (!strict && ISDIGIT (*p)) { /* Looks like a number. */ @@ -4605,10 +4726,10 @@ pa_parse_number (s, is_float) { /* The number is specified in hex. */ p += 2; - while (isdigit (*p) || ((*p >= 'a') && (*p <= 'f')) + while (ISDIGIT (*p) || ((*p >= 'a') && (*p <= 'f')) || ((*p >= 'A') && (*p <= 'F'))) { - if (isdigit (*p)) + if (ISDIGIT (*p)) num = num * 16 + *p - '0'; else if (*p >= 'a' && *p <= 'f') num = num * 16 + *p - 'a' + 10; @@ -4620,7 +4741,7 @@ pa_parse_number (s, is_float) else { /* The number is specified in decimal. */ - while (isdigit (*p)) + while (ISDIGIT (*p)) { num = num * 10 + *p - '0'; ++p; @@ -4672,7 +4793,7 @@ pa_parse_number (s, is_float) num = 2; p++; } - else if (!isdigit (*p)) + else if (!ISDIGIT (*p)) { if (print_errors) as_bad (_("Undefined register: '%s'."), name); @@ -4682,7 +4803,7 @@ pa_parse_number (s, is_float) { do num = num * 10 + *p++ - '0'; - while (isdigit (*p)); + while (ISDIGIT (*p)); } } else @@ -4727,7 +4848,7 @@ pa_parse_number (s, is_float) num = S_GET_VALUE (sym); /* Well, we don't really have one, but we do have a register, so... */ - have_prefix = true; + have_prefix = TRUE; } else if (S_GET_SEGMENT (sym) == &bfd_abs_section) num = S_GET_VALUE (sym); @@ -4743,7 +4864,7 @@ pa_parse_number (s, is_float) /* There is where we'd come for an undefined symbol or for an empty string. For an empty string we will return zero. That's a concession made for - compatability with the braindamaged HP assemblers. */ + compatibility with the braindamaged HP assemblers. */ if (*name == 0) num = 0; else @@ -4766,7 +4887,7 @@ pa_parse_number (s, is_float) return 0; } -#define REG_NAME_CNT (sizeof(pre_defined_registers) / sizeof(struct pd_reg)) +#define REG_NAME_CNT (sizeof (pre_defined_registers) / sizeof (struct pd_reg)) /* Given NAME, find the register number associated with that name, return the integer value associated with the given name or -1 on failure. */ @@ -5034,16 +5155,16 @@ pa_chk_field_selector (str) *str = *str + 1; if ((*str)[1] == '\'' || (*str)[1] == '%') - name[0] = tolower ((*str)[0]), + name[0] = TOLOWER ((*str)[0]), name[1] = 0; else if ((*str)[2] == '\'' || (*str)[2] == '%') - name[0] = tolower ((*str)[0]), - name[1] = tolower ((*str)[1]), + 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[0] = TOLOWER ((*str)[0]), + name[1] = TOLOWER ((*str)[1]), + name[2] = TOLOWER ((*str)[2]), name[3] = 0; else return e_fsel; @@ -5114,11 +5235,11 @@ pa_get_absolute_expression (insn, 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 + The PA assembly syntax is ambiguous 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 r5? - If we get a modulo expresion When looking for an absolute, we try + If we get a modulo expression 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) { @@ -5128,7 +5249,7 @@ pa_get_absolute_expression (insn, strp) input_line_pointer = *strp; s = *strp; while (*s != ',' && *s != ' ' && *s != '\t') - s++; + s++; c = *s; *s = 0; @@ -5256,16 +5377,11 @@ pa_parse_nullif (s) } /* Parse a non-negated compare/subtract completer returning the - number (for encoding in instrutions) of the given completer. - - ISBRANCH specifies whether or not this is parsing a condition - completer for a branch (vs a nullification completer for a - computational instruction. */ + number (for encoding in instructions) of the given completer. */ static int -pa_parse_nonneg_cmpsub_cmpltr (s, isbranch) +pa_parse_nonneg_cmpsub_cmpltr (s) char **s; - int isbranch; { int cmpltr; char *name = *s + 1; @@ -5312,7 +5428,7 @@ pa_parse_nonneg_cmpsub_cmpltr (s, isbranch) } /* If we have something like addb,n then there is no condition completer. */ - else if (strcasecmp (name, "n") == 0 && isbranch) + else if (strcasecmp (name, "n") == 0) { cmpltr = 0; nullify = 1; @@ -5332,16 +5448,11 @@ pa_parse_nonneg_cmpsub_cmpltr (s, isbranch) } /* Parse a negated compare/subtract completer returning the - number (for encoding in instrutions) of the given completer. - - ISBRANCH specifies whether or not this is parsing a condition - completer for a branch (vs a nullification completer for a - computational instruction. */ + number (for encoding in instructions) of the given completer. */ static int -pa_parse_neg_cmpsub_cmpltr (s, isbranch) +pa_parse_neg_cmpsub_cmpltr (s) char **s; - int isbranch; { int cmpltr; char *name = *s + 1; @@ -5392,7 +5503,7 @@ pa_parse_neg_cmpsub_cmpltr (s, isbranch) } /* If we have something like addb,n then there is no condition completer. */ - else if (strcasecmp (name, "n") == 0 && isbranch) + else if (strcasecmp (name, "n") == 0) { cmpltr = 0; nullify = 1; @@ -5412,7 +5523,7 @@ pa_parse_neg_cmpsub_cmpltr (s, isbranch) } /* Parse a 64 bit compare and branch completer returning the number (for - encoding in instrutions) of the given completer. + encoding in instructions) of the given completer. Nonnegated comparisons are returned as 0-7, negated comparisons are returned as 8-15. */ @@ -5509,7 +5620,7 @@ pa_parse_cmpb_64_cmpltr (s) } /* Parse a 64 bit compare immediate and branch completer returning the number - (for encoding in instrutions) of the given completer. */ + (for encoding in instructions) of the given completer. */ static int pa_parse_cmpib_64_cmpltr (s) @@ -5571,21 +5682,17 @@ pa_parse_cmpib_64_cmpltr (s) } /* Parse a non-negated addition completer returning the number - (for encoding in instrutions) of the given completer. - - ISBRANCH specifies whether or not this is parsing a condition - completer for a branch (vs a nullification completer for a - computational instruction. */ + (for encoding in instructions) of the given completer. */ static int -pa_parse_nonneg_add_cmpltr (s, isbranch) +pa_parse_nonneg_add_cmpltr (s) char **s; - int isbranch; { int cmpltr; char *name = *s + 1; char c; char *save_s = *s; + int nullify = 0; cmpltr = 0; if (**s == ',') @@ -5625,9 +5732,10 @@ pa_parse_nonneg_add_cmpltr (s, isbranch) } /* If we have something like addb,n then there is no condition completer. */ - else if (strcasecmp (name, "n") == 0 && isbranch) + else if (strcasecmp (name, "n") == 0) { cmpltr = 0; + nullify = 1; } else { @@ -5637,28 +5745,24 @@ pa_parse_nonneg_add_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 negated addition completer returning the number - (for encoding in instrutions) of the given completer. - - ISBRANCH specifies whether or not this is parsing a condition - completer for a branch (vs a nullification completer for a - computational instruction). */ + (for encoding in instructions) of the given completer. */ static int -pa_parse_neg_add_cmpltr (s, isbranch) +pa_parse_neg_add_cmpltr (s) char **s; - int isbranch; { int cmpltr; char *name = *s + 1; char c; char *save_s = *s; + int nullify = 0; cmpltr = 0; if (**s == ',') @@ -5702,9 +5806,10 @@ pa_parse_neg_add_cmpltr (s, isbranch) } /* If we have something like addb,n then there is no condition completer. */ - else if (strcasecmp (name, "n") == 0 && isbranch) + else if (strcasecmp (name, "n") == 0) { cmpltr = 0; + nullify = 1; } else { @@ -5714,14 +5819,14 @@ pa_parse_neg_add_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 64 bit wide mode add and branch completer returning the number (for - encoding in instrutions) of the given completer. */ + encoding in instructions) of the given completer. */ static int pa_parse_addb_64_cmpltr (s) @@ -5827,6 +5932,7 @@ pa_parse_addb_64_cmpltr (s) alignment of the subspace if necessary. */ static void pa_align (bytes) + int bytes; { /* We must have a valid space and subspace. */ pa_check_current_space_and_subspace (); @@ -5836,8 +5942,8 @@ pa_align (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)); + if (exact_log2 (bytes) != -1) + record_alignment (current_subspace->ssd_seg, exact_log2 (bytes)); } #endif @@ -5847,10 +5953,7 @@ static void pa_block (z) int z ATTRIBUTE_UNUSED; { - char *p; - long int temp_fill; unsigned int temp_size; - unsigned int i; #ifdef OBJ_SOM /* We must have a valid space and subspace. */ @@ -5859,20 +5962,16 @@ pa_block (z) temp_size = get_absolute_expression (); - /* Always fill with zeros, that's what the HP assembler does. */ - temp_fill = 0; - - p = frag_var (rs_fill, (int) temp_size, (int) temp_size, - (relax_substateT) 0, (symbolS *) 0, (offsetT) 1, NULL); - memset (p, 0, temp_size); - - /* Convert 2 bytes at a time. */ - - for (i = 0; i < temp_size; i += 2) + if (temp_size > 0x3FFFFFFF) { - md_number_to_chars (p + i, - (valueT) temp_fill, - (int) ((temp_size - i) > 2 ? 2 : (temp_size - i))); + as_bad (_("Argument to .BLOCK/.BLOCKZ must be between 0 and 0x3fffffff")); + temp_size = 0; + } + else + { + /* Always fill with zeros, that's what the HP assembler does. */ + char *p = frag_var (rs_fill, 1, 1, 0, NULL, temp_size, NULL); + *p = 0; } pa_undefine_label (); @@ -5887,14 +5986,14 @@ pa_brtab (begin) { #ifdef OBJ_SOM - /* The BRTAB relocations are only availble in SOM (to denote + /* The BRTAB relocations are only available 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); + e_fsel, 0, 0, 0); #endif demand_empty_rest_of_line (); @@ -5913,13 +6012,13 @@ pa_try (begin) if (! begin) expression (&exp); - /* The TRY relocations are only availble in SOM (to denote + /* The TRY relocations are only available 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); + e_fsel, 0, 0, 0); #endif demand_empty_rest_of_line (); @@ -6020,21 +6119,18 @@ static void pa_build_unwind_subspace (call_info) struct call_info *call_info; { - char *unwind; asection *seg, *save_seg; subsegT save_subseg; - unsigned int i; + unsigned int unwind; int reloc; - char c, *p; + char *p; - if (now_seg != text_section) + if ((bfd_get_section_flags (stdoutput, now_seg) + & (SEC_ALLOC | SEC_LOAD | SEC_READONLY)) + != (SEC_ALLOC | SEC_LOAD | SEC_READONLY)) return; - if (bfd_get_arch_info (stdoutput)->bits_per_address == 32) - reloc = R_PARISC_DIR32; - else - reloc = R_PARISC_SEGREL32; - + reloc = R_PARISC_SEGREL32; save_seg = now_seg; save_subseg = now_subseg; /* Get into the right seg/subseg. This may involve creating @@ -6054,17 +6150,14 @@ pa_build_unwind_subspace (call_info) /* Get some space to hold relocation information for the unwind descriptor. */ - p = frag_more (4); - md_number_to_chars (p, 0, 4); + p = frag_more (16); /* Relocation info. for start offset of the function. */ + md_number_to_chars (p, 0, 4); fix_new_hppa (frag_now, p - frag_now->fr_literal, 4, call_info->start_symbol, (offsetT) 0, (expressionS *) NULL, 0, reloc, - e_fsel, 32, 0, NULL); - - p = frag_more (4); - md_number_to_chars (p, 0, 4); + e_fsel, 32, 0, 0); /* Relocation info. for end offset of the function. @@ -6073,21 +6166,18 @@ pa_build_unwind_subspace (call_info) 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. */ - - fix_new_hppa (frag_now, p - frag_now->fr_literal, 4, + md_number_to_chars (p + 4, 0, 4); + fix_new_hppa (frag_now, p + 4 - frag_now->fr_literal, 4, call_info->end_symbol, (offsetT) 0, (expressionS *) NULL, 0, reloc, - e_fsel, 32, 0, NULL); + e_fsel, 32, 0, 0); - /* Dump it. */ - unwind = (char *) &call_info->ci_unwind; - for (i = 8; i < sizeof (struct unwind_table); i++) - { - c = *(unwind + i); - { - FRAG_APPEND_1_CHAR (c); - } - } + /* Dump the descriptor. */ + unwind = UNWIND_LOW32 (&call_info->ci_unwind.descriptor); + md_number_to_chars (p + 8, unwind, 4); + + unwind = UNWIND_HIGH32 (&call_info->ci_unwind.descriptor); + md_number_to_chars (p + 12, unwind, 4); /* Return back to the original segment/subsegment. */ subseg_set (save_seg, save_subseg); @@ -6239,7 +6329,7 @@ pa_callinfo (unused) demand_empty_rest_of_line (); } -#if !(defined (OBJ_ELF) && defined (TE_LINUX)) +#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD))) /* Switch to the text space. Like s_text, but delete our label when finished. */ static void @@ -6308,8 +6398,9 @@ pa_comm (unused) if (symbol) { + symbol_get_bfdsym (symbol)->flags |= BSF_OBJECT; S_SET_VALUE (symbol, size); - S_SET_SEGMENT (symbol, bfd_und_section_ptr); + S_SET_SEGMENT (symbol, bfd_com_section_ptr); S_SET_EXTERNAL (symbol); /* colon() has already set the frag to the current location in the @@ -6319,7 +6410,7 @@ pa_comm (unused) } demand_empty_rest_of_line (); } -#endif /* !(defined (OBJ_ELF) && defined (TE_LINUX)) */ +#endif /* !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD))) */ /* Process a .END pseudo-op. */ @@ -6345,7 +6436,7 @@ pa_enter (unused) } /* Process a .ENTRY pseudo-op. .ENTRY marks the beginning of the - procesure. */ + procedure. */ static void pa_entry (unused) int unused ATTRIBUTE_UNUSED; @@ -6377,12 +6468,14 @@ pa_entry (unused) denote the entry and exit points. */ if (last_call_info->start_symbol != NULL) { - char *where = frag_more (0); + char *where; + unsigned int u; + where = frag_more (0); + u = UNWIND_LOW32 (&last_call_info->ci_unwind.descriptor); fix_new_hppa (frag_now, where - frag_now->fr_literal, 0, NULL, (offsetT) 0, NULL, - 0, R_HPPA_ENTRY, e_fsel, 0, 0, - (int *) &last_call_info->ci_unwind.descriptor); + 0, R_HPPA_ENTRY, e_fsel, 0, 0, u); } #endif } @@ -6490,7 +6583,7 @@ process_exit () fix_new_hppa (frag_now, where - frag_now->fr_literal, 0, NULL, (offsetT) 0, NULL, 0, R_HPPA_EXIT, e_fsel, 0, 0, - (int *) &last_call_info->ci_unwind.descriptor + 1); + UNWIND_HIGH32 (&last_call_info->ci_unwind.descriptor)); #endif } @@ -6701,7 +6794,7 @@ pa_type_args (symbolP, is_export) #endif *input_line_pointer = c; } - /* Privelege level. */ + /* Privilege level. */ else if ((strncasecmp (name, "priv_lev", 8)) == 0) { p = input_line_pointer; @@ -6756,9 +6849,9 @@ pa_import (unused) } else { - /* Sigh. To be compatable with the HP assembler and to help + /* Sigh. To be compatible with the HP assembler and to help poorly written assembly code, we assign a type based on - the the current segment. Note only BSF_FUNCTION really + the current segment. Note only BSF_FUNCTION really matters, we do not need to set the full SYMBOL_TYPE_* info. */ if (now_seg == text_section) symbol_get_bfdsym (symbol)->flags |= BSF_FUNCTION; @@ -6985,7 +7078,7 @@ pa_proc (unused) demand_empty_rest_of_line (); } -/* Process the syntatical end of a procedure. Make sure all the +/* Process the syntactical end of a procedure. Make sure all the appropriate pseudo-ops were found within the procedure. */ static void @@ -7021,12 +7114,14 @@ pa_procend (unused) information when the label appears after the proc/procend. */ if (within_entry_exit) { - char *where = frag_more (0); + char *where; + unsigned int u; + where = frag_more (0); + u = UNWIND_LOW32 (&last_call_info->ci_unwind.descriptor); fix_new_hppa (frag_now, where - frag_now->fr_literal, 0, NULL, (offsetT) 0, NULL, - 0, R_HPPA_ENTRY, e_fsel, 0, 0, - (int *) &last_call_info->ci_unwind.descriptor); + 0, R_HPPA_ENTRY, e_fsel, 0, 0, u); } #endif } @@ -7062,7 +7157,7 @@ pa_procend (unused) return log2 (VALUE). Else return -1. */ static int -log2 (value) +exact_log2 (value) int value; { int shift = 0; @@ -7192,7 +7287,7 @@ pa_parse_space_stmt (space_name, create_flag) /* If create_flag is nonzero, then create the new space with the attributes computed above. Else set the values in an already existing space -- this can only happen for - the first occurence of a built-in space. */ + the first occurrence of a built-in space. */ if (create_flag) space = create_new_space (space_name, spnum, loadable, defined, private, sort, seg, 1); @@ -7369,7 +7464,7 @@ pa_subspace (create_new) int create_new; { char *name, *ss_name, c; - char loadable, code_only, common, dup_common, zero, sort; + char loadable, code_only, comdat, common, dup_common, zero, sort; int i, access, space_index, alignment, quadrant, applicable, flags; sd_chain_struct *space; ssd_chain_struct *ssd; @@ -7395,6 +7490,7 @@ pa_subspace (create_new) sort = 0; access = 0x7f; loadable = 1; + comdat = 0; common = 0; dup_common = 0; code_only = 0; @@ -7429,6 +7525,7 @@ pa_subspace (create_new) if (strcasecmp (pa_def_subspaces[i].name, ss_name) == 0) { loadable = pa_def_subspaces[i].loadable; + comdat = pa_def_subspaces[i].comdat; common = pa_def_subspaces[i].common; dup_common = pa_def_subspaces[i].dup_common; code_only = pa_def_subspaces[i].code_only; @@ -7464,7 +7561,7 @@ pa_subspace (create_new) *input_line_pointer = c; input_line_pointer++; alignment = get_absolute_expression (); - if (log2 (alignment) == -1) + if (exact_log2 (alignment) == -1) { as_bad (_("Alignment must be a power of 2")); alignment = 1; @@ -7492,6 +7589,11 @@ pa_subspace (create_new) *input_line_pointer = c; loadable = 0; } + else if ((strncasecmp (name, "comdat", 6) == 0)) + { + *input_line_pointer = c; + comdat = 1; + } else if ((strncasecmp (name, "common", 6) == 0)) { *input_line_pointer = c; @@ -7524,8 +7626,17 @@ pa_subspace (create_new) flags |= (SEC_ALLOC | SEC_LOAD); if (code_only) flags |= SEC_CODE; - if (common || dup_common) - flags |= SEC_IS_COMMON; + + /* These flags are used to implement various flavors of initialized + common. The SOM linker discards duplicate subspaces when they + have the same "key" symbol name. This support is more like + GNU linkonce than BFD common. Further, pc-relative relocations + are converted to section relative relocations in BFD common + sections. This complicates the handling of relocations in + common sections containing text and isn't currently supported + correctly in the SOM BFD backend. */ + if (comdat || common || dup_common) + flags |= SEC_LINK_ONCE; flags |= SEC_RELOC | SEC_HAS_CONTENTS; @@ -7556,7 +7667,7 @@ pa_subspace (create_new) bfd_set_section_flags (stdoutput, section, applicable); /* Record any alignment request for this section. */ - record_alignment (section, log2 (alignment)); + record_alignment (section, exact_log2 (alignment)); /* Set the starting offset for this section. */ bfd_set_section_vma (stdoutput, section, @@ -7567,16 +7678,16 @@ pa_subspace (create_new) if (ssd) current_subspace = update_subspace (space, ss_name, loadable, - code_only, common, dup_common, - sort, zero, access, space_index, - alignment, quadrant, + code_only, comdat, common, + dup_common, sort, zero, access, + space_index, alignment, quadrant, section); else current_subspace = create_new_subspace (space, ss_name, loadable, - code_only, common, + code_only, comdat, common, dup_common, zero, sort, access, space_index, - alignment, quadrant, section); + alignment, quadrant, section); demand_empty_rest_of_line (); current_subspace->ssd_seg = section; @@ -7697,6 +7808,7 @@ pa_spaces_begin () create_new_subspace (space, name, pa_def_subspaces[i].loadable, pa_def_subspaces[i].code_only, + pa_def_subspaces[i].comdat, pa_def_subspaces[i].common, pa_def_subspaces[i].dup_common, pa_def_subspaces[i].zero, @@ -7718,7 +7830,7 @@ create_new_space (name, spnum, loadable, defined, private, sort, seg, user_defined) char *name; int spnum; - int loadable; + int loadable ATTRIBUTE_UNUSED; int defined; int private; int sort; @@ -7798,16 +7910,19 @@ create_new_space (name, spnum, loadable, defined, private, order as defined by the SORT entries. */ static ssd_chain_struct * -create_new_subspace (space, name, loadable, code_only, common, +create_new_subspace (space, name, loadable, code_only, comdat, common, dup_common, is_zero, sort, access, space_index, alignment, quadrant, seg) sd_chain_struct *space; char *name; - int loadable, code_only, common, dup_common, is_zero; + int loadable ATTRIBUTE_UNUSED; + int code_only ATTRIBUTE_UNUSED; + int comdat, common, dup_common; + int is_zero ATTRIBUTE_UNUSED; int sort; int access; - int space_index; - int alignment; + int space_index ATTRIBUTE_UNUSED; + int alignment ATTRIBUTE_UNUSED; int quadrant; asection *seg; { @@ -7860,8 +7975,8 @@ create_new_subspace (space, name, loadable, code_only, common, } #ifdef obj_set_subsection_attributes - obj_set_subsection_attributes (seg, space->sd_seg, access, - sort, quadrant); + obj_set_subsection_attributes (seg, space->sd_seg, access, sort, + quadrant, comdat, common, dup_common); #endif return chain_entry; @@ -7871,19 +7986,20 @@ create_new_subspace (space, name, loadable, code_only, common, various arguments. Return the modified subspace chain entry. */ static ssd_chain_struct * -update_subspace (space, name, loadable, code_only, common, dup_common, sort, - zero, access, space_index, alignment, quadrant, section) +update_subspace (space, name, loadable, code_only, comdat, common, dup_common, + sort, zero, access, space_index, alignment, quadrant, section) sd_chain_struct *space; char *name; - int loadable; - int code_only; + int loadable ATTRIBUTE_UNUSED; + int code_only ATTRIBUTE_UNUSED; + int comdat; int common; int dup_common; - int zero; + int zero ATTRIBUTE_UNUSED; int sort; int access; - int space_index; - int alignment; + int space_index ATTRIBUTE_UNUSED; + int alignment ATTRIBUTE_UNUSED; int quadrant; asection *section; { @@ -7892,8 +8008,8 @@ update_subspace (space, name, loadable, code_only, common, dup_common, sort, chain_entry = is_defined_subspace (name); #ifdef obj_set_subsection_attributes - obj_set_subsection_attributes (section, space->sd_seg, access, - sort, quadrant); + obj_set_subsection_attributes (section, space->sd_seg, access, sort, + quadrant, comdat, common, dup_common); #endif return chain_entry; @@ -7945,9 +8061,14 @@ pa_segment_to_space (seg) return NULL; } -/* Return the space chain entry for the subspace with the name NAME or - NULL if no such subspace exists. +/* Return the first space chain entry for the subspace with the name + NAME or NULL if no such subspace exists. + When there are multiple subspaces with the same name, switching to + the first (i.e., default) subspace is preferable in most situations. + For example, it wouldn't be desirable to merge COMDAT data with non + COMDAT data. + Uses a linear search through all the spaces and subspaces, this may not be appropriate if we ever being placing each function in its own subspace. */ @@ -8053,16 +8174,6 @@ pa_subspace_start (space, quadrant) return 0; return 0; } - -/* FIXME. Needs documentation. */ -static int -pa_next_subseg (space) - sd_chain_struct *space; -{ - - space->sd_last_subseg++; - return space->sd_last_subseg; -} #endif /* Helper function for pa_stringer. Used to find the end of @@ -8126,11 +8237,11 @@ pa_stringer (append_zero) s++; for (num_digit = 0, number = 0, dg = *s; num_digit < 2 - && (isdigit (dg) || (dg >= 'a' && dg <= 'f') + && (ISDIGIT (dg) || (dg >= 'a' && dg <= 'f') || (dg >= 'A' && dg <= 'F')); num_digit++) { - if (isdigit (dg)) + if (ISDIGIT (dg)) number = number * 16 + dg - '0'; else if (dg >= 'a' && dg <= 'f') number = number * 16 + dg - 'a' + 10; @@ -8285,31 +8396,58 @@ pa_lsym (unused) any fixup which creates entries in the DLT (eg they use "T" field selectors). - Reject reductions involving symbols with external scope; such - reductions make life a living hell for object file editors. - - FIXME. Also reject R_HPPA relocations which are 32bits wide in - the code space. The SOM BFD backend doesn't know how to pull the - right bits out of an instruction. */ + ??? Reject reductions involving symbols with external scope; such + reductions make life a living hell for object file editors. */ int hppa_fix_adjustable (fixp) fixS *fixp; { +#ifdef OBJ_ELF + reloc_type code; +#endif struct hppa_fix_struct *hppa_fix; hppa_fix = (struct hppa_fix_struct *) fixp->tc_fix_data; -#ifdef OBJ_SOM - /* Reject reductions of symbols in 32bit relocs. */ - if (fixp->fx_r_type == R_HPPA && hppa_fix->fx_r_format == 32) - return 0; -#endif - #ifdef OBJ_ELF - if (fixp->fx_r_type == (int) R_PARISC_GNU_VTINHERIT - || fixp->fx_r_type == (int) R_PARISC_GNU_VTENTRY) - return 0; + /* LR/RR selectors are implicitly used for a number of different relocation + types. We must ensure that none of these types are adjusted (see below) + even if they occur with a different selector. */ + code = elf_hppa_reloc_final_type (stdoutput, fixp->fx_r_type, + hppa_fix->fx_r_format, + hppa_fix->fx_r_field); + + switch (code) + { + /* Relocation types which use e_lrsel. */ + case R_PARISC_DIR21L: + case R_PARISC_DLTREL21L: + case R_PARISC_DPREL21L: + case R_PARISC_PLTOFF21L: + + /* Relocation types which use e_rrsel. */ + case R_PARISC_DIR14R: + case R_PARISC_DIR14DR: + case R_PARISC_DIR14WR: + case R_PARISC_DIR17R: + case R_PARISC_DLTREL14R: + case R_PARISC_DLTREL14DR: + case R_PARISC_DLTREL14WR: + case R_PARISC_DPREL14R: + case R_PARISC_DPREL14DR: + case R_PARISC_DPREL14WR: + case R_PARISC_PLTOFF14R: + case R_PARISC_PLTOFF14DR: + case R_PARISC_PLTOFF14WR: + + /* Other types that we reject for reduction. */ + case R_PARISC_GNU_VTENTRY: + case R_PARISC_GNU_VTINHERIT: + return 0; + default: + break; + } #endif /* Reject reductions of symbols in sym1-sym2 expressions when @@ -8321,11 +8459,7 @@ hppa_fix_adjustable (fixp) if (fixp->fx_addsy && fixp->fx_subsy && (hppa_fix->segment->flags & SEC_CODE)) - { - /* Apparently sy_used_in_reloc never gets set for sub symbols. */ - symbol_mark_used_in_reloc (fixp->fx_subsy); - return 0; - } + return 0; /* We can't adjust any relocs that use LR% and RR% field selectors. @@ -8349,7 +8483,7 @@ hppa_fix_adjustable (fixp) . RR%sect+4092 == (R%sect)+4092 . RR%sect+4096 == (R%sect)-4096 and the last address loses because rounding the addend to 8k - mutiples takes us up to 8192 with an offset of -4096. + multiples takes us up to 8192 with an offset of -4096. In cases where the LR% expression is identical to the RR% one we will never have a problem, but is so happens that gcc rounds @@ -8372,19 +8506,15 @@ hppa_fix_adjustable (fixp) || hppa_fix->fx_r_field == e_lpsel) return 0; - if (fixp->fx_addsy && (S_IS_EXTERNAL (fixp->fx_addsy) - || S_IS_WEAK (fixp->fx_addsy))) - return 0; - /* Reject absolute calls (jumps). */ if (hppa_fix->fx_r_type == R_HPPA_ABS_CALL) return 0; /* Reject reductions of function symbols. */ - if (fixp->fx_addsy == 0 || ! S_IS_FUNCTION (fixp->fx_addsy)) - return 1; + if (fixp->fx_addsy != 0 && S_IS_FUNCTION (fixp->fx_addsy)) + return 0; - return 0; + return 1; } /* Return nonzero if the fixup in FIXP will require a relocation, @@ -8396,7 +8526,6 @@ hppa_force_relocation (fixp) struct fix *fixp; { struct hppa_fix_struct *hppa_fixp; - int distance; hppa_fixp = (struct hppa_fix_struct *) fixp->tc_fix_data; #ifdef OBJ_SOM @@ -8416,26 +8545,48 @@ hppa_force_relocation (fixp) return 1; #endif + assert (fixp->fx_addsy != NULL); + /* Ensure we emit a relocation for global symbols so that dynamic linking works. */ - if (fixp->fx_addsy && (S_IS_EXTERNAL (fixp->fx_addsy) - || S_IS_WEAK (fixp->fx_addsy))) + if (S_FORCE_RELOC (fixp->fx_addsy, 1)) return 1; /* 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 + entry if they're going to need either an argument relocation or long call stub. */ - if (fixp->fx_pcrel && fixp->fx_addsy - && (arg_reloc_stub_needed (symbol_arg_reloc_info (fixp->fx_addsy), - hppa_fixp->fx_arg_reloc))) + if (fixp->fx_pcrel + && arg_reloc_stub_needed (symbol_arg_reloc_info (fixp->fx_addsy), + hppa_fixp->fx_arg_reloc)) return 1; - distance = (fixp->fx_offset + S_GET_VALUE (fixp->fx_addsy) - - md_pcrel_from (fixp)); - /* Now check and see if we're going to need a long-branch stub. */ - if (fixp->fx_r_type == (int) R_HPPA_PCREL_CALL - && (distance > 262143 || distance < -262144)) - return 1; + /* Now check to see if we're going to need a long-branch stub. */ + if (fixp->fx_r_type == (int) R_HPPA_PCREL_CALL) + { + long pc = md_pcrel_from (fixp); + valueT distance, min_stub_distance; + + distance = fixp->fx_offset + S_GET_VALUE (fixp->fx_addsy) - pc - 8; + + /* Distance to the closest possible stub. This will detect most + but not all circumstances where a stub will not work. */ + min_stub_distance = pc + 16; +#ifdef OBJ_SOM + if (last_call_info != NULL) + min_stub_distance -= S_GET_VALUE (last_call_info->start_symbol); +#endif + + if ((distance + 8388608 >= 16777216 + && min_stub_distance <= 8388608) + || (hppa_fixp->fx_r_format == 17 + && distance + 262144 >= 524288 + && min_stub_distance <= 262144) + || (hppa_fixp->fx_r_format == 12 + && distance + 8192 >= 16384 + && min_stub_distance <= 8192) + ) + return 1; + } if (fixp->fx_r_type == (int) R_HPPA_ABS_CALL) return 1; @@ -8447,7 +8598,7 @@ hppa_force_relocation (fixp) /* Now for some ELF specific code. FIXME. */ #ifdef OBJ_ELF /* Mark the end of a function so that it's possible to compute - the size of the function in hppa_elf_final_processing. */ + the size of the function in elf_hppa_final_processing. */ static void hppa_elf_mark_end_of_function () @@ -8531,13 +8682,6 @@ elf_hppa_final_processing () } } -void -pa_end_of_source () -{ - if (debug_type == DEBUG_DWARF2) - dwarf2_finish (); -} - static void pa_vtable_entry (ignore) int ignore ATTRIBUTE_UNUSED;