/mingw-w64-v2.0.999/binutils/src/gas/config/tc-hppa.c
C | 8793 lines | 6692 code | 949 blank | 1152 comment | 2127 complexity | e37f474bfc1a5821e819997f4d82dff1 MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-1.0, LGPL-3.0, Unlicense, GPL-2.0, LGPL-2.0, BSD-3-Clause, GPL-3.0
Large files files are truncated, but you can click here to view the full file
- /* tc-hppa.c -- Assemble for the PA
- Copyright 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012
- 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 3, or (at your option)
- any later version.
- GAS is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- 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, 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 "as.h"
- #include "safe-ctype.h"
- #include "subsegs.h"
- #include "dw2gencfi.h"
- #include "bfd/libhppa.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
- /* If we are using ELF, then we probably can support dwarf2 debug
- records. Furthermore, if we are supporting dwarf2 debug records,
- then we want to use the assembler support for compact line numbers. */
- #ifdef OBJ_ELF
- #include "dwarf2dbg.h"
- /* 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. */
- typedef enum elf_hppa_reloc_type reloc_type;
- /* Object file formats specify BFD symbol types. */
- typedef elf_symbol_type obj_symbol_type;
- #define symbol_arg_reloc_info(sym)\
- (((obj_symbol_type *) symbol_get_bfdsym (sym))->tc_data.hppa_arg_reloc)
- #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
- to store a copyright string. */
- #define obj_version obj_elf_version
- #define obj_copyright obj_elf_version
- #define UNWIND_SECTION_NAME ".PARISC.unwind"
- #endif /* OBJ_ELF */
- #ifdef OBJ_SOM
- /* Names of various debugging spaces/subspaces. */
- #define GDB_DEBUG_SPACE_NAME "$GDB_DEBUG$"
- #define GDB_STRINGS_SUBSPACE_NAME "$GDB_STRINGS$"
- #define GDB_SYMBOLS_SUBSPACE_NAME "$GDB_SYMBOLS$"
- #define UNWIND_SECTION_NAME "$UNWIND$"
- /* Object file formats specify relocation types. */
- typedef int reloc_type;
- /* SOM objects can have both a version string and a copyright string. */
- #define obj_version obj_som_version
- #define obj_copyright obj_som_copyright
- /* 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;
- #define symbol_arg_reloc_info(sym)\
- (((obj_symbol_type *) symbol_get_bfdsym (sym))->tc_data.ap.hppa_arg_reloc)
- /* This apparently isn't in older versions of hpux reloc.h. */
- #ifndef R_DLT_REL
- #define R_DLT_REL 0x78
- #endif
- #ifndef R_N0SEL
- #define R_N0SEL 0xd8
- #endif
- #ifndef R_N1SEL
- #define R_N1SEL 0xd9
- #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. */
- struct unwind_desc
- {
- unsigned int cannot_unwind:1;
- unsigned int millicode:1;
- unsigned int millicode_save_rest:1;
- unsigned int region_desc:2;
- unsigned int save_sr:2;
- unsigned int entry_fr:4;
- unsigned int entry_gr:5;
- unsigned int args_stored:1;
- unsigned int call_fr:5;
- unsigned int call_gr:5;
- unsigned int save_sp:1;
- unsigned int save_rp:1;
- unsigned int save_rp_in_frame:1;
- unsigned int extn_ptr_defined:1;
- unsigned int cleanup_defined:1;
- unsigned int hpe_interrupt_marker:1;
- unsigned int hpux_interrupt_marker:1;
- unsigned int reserved:3;
- 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
- descriptor. */
- unsigned int start_offset;
- unsigned int end_offset;
- struct unwind_desc descriptor;
- };
- /* This structure is used by the .callinfo, .enter, .leave pseudo-ops to
- control the entry and exit code they generate. It is also used in
- creation of the correct stack unwind descriptors.
- NOTE: GAS does not support .enter and .leave for the generation of
- prologues and epilogues. FIXME.
- The fields in structure roughly correspond to the arguments available on the
- .callinfo pseudo-op. */
- struct call_info
- {
- /* The unwind descriptor being built. */
- struct unwind_table ci_unwind;
- /* Name of this function. */
- symbolS *start_symbol;
- /* (temporary) symbol used to mark the end of this function. */
- symbolS *end_symbol;
- /* Next entry in the chain. */
- struct call_info *ci_next;
- };
- /* Operand formats for FP instructions. Note not all FP instructions
- allow all four formats to be used (for example fmpysub only allows
- SGL and DBL). */
- typedef enum
- {
- SGL, DBL, ILLEGAL_FMT, QUAD, W, UW, DW, UDW, QW, UQW
- }
- fp_operand_format;
- /* This fully describes the symbol types which may be attached to
- an EXPORT or IMPORT directive. Only SOM uses this formation
- (ELF has no need for it). */
- typedef enum
- {
- SYMBOL_TYPE_UNKNOWN,
- SYMBOL_TYPE_ABSOLUTE,
- SYMBOL_TYPE_CODE,
- SYMBOL_TYPE_DATA,
- SYMBOL_TYPE_ENTRY,
- SYMBOL_TYPE_MILLICODE,
- SYMBOL_TYPE_PLABEL,
- SYMBOL_TYPE_PRI_PROG,
- SYMBOL_TYPE_SEC_PROG,
- }
- pa_symbol_type;
- /* This structure contains information needed to assemble
- individual instructions. */
- struct pa_it
- {
- /* Holds the opcode after parsing by pa_ip. */
- unsigned long opcode;
- /* Holds an expression associated with the current instruction. */
- expressionS exp;
- /* Does this instruction use PC-relative addressing. */
- int pcrel;
- /* Floating point formats for operand1 and operand2. */
- fp_operand_format fpof1;
- fp_operand_format fpof2;
- /* Whether or not we saw a truncation request on an fcnv insn. */
- int trunc;
- /* Holds the field selector for this instruction
- (for example L%, LR%, etc). */
- long field_selector;
- /* Holds any argument relocation bits associated with this
- instruction. (instruction should be some sort of call). */
- unsigned int arg_reloc;
- /* The format specification for this instruction. */
- int format;
- /* The relocation (if any) associated with this instruction. */
- reloc_type reloc;
- };
- /* PA-89 floating point registers are arranged like this:
- +--------------+--------------+
- | 0 or 16L | 16 or 16R |
- +--------------+--------------+
- | 1 or 17L | 17 or 17R |
- +--------------+--------------+
- | | |
- . . .
- . . .
- . . .
- | | |
- +--------------+--------------+
- | 14 or 30L | 30 or 30R |
- +--------------+--------------+
- | 15 or 31L | 31 or 31R |
- +--------------+--------------+ */
- /* Additional information needed to build argument relocation stubs. */
- struct call_desc
- {
- /* The argument relocation specification. */
- unsigned int arg_reloc;
- /* Number of arguments. */
- unsigned int arg_count;
- };
- #ifdef OBJ_SOM
- /* This structure defines an entry in the subspace dictionary
- chain. */
- struct subspace_dictionary_chain
- {
- /* Nonzero if this space has been defined by the user code. */
- unsigned int ssd_defined;
- /* Name of this subspace. */
- char *ssd_name;
- /* GAS segment and subsegment associated with this subspace. */
- asection *ssd_seg;
- int ssd_subseg;
- /* Next space in the subspace dictionary chain. */
- struct subspace_dictionary_chain *ssd_next;
- };
- typedef struct subspace_dictionary_chain ssd_chain_struct;
- /* This structure defines an entry in the subspace dictionary
- chain. */
- struct space_dictionary_chain
- {
- /* Nonzero if this space has been defined by the user code or
- as a default space. */
- unsigned int sd_defined;
- /* Nonzero if this spaces has been defined by the user code. */
- unsigned int sd_user_defined;
- /* The space number (or index). */
- unsigned int sd_spnum;
- /* The name of this subspace. */
- char *sd_name;
- /* GAS segment to which this subspace corresponds. */
- asection *sd_seg;
- /* Current subsegment number being used. */
- int sd_last_subseg;
- /* The chain of subspaces contained within this space. */
- ssd_chain_struct *sd_subspaces;
- /* The next entry in the space dictionary chain. */
- struct space_dictionary_chain *sd_next;
- };
- typedef struct space_dictionary_chain sd_chain_struct;
- /* This structure defines attributes of the default subspace
- dictionary entries. */
- struct default_subspace_dict
- {
- /* Name of the subspace. */
- char *name;
- /* FIXME. Is this still needed? */
- char defined;
- /* Nonzero if this subspace is loadable. */
- char loadable;
- /* 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;
- /* Nonzero if this is a common subspace which allows symbols
- to be multiply defined. */
- char dup_common;
- /* Nonzero if this subspace should be zero filled. */
- char zero;
- /* Sort key for this subspace. */
- unsigned char sort;
- /* Access control bits for this subspace. Can represent RWX access
- as well as privilege level changes for gateways. */
- int access;
- /* Index of containing space. */
- int space_index;
- /* Alignment (in bytes) of this subspace. */
- int alignment;
- /* Quadrant within space where this subspace should be loaded. */
- int quadrant;
- /* An index into the default spaces array. */
- int def_space_index;
- /* Subsegment associated with this subspace. */
- subsegT subsegment;
- };
- /* This structure defines attributes of the default space
- dictionary entries. */
- struct default_space_dict
- {
- /* Name of the space. */
- char *name;
- /* Space number. It is possible to identify spaces within
- assembly code numerically! */
- int spnum;
- /* Nonzero if this space is loadable. */
- char loadable;
- /* Nonzero if this space is "defined". FIXME is still needed */
- char defined;
- /* Nonzero if this space can not be shared. */
- char private;
- /* Sort key for this space. */
- unsigned char sort;
- /* Segment associated with this space. */
- asection *segment;
- };
- #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_alt fx_r_field;
- /* Type of fixup. */
- int fx_r_type;
- /* Format of fixup. */
- int fx_r_format;
- /* Argument relocation bits. */
- unsigned int fx_arg_reloc;
- /* The segment this fixup appears in. */
- segT segment;
- };
- /* Structure to hold information about predefined registers. */
- struct pd_reg
- {
- char *name;
- int value;
- };
- /* This structure defines the mapping from a FP condition string
- to a condition number which can be recorded in an instruction. */
- struct fp_cond_map
- {
- char *string;
- int cond;
- };
- /* This structure defines a mapping from a field selector
- string to a field selector type. */
- struct selector_entry
- {
- char *prefix;
- int field_selector;
- };
- /* Prototypes for functions local to tc-hppa.c. */
- #ifdef OBJ_SOM
- static void pa_check_current_space_and_subspace (void);
- #endif
- #if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
- static void pa_text (int);
- static void pa_data (int);
- static void pa_comm (int);
- #endif
- #ifdef OBJ_SOM
- static int exact_log2 (int);
- static void pa_compiler (int);
- static void pa_align (int);
- static void pa_space (int);
- static void pa_spnum (int);
- static void pa_subspace (int);
- static sd_chain_struct *create_new_space (char *, int, int,
- int, int, int,
- asection *, int);
- static ssd_chain_struct *create_new_subspace (sd_chain_struct *,
- char *, int, int,
- int, int, int, int,
- int, int, int, int,
- int, asection *);
- static ssd_chain_struct *update_subspace (sd_chain_struct *,
- char *, int, int, int,
- int, int, int, int,
- int, int, int, int,
- asection *);
- static sd_chain_struct *is_defined_space (char *);
- static ssd_chain_struct *is_defined_subspace (char *);
- static sd_chain_struct *pa_segment_to_space (asection *);
- static ssd_chain_struct *pa_subsegment_to_subspace (asection *,
- subsegT);
- static sd_chain_struct *pa_find_space_by_number (int);
- static unsigned int pa_subspace_start (sd_chain_struct *, int);
- static sd_chain_struct *pa_parse_space_stmt (char *, int);
- #endif
- /* File and globally 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;
- /* 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;
- /* The last call_info (for functions) structure
- seen so it can be associated with fixups and
- function labels. */
- static struct call_info *last_call_info;
- /* The last call description (for actual calls). */
- 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[] = "*?=<>";
- /* This array holds the chars that only start a comment at the beginning of
- a line. If the line seems to have the form '# 123 filename'
- .line and .file directives will appear in the pre-processed output.
- Note that input_file.c hand checks for '#' at the beginning of the
- first line of the input file. This is because the compiler outputs
- #NO_APP at the beginning of its output.
- Also note that C style comments will always work. */
- const char line_comment_chars[] = "#";
- /* This array holds the chars that always start a comment. If the
- pre-processor is disabled, these aren't very useful. */
- const char comment_chars[] = ";";
- /* This array holds the characters which act as line separators. */
- const char line_separator_chars[] = "!";
- /* Chars that can be used to separate mant from exp in floating point nums. */
- const char EXP_CHARS[] = "eE";
- /* Chars that mean this number is a floating point constant.
- As in 0f12.456 or 0d1.2345e12.
- Be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
- changed in read.c. Ideally it shouldn't have to know about it
- at all, but nothing is ideal around here. */
- const char FLT_CHARS[] = "rRsSfFdDxXpP";
- static struct pa_it the_insn;
- /* 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;
- /* Nonzero if a .callinfo appeared within the current procedure. */
- static int callinfo_found;
- /* Nonzero if the assembler is currently within a .entry/.exit pair. */
- static int within_entry_exit;
- /* Nonzero if the assembler is currently within a procedure definition. */
- static int within_procedure;
- /* Handle on structure which keep track of the last symbol
- seen in each subspace. */
- static label_symbol_struct *label_symbols_rootp = NULL;
- /* Holds the last field selector. */
- static int hppa_field_selector;
- /* 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.
- 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
- point registers being numbered from FP_REG_BASE upwards.
- The bit specified with FP_REG_RSEL is set if the floating point
- register has a `r' suffix. */
- #define FP_REG_BASE 64
- #define FP_REG_RSEL 128
- static int pa_number;
- #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;
- /* List of registers that are pre-defined:
- Each general register has one predefined name of the form
- %r<REGNUM> which has the value <REGNUM>.
- Space and control registers are handled in a similar manner,
- but use %sr<REGNUM> and %cr<REGNUM> as their predefined names.
- Likewise for the floating point registers, but of the form
- %fr<REGNUM>. Floating point registers have additional predefined
- names with 'L' and 'R' suffixes (e.g. %fr19L, %fr19R) which
- again have the value <REGNUM>.
- Many registers also have synonyms:
- %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
- Almost every control register has a synonym; they are not listed
- here for brevity.
- The table is sorted. Suitable for searching by a binary search. */
- static const struct pd_reg pre_defined_registers[] =
- {
- {"%arg0", 26},
- {"%arg1", 25},
- {"%arg2", 24},
- {"%arg3", 23},
- {"%cr0", 0},
- {"%cr10", 10},
- {"%cr11", 11},
- {"%cr12", 12},
- {"%cr13", 13},
- {"%cr14", 14},
- {"%cr15", 15},
- {"%cr16", 16},
- {"%cr17", 17},
- {"%cr18", 18},
- {"%cr19", 19},
- {"%cr20", 20},
- {"%cr21", 21},
- {"%cr22", 22},
- {"%cr23", 23},
- {"%cr24", 24},
- {"%cr25", 25},
- {"%cr26", 26},
- {"%cr27", 27},
- {"%cr28", 28},
- {"%cr29", 29},
- {"%cr30", 30},
- {"%cr31", 31},
- {"%cr8", 8},
- {"%cr9", 9},
- {"%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},
- {"%fr1", 1 + FP_REG_BASE},
- {"%fr10", 10 + FP_REG_BASE},
- {"%fr10l", 10 + FP_REG_BASE},
- {"%fr10r", 10 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr11", 11 + FP_REG_BASE},
- {"%fr11l", 11 + FP_REG_BASE},
- {"%fr11r", 11 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr12", 12 + FP_REG_BASE},
- {"%fr12l", 12 + FP_REG_BASE},
- {"%fr12r", 12 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr13", 13 + FP_REG_BASE},
- {"%fr13l", 13 + FP_REG_BASE},
- {"%fr13r", 13 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr14", 14 + FP_REG_BASE},
- {"%fr14l", 14 + FP_REG_BASE},
- {"%fr14r", 14 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr15", 15 + FP_REG_BASE},
- {"%fr15l", 15 + FP_REG_BASE},
- {"%fr15r", 15 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr16", 16 + FP_REG_BASE},
- {"%fr16l", 16 + FP_REG_BASE},
- {"%fr16r", 16 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr17", 17 + FP_REG_BASE},
- {"%fr17l", 17 + FP_REG_BASE},
- {"%fr17r", 17 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr18", 18 + FP_REG_BASE},
- {"%fr18l", 18 + FP_REG_BASE},
- {"%fr18r", 18 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr19", 19 + FP_REG_BASE},
- {"%fr19l", 19 + FP_REG_BASE},
- {"%fr19r", 19 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr1l", 1 + FP_REG_BASE},
- {"%fr1r", 1 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr2", 2 + FP_REG_BASE},
- {"%fr20", 20 + FP_REG_BASE},
- {"%fr20l", 20 + FP_REG_BASE},
- {"%fr20r", 20 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr21", 21 + FP_REG_BASE},
- {"%fr21l", 21 + FP_REG_BASE},
- {"%fr21r", 21 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr22", 22 + FP_REG_BASE},
- {"%fr22l", 22 + FP_REG_BASE},
- {"%fr22r", 22 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr23", 23 + FP_REG_BASE},
- {"%fr23l", 23 + FP_REG_BASE},
- {"%fr23r", 23 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr24", 24 + FP_REG_BASE},
- {"%fr24l", 24 + FP_REG_BASE},
- {"%fr24r", 24 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr25", 25 + FP_REG_BASE},
- {"%fr25l", 25 + FP_REG_BASE},
- {"%fr25r", 25 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr26", 26 + FP_REG_BASE},
- {"%fr26l", 26 + FP_REG_BASE},
- {"%fr26r", 26 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr27", 27 + FP_REG_BASE},
- {"%fr27l", 27 + FP_REG_BASE},
- {"%fr27r", 27 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr28", 28 + FP_REG_BASE},
- {"%fr28l", 28 + FP_REG_BASE},
- {"%fr28r", 28 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr29", 29 + FP_REG_BASE},
- {"%fr29l", 29 + FP_REG_BASE},
- {"%fr29r", 29 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr2l", 2 + FP_REG_BASE},
- {"%fr2r", 2 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr3", 3 + FP_REG_BASE},
- {"%fr30", 30 + FP_REG_BASE},
- {"%fr30l", 30 + FP_REG_BASE},
- {"%fr30r", 30 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr31", 31 + FP_REG_BASE},
- {"%fr31l", 31 + FP_REG_BASE},
- {"%fr31r", 31 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr3l", 3 + FP_REG_BASE},
- {"%fr3r", 3 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr4", 4 + FP_REG_BASE},
- {"%fr4l", 4 + FP_REG_BASE},
- {"%fr4r", 4 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr5", 5 + FP_REG_BASE},
- {"%fr5l", 5 + FP_REG_BASE},
- {"%fr5r", 5 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr6", 6 + FP_REG_BASE},
- {"%fr6l", 6 + FP_REG_BASE},
- {"%fr6r", 6 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr7", 7 + FP_REG_BASE},
- {"%fr7l", 7 + FP_REG_BASE},
- {"%fr7r", 7 + FP_REG_BASE + FP_REG_RSEL},
- {"%fr8", 8 + FP_REG_BASE},
- {"%fr8l", 8 + FP_REG_BASE},
- {"%fr8r", 8 + FP_REG_BASE + FP_REG_RSEL},
- {"%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},
- {"%ipsw", 22},
- {"%isr", 20},
- {"%itmr", 16},
- {"%iva", 14},
- #if TARGET_ARCH_SIZE == 64
- {"%mrp", 2},
- #else
- {"%mrp", 31},
- #endif
- {"%pcoq", 18},
- {"%pcsq", 17},
- {"%pidr1", 8},
- {"%pidr2", 9},
- {"%pidr3", 12},
- {"%pidr4", 13},
- {"%ppda", 24},
- {"%r0", 0},
- {"%r1", 1},
- {"%r10", 10},
- {"%r11", 11},
- {"%r12", 12},
- {"%r13", 13},
- {"%r14", 14},
- {"%r15", 15},
- {"%r16", 16},
- {"%r17", 17},
- {"%r18", 18},
- {"%r19", 19},
- {"%r2", 2},
- {"%r20", 20},
- {"%r21", 21},
- {"%r22", 22},
- {"%r23", 23},
- {"%r24", 24},
- {"%r25", 25},
- {"%r26", 26},
- {"%r27", 27},
- {"%r28", 28},
- {"%r29", 29},
- {"%r3", 3},
- {"%r30", 30},
- {"%r31", 31},
- {"%r4", 4},
- {"%r5", 5},
- {"%r6", 6},
- {"%r7", 7},
- {"%r8", 8},
- {"%r9", 9},
- {"%rctr", 0},
- {"%ret0", 28},
- {"%ret1", 29},
- {"%rp", 2},
- {"%sar", 11},
- {"%sp", 30},
- {"%sr0", 0},
- {"%sr1", 1},
- {"%sr2", 2},
- {"%sr3", 3},
- {"%sr4", 4},
- {"%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},
- {"%tr3", 27},
- {"%tr4", 28},
- {"%tr5", 29},
- {"%tr6", 30},
- {"%tr7", 31}
- };
- /* 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
- for < first, we would get a false match. */
- static const struct fp_cond_map fp_cond_map[] =
- {
- {"false?", 0},
- {"false", 1},
- {"true?", 30},
- {"true", 31},
- {"!<=>", 3},
- {"!?>=", 8},
- {"!?<=", 16},
- {"!<>", 7},
- {"!>=", 11},
- {"!?>", 12},
- {"?<=", 14},
- {"!<=", 19},
- {"!?<", 20},
- {"?>=", 22},
- {"!?=", 24},
- {"!=t", 27},
- {"<=>", 29},
- {"=t", 5},
- {"?=", 6},
- {"?<", 10},
- {"<=", 13},
- {"!>", 15},
- {"?>", 18},
- {">=", 21},
- {"!<", 23},
- {"<>", 25},
- {"!=", 26},
- {"!?", 28},
- {"?", 2},
- {"=", 4},
- {"<", 9},
- {">", 17}
- };
- static const struct selector_entry selector_table[] =
- {
- {"f", e_fsel},
- {"l", e_lsel},
- {"ld", e_ldsel},
- {"lp", e_lpsel},
- {"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},
- {"rp", e_rpsel},
- {"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
- #define GDB_STRINGS GDB_STRINGS_SUBSPACE_NAME
- /* pre-defined subsegments (subspaces) for the HPPA. */
- #define SUBSEG_CODE 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
- #define SUBSEG_GDB_SYMBOLS 1
- static struct default_subspace_dict pa_def_subspaces[] =
- {
- {"$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[] =
- {
- {"$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. */
- /* 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
- #define SPACE_SPNUM(space_chain) (space_chain)->sd_spnum
- #define SPACE_NAME(space_chain) (space_chain)->sd_name
- #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')
- /* Store immediate values of shift/deposit/extract functions. */
- #define SAVE_IMMEDIATE(VALUE) \
- { \
- if (immediate_check) \
- { \
- if (pos == -1) \
- pos = (VALUE); \
- else if (len == -1) \
- len = (VALUE); \
- } \
- }
- /* Insert FIELD into OPCODE starting at bit START. Continue pa_ip
- main loop after insertion. */
- #define INSERT_FIELD_AND_CONTINUE(OPCODE, FIELD, START) \
- { \
- ((OPCODE) |= (FIELD) << (START)); \
- continue; \
- }
- /* 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) \
- { \
- if ((FIELD) > (HIGH) || (FIELD) < (LOW)) \
- { \
- if (! IGNORE) \
- as_bad (_("Field out of range [%d..%d] (%d)."), (LOW), (HIGH), \
- (int) (FIELD));\
- break; \
- } \
- }
- /* 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) \
- { \
- if ((FIELD) & ((ALIGN) - 1)) \
- { \
- if (! IGNORE) \
- as_bad (_("Field not properly aligned [%d] (%d)."), (ALIGN), \
- (int) (FIELD));\
- break; \
- } \
- }
- #define is_DP_relative(exp) \
- ((exp).X_op == O_subtract \
- && strcmp (S_GET_NAME ((exp).X_op_symbol), "$global$") == 0)
- #define is_SB_relative(exp) \
- ((exp).X_op == O_subtract \
- && strcmp (S_GET_NAME ((exp).X_op_symbol), "$segrel$") == 0)
- #define is_PC_relative(exp) \
- ((exp).X_op == O_subtract \
- && strcmp (S_GET_NAME ((exp).X_op_symbol), "$PIC_pcrel$0") == 0)
- #define is_tls_gdidx(exp) \
- ((exp).X_op == O_subtract \
- && strcmp (S_GET_NAME ((exp).X_op_symbol), "$tls_gdidx$") == 0)
- #define is_tls_ldidx(exp) \
- ((exp).X_op == O_subtract \
- && strcmp (S_GET_NAME ((exp).X_op_symbol), "$tls_ldidx$") == 0)
- #define is_tls_dtpoff(exp) \
- ((exp).X_op == O_subtract \
- && strcmp (S_GET_NAME ((exp).X_op_symbol), "$tls_dtpoff$") == 0)
- #define is_tls_ieoff(exp) \
- ((exp).X_op == O_subtract \
- && strcmp (S_GET_NAME ((exp).X_op_symbol), "$tls_ieoff$") == 0)
- #define is_tls_leoff(exp) \
- ((exp).X_op == O_subtract \
- && strcmp (S_GET_NAME ((exp).X_op_symbol), "$tls_leoff$") == 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 (void)
- {
- 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. */
- static label_symbol_struct *
- pa_get_label (void)
- {
- label_symbol_struct *label_chain;
- for (label_chain = label_symbols_rootp;
- label_chain;
- label_chain = label_chain->lss_next)
- {
- #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;
- }
- /* Defines a label for the current space. If one is already defined,
- this function will replace it with the new label. */
- void
- pa_define_label (symbolS *symbol)
- {
- label_symbol_struct *label_chain = pa_get_label ();
- if (label_chain)
- label_chain->lss_label = symbol;
- else
- {
- /* Create a new label entry and add it to the head of the chain. */
- label_chain = xmalloc (sizeof (label_symbol_struct));
- label_chain->lss_label = symbol;
- #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)
- label_chain->lss_next = label_symbols_rootp;
- label_symbols_rootp = label_chain;
- }
- #ifdef OBJ_ELF
- dwarf2_emit_label (symbol);
- #endif
- }
- /* Removes a label definition for the current space.
- If there is no label_symbol_struct entry, then no action is taken. */
- static void
- pa_undefine_label (void)
- {
- label_symbol_struct *label_chain;
- label_symbol_struct *prev_label_chain = NULL;
- for (label_chain = label_symbols_rootp;
- label_chain;
- label_chain = label_chain->lss_next)
- {
- 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)
- prev_label_chain->lss_next = label_chain->lss_next;
- else
- label_symbols_rootp = label_chain->lss_next;
- free (label_chain);
- break;
- }
- prev_label_chain = label_chain;
- }
- }
- /* An HPPA-specific version of fix_new. This is required because the HPPA
- 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
- tc_fix_data field. */
- static void
- fix_new_hppa (fragS *frag,
- int where,
- int size,
- symbolS *add_symbol,
- offsetT offset,
- expressionS *exp,
- int pcrel,
- bfd_reloc_code_real_type r_type,
- enum hppa_reloc_field_selector_type_alt r_field,
- int r_format,
- unsigned int arg_reloc,
- int unwind_bits ATTRIBUTE_UNUSED)
- {
- fixS *new_fix;
- struct hppa_fix_struct *hppa_fix = obstack_alloc (¬es, sizeof (struct hppa_fix_struct));
- if (exp != NULL)
- new_fix = fix_new_exp (frag, where, size, exp, pcrel, r_type);
- else
- new_fix = fix_new (frag, where, size, add_symbol, offset, pcrel, r_type);
- new_fix->tc_fix_data = (void *) hppa_fix;
- hppa_fix->fx_r_type = r_type;
- hppa_fix->fx_r_field = r_field;
- hppa_fix->fx_r_format = r_format;
- hppa_fix->fx_arg_reloc = arg_reloc;
- hppa_fix->segment = now_seg;
- #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
- it now so as not to confuse write.c. Ditto for $PIC_pcrel$0. */
- if (new_fix->fx_subsy
- && (strcmp (S_GET_NAME (new_fix->fx_subsy), "$global$") == 0
- || strcmp (S_GET_NAME (new_fix->fx_subsy), "$segrel$") == 0
- || strcmp (S_GET_NAME (new_fix->fx_subsy), "$PIC_pcrel$0") == 0
- || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_gdidx$") == 0
- || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_ldidx$") == 0
- || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_dtpoff$") == 0
- || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_ieoff$") == 0
- || strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_leoff$") == 0))
- new_fix->fx_subsy = NULL;
- }
- /* This fix_new is called by cons via TC_CONS_FIX_NEW.
- hppa_field_selector is set by the parse_cons_expression_hppa. */
- void
- cons_fix_new_hppa (fragS *frag, int where, int size, expressionS *exp)
- {
- unsigned int rel_type;
- /* 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;
- #ifdef OBJ_ELF
- else if (is_SB_relative (*exp))
- rel_type = R_PARISC_SEGREL32;
- else if (is_tls_gdidx (*exp))
- rel_type = R_PARISC_TLS_GD21L;
- else if (is_tls_ldidx (*exp))
- rel_type = R_PARISC_TLS_LDM21L;
- else if (is_tls_dtpoff (*exp))
- rel_type = R_PARISC_TLS_LDO21L;
- else if (is_tls_ieoff (*exp))
- rel_type = R_PARISC_TLS_IE21L;
- else if (is_tls_leoff (*exp))
- rel_type = R_PARISC_TLS_LE21L;
- #endif
- else if (is_complex (*exp))
- rel_type = R_HPPA_COMPLEX;
- else
- rel_type = R_HPPA;
- if (hppa_field_selector != e_psel && hppa_field_selector != e_fsel)
- {
- as_warn (_("Invalid field selector. Assuming F%%."));
- hppa_field_selector = e_fsel;
- }
- fix_new_hppa (frag, where, size,
- (symbolS *) NULL, (offsetT) 0, exp, 0, rel_type,
- hppa_field_selector, size * 8, 0, 0);
- /* Reset field selector to its default state. */
- hppa_field_selector = 0;
- }
- /* Mark (via expr_end) the end of an expression (I think). FIXME. */
- static void
- get_expression (char *str)
- {
- char *save_in;
- asection *seg;
- save_in = input_line_pointer;
- input_line_pointer = str;
- seg = expression (&the_insn.exp);
- if (!(seg == absolute_section
- || seg == undefined_section
- || SEG_NORMAL (seg)))
- {
- as_warn (_("Bad segment in expression."));
- expr_end = input_line_pointer;
- input_line_pointer = save_in;
- return;
- }
- expr_end = input_line_pointer;
- input_line_pointer = save_in;
- }
- /* Parse a PA nullification completer (,n). Return nonzero if the
- completer was found; return zero if no completer was found. */
- static int
- pa_parse_nullif (char **s)
- {
- int nullif;
- nullif = 0;
- if (**s == ',')
- {
- *s = *s + 1;
- if (strncasecmp (*s, "n", 1) == 0)
- nullif = 1;
- else
- {
- as_bad (_("Invalid Nullification: (%c)"), **s);
- nullif = 0;
- }
- *s = *s + 1;
- }
- return nullif;
- }
- char *
- md_atof (int type, char *litP, int *sizeP)
- {
- return ieee_md_atof (type, litP, sizeP, TRUE);
- }
- /* Write out big-endian. */
- void
- md_number_to_chars (char *buf, valueT val, int n)
- {
- number_to_chars_bigendian (buf, val, n);
- }
- /* Translate internal representation of relocation info to BFD target
- format. */
- arelent **
- tc_gen_reloc (asection *section, fixS *fixp)
- {
- arelent *reloc;
- struct hppa_fix_struct *hppa_fixp;
- static arelent *no_relocs = NULL;
- arelent **relocs;
- reloc_type **codes;
- reloc_type code;
- int n_relocs;
- int i;
- hppa_fixp = (struct hppa_fix_struct *) fixp->tc_fix_data;
- if (fixp->fx_addsy == 0)
- return &no_relocs;
- gas_assert (hppa_fixp != 0);
- gas_assert (section != 0);
- reloc = xmalloc (sizeof (arelent));
- reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
- *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
- /* Allow fixup_segment to recognize hand-written pc-relative relocations.
- When we went through cons_fix_new_hppa, we classified them as complex. */
- /* ??? It might be better to hide this +8 stuff in tc_cfi_emit_pcrel_expr,
- undefine DIFF_EXPR_OK, and let these sorts of complex expressions fail
- when R_HPPA_COMPLEX == R_PARISC_UNIMPLEMENTED. */
- if (fixp->fx_r_type == (bfd_reloc_code_real_type) R_HPPA_COMPLEX
- && fixp->fx_pcrel)
- {
- fixp->fx_r_type = R_HPPA_PCREL_CALL;
- fixp->fx_offset += 8;
- }
- codes = hppa_gen_reloc_type (stdoutput,
- fixp->fx_r_type,
- hppa_fixp->fx_r_format,
- hppa_fixp->fx_r_field,
- fixp->fx_subsy != NULL,
- symbol_get_bfdsym (fixp->fx_addsy));
- if (codes == NULL)
- {
- as_bad_where (fixp->fx_file, fixp->fx_line, _("Cannot handle fixup"));
- abort ();
- }
- for (n_relocs = 0; codes[n_relocs]; n_relocs++)
- ;
- relocs = xmalloc (sizeof (arelent *) * n_relocs + 1);
- reloc = xmalloc (sizeof (arelent) * n_relocs);
- for (i = 0; i < n_relocs; i++)
- relocs[i] = &reloc[i];
- relocs[n_relocs] = NULL;
- #ifdef OBJ_ELF
- switch (fixp->fx_r_type)
- {
- default:
- gas_assert (n_relocs == 1);
- code = *codes[0];
- /* Now, do any processing that is dependent on the relocation type. */
- switch (code)
- {
- 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). This adjustment is done in
- bfd/elf32-hppa.c:elf32_hppa_relocate_section.
- 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;
- #ifdef ELF_ARG_RELOC
- case R_PARISC_PCREL17R:
- case R_PARISC_PCREL17F:
- case R_PARISC_PCREL17C:
- case R_PARISC_DIR17R:
- case R_PARISC_DIR17F:
- case R_PARISC_PCREL21L:
- case R_PARISC_DIR21L:
- reloc->addend = HPPA_R_ADDEND (hppa_fixp->fx_arg_reloc,
- fixp->fx_offset);
- 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 = 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;
- gas_assert (reloc->howto && (unsigned int) code == reloc->howto->type);
- break;
- }
- #else /* OBJ_SOM */
- /* Walk over reach relocation returned by the BFD backend. */
- for (i = 0; i < n_relocs; i++)
- {
- code = *codes[i];
- relocs[i]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
- *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
- relocs[i]->howto =
- bfd_reloc_type_lookup (stdoutput,
- (bfd_reloc_code_real_type) 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. */
- gas_assert (i == 1);
- relocs[0]->sym_ptr_ptr
- = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr;
- relocs[0]->howto
- = bfd_reloc_type_lookup (stdoutput,
- (bfd_reloc_code_real_type) *codes[0]);
- relocs[0]->address = fixp->fx_frag->fr_address + fixp->fx_where;
- relocs[0]->addend = 0;
- relocs[1]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
- *relocs[1]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
- relocs[1]->howto
- = bfd_reloc_type_lookup (stdoutput,
- (bfd_reloc_code_real_type) *codes[1]);
- relocs[1]->address = fixp->fx_frag->fr_address + fixp->fx_where;
- relocs[1]->addend = 0;
- relocs[2]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
- *relocs[2]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
- relocs[2]->howto
- = bfd_reloc_type_lookup (stdoutput,
- (bfd_reloc_code_real_type) *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_section_ptr->symbol_ptr_ptr;
- relocs[3]->howto
- = bfd_reloc_type_lookup (stdoutput,
- (bfd_reloc_code_real_type) *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_section_ptr->symbol_ptr_ptr;
- relocs[4]->howto
- = bfd_reloc_type_lookup (stdoutput,
- (bfd_reloc_code_real_type) *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!
- 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;
- case R_N_MODE:
- case R_S_MODE:
- case R_D_MODE:
- case R_R_MODE:
- 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 = xmalloc (sizeof (asymbol *));
- *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
- relocs[i]->addend = 0;
- break;
- case R_END_TRY:
- case R_ENTRY:
- case R_EXIT:
- /* There is no symbol associated with these fixups. */
- relocs[i]->sym_ptr_ptr = 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;
- }
- /* Process any machine dependent frag types. */
- void
- md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
- asection *sec ATTRIBUTE_UNUSED,
- fragS *fragP)
- {
- unsigned int address;
- if (fragP->fr_type == rs_machine_dependent)
- {
- switch ((int) fragP->fr_subtype)
- {
- case 0:
- fragP->fr_type = rs_fill;
- know (fragP->fr_var == 1);
- know (fragP->fr_next);
- address = fragP->fr_address + fragP->fr_fix;
- if (address % fragP->fr_offset)
- {
- fragP->fr_offset =
- fragP->fr_next->fr_address
- - fragP->fr_address
- - fragP->fr_fix;
- }
- else
- fragP->fr_offset = 0;
- break;
- }
- }
- }
- /* Round up a section size to the appropriate boundary. */
- valueT
- md_section_align (asection *segment, valueT size)
- {
- int align = bfd_get_section_alignment (stdoutput, segment);
- int align2 = (1 << align) - 1;
- return (size + align2) & ~align2;
- }
- /* Return the approximate size of a frag before relaxation has occurred. */
- int
- md_estimate_size_before_relax (fragS *fragP, asection *segment ATTRIBUTE_UNUSED)
- {
- int size;
- size = 0;
- while ((fragP->fr_fix + size) % fragP->fr_offset)
- size++;
- return size;
- }
- #ifdef OBJ_ELF
- # ifdef WARN_COMMENTS
- const char *md_shortopts = "Vc";
- # else
- const char *md_shortopts = "V";
- # endif
- #else
- # ifdef WARN_COMMENTS
- const char *md_shortopts = "c";
- # else
- const char *md_shortopts = "";
- # endif
- #endif
- struct option md_longopts[] =
- {
- #ifdef WARN_COMMENTS
- {"warn-comment", no_argument, NULL, 'c'},
- #endif
- {NULL, no_argument, NULL, 0}
- };
- size_t md_longopts_size = sizeof (md_longopts);
- int
- md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
- {
- switch (c)
- {
- default:
- return 0;
- #ifdef OBJ_ELF
- case 'V':
- print_version_id ();
- break;
- #endif
- #ifdef WARN_COMMENTS
- case 'c':
- warn_comment = 1;
- break;
- #endif
- }
- return 1;
- }
- void
- md_show_usage (FILE *stream ATTRIBUTE_UNUSED)
- {
- #ifdef OBJ_ELF
- fprintf (stream, _("\
- -Q ignored\n"));
- #endif
- #ifdef WARN_COMMENTS
- fprintf (stream, _("\
- -c print a warning if a comment is found\n"));
- #endif
- }
- /* We have no need to default values of symbols. */
- symbolS *
- md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
- {
- return NULL;
- }
- #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) \
- (((CALLER) ^ (CALLEE)) & nonzero_dibits (CALLER) & nonzero_dibits (CALLEE))
- #else
- #define arg_reloc_stub_needed(CALLER, CALLEE) 0
- #endif
- /* Apply a fixup to an instruction. */
- void
- md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
- {
- char *fixpos;
- struct hppa_fix_struct *hppa_fixP;
- offsetT new_val;
- int insn, val, fmt;
- /* 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_BEGIN_BRTAB
- || fixP->fx_r_type == R_HPPA_END_BRTAB
- || fixP->fx_r_type == R_HPPA_BEGIN_TRY)
- 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;
- }
- #endif
- #ifdef OBJ_ELF
- if (fixP->fx_r_type == (int) R_PARISC_GNU_VTENTRY
- || fixP->fx_r_type == (int) R_PARISC_GNU_VTINHERIT)
- return;
- #endif
- 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)
- {
- /* 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 someth…
Large files files are truncated, but you can click here to view the full file