#include <stdio.h>
#include "as.h"
#include "safe-ctype.h"
#include "subsegs.h"
#include "bfd/libhppa.h"
#include "opcode/hppa.h"
#if defined (OBJ_ELF) && defined (OBJ_SOM)
error only one of OBJ_ELF and OBJ_SOM can be defined
#endif
#ifdef OBJ_ELF
#include "dwarf2dbg.h"
typedef enum elf_hppa_reloc_type reloc_type;
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
#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
#define obj_version obj_elf_version
#define obj_copyright obj_elf_version
#define UNWIND_SECTION_NAME ".PARISC.unwind"
#endif
#ifdef OBJ_SOM
#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$"
typedef int reloc_type;
#define obj_version obj_som_version
#define obj_copyright obj_som_copyright
#define hppa_gen_reloc_type hppa_som_gen_reloc_type
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)
#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
#if TARGET_ARCH_SIZE == 64
#define DEFAULT_LEVEL 25
#else
#define DEFAULT_LEVEL 10
#endif
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;
};
#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
{
unsigned int start_offset;
unsigned int end_offset;
struct unwind_desc descriptor;
};
struct call_info
{
struct unwind_table ci_unwind;
symbolS *start_symbol;
symbolS *end_symbol;
struct call_info *ci_next;
};
typedef enum
{
SGL, DBL, ILLEGAL_FMT, QUAD, W, UW, DW, UDW, QW, UQW
}
fp_operand_format;
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;
struct pa_it
{
unsigned long opcode;
expressionS exp;
int pcrel;
fp_operand_format fpof1;
fp_operand_format fpof2;
int trunc;
long field_selector;
unsigned int arg_reloc;
int format;
reloc_type reloc;
};
struct call_desc
{
unsigned int arg_reloc;
unsigned int arg_count;
};
#ifdef OBJ_SOM
struct subspace_dictionary_chain
{
unsigned int ssd_defined;
char *ssd_name;
asection *ssd_seg;
int ssd_subseg;
struct subspace_dictionary_chain *ssd_next;
};
typedef struct subspace_dictionary_chain ssd_chain_struct;
struct space_dictionary_chain
{
unsigned int sd_defined;
unsigned int sd_user_defined;
unsigned int sd_spnum;
char *sd_name;
asection *sd_seg;
int sd_last_subseg;
ssd_chain_struct *sd_subspaces;
struct space_dictionary_chain *sd_next;
};
typedef struct space_dictionary_chain sd_chain_struct;
struct default_subspace_dict
{
char *name;
char defined;
char loadable;
char code_only;
char comdat;
char common;
char dup_common;
char zero;
unsigned char sort;
int access;
int space_index;
int alignment;
int quadrant;
int def_space_index;
subsegT subsegment;
};
struct default_space_dict
{
char *name;
int spnum;
char loadable;
char defined;
char private;
unsigned char sort;
asection *segment;
};
#endif
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;
struct hppa_fix_struct
{
enum hppa_reloc_field_selector_type_alt fx_r_field;
int fx_r_type;
int fx_r_format;
unsigned int fx_arg_reloc;
segT segment;
};
struct pd_reg
{
char *name;
int value;
};
struct fp_cond_map
{
char *string;
int cond;
};
struct selector_entry
{
char *prefix;
int field_selector;
};
#ifdef OBJ_SOM
static void pa_check_current_space_and_subspace PARAMS ((void));
#endif
#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));
#endif
static fp_operand_format pa_parse_fp_format PARAMS ((char **s));
static void pa_cons PARAMS ((int));
static void pa_float_cons PARAMS ((int));
static void pa_fill PARAMS ((int));
static void pa_lcomm PARAMS ((int));
static void pa_lsym PARAMS ((int));
static void pa_stringer PARAMS ((int));
static void pa_version PARAMS ((int));
static int pa_parse_fp_cmp_cond PARAMS ((char **));
static int get_expression PARAMS ((char *));
static int pa_get_absolute_expression PARAMS ((struct pa_it *, char **));
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 **));
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 **));
static void pa_block PARAMS ((int));
static void pa_brtab PARAMS ((int));
static void pa_try PARAMS ((int));
static void pa_call PARAMS ((int));
static void pa_call_args PARAMS ((struct call_desc *));
static void pa_callinfo PARAMS ((int));
static void pa_copyright PARAMS ((int));
static void pa_end PARAMS ((int));
static void pa_enter PARAMS ((int));
static void pa_entry PARAMS ((int));
static void pa_equ PARAMS ((int));
static void pa_exit PARAMS ((int));
static void pa_export PARAMS ((int));
static void pa_type_args PARAMS ((symbolS *, int));
static void pa_import PARAMS ((int));
static void pa_label PARAMS ((int));
static void pa_leave PARAMS ((int));
static void pa_level PARAMS ((int));
static void pa_origin PARAMS ((int));
static void pa_proc PARAMS ((int));
static void pa_procend PARAMS ((int));
static void pa_param PARAMS ((int));
static void pa_undefine_label PARAMS ((void));
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 exact_log2 PARAMS ((int));
static void pa_compiler PARAMS ((int));
static void pa_align PARAMS ((int));
static void pa_space PARAMS ((int));
static void pa_spnum PARAMS ((int));
static void pa_subspace PARAMS ((int));
static sd_chain_struct *create_new_space PARAMS ((char *, int, int,
int, int, int,
asection *, int));
static ssd_chain_struct *create_new_subspace PARAMS ((sd_chain_struct *,
char *, 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,
asection *));
static sd_chain_struct *is_defined_space PARAMS ((char *));
static ssd_chain_struct *is_defined_subspace PARAMS ((char *));
static sd_chain_struct *pa_segment_to_space PARAMS ((asection *));
static ssd_chain_struct *pa_subsegment_to_subspace PARAMS ((asection *,
subsegT));
static sd_chain_struct *pa_find_space_by_number PARAMS ((int));
static unsigned int pa_subspace_start PARAMS ((sd_chain_struct *, int));
static sd_chain_struct *pa_parse_space_stmt PARAMS ((char *, int));
static void pa_spaces_begin PARAMS ((void));
#endif
static void pa_ip PARAMS ((char *));
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));
static int is_end_of_statement PARAMS ((void));
static int reg_name_search PARAMS ((char *));
static int pa_chk_field_selector PARAMS ((char **));
static int is_same_frag PARAMS ((fragS *, fragS *));
static void process_exit PARAMS ((void));
static unsigned int pa_stringer_aux PARAMS ((char *));
static fp_operand_format pa_parse_fp_cnv_format PARAMS ((char **s));
static int pa_parse_ftest_gfx_completer PARAMS ((char **));
#ifdef OBJ_ELF
static void hppa_elf_mark_end_of_function PARAMS ((void));
static void pa_build_unwind_subspace PARAMS ((struct call_info *));
static void pa_vtable_entry PARAMS ((int));
static void pa_vtable_inherit PARAMS ((int));
#endif
#ifdef OBJ_SOM
static sd_chain_struct *space_dict_root;
static sd_chain_struct *space_dict_last;
static sd_chain_struct *current_space;
static ssd_chain_struct *current_subspace;
#endif
static struct call_info *call_info_root;
static struct call_info *last_call_info;
static struct call_desc last_call_desc;
static struct hash_control *op_hash = NULL;
const char hppa_symbol_chars[] = "*?=<>";
const pseudo_typeS md_pseudo_table[] =
{
#ifdef OBJ_SOM
{"align", pa_align, 8},
#endif
#ifdef OBJ_ELF
{"align", s_align_bytes, 8},
#endif
{"begin_brtab", pa_brtab, 1},
{"begin_try", pa_try, 1},
{"block", pa_block, 1},
{"blockz", pa_block, 0},
{"byte", pa_cons, 1},
{"call", pa_call, 0},
{"callinfo", pa_callinfo, 0},
#if defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD))
{"code", obj_elf_text, 0},
#else
{"code", pa_text, 0},
{"comm", pa_comm, 0},
#endif
#ifdef OBJ_SOM
{"compiler", pa_compiler, 0},
#endif
{"copyright", pa_copyright, 0},
#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) || defined (TE_NetBSD)))
{"end_try", pa_try, 0},
#endif
{"enter", pa_enter, 0},
{"entry", pa_entry, 0},
{"equ", pa_equ, 0},
{"exit", pa_exit, 0},
{"export", pa_export, 0},
{"fill", pa_fill, 0},
{"float", pa_float_cons, 'f'},
{"half", pa_cons, 2},
{"import", pa_import, 0},
{"int", pa_cons, 4},
{"label", pa_label, 0},
{"lcomm", pa_lcomm, 0},
{"leave", pa_leave, 0},
{"level", pa_level, 0},
{"long", pa_cons, 4},
{"lsym", pa_lsym, 0},
#ifdef OBJ_SOM
{"nsubspa", pa_subspace, 1},
#endif
{"octa", pa_cons, 16},
{"org", pa_origin, 0},
{"origin", pa_origin, 0},
{"param", pa_param, 0},
{"proc", pa_proc, 0},
{"procend", pa_procend, 0},
{"quad", pa_cons, 8},
{"reg", pa_equ, 1},
{"short", pa_cons, 2},
{"single", pa_float_cons, 'f'},
#ifdef OBJ_SOM
{"space", pa_space, 0},
{"spnum", pa_spnum, 0},
#endif
{"string", pa_stringer, 0},
{"stringz", pa_stringer, 1},
#ifdef OBJ_SOM
{"subspa", pa_subspace, 0},
#endif
#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
{"text", pa_text, 0},
#endif
{"version", pa_version, 0},
#ifdef OBJ_ELF
{"vtable_entry", pa_vtable_entry, 0},
{"vtable_inherit", pa_vtable_inherit, 0},
#endif
{"word", pa_cons, 4},
{NULL, 0, 0}
};
const char line_comment_chars[] = "#";
const char comment_chars[] = ";";
const char line_separator_chars[] = "!";
const char EXP_CHARS[] = "eE";
const char FLT_CHARS[] = "rRsSfFdDxXpP";
static struct pa_it the_insn;
static char *expr_end;
static int callinfo_found;
static int within_entry_exit;
static int within_procedure;
static label_symbol_struct *label_symbols_rootp = NULL;
static int hppa_field_selector;
static int strict = 0;
#define FP_REG_BASE 64
#define FP_REG_RSEL 128
static int pa_number;
#ifdef OBJ_SOM
static symbolS *dummy_symbol;
#endif
static int print_errors = 1;
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", 5},
{"%farg1", 6},
{"%farg2", 7},
{"%farg3", 8},
{"%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}
};
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
#define GDB_SYMBOLS GDB_SYMBOLS_SUBSPACE_NAME
#define GDB_STRINGS GDB_STRINGS_SUBSPACE_NAME
#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}
};
#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
#define IS_R_SELECT(S) (*(S) == 'R' || *(S) == 'r')
#define IS_L_SELECT(S) (*(S) == 'L' || *(S) == 'l')
#define INSERT_FIELD_AND_CONTINUE(OPCODE, FIELD, START) \
{ \
((OPCODE) |= (FIELD) << (START)); \
continue; \
}
#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; \
} \
}
#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; \
} \
}
#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_PC_relative(exp) \
((exp).X_op == O_subtract \
&& strcmp (S_GET_NAME ((exp).X_op_symbol), "$PIC_pcrel$0") == 0)
#define is_complex(exp) \
((exp).X_op != O_constant && (exp).X_op != O_symbol)
void
pa_check_eof ()
{
if (within_entry_exit)
as_fatal (_("Missing .exit\n"));
if (within_procedure)
as_fatal (_("Missing .procend\n"));
}
static label_symbol_struct *
pa_get_label ()
{
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;
}
void
pa_define_label (symbol)
symbolS *symbol;
{
label_symbol_struct *label_chain = pa_get_label ();
if (label_chain)
label_chain->lss_label = symbol;
else
{
label_chain
= (label_symbol_struct *) 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;
}
}
static void
pa_undefine_label ()
{
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
)
{
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;
}
}
static void
fix_new_hppa (frag, where, size, add_symbol, offset, exp, pcrel,
r_type, r_field, r_format, arg_reloc, unwind_bits)
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 = (struct hppa_fix_struct *)
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
if (new_fix->fx_subsy
&& (strcmp (S_GET_NAME (new_fix->fx_subsy), "$global$") == 0
|| strcmp (S_GET_NAME (new_fix->fx_subsy), "$PIC_pcrel$0") == 0))
new_fix->fx_subsy = NULL;
}
void
parse_cons_expression_hppa (exp)
expressionS *exp;
{
hppa_field_selector = pa_chk_field_selector (&input_line_pointer);
expression (exp);
}
void
cons_fix_new_hppa (frag, where, size, exp)
fragS *frag;
int where;
int size;
expressionS *exp;
{
unsigned int rel_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
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);
hppa_field_selector = 0;
}
void
md_begin ()
{
const char *retval = NULL;
int lose = 0;
unsigned int i = 0;
last_call_info = NULL;
call_info_root = NULL;
if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, DEFAULT_LEVEL))
as_warn (_("could not set architecture and machine"));
if (flag_readonly_data_in_text)
{
as_warn (_("-R option not supported on this target."));
flag_readonly_data_in_text = 0;
}
#ifdef OBJ_SOM
pa_spaces_begin ();
#endif
op_hash = hash_new ();
while (i < NUMOPCODES)
{
const char *name = pa_opcodes[i].name;
retval = hash_insert (op_hash, name, (struct pa_opcode *) &pa_opcodes[i]);
if (retval != NULL && *retval != '\0')
{
as_fatal (_("Internal error: can't hash `%s': %s\n"), name, retval);
lose = 1;
}
do
{
if ((pa_opcodes[i].match & pa_opcodes[i].mask)
!= pa_opcodes[i].match)
{
fprintf (stderr, _("internal error: losing opcode: `%s' \"%s\"\n"),
pa_opcodes[i].name, pa_opcodes[i].args);
lose = 1;
}
++i;
}
while (i < NUMOPCODES && !strcmp (pa_opcodes[i].name, name));
}
if (lose)
as_fatal (_("Broken assembler. No assembly attempted."));
#ifdef OBJ_SOM
subseg_set (text_section, 0);
#endif
#ifdef OBJ_SOM
dummy_symbol = symbol_find_or_make ("L$dummy");
S_SET_SEGMENT (dummy_symbol, text_section);
(void) symbol_get_bfdsym (dummy_symbol);
#endif
}
void
md_assemble (str)
char *str;
{
char *to;
assert (str);
if (within_procedure && last_call_info->start_symbol == NULL)
{
label_symbol_struct *label_symbol = pa_get_label ();
if (label_symbol)
{
if (label_symbol->lss_label)
{
last_call_info->start_symbol = label_symbol->lss_label;
symbol_get_bfdsym (label_symbol->lss_label)->flags
|= BSF_FUNCTION;
#ifdef OBJ_SOM
if (within_entry_exit)
{
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, u);
}
#endif
}
else
as_bad (_("Missing function name for .PROC (corrupted label chain)"));
}
else
as_bad (_("Missing function name for .PROC"));
}
pa_ip (str);
to = frag_more (4);
md_number_to_chars (to, the_insn.opcode, 4);
if (the_insn.reloc != R_HPPA_NONE)
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, 0);
#ifdef OBJ_ELF
dwarf2_emit_insn (4);
#endif
}
static void
pa_ip (str)
char *str;
{
char *error_message = "";
char *s, c, *argstart, *name, *save_s;
const char *args;
int match = FALSE;
int comma = 0;
int cmpltr, nullif, flag, cond, num;
unsigned long opcode;
struct pa_opcode *insn;
#ifdef OBJ_SOM
pa_check_current_space_and_subspace ();
#endif
for (s = str; *s != ' ' && *s != '\t' && *s != '\n' && *s != '\0'; s++)
*s = TOLOWER (*s);
for (s = str;
ISUPPER (*s) || ISLOWER (*s) || (*s >= '0' && *s <= '3');
++s)
;
switch (*s)
{
case '\0':
break;
case ',':
comma = 1;
case ' ':
*s++ = '\0';
break;
default:
as_fatal (_("Unknown opcode: `%s'"), str);
}
if ((insn = (struct pa_opcode *) hash_find (op_hash, str)) == NULL)
{
as_bad ("Unknown opcode: `%s'", str);
return;
}
if (comma)
{
*--s = ',';
}
argstart = s;
for (;;)
{
opcode = insn->match;
strict = (insn->flags & FLAG_STRICT);
memset (&the_insn, 0, sizeof (the_insn));
the_insn.reloc = R_HPPA_NONE;
if (insn->arch < 20
&& bfd_get_mach (stdoutput) < insn->arch)
{
if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, insn->arch))
as_warn (_("could not update architecture and machine"));
}
else if (bfd_get_mach (stdoutput) < insn->arch)
{
match = FALSE;
goto failed;
}
for (args = insn->args;; ++args)
{
while (*s == ' ' || *s == '\t')
s++;
switch (*args)
{
case '\0':
if (*s == '\0')
match = TRUE;
break;
case '+':
if (*s == '+')
{
++s;
continue;
}
if (*s == '-')
continue;
break;
case '(':
case ')':
case ',':
case ' ':
if (*s++ == *args)
continue;
break;
case 'b':
case '^':
if (!pa_parse_number (&s, 0))
break;
num = pa_number;
CHECK_FIELD (num, 31, 0, 0);
INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
case '!':
while (*s == ' ' || *s == '\t')
s = s + 1;
if (!strncasecmp (s, "%sar", 4))
{
s += 4;
continue;
}
else if (!strncasecmp (s, "%cr11", 5))
{
s += 5;
continue;
}
break;
case 'x':
if (!pa_parse_number (&s, 0))
break;
num = pa_number;
CHECK_FIELD (num, 31, 0, 0);
INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
case 't':
if (!pa_parse_number (&s, 0))
break;
num = pa_number;
CHECK_FIELD (num, 31, 0, 0);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
case 'a':
if (!pa_parse_number (&s, 0))
break;
num = pa_number;
CHECK_FIELD (num, 31, 0, 0);
opcode |= num << 16;
INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
case 'T':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 32, 1, 0);
INSERT_FIELD_AND_CONTINUE (opcode, 32 - num, 0);
case '5':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 15, -16, strict);
num = low_sign_unext (num, 5);
INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
case 'V':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 15, -16, strict);
num = low_sign_unext (num, 5);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
case 'r':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 31, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
case 'R':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 31, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
case 'U':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 1023, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
case 's':
if (!pa_parse_number (&s, 0))
break;
num = pa_number;
CHECK_FIELD (num, 3, 0, 1);
INSERT_FIELD_AND_CONTINUE (opcode, num, 14);
case 'S':
if (!pa_parse_number (&s, 0))
break;
num = pa_number;
CHECK_FIELD (num, 7, 0, 1);
opcode |= re_assemble_3 (num);
continue;
case 'c':
switch (*++args)
{
case 'X':
case 'x':
{
int uu = 0;
int m = 0;
int i = 0;
while (*s == ',' && i < 2)
{
s++;
if (strncasecmp (s, "sm", 2) == 0)
{
uu = 1;
m = 1;
s++;
i++;
}
else if (strncasecmp (s, "m", 1) == 0)
m = 1;
else if ((strncasecmp (s, "s ", 2) == 0)
|| (strncasecmp (s, "s,", 2) == 0))
uu = 1;
else if (strict)
{
s--;
break;
}
else
as_bad (_("Invalid Indexed Load Completer."));
s++;
i++;
}
if (i > 2)
as_bad (_("Invalid Indexed Load Completer Syntax."));
opcode |= m << 5;
INSERT_FIELD_AND_CONTINUE (opcode, uu, 13);
}
case 'M':
case 'm':
case 'q':
case 'J':
case 'e':
{
int a = 0;
int m = 0;
if (*s == ',')
{
int found = 0;
s++;
if (strncasecmp (s, "ma", 2) == 0)
{
a = 0;
m = 1;
found = 1;
}
else if (strncasecmp (s, "mb", 2) == 0)
{
a = 1;
m = 1;
found = 1;
}
if (!found && strict)
s--;
else
{
if (!found)
as_bad (_("Invalid Short Load/Store Completer."));
s += 2;
}
}
else if (*args == 'e')
break;
if (*args == 'm' || *args == 'M')
{
opcode |= m << 5;
INSERT_FIELD_AND_CONTINUE (opcode, a, 13);
}
else if (*args == 'q')
{
opcode |= m << 3;
INSERT_FIELD_AND_CONTINUE (opcode, a, 2);
}
else if (*args == 'J')
{
INSERT_FIELD_AND_CONTINUE (opcode, a, 2);
}
else if (*args == 'e')
{
opcode |= a;
continue;
}
}
case 'A':
case 's':
{
int a = 0;
int m = 0;
int i = 0;
while (*s == ',' && i < 2)
{
s++;
if (strncasecmp (s, "m", 1) == 0)
m = 1;
else if ((strncasecmp (s, "b ", 2) == 0)
|| (strncasecmp (s, "b,", 2) == 0))
a = 0;
else if (strncasecmp (s, "e", 1) == 0)
a = 1;
else if (strict)
{
s--;
break;
}
else
as_bad (_("Invalid Store Bytes Short Completer"));
s++;
i++;
}
if (i > 2)
as_bad (_("Invalid Store Bytes Short Completer"));
opcode |= m << 5;
INSERT_FIELD_AND_CONTINUE (opcode, a, 13);
}
case 'c':
cmpltr = 0;
if (!strncmp (s, ",sl", 3))
{
s += 3;
cmpltr = 2;
}
INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 10);
case 'C':
cmpltr = 0;
if (!strncmp (s, ",sl", 3))
{
s += 3;
cmpltr = 2;
}
else if (!strncmp (s, ",bc", 3))
{
s += 3;
cmpltr = 1;
}
INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 10);
case 'd':
cmpltr = 0;
if (!strncmp (s, ",co", 3))
{
s += 3;
cmpltr = 1;
}
INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 10);
case 'o':
if (strncmp (s, ",o", 2) != 0)
break;
s += 2;
continue;
case 'g':
if (strncasecmp (s, ",gate", 5) != 0)
break;
s += 5;
continue;
case 'p':
if (strncasecmp (s, ",l,push", 7) != 0)
break;
s += 7;
continue;
case 'l':
if (strncasecmp (s, ",l", 2) != 0)
break;
s += 2;
continue;
case 'P':
if (strncasecmp (s, ",pop", 4) != 0)
break;
s += 4;
continue;
case 'L':
if (strncasecmp (s, ",l", 2) != 0)
break;
s += 2;
continue;
case 'w':
flag = 0;
if (!strncasecmp (s, ",w", 2))
{
flag = 1;
s += 2;
}
else if (!strncasecmp (s, ",r", 2))
{
flag = 0;
s += 2;
}
INSERT_FIELD_AND_CONTINUE (opcode, flag, 6);
case 'W':
if (strncasecmp (s, ",w", 2) != 0)
break;
s += 2;
continue;
case 'r':
flag = 0;
if (!strncasecmp (s, ",r", 2))
{
flag = 5;
s += 2;
}
INSERT_FIELD_AND_CONTINUE (opcode, flag, 5);
case 'Z':
if (*s == ',' && (*(s + 1) == 'm' || *(s + 1) == 'M'))
{
flag = 1;
s += 2;
}
else
flag = 0;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 5);
case 'i':
flag = 0;
if (!strncasecmp (s, ",i", 2))
{
flag = 1;
s += 2;
}
INSERT_FIELD_AND_CONTINUE (opcode, flag, 6);
case 'z':
flag = 1;
if (!strncasecmp (s, ",z", 2))
{
flag = 0;
s += 2;
}
INSERT_FIELD_AND_CONTINUE (opcode, flag, 10);
case 'a':
flag = 1;
if (!strncasecmp (s, ",l", 2))
{
flag = 2;
s += 2;
}
else if (!strncasecmp (s, ",tsv", 4))
{
flag = 3;
s += 4;
}
INSERT_FIELD_AND_CONTINUE (opcode, flag, 10);
case 'Y':
flag = 0;
if (!strncasecmp (s, ",dc,tsv", 7) ||
!strncasecmp (s, ",tsv,dc", 7))
{
flag = 1;
s += 7;
}
else if (!strncasecmp (s, ",dc", 3))
{
flag = 0;
s += 3;
}
else
break;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
case 'y':
flag = 0;
if (!strncasecmp (s, ",c,tsv", 6) ||
!strncasecmp (s, ",tsv,c", 6))
{
flag = 1;
s += 6;
}
else if (!strncasecmp (s, ",c", 2))
{
flag = 0;
s += 2;
}
else
break;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
case 'v':
flag = 0;
if (!strncasecmp (s, ",tsv", 4))
{
flag = 1;
s += 4;
}
INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
case 't':
flag = 0;
if (!strncasecmp (s, ",tc,tsv", 7) ||
!strncasecmp (s, ",tsv,tc", 7))
{
flag = 1;
s += 7;
}
else if (!strncasecmp (s, ",tc", 3))
{
flag = 0;
s += 3;
}
else
break;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
case 'B':
flag = 0;
if (!strncasecmp (s, ",db,tsv", 7) ||
!strncasecmp (s, ",tsv,db", 7))
{
flag = 1;
s += 7;
}
else if (!strncasecmp (s, ",db", 3))
{
flag = 0;
s += 3;
}
else
break;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
case 'b':
flag = 0;
if (!strncasecmp (s, ",b,tsv", 6) ||
!strncasecmp (s, ",tsv,b", 6))
{
flag = 1;
s += 6;
}
else if (!strncasecmp (s, ",b", 2))
{
flag = 0;
s += 2;
}
else
break;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
case 'T':
flag = 0;
if (!strncasecmp (s, ",tc", 3))
{
flag = 1;
s += 3;
}
INSERT_FIELD_AND_CONTINUE (opcode, flag, 6);
case 'S':
{
int sign = 1;
if (strncasecmp (s, ",s", 2) == 0)
{
sign = 1;
s += 2;
}
else if (strncasecmp (s, ",u", 2) == 0)
{
sign = 0;
s += 2;
}
INSERT_FIELD_AND_CONTINUE (opcode, sign, 10);
}
case 'h':
if (*s++ == ',')
{
int lr = 0;
if (*s == 'r')
lr = 2;
else if (*s == 'l')
lr = 0;
else
as_bad (_("Invalid left/right combination completer"));
s++;
INSERT_FIELD_AND_CONTINUE (opcode, lr, 13);
}
else
as_bad (_("Invalid left/right combination completer"));
break;
case 'H':
{
int sat = 3;
if (strncasecmp (s, ",ss", 3) == 0)
{
sat = 1;
s += 3;
}
else if (strncasecmp (s, ",us", 3) == 0)
{
sat = 0;
s += 3;
}
INSERT_FIELD_AND_CONTINUE (opcode, sat, 6);
}
case '*':
if (*s++ == ',')
{
int permloc[4];
int perm = 0;
int i = 0;
permloc[0] = 13;
permloc[1] = 10;
permloc[2] = 8;
permloc[3] = 6;
for (; i < 4; i++)
{
switch (*s++)
{
case '0':
perm = 0;
break;
case '1':
perm = 1;
break;
case '2':
perm = 2;
break;
case '3':
perm = 3;
break;
default:
as_bad (_("Invalid permutation completer"));
}
opcode |= perm << permloc[i];
}
continue;
}
else
as_bad (_("Invalid permutation completer"));
break;
default:
abort ();
}
break;
case '?':
{
args++;
switch (*args)
{
case 'f':
cond = pa_parse_fp_cmp_cond (&s);
INSERT_FIELD_AND_CONTINUE (opcode, cond, 0);
case 'A':
case 'a':
cmpltr = 0;
flag = 0;
if (*s == ',')
{
s++;
if (*args == 'A')
{
if (*s == '*')
s++;
else
break;
}
else if (*s == '*')
break;
name = s;
while (*s != ',' && *s != ' ' && *s != '\t')
s += 1;
c = *s;
*s = 0x00;
if (strcmp (name, "=") == 0)
cmpltr = 1;
else if (strcmp (name, "<") == 0)
cmpltr = 2;
else if (strcmp (name, "<=") == 0)
cmpltr = 3;
else if (strcasecmp (name, "nuv") == 0)
cmpltr = 4;
else if (strcasecmp (name, "znv") == 0)
cmpltr = 5;
else if (strcasecmp (name, "sv") == 0)
cmpltr = 6;
else if (strcasecmp (name, "od") == 0)
cmpltr = 7;
else if (strcasecmp (name, "tr") == 0)
{
cmpltr = 0;
flag = 1;
}
else if (strcmp (name, "<>") == 0)
{
cmpltr = 1;
flag = 1;
}
else if (strcmp (name, ">=") == 0)
{
cmpltr = 2;
flag = 1;
}
else if (strcmp (name, ">") == 0)
{
cmpltr = 3;
flag = 1;
}
else if (strcasecmp (name, "uv") == 0)
{
cmpltr = 4;
flag = 1;
}
else if (strcasecmp (name, "vnz") == 0)
{
cmpltr = 5;
flag = 1;
}
else if (strcasecmp (name, "nsv") == 0)
{
cmpltr = 6;
flag = 1;
}
else if (strcasecmp (name, "ev") == 0)
{
cmpltr = 7;
flag = 1;
}
else if (*args == 'a' || *name)
as_bad (_("Invalid Add Condition: %s"), name);
*s = c;
}
opcode |= cmpltr << 13;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
case 'd':
cmpltr = pa_parse_nonneg_add_cmpltr (&s);
if (cmpltr < 0)
{
as_bad (_("Invalid Add and Branch Condition"));
cmpltr = 0;
}
INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
case 'W':
cmpltr = pa_parse_addb_64_cmpltr (&s);
if (cmpltr < 0)
{
as_bad (_("Invalid Add and Branch Condition"));
cmpltr = 0;
}
else
{
opcode |= (cmpltr & 8) << 24;
}
INSERT_FIELD_AND_CONTINUE (opcode, cmpltr & 7, 13);
case '@':
save_s = s;
cmpltr = pa_parse_nonneg_add_cmpltr (&s);
if (cmpltr < 0)
{
s = save_s;
cmpltr = pa_parse_neg_add_cmpltr (&s);
if (cmpltr < 0)
{
as_bad (_("Invalid Compare/Subtract Condition"));
cmpltr = 0;
}
else
{
opcode |= 1 << 27;
}
}
INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
case 'B':
case 'b':
cmpltr = 0;
if (*s == ',')
{
s++;
if (*args == 'B')
{
if (*s == '*')
s++;
else
break;
}
else if (*s == '*')
break;
if (strncmp (s, "<", 1) == 0)
{
cmpltr = 0;
s++;
}
else if (strncmp (s, ">=", 2) == 0)
{
cmpltr = 1;
s += 2;
}
else
as_bad (_("Invalid Bit Branch Condition: %c"), *s);
}
INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 15);
case 'S':
case 's':
cmpltr = 0;
flag = 0;
if (*s == ',')
{
s++;
if (*args == 'S')
{
if (*s == '*')
s++;
else
break;
}
else if (*s == '*')
break;
name = s;
while (*s != ',' && *s != ' ' && *s != '\t')
s += 1;
c = *s;
*s = 0x00;
if (strcmp (name, "=") == 0)
cmpltr = 1;
else if (strcmp (name, "<") == 0)
cmpltr = 2;
else if (strcmp (name, "<=") == 0)
cmpltr = 3;
else if (strcasecmp (name, "<<") == 0)
cmpltr = 4;
else if (strcasecmp (name, "<<=") == 0)
cmpltr = 5;
else if (strcasecmp (name, "sv") == 0)
cmpltr = 6;
else if (strcasecmp (name, "od") == 0)
cmpltr = 7;
else if (strcasecmp (name, "tr") == 0)
{
cmpltr = 0;
flag = 1;
}
else if (strcmp (name, "<>") == 0)
{
cmpltr = 1;
flag = 1;
}
else if (strcmp (name, ">=") == 0)
{
cmpltr = 2;
flag = 1;
}
else if (strcmp (name, ">") == 0)
{
cmpltr = 3;
flag = 1;
}
else if (strcasecmp (name, ">>=") == 0)
{
cmpltr = 4;
flag = 1;
}
else if (strcasecmp (name, ">>") == 0)
{
cmpltr = 5;
flag = 1;
}
else if (strcasecmp (name, "nsv") == 0)
{
cmpltr = 6;
flag = 1;
}
else if (strcasecmp (name, "ev") == 0)
{
cmpltr = 7;
flag = 1;
}
else if (*args != 'S' || *name)
as_bad (_("Invalid Compare/Subtract Condition: %s"),
name);
*s = c;
}
opcode |= cmpltr << 13;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
case 't':
cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s);
if (cmpltr < 0)
{
as_bad (_("Invalid Compare/Subtract Condition"));
cmpltr = 0;
}
INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
case 'n':
save_s = s;
cmpltr = pa_parse_nonneg_cmpsub_cmpltr (&s);
if (cmpltr < 0)
{
s = save_s;
cmpltr = pa_parse_neg_cmpsub_cmpltr (&s);
if (cmpltr < 0)
{
as_bad (_("Invalid Compare and Branch Condition"));
cmpltr = 0;
}
else
{
opcode |= 1 << 27;
}
}
INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
case 'N':
cmpltr = pa_parse_cmpb_64_cmpltr (&s);
if (cmpltr >= 0)
{
opcode |= (cmpltr & 8) << 26;
}
else
break;
INSERT_FIELD_AND_CONTINUE (opcode, cmpltr & 7, 13);
case 'Q':
cmpltr = pa_parse_cmpib_64_cmpltr (&s);
if (cmpltr < 0)
break;
INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
case 'L':
case 'l':
cmpltr = 0;
flag = 0;
if (*s == ',')
{
s++;
if (*args == 'L')
{
if (*s == '*')
s++;
else
break;
}
else if (*s == '*')
break;
name = s;
while (*s != ',' && *s != ' ' && *s != '\t')
s += 1;
c = *s;
*s = 0x00;
if (strcmp (name, "=") == 0)
cmpltr = 1;
else if (strcmp (name, "<") == 0)
cmpltr = 2;
else if (strcmp (name, "<=") == 0)
cmpltr = 3;
else if (strcasecmp (name, "od") == 0)
cmpltr = 7;
else if (strcasecmp (name, "tr") == 0)
{
cmpltr = 0;
flag = 1;
}
else if (strcmp (name, "<>") == 0)
{
cmpltr = 1;
flag = 1;
}
else if (strcmp (name, ">=") == 0)
{
cmpltr = 2;
flag = 1;
}
else if (strcmp (name, ">") == 0)
{
cmpltr = 3;
flag = 1;
}
else if (strcasecmp (name, "ev") == 0)
{
cmpltr = 7;
flag = 1;
}
else if (*args != 'L' || *name)
as_bad (_("Invalid Logical Instruction Condition."));
*s = c;
}
opcode |= cmpltr << 13;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
case 'X':
case 'x':
case 'y':
cmpltr = 0;
if (*s == ',')
{
save_s = s++;
if (*args == 'X')
{
if (*s == '*')
s++;
else
break;
}
else if (*s == '*')
break;
name = s;
while (*s != ',' && *s != ' ' && *s != '\t')
s += 1;
c = *s;
*s = 0x00;
if (strcmp (name, "=") == 0)
cmpltr = 1;
else if (strcmp (name, "<") == 0)
cmpltr = 2;
else if (strcasecmp (name, "od") == 0)
cmpltr = 3;
else if (strcasecmp (name, "tr") == 0)
cmpltr = 4;
else if (strcmp (name, "<>") == 0)
cmpltr = 5;
else if (strcmp (name, ">=") == 0)
cmpltr = 6;
else if (strcasecmp (name, "ev") == 0)
cmpltr = 7;
else if (strcasecmp (name, "n") == 0 && *args == 'y')
{
*s = c;
s = save_s;
continue;
}
else if (*args != 'X' || *name)
as_bad (_("Invalid Shift/Extract/Deposit Condition."));
*s = c;
}
INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
case 'U':
case 'u':
cmpltr = 0;
flag = 0;
if (*s == ',')
{
s++;
if (*args == 'U')
{
if (*s == '*')
s++;
else
break;
}
else if (*s == '*')
break;
if (strncasecmp (s, "sbz", 3) == 0)
{
cmpltr = 2;
s += 3;
}
else if (strncasecmp (s, "shz", 3) == 0)
{
cmpltr = 3;
s += 3;
}
else if (strncasecmp (s, "sdc", 3) == 0)
{
cmpltr = 4;
s += 3;
}
else if (strncasecmp (s, "sbc", 3) == 0)
{
cmpltr = 6;
s += 3;
}
else if (strncasecmp (s, "shc", 3) == 0)
{
cmpltr = 7;
s += 3;
}
else if (strncasecmp (s, "tr", 2) == 0)
{
cmpltr = 0;
flag = 1;
s += 2;
}
else if (strncasecmp (s, "nbz", 3) == 0)
{
cmpltr = 2;
flag = 1;
s += 3;
}
else if (strncasecmp (s, "nhz", 3) == 0)
{
cmpltr = 3;
flag = 1;
s += 3;
}
else if (strncasecmp (s, "ndc", 3) == 0)
{
cmpltr = 4;
flag = 1;
s += 3;
}
else if (strncasecmp (s, "nbc", 3) == 0)
{
cmpltr = 6;
flag = 1;
s += 3;
}
else if (strncasecmp (s, "nhc", 3) == 0)
{
cmpltr = 7;
flag = 1;
s += 3;
}
else if (strncasecmp (s, "swz", 3) == 0)
{
cmpltr = 1;
flag = 0;
s += 3;
}
else if (strncasecmp (s, "swc", 3) == 0)
{
cmpltr = 5;
flag = 0;
s += 3;
}
else if (strncasecmp (s, "nwz", 3) == 0)
{
cmpltr = 1;
flag = 1;
s += 3;
}
else if (strncasecmp (s, "nwc", 3) == 0)
{
cmpltr = 5;
flag = 1;
s += 3;
}
else if (*args != 'U' || (*s != ' ' && *s != '\t'))
as_bad (_("Invalid Unit Instruction Condition."));
}
opcode |= cmpltr << 13;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
default:
abort ();
}
break;
}
case 'n':
nullif = pa_parse_nullif (&s);
INSERT_FIELD_AND_CONTINUE (opcode, nullif, 1);
case 'N':
nullif = pa_parse_nullif (&s);
INSERT_FIELD_AND_CONTINUE (opcode, nullif, 5);
case 'L':
if (*s == ',' && strncasecmp (s + 1, "%r2", 3) == 0)
s += 4;
else if (*s == ',' && strncasecmp (s + 1, "%rp", 3) == 0)
s += 4;
else
break;
continue;
case 'h':
get_expression (s);
s = expr_end;
if (the_insn.exp.X_op == O_constant)
{
num = evaluate_absolute (&the_insn);
CHECK_FIELD (num, 6, 0, 0);
num++;
INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
}
else
break;
case 'm':
get_expression (s);
if (the_insn.exp.X_op == O_constant)
{
s = expr_end;
num = evaluate_absolute (&the_insn);
CHECK_FIELD (num, 6, 0, 0);
num = (num + 1) ^ 1;
INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
}
else
break;
case '=':
{
num = pa_parse_ftest_gfx_completer (&s);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
}
case 'i':
the_insn.field_selector = pa_chk_field_selector (&s);
get_expression (s);
s = expr_end;
if (the_insn.exp.X_op == O_constant)
{
num = evaluate_absolute (&the_insn);
CHECK_FIELD (num, 1023, -1024, 0);
num = low_sign_unext (num, 11);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
}
else
{
if (is_DP_relative (the_insn.exp))
the_insn.reloc = R_HPPA_GOTOFF;
else if (is_PC_relative (the_insn.exp))
the_insn.reloc = R_HPPA_PCREL_CALL;
else
the_insn.reloc = R_HPPA;
the_insn.format = 11;
continue;
}
case 'J':
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;
CHECK_FIELD (num, 8191, -8192, 0);
num = low_sign_unext (num, 14);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
}
break;
case 'K':
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, 8191, -8192, 0);
num = low_sign_unext (num, 14);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
}
break;
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;
CHECK_FIELD (num, 32767, -32768, 0);
num = re_assemble_16 (num);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
}
break;
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;
case '#':
the_insn.field_selector = pa_chk_field_selector (&s);
get_expression (s);
s = expr_end;
if (the_insn.exp.X_op == O_constant)
{
num = evaluate_absolute (&the_insn);
if (num & 0x7)
break;
CHECK_FIELD (num, 8191, -8192, 0);
if (num < 0)
opcode |= 1;
num &= 0x1fff;
num >>= 3;
INSERT_FIELD_AND_CONTINUE (opcode, num, 4);
}
else
{
if (is_DP_relative (the_insn.exp))
the_insn.reloc = R_HPPA_GOTOFF;
else if (is_PC_relative (the_insn.exp))
the_insn.reloc = R_HPPA_PCREL_CALL;
else
the_insn.reloc = R_HPPA;
the_insn.format = 14;
continue;
}
break;
case 'd':
the_insn.field_selector = pa_chk_field_selector (&s);
get_expression (s);
s = expr_end;
if (the_insn.exp.X_op == O_constant)
{
num = evaluate_absolute (&the_insn);
if (num & 0x3)
break;
CHECK_FIELD (num, 8191, -8192, 0);
if (num < 0)
opcode |= 1;
num &= 0x1fff;
num >>= 2;
INSERT_FIELD_AND_CONTINUE (opcode, num, 3);
}
else
{
if (is_DP_relative (the_insn.exp))
the_insn.reloc = R_HPPA_GOTOFF;
else if (is_PC_relative (the_insn.exp))
the_insn.reloc = R_HPPA_PCREL_CALL;
else
the_insn.reloc = R_HPPA;
the_insn.format = 14;
continue;
}
case 'j':
the_insn.field_selector = pa_chk_field_selector (&s);
get_expression (s);
s = expr_end;
if (the_insn.exp.X_op == O_constant)
{
num = evaluate_absolute (&the_insn);
CHECK_FIELD (num, 8191, -8192, 0);
num = low_sign_unext (num, 14);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
}
else
{
if (is_DP_relative (the_insn.exp))
the_insn.reloc = R_HPPA_GOTOFF;
else if (is_PC_relative (the_insn.exp))
the_insn.reloc = R_HPPA_PCREL_CALL;
else
the_insn.reloc = R_HPPA;
the_insn.format = 14;
continue;
}
case 'k':
the_insn.field_selector = pa_chk_field_selector (&s);
get_expression (s);
s = expr_end;
if (the_insn.exp.X_op == O_constant)
{
num = evaluate_absolute (&the_insn);
CHECK_FIELD (num >> 11, 1048575, -1048576, 0);
opcode |= re_assemble_21 (num);
continue;
}
else
{
if (is_DP_relative (the_insn.exp))
the_insn.reloc = R_HPPA_GOTOFF;
else if (is_PC_relative (the_insn.exp))
the_insn.reloc = R_HPPA_PCREL_CALL;
else
the_insn.reloc = R_HPPA;
the_insn.format = 21;
continue;
}
case 'l':
the_insn.field_selector = pa_chk_field_selector (&s);
get_expression (s);
s = expr_end;
if (the_insn.exp.X_op == O_constant)
{
num = evaluate_absolute (&the_insn);
CHECK_FIELD (num, 32767, -32768, 0);
opcode |= re_assemble_16 (num);
continue;
}
else
{
if (is_DP_relative (the_insn.exp))
the_insn.reloc = R_HPPA_GOTOFF;
else if (is_PC_relative (the_insn.exp))
the_insn.reloc = R_HPPA_PCREL_CALL;
else
the_insn.reloc = R_HPPA;
the_insn.format = 14;
continue;
}
case 'y':
the_insn.field_selector = pa_chk_field_selector (&s);
get_expression (s);
s = expr_end;
if (the_insn.exp.X_op == O_constant)
{
num = evaluate_absolute (&the_insn);
CHECK_FIELD (num, 32767, -32768, 0);
CHECK_ALIGN (num, 4, 0);
opcode |= re_assemble_16 (num);
continue;
}
else
{
if (is_DP_relative (the_insn.exp))
the_insn.reloc = R_HPPA_GOTOFF;
else if (is_PC_relative (the_insn.exp))
the_insn.reloc = R_HPPA_PCREL_CALL;
else
the_insn.reloc = R_HPPA;
the_insn.format = 14;
continue;
}
case '&':
the_insn.field_selector = pa_chk_field_selector (&s);
get_expression (s);
s = expr_end;
if (the_insn.exp.X_op == O_constant)
{
num = evaluate_absolute (&the_insn);
CHECK_FIELD (num, 32767, -32768, 0);
CHECK_ALIGN (num, 8, 0);
opcode |= re_assemble_16 (num);
continue;
}
else
{
if (is_DP_relative (the_insn.exp))
the_insn.reloc = R_HPPA_GOTOFF;
else if (is_PC_relative (the_insn.exp))
the_insn.reloc = R_HPPA_PCREL_CALL;
else
the_insn.reloc = R_HPPA;
the_insn.format = 14;
continue;
}
case 'w':
the_insn.field_selector = pa_chk_field_selector (&s);
get_expression (s);
s = expr_end;
the_insn.pcrel = 1;
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)
{
as_bad (_("Branch to unaligned address"));
break;
}
if (the_insn.exp.X_add_symbol)
num -= 8;
CHECK_FIELD (num, 8191, -8192, 0);
opcode |= re_assemble_12 (num >> 2);
continue;
}
else
{
the_insn.reloc = R_HPPA_PCREL_CALL;
the_insn.format = 12;
the_insn.arg_reloc = last_call_desc.arg_reloc;
memset (&last_call_desc, 0, sizeof (struct call_desc));
s = expr_end;
continue;
}
case 'W':
the_insn.field_selector = pa_chk_field_selector (&s);
get_expression (s);
s = expr_end;
the_insn.pcrel = 1;
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)
{
as_bad (_("Branch to unaligned address"));
break;
}
if (the_insn.exp.X_add_symbol)
num -= 8;
CHECK_FIELD (num, 262143, -262144, 0);
opcode |= re_assemble_17 (num >> 2);
continue;
}
else
{
the_insn.reloc = R_HPPA_PCREL_CALL;
the_insn.format = 17;
the_insn.arg_reloc = last_call_desc.arg_reloc;
memset (&last_call_desc, 0, sizeof (struct call_desc));
continue;
}
case 'X':
the_insn.field_selector = pa_chk_field_selector (&s);
get_expression (s);
s = expr_end;
the_insn.pcrel = 1;
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)
{
as_bad (_("Branch to unaligned address"));
break;
}
if (the_insn.exp.X_add_symbol)
num -= 8;
CHECK_FIELD (num, 8388607, -8388608, 0);
opcode |= re_assemble_22 (num >> 2);
}
else
{
the_insn.reloc = R_HPPA_PCREL_CALL;
the_insn.format = 22;
the_insn.arg_reloc = last_call_desc.arg_reloc;
memset (&last_call_desc, 0, sizeof (struct call_desc));
continue;
}
case 'z':
the_insn.field_selector = pa_chk_field_selector (&s);
get_expression (s);
s = expr_end;
the_insn.pcrel = 0;
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)
{
as_bad (_("Branch to unaligned address"));
break;
}
if (the_insn.exp.X_add_symbol)
num -= 8;
CHECK_FIELD (num, 262143, -262144, 0);
opcode |= re_assemble_17 (num >> 2);
continue;
}
else
{
the_insn.reloc = R_HPPA_ABS_CALL;
the_insn.format = 17;
the_insn.arg_reloc = last_call_desc.arg_reloc;
memset (&last_call_desc, 0, sizeof (struct call_desc));
continue;
}
case 'Z':
if (*s == ',' && *(s + 1) == '%' && *(s + 3) == '1'
&& (*(s + 2) == 'r' || *(s + 2) == 'R'))
{
s += 4;
continue;
}
else
break;
case 'Y':
if (strncasecmp (s, "%sr0,%r31", 9) != 0)
break;
s += 9;
continue;
case '@':
if (*s != '0')
break;
s++;
continue;
case '.':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 3, 1, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
case '*':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 15, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
case 'p':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 31, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, 31 - num, 5);
case '~':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 63, 0, strict);
num = 63 - num;
opcode |= (num & 0x20) << 6;
INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 5);
case '%':
flag = 0;
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 64, 1, strict);
num--;
opcode |= (num & 0x20) << 3;
num = 31 - (num & 0x1f);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
case '|':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 64, 1, strict);
num--;
opcode |= (num & 0x20) << 7;
num = 31 - (num & 0x1f);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
case 'P':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 31, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 5);
case 'q':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 63, 0, strict);
opcode |= (num & 0x20) << 6;
INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 5);
case 'B':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 63, 0, strict);
if (num & 0x20)
;
else
opcode |= (1 << 13);
INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 21);
case 'Q':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 31, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
case '$':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 511, 1, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 3);
case 'A':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 8191, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 13);
case 'D':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 67108863, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
case 'v':
if (*s++ != ',')
as_bad (_("Invalid SFU identifier"));
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 7, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
case 'O':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 1048575, 0, strict);
num = (num & 0x1f) | ((num & 0x000fffe0) << 6);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
case 'o':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 32767, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 11);
case '0':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 1023, 0, strict);
num = (num & 0x1f) | ((num & 0x000003e0) << 6);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
case '1':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 32767, 0, strict);
num = (num & 0x1f) | ((num & 0x00007fe0) << 6);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
case 'u':
if (*s++ != ',')
as_bad (_("Invalid COPR identifier"));
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 7, 0, strict);
INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
case '2':
num = pa_get_absolute_expression (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
CHECK_FIELD (num, 4194303, 0, strict);
num = (num & 0x1f) | ((num & 0x003fffe0) << 4);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
case '{':
if (*s == ',' && *(s+1) == 't')
{
the_insn.trunc = 1;
s += 2;
}
else
the_insn.trunc = 0;
flag = pa_parse_fp_cnv_format (&s);
the_insn.fpof1 = flag;
if (flag == W || flag == UW)
flag = SGL;
if (flag == DW || flag == UDW)
flag = DBL;
if (flag == QW || flag == UQW)
flag = QUAD;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
case '_':
s--;
flag = pa_parse_fp_cnv_format (&s);
the_insn.fpof2 = flag;
if (flag == W || flag == UW)
flag = SGL;
if (flag == DW || flag == UDW)
flag = DBL;
if (flag == QW || flag == UQW)
flag = QUAD;
opcode |= flag << 13;
if (the_insn.fpof1 == SGL
|| the_insn.fpof1 == DBL
|| the_insn.fpof1 == QUAD)
{
if (the_insn.fpof2 == SGL
|| the_insn.fpof2 == DBL
|| the_insn.fpof2 == QUAD)
flag = 0;
else if (the_insn.fpof2 == W
|| the_insn.fpof2 == DW
|| the_insn.fpof2 == QW)
flag = 2;
else if (the_insn.fpof2 == UW
|| the_insn.fpof2 == UDW
|| the_insn.fpof2 == UQW)
flag = 6;
else
abort ();
}
else if (the_insn.fpof1 == W
|| the_insn.fpof1 == DW
|| the_insn.fpof1 == QW)
{
if (the_insn.fpof2 == SGL
|| the_insn.fpof2 == DBL
|| the_insn.fpof2 == QUAD)
flag = 1;
else
abort ();
}
else if (the_insn.fpof1 == UW
|| the_insn.fpof1 == UDW
|| the_insn.fpof1 == UQW)
{
if (the_insn.fpof2 == SGL
|| the_insn.fpof2 == DBL
|| the_insn.fpof2 == QUAD)
flag = 5;
else
abort ();
}
flag |= the_insn.trunc;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 15);
case 'F':
flag = pa_parse_fp_format (&s);
the_insn.fpof1 = flag;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
case 'G':
s--;
flag = pa_parse_fp_format (&s);
the_insn.fpof2 = flag;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 13);
case 'I':
flag = pa_parse_fp_format (&s);
the_insn.fpof1 = flag;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
case 'H':
flag = pa_parse_fp_format (&s);
switch (flag)
{
case SGL:
opcode |= 0x20;
case DBL:
the_insn.fpof1 = flag;
continue;
case QUAD:
case ILLEGAL_FMT:
default:
as_bad (_("Invalid Floating Point Operand Format."));
}
break;
case 'f':
switch (*++args)
{
case 't':
if (!pa_parse_number (&s, 3))
break;
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
case 'T':
{
if (!pa_parse_number (&s, 1))
break;
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
opcode |= num;
if (need_pa11_opcode ()
&& ((opcode & 0xfc000000) == 0x30000000))
opcode |= 1 << 27;
opcode |= (pa_number & FP_REG_RSEL ? 1 << 6 : 0);
continue;
}
case 'a':
{
if (!pa_parse_number (&s, 1))
break;
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
opcode |= num << 21;
if (need_pa11_opcode ())
{
opcode |= (pa_number & FP_REG_RSEL ? 1 << 7 : 0);
opcode |= 1 << 27;
}
continue;
}
case 'X':
case 'A':
{
if (!pa_parse_number (&s, 1))
break;
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
opcode |= num << 21;
opcode |= (pa_number & FP_REG_RSEL ? 1 << 7 : 0);
continue;
}
case 'b':
{
if (!pa_parse_number (&s, 1))
break;
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
opcode |= num << 16;
if (need_pa11_opcode ())
{
opcode |= (pa_number & FP_REG_RSEL ? 1 << 12 : 0);
opcode |= 1 << 27;
}
continue;
}
case 'B':
{
if (!pa_parse_number (&s, 1))
break;
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
opcode |= num << 16;
opcode |= (pa_number & FP_REG_RSEL ? 1 << 12 : 0);
continue;
}
case 'C':
{
if (!pa_parse_number (&s, 1))
break;
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
opcode |= (num & 0x1c) << 11;
opcode |= (num & 0x03) << 9;
opcode |= (pa_number & FP_REG_RSEL ? 1 << 8 : 0);
continue;
}
case 'i':
{
if (!pa_parse_number (&s, 1))
break;
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
if (the_insn.fpof1 == SGL)
{
if (num < 16)
{
as_bad (_("Invalid register for single precision fmpyadd or fmpysub"));
break;
}
num &= 0xF;
num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
}
INSERT_FIELD_AND_CONTINUE (opcode, num, 21);
}
case 'j':
{
if (!pa_parse_number (&s, 1))
break;
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
if (the_insn.fpof1 == SGL)
{
if (num < 16)
{
as_bad (_("Invalid register for single precision fmpyadd or fmpysub"));
break;
}
num &= 0xF;
num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
}
INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
}
case 'k':
{
if (!pa_parse_number (&s, 1))
break;
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
if (the_insn.fpof1 == SGL)
{
if (num < 16)
{
as_bad (_("Invalid register for single precision fmpyadd or fmpysub"));
break;
}
num &= 0xF;
num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
}
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
}
case 'l':
{
if (!pa_parse_number (&s, 1))
break;
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
if (the_insn.fpof1 == SGL)
{
if (num < 16)
{
as_bad (_("Invalid register for single precision fmpyadd or fmpysub"));
break;
}
num &= 0xF;
num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
}
INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
}
case 'm':
{
if (!pa_parse_number (&s, 1))
break;
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
if (the_insn.fpof1 == SGL)
{
if (num < 16)
{
as_bad (_("Invalid register for single precision fmpyadd or fmpysub"));
break;
}
num &= 0xF;
num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
}
INSERT_FIELD_AND_CONTINUE (opcode, num, 11);
}
case 'E':
case 'e':
{
if (!pa_parse_number (&s, 1))
break;
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
opcode |= num << 16;
if (need_pa11_opcode ())
{
opcode |= (pa_number & FP_REG_RSEL ? 1 << 1 : 0);
}
continue;
}
case 'x':
if (!pa_parse_number (&s, 3))
break;
num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
default:
abort ();
}
break;
default:
abort ();
}
break;
}
failed:
if (!match)
{
if (&insn[1] - pa_opcodes < (int) NUMOPCODES
&& !strcmp (insn->name, insn[1].name))
{
++insn;
s = argstart;
continue;
}
else
{
as_bad (_("Invalid operands %s"), error_message);
return;
}
}
break;
}
the_insn.opcode = opcode;
}
#define MAX_LITTLENUMS 6
char *
md_atof (type, litP, sizeP)
char type;
char *litP;
int *sizeP;
{
int prec;
LITTLENUM_TYPE words[MAX_LITTLENUMS];
LITTLENUM_TYPE *wordP;
char *t;
switch (type)
{
case 'f':
case 'F':
case 's':
case 'S':
prec = 2;
break;
case 'd':
case 'D':
case 'r':
case 'R':
prec = 4;
break;
case 'x':
case 'X':
prec = 6;
break;
case 'p':
case 'P':
prec = 6;
break;
default:
*sizeP = 0;
return _("Bad call to MD_ATOF()");
}
t = atof_ieee (input_line_pointer, type, words);
if (t)
input_line_pointer = t;
*sizeP = prec * sizeof (LITTLENUM_TYPE);
for (wordP = words; prec--;)
{
md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE));
litP += sizeof (LITTLENUM_TYPE);
}
return NULL;
}
void
md_number_to_chars (buf, val, n)
char *buf;
valueT val;
int n;
{
number_to_chars_bigendian (buf, val, n);
}
arelent **
tc_gen_reloc (section, fixp)
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;
assert (hppa_fixp != 0);
assert (section != 0);
reloc = (arelent *) xmalloc (sizeof (arelent));
reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
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 = (arelent **) xmalloc (sizeof (arelent *) * n_relocs + 1);
reloc = (arelent *) xmalloc (sizeof (arelent) * n_relocs);
for (i = 0; i < n_relocs; i++)
relocs[i] = &reloc[i];
relocs[n_relocs] = NULL;
#ifdef OBJ_ELF
switch (fixp->fx_r_type)
{
default:
assert (n_relocs == 1);
code = *codes[0];
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:
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:
if (strcmp (section->name, UNWIND_SECTION_NAME) == 0)
code = R_PARISC_SEGREL32;
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
for (i = 0; i < n_relocs; i++)
{
code = *codes[i];
relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
*relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
relocs[i]->howto =
bfd_reloc_type_lookup (stdoutput,
(bfd_reloc_code_real_type) code);
relocs[i]->address = fixp->fx_frag->fr_address + fixp->fx_where;
switch (code)
{
case R_COMP2:
assert (i == 1);
relocs[0]->sym_ptr_ptr = (asymbol **) &(bfd_abs_symbol);
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 = (asymbol **) 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 = (asymbol **) 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_symbol);
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_symbol);
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:
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:
relocs[i]->sym_ptr_ptr = (asymbol **) 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:
relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
*relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
relocs[i]->addend = fixp->fx_offset;
break;
default:
relocs[i]->addend = fixp->fx_offset;
}
}
done:
#endif
return relocs;
}
void
md_convert_frag (abfd, sec, fragP)
register bfd *abfd ATTRIBUTE_UNUSED;
register asection *sec ATTRIBUTE_UNUSED;
register 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;
}
}
}
valueT
md_section_align (segment, size)
asection *segment;
valueT size;
{
int align = bfd_get_section_alignment (stdoutput, segment);
int align2 = (1 << align) - 1;
return (size + align2) & ~align2;
}
int
md_estimate_size_before_relax (fragP, segment)
register 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 (c, arg)
int c ATTRIBUTE_UNUSED;
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 (stream)
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
}
symbolS *
md_undefined_symbol (name)
char *name ATTRIBUTE_UNUSED;
{
return 0;
}
#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
void
md_apply_fix3 (fixP, valP, seg)
fixS *fixP;
valueT *valP;
segT seg ATTRIBUTE_UNUSED;
{
unsigned char *buf;
struct hppa_fix_struct *hppa_fixP;
offsetT new_val;
int insn, val, fmt;
#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;
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;
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;
}
buf = (unsigned char *) (fixP->fx_frag->fr_literal + fixP->fx_where);
insn = bfd_get_32 (stdoutput, buf);
fmt = bfd_hppa_insn2fmt (stdoutput, insn);
if ((fixP->fx_addsy != NULL
|| fixP->fx_r_type == (int) R_HPPA_NONE)
#ifdef OBJ_SOM
&& fmt != 32
#endif
)
new_val = ((fmt == 12 || fmt == 17 || fmt == 22) ? 8 : 0);
#ifdef OBJ_SOM
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);
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);
}
switch (fmt)
{
case 10:
CHECK_FIELD_WHERE (new_val, 8191, -8192,
fixP->fx_file, fixP->fx_line);
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 & ~ 0x3ff9) | (((val & 0x1ffc) << 1)
| ((val & 0x2000) >> 13));
break;
case 14:
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;
case 21:
CHECK_FIELD_WHERE (new_val, 1048575, -1048576,
fixP->fx_file, fixP->fx_line);
val = new_val;
insn = (insn & ~ 0x1fffff) | re_assemble_21 (val);
break;
case 11:
CHECK_FIELD_WHERE (new_val, 1023, -1024,
fixP->fx_file, fixP->fx_line);
val = new_val;
insn = (insn & ~ 0x7ff) | low_sign_unext (val, 11);
break;
case 12:
CHECK_FIELD_WHERE (new_val - 8, 8191, -8192,
fixP->fx_file, fixP->fx_line);
val = new_val - 8;
insn = (insn & ~ 0x1ffd) | re_assemble_12 (val >> 2);
break;
case 17:
{
offsetT distance = * valP;
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);
CHECK_FIELD_WHERE (new_val - 8, 262143, -262144,
fixP->fx_file, fixP->fx_line);
val = new_val - 8;
insn = (insn & ~ 0x1f1ffd) | re_assemble_17 (val >> 2);
break;
}
case 22:
{
offsetT distance = * valP;
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);
CHECK_FIELD_WHERE (new_val - 8, 8388607, -8388608,
fixP->fx_file, fixP->fx_line);
val = new_val - 8;
insn = (insn & ~ 0x3ff1ffd) | re_assemble_22 (val >> 2);
break;
}
case -10:
val = new_val;
insn = (insn & ~ 0xfff1) | re_assemble_16 (val & -8);
break;
case -16:
val = new_val;
insn = (insn & ~ 0xfff9) | re_assemble_16 (val & -4);
break;
case 16:
val = new_val;
insn = (insn & ~ 0xffff) | re_assemble_16 (val);
break;
case 32:
insn = new_val;
break;
default:
as_bad_where (fixP->fx_file, fixP->fx_line,
_("Unknown relocation encountered in md_apply_fix."));
return;
}
bfd_put_32 (stdoutput, insn, buf);
}
long
md_pcrel_from (fixP)
fixS *fixP;
{
return fixP->fx_where + fixP->fx_frag->fr_address;
}
static int
is_end_of_statement ()
{
return ((*input_line_pointer == '\n')
|| (*input_line_pointer == ';')
|| (*input_line_pointer == '!'));
}
static int
pa_parse_number (s, is_float)
char **s;
int is_float;
{
int num;
char *name;
char c;
symbolS *sym;
int status;
char *p = *s;
bfd_boolean have_prefix;
while (*p == ' ' || *p == '\t')
p = p + 1;
pa_number = -1;
have_prefix = 0;
num = 0;
if (!strict && ISDIGIT (*p))
{
if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X'))
{
p += 2;
while (ISDIGIT (*p) || ((*p >= 'a') && (*p <= 'f'))
|| ((*p >= 'A') && (*p <= 'F')))
{
if (ISDIGIT (*p))
num = num * 16 + *p - '0';
else if (*p >= 'a' && *p <= 'f')
num = num * 16 + *p - 'a' + 10;
else
num = num * 16 + *p - 'A' + 10;
++p;
}
}
else
{
while (ISDIGIT (*p))
{
num = num * 10 + *p - '0';
++p;
}
}
pa_number = num;
if (is_float)
{
pa_number += FP_REG_BASE;
if (! (is_float & 2))
{
if (IS_R_SELECT (p))
{
pa_number += FP_REG_RSEL;
++p;
}
else if (IS_L_SELECT (p))
{
++p;
}
}
}
}
else if (*p == '%')
{
have_prefix = 1;
name = p;
p++;
c = *p;
if (c == 'r')
{
p++;
if (*p == 'e' && *(p + 1) == 't'
&& (*(p + 2) == '0' || *(p + 2) == '1'))
{
p += 2;
num = *p - '0' + 28;
p++;
}
else if (*p == 'p')
{
num = 2;
p++;
}
else if (!ISDIGIT (*p))
{
if (print_errors)
as_bad (_("Undefined register: '%s'."), name);
num = -1;
}
else
{
do
num = num * 10 + *p++ - '0';
while (ISDIGIT (*p));
}
}
else
{
while (is_part_of_name (c))
{
p = p + 1;
c = *p;
}
*p = 0;
status = reg_name_search (name);
if (status >= 0)
num = status;
else
{
if (print_errors)
as_bad (_("Undefined register: '%s'."), name);
num = -1;
}
*p = c;
}
pa_number = num;
}
else
{
name = p;
c = *p;
while (is_part_of_name (c))
{
p = p + 1;
c = *p;
}
*p = 0;
if ((sym = symbol_find (name)) != NULL)
{
if (S_GET_SEGMENT (sym) == reg_section)
{
num = S_GET_VALUE (sym);
have_prefix = TRUE;
}
else if (S_GET_SEGMENT (sym) == &bfd_abs_section)
num = S_GET_VALUE (sym);
else if (!strict)
{
if (print_errors)
as_bad (_("Non-absolute symbol: '%s'."), name);
num = -1;
}
}
else if (!strict)
{
if (*name == 0)
num = 0;
else
{
if (print_errors)
as_bad (_("Undefined absolute constant: '%s'."), name);
num = -1;
}
}
*p = c;
pa_number = num;
}
if (!strict || have_prefix)
{
*s = p;
return 1;
}
return 0;
}
#define REG_NAME_CNT (sizeof (pre_defined_registers) / sizeof (struct pd_reg))
static int
reg_name_search (name)
char *name;
{
int middle, low, high;
int cmp;
low = 0;
high = REG_NAME_CNT - 1;
do
{
middle = (low + high) / 2;
cmp = strcasecmp (name, pre_defined_registers[middle].name);
if (cmp < 0)
high = middle - 1;
else if (cmp > 0)
low = middle + 1;
else
return pre_defined_registers[middle].value;
}
while (low <= high);
return -1;
}
static int
need_pa11_opcode ()
{
if ((pa_number & FP_REG_RSEL) != 0
&& !(the_insn.fpof1 == DBL && the_insn.fpof2 == DBL))
{
if (bfd_get_mach (stdoutput) < pa11)
{
if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, pa11))
as_warn (_("could not update architecture and machine"));
}
return TRUE;
}
else
return FALSE;
}
static int
pa_parse_fp_cmp_cond (s)
char **s;
{
int cond, i;
cond = 0;
for (i = 0; i < 32; i++)
{
if (strncasecmp (*s, fp_cond_map[i].string,
strlen (fp_cond_map[i].string)) == 0)
{
cond = fp_cond_map[i].cond;
*s += strlen (fp_cond_map[i].string);
if (**s != ' ' && **s != '\t')
{
*s -= strlen (fp_cond_map[i].string);
break;
}
while (**s == ' ' || **s == '\t')
*s = *s + 1;
return cond;
}
}
as_bad (_("Invalid FP Compare Condition: %s"), *s);
while (**s != ',' && **s != ' ' && **s != '\t')
*s += 1;
return 0;
}
static int
pa_parse_ftest_gfx_completer (s)
char **s;
{
int value;
value = 0;
if (strncasecmp (*s, "acc8", 4) == 0)
{
value = 5;
*s += 4;
}
else if (strncasecmp (*s, "acc6", 4) == 0)
{
value = 9;
*s += 4;
}
else if (strncasecmp (*s, "acc4", 4) == 0)
{
value = 13;
*s += 4;
}
else if (strncasecmp (*s, "acc2", 4) == 0)
{
value = 17;
*s += 4;
}
else if (strncasecmp (*s, "acc", 3) == 0)
{
value = 1;
*s += 3;
}
else if (strncasecmp (*s, "rej8", 4) == 0)
{
value = 6;
*s += 4;
}
else if (strncasecmp (*s, "rej", 3) == 0)
{
value = 2;
*s += 3;
}
else
{
value = 0;
as_bad (_("Invalid FTEST completer: %s"), *s);
}
return value;
}
static fp_operand_format
pa_parse_fp_cnv_format (s)
char **s;
{
int format;
format = SGL;
if (**s == ',')
{
*s += 1;
if (strncasecmp (*s, "sgl", 3) == 0)
{
format = SGL;
*s += 4;
}
else if (strncasecmp (*s, "dbl", 3) == 0)
{
format = DBL;
*s += 4;
}
else if (strncasecmp (*s, "quad", 4) == 0)
{
format = QUAD;
*s += 5;
}
else if (strncasecmp (*s, "w", 1) == 0)
{
format = W;
*s += 2;
}
else if (strncasecmp (*s, "uw", 2) == 0)
{
format = UW;
*s += 3;
}
else if (strncasecmp (*s, "dw", 2) == 0)
{
format = DW;
*s += 3;
}
else if (strncasecmp (*s, "udw", 3) == 0)
{
format = UDW;
*s += 4;
}
else if (strncasecmp (*s, "qw", 2) == 0)
{
format = QW;
*s += 3;
}
else if (strncasecmp (*s, "uqw", 3) == 0)
{
format = UQW;
*s += 4;
}
else
{
format = ILLEGAL_FMT;
as_bad (_("Invalid FP Operand Format: %3s"), *s);
}
}
return format;
}
static fp_operand_format
pa_parse_fp_format (s)
char **s;
{
int format;
format = SGL;
if (**s == ',')
{
*s += 1;
if (strncasecmp (*s, "sgl", 3) == 0)
{
format = SGL;
*s += 4;
}
else if (strncasecmp (*s, "dbl", 3) == 0)
{
format = DBL;
*s += 4;
}
else if (strncasecmp (*s, "quad", 4) == 0)
{
format = QUAD;
*s += 5;
}
else
{
format = ILLEGAL_FMT;
as_bad (_("Invalid FP Operand Format: %3s"), *s);
}
}
return format;
}
static int
pa_chk_field_selector (str)
char **str;
{
int middle, low, high;
int cmp;
char name[4];
while (**str == ' ' || **str == '\t' || **str == '\n' || **str == '\f')
*str = *str + 1;
if ((*str)[1] == '\'' || (*str)[1] == '%')
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[2] = 0;
else if ((*str)[3] == '\'' || (*str)[3] == '%')
name[0] = TOLOWER ((*str)[0]),
name[1] = TOLOWER ((*str)[1]),
name[2] = TOLOWER ((*str)[2]),
name[3] = 0;
else
return e_fsel;
low = 0;
high = sizeof (selector_table) / sizeof (struct selector_entry) - 1;
do
{
middle = (low + high) / 2;
cmp = strcmp (name, selector_table[middle].prefix);
if (cmp < 0)
high = middle - 1;
else if (cmp > 0)
low = middle + 1;
else
{
*str += strlen (name) + 1;
#ifndef OBJ_SOM
if (selector_table[middle].field_selector == e_nsel)
return e_fsel;
#endif
return selector_table[middle].field_selector;
}
}
while (low <= high);
return e_fsel;
}
static int
get_expression (str)
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 1;
}
expr_end = input_line_pointer;
input_line_pointer = save_in;
return 0;
}
static int
pa_get_absolute_expression (insn, strp)
struct pa_it *insn;
char **strp;
{
char *save_in;
insn->field_selector = pa_chk_field_selector (strp);
save_in = input_line_pointer;
input_line_pointer = *strp;
expression (&insn->exp);
if (insn->exp.X_op == O_modulus)
{
char *s, c;
int retval;
input_line_pointer = *strp;
s = *strp;
while (*s != ',' && *s != ' ' && *s != '\t')
s++;
c = *s;
*s = 0;
retval = pa_get_absolute_expression (insn, strp);
input_line_pointer = save_in;
*s = c;
return evaluate_absolute (insn);
}
if (insn->exp.X_op != O_constant && strict)
{
expr_end = input_line_pointer;
input_line_pointer = save_in;
return 0;
}
if (insn->exp.X_op != O_constant)
{
as_bad (_("Bad segment (should be absolute)."));
expr_end = input_line_pointer;
input_line_pointer = save_in;
return 0;
}
expr_end = input_line_pointer;
input_line_pointer = save_in;
return evaluate_absolute (insn);
}
static int
evaluate_absolute (insn)
struct pa_it *insn;
{
offsetT value;
expressionS exp;
int field_selector = insn->field_selector;
exp = insn->exp;
value = exp.X_add_number;
return hppa_field_adjust (0, value, field_selector);
}
static unsigned int
pa_build_arg_reloc (type_name)
char *type_name;
{
if (strncasecmp (type_name, "no", 2) == 0)
return 0;
if (strncasecmp (type_name, "gr", 2) == 0)
return 1;
else if (strncasecmp (type_name, "fr", 2) == 0)
return 2;
else if (strncasecmp (type_name, "fu", 2) == 0)
return 3;
else
as_bad (_("Invalid argument location: %s\n"), type_name);
return 0;
}
static unsigned int
pa_align_arg_reloc (reg, arg_reloc)
unsigned int reg;
unsigned int arg_reloc;
{
unsigned int new_reloc;
new_reloc = arg_reloc;
switch (reg)
{
case 0:
new_reloc <<= 8;
break;
case 1:
new_reloc <<= 6;
break;
case 2:
new_reloc <<= 4;
break;
case 3:
new_reloc <<= 2;
break;
default:
as_bad (_("Invalid argument description: %d"), reg);
}
return new_reloc;
}
static int
pa_parse_nullif (s)
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;
}
static int
pa_parse_nonneg_cmpsub_cmpltr (s)
char **s;
{
int cmpltr;
char *name = *s + 1;
char c;
char *save_s = *s;
int nullify = 0;
cmpltr = 0;
if (**s == ',')
{
*s += 1;
while (**s != ',' && **s != ' ' && **s != '\t')
*s += 1;
c = **s;
**s = 0x00;
if (strcmp (name, "=") == 0)
{
cmpltr = 1;
}
else if (strcmp (name, "<") == 0)
{
cmpltr = 2;
}
else if (strcmp (name, "<=") == 0)
{
cmpltr = 3;
}
else if (strcmp (name, "<<") == 0)
{
cmpltr = 4;
}
else if (strcmp (name, "<<=") == 0)
{
cmpltr = 5;
}
else if (strcasecmp (name, "sv") == 0)
{
cmpltr = 6;
}
else if (strcasecmp (name, "od") == 0)
{
cmpltr = 7;
}
else if (strcasecmp (name, "n") == 0)
{
cmpltr = 0;
nullify = 1;
}
else
{
cmpltr = -1;
}
**s = c;
}
if (nullify)
*s = save_s;
return cmpltr;
}
static int
pa_parse_neg_cmpsub_cmpltr (s)
char **s;
{
int cmpltr;
char *name = *s + 1;
char c;
char *save_s = *s;
int nullify = 0;
cmpltr = 0;
if (**s == ',')
{
*s += 1;
while (**s != ',' && **s != ' ' && **s != '\t')
*s += 1;
c = **s;
**s = 0x00;
if (strcasecmp (name, "tr") == 0)
{
cmpltr = 0;
}
else if (strcmp (name, "<>") == 0)
{
cmpltr = 1;
}
else if (strcmp (name, ">=") == 0)
{
cmpltr = 2;
}
else if (strcmp (name, ">") == 0)
{
cmpltr = 3;
}
else if (strcmp (name, ">>=") == 0)
{
cmpltr = 4;
}
else if (strcmp (name, ">>") == 0)
{
cmpltr = 5;
}
else if (strcasecmp (name, "nsv") == 0)
{
cmpltr = 6;
}
else if (strcasecmp (name, "ev") == 0)
{
cmpltr = 7;
}
else if (strcasecmp (name, "n") == 0)
{
cmpltr = 0;
nullify = 1;
}
else
{
cmpltr = -1;
}
**s = c;
}
if (nullify)
*s = save_s;
return cmpltr;
}
static int
pa_parse_cmpb_64_cmpltr (s)
char **s;
{
int cmpltr;
char *name = *s + 1;
char c;
cmpltr = -1;
if (**s == ',')
{
*s += 1;
while (**s != ',' && **s != ' ' && **s != '\t')
*s += 1;
c = **s;
**s = 0x00;
if (strcmp (name, "*") == 0)
{
cmpltr = 0;
}
else if (strcmp (name, "*=") == 0)
{
cmpltr = 1;
}
else if (strcmp (name, "*<") == 0)
{
cmpltr = 2;
}
else if (strcmp (name, "*<=") == 0)
{
cmpltr = 3;
}
else if (strcmp (name, "*<<") == 0)
{
cmpltr = 4;
}
else if (strcmp (name, "*<<=") == 0)
{
cmpltr = 5;
}
else if (strcasecmp (name, "*sv") == 0)
{
cmpltr = 6;
}
else if (strcasecmp (name, "*od") == 0)
{
cmpltr = 7;
}
else if (strcasecmp (name, "*tr") == 0)
{
cmpltr = 8;
}
else if (strcmp (name, "*<>") == 0)
{
cmpltr = 9;
}
else if (strcmp (name, "*>=") == 0)
{
cmpltr = 10;
}
else if (strcmp (name, "*>") == 0)
{
cmpltr = 11;
}
else if (strcmp (name, "*>>=") == 0)
{
cmpltr = 12;
}
else if (strcmp (name, "*>>") == 0)
{
cmpltr = 13;
}
else if (strcasecmp (name, "*nsv") == 0)
{
cmpltr = 14;
}
else if (strcasecmp (name, "*ev") == 0)
{
cmpltr = 15;
}
else
{
cmpltr = -1;
}
**s = c;
}
return cmpltr;
}
static int
pa_parse_cmpib_64_cmpltr (s)
char **s;
{
int cmpltr;
char *name = *s + 1;
char c;
cmpltr = -1;
if (**s == ',')
{
*s += 1;
while (**s != ',' && **s != ' ' && **s != '\t')
*s += 1;
c = **s;
**s = 0x00;
if (strcmp (name, "*<<") == 0)
{
cmpltr = 0;
}
else if (strcmp (name, "*=") == 0)
{
cmpltr = 1;
}
else if (strcmp (name, "*<") == 0)
{
cmpltr = 2;
}
else if (strcmp (name, "*<=") == 0)
{
cmpltr = 3;
}
else if (strcmp (name, "*>>=") == 0)
{
cmpltr = 4;
}
else if (strcmp (name, "*<>") == 0)
{
cmpltr = 5;
}
else if (strcasecmp (name, "*>=") == 0)
{
cmpltr = 6;
}
else if (strcasecmp (name, "*>") == 0)
{
cmpltr = 7;
}
else
{
cmpltr = -1;
}
**s = c;
}
return cmpltr;
}
static int
pa_parse_nonneg_add_cmpltr (s)
char **s;
{
int cmpltr;
char *name = *s + 1;
char c;
char *save_s = *s;
int nullify = 0;
cmpltr = 0;
if (**s == ',')
{
*s += 1;
while (**s != ',' && **s != ' ' && **s != '\t')
*s += 1;
c = **s;
**s = 0x00;
if (strcmp (name, "=") == 0)
{
cmpltr = 1;
}
else if (strcmp (name, "<") == 0)
{
cmpltr = 2;
}
else if (strcmp (name, "<=") == 0)
{
cmpltr = 3;
}
else if (strcasecmp (name, "nuv") == 0)
{
cmpltr = 4;
}
else if (strcasecmp (name, "znv") == 0)
{
cmpltr = 5;
}
else if (strcasecmp (name, "sv") == 0)
{
cmpltr = 6;
}
else if (strcasecmp (name, "od") == 0)
{
cmpltr = 7;
}
else if (strcasecmp (name, "n") == 0)
{
cmpltr = 0;
nullify = 1;
}
else
{
cmpltr = -1;
}
**s = c;
}
if (nullify)
*s = save_s;
return cmpltr;
}
static int
pa_parse_neg_add_cmpltr (s)
char **s;
{
int cmpltr;
char *name = *s + 1;
char c;
char *save_s = *s;
int nullify = 0;
cmpltr = 0;
if (**s == ',')
{
*s += 1;
while (**s != ',' && **s != ' ' && **s != '\t')
*s += 1;
c = **s;
**s = 0x00;
if (strcasecmp (name, "tr") == 0)
{
cmpltr = 0;
}
else if (strcmp (name, "<>") == 0)
{
cmpltr = 1;
}
else if (strcmp (name, ">=") == 0)
{
cmpltr = 2;
}
else if (strcmp (name, ">") == 0)
{
cmpltr = 3;
}
else if (strcasecmp (name, "uv") == 0)
{
cmpltr = 4;
}
else if (strcasecmp (name, "vnz") == 0)
{
cmpltr = 5;
}
else if (strcasecmp (name, "nsv") == 0)
{
cmpltr = 6;
}
else if (strcasecmp (name, "ev") == 0)
{
cmpltr = 7;
}
else if (strcasecmp (name, "n") == 0)
{
cmpltr = 0;
nullify = 1;
}
else
{
cmpltr = -1;
}
**s = c;
}
if (nullify)
*s = save_s;
return cmpltr;
}
static int
pa_parse_addb_64_cmpltr (s)
char **s;
{
int cmpltr;
char *name = *s + 1;
char c;
char *save_s = *s;
int nullify = 0;
cmpltr = 0;
if (**s == ',')
{
*s += 1;
while (**s != ',' && **s != ' ' && **s != '\t')
*s += 1;
c = **s;
**s = 0x00;
if (strcmp (name, "=") == 0)
{
cmpltr = 1;
}
else if (strcmp (name, "<") == 0)
{
cmpltr = 2;
}
else if (strcmp (name, "<=") == 0)
{
cmpltr = 3;
}
else if (strcasecmp (name, "nuv") == 0)
{
cmpltr = 4;
}
else if (strcasecmp (name, "*=") == 0)
{
cmpltr = 5;
}
else if (strcasecmp (name, "*<") == 0)
{
cmpltr = 6;
}
else if (strcasecmp (name, "*<=") == 0)
{
cmpltr = 7;
}
else if (strcmp (name, "tr") == 0)
{
cmpltr = 8;
}
else if (strcmp (name, "<>") == 0)
{
cmpltr = 9;
}
else if (strcmp (name, ">=") == 0)
{
cmpltr = 10;
}
else if (strcmp (name, ">") == 0)
{
cmpltr = 11;
}
else if (strcasecmp (name, "uv") == 0)
{
cmpltr = 12;
}
else if (strcasecmp (name, "*<>") == 0)
{
cmpltr = 13;
}
else if (strcasecmp (name, "*>=") == 0)
{
cmpltr = 14;
}
else if (strcasecmp (name, "*>") == 0)
{
cmpltr = 15;
}
else if (strcasecmp (name, "n") == 0)
{
cmpltr = 0;
nullify = 1;
}
else
{
cmpltr = -1;
}
**s = c;
}
if (nullify)
*s = save_s;
return cmpltr;
}
#ifdef OBJ_SOM
static void
pa_align (bytes)
int bytes;
{
pa_check_current_space_and_subspace ();
s_align_bytes (bytes);
if (exact_log2 (bytes) != -1)
record_alignment (current_subspace->ssd_seg, exact_log2 (bytes));
}
#endif
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
pa_check_current_space_and_subspace ();
#endif
temp_size = get_absolute_expression ();
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);
for (i = 0; i < temp_size; i += 2)
{
md_number_to_chars (p + i,
(valueT) temp_fill,
(int) ((temp_size - i) > 2 ? 2 : (temp_size - i)));
}
pa_undefine_label ();
demand_empty_rest_of_line ();
}
static void
pa_brtab (begin)
int begin ATTRIBUTE_UNUSED;
{
#ifdef OBJ_SOM
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, 0);
#endif
demand_empty_rest_of_line ();
}
static void
pa_try (begin)
int begin ATTRIBUTE_UNUSED;
{
#ifdef OBJ_SOM
expressionS exp;
char *where = frag_more (0);
if (! begin)
expression (&exp);
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, 0);
#endif
demand_empty_rest_of_line ();
}
static void
pa_call (unused)
int unused ATTRIBUTE_UNUSED;
{
#ifdef OBJ_SOM
pa_check_current_space_and_subspace ();
#endif
pa_call_args (&last_call_desc);
demand_empty_rest_of_line ();
}
static void
pa_call_args (call_desc)
struct call_desc *call_desc;
{
char *name, c, *p;
unsigned int temp, arg_reloc;
while (!is_end_of_statement ())
{
name = input_line_pointer;
c = get_symbol_end ();
if ((strncasecmp (name, "argw", 4) == 0))
{
temp = atoi (name + 4);
p = input_line_pointer;
*p = c;
input_line_pointer++;
name = input_line_pointer;
c = get_symbol_end ();
arg_reloc = pa_build_arg_reloc (name);
call_desc->arg_reloc |= pa_align_arg_reloc (temp, arg_reloc);
}
else if ((strncasecmp (name, "rtnval", 6) == 0))
{
p = input_line_pointer;
*p = c;
input_line_pointer++;
name = input_line_pointer;
c = get_symbol_end ();
arg_reloc = pa_build_arg_reloc (name);
call_desc->arg_reloc |= (arg_reloc & 0x3);
}
else
{
as_bad (_("Invalid .CALL argument: %s"), name);
}
p = input_line_pointer;
*p = c;
if (!is_end_of_statement ())
input_line_pointer++;
}
}
static int
is_same_frag (frag1, frag2)
fragS *frag1;
fragS *frag2;
{
if (frag1 == NULL)
return (FALSE);
else if (frag2 == NULL)
return (FALSE);
else if (frag1 == frag2)
return (TRUE);
else if (frag2->fr_type == rs_fill && frag2->fr_fix == 0)
return (is_same_frag (frag1, frag2->fr_next));
else
return (FALSE);
}
#ifdef OBJ_ELF
static void
pa_build_unwind_subspace (call_info)
struct call_info *call_info;
{
asection *seg, *save_seg;
subsegT save_subseg;
unsigned int unwind;
int reloc;
char *p;
if ((bfd_get_section_flags (stdoutput, now_seg)
& (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
!= (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
return;
reloc = R_PARISC_SEGREL32;
save_seg = now_seg;
save_subseg = now_subseg;
seg = bfd_get_section_by_name (stdoutput, UNWIND_SECTION_NAME);
if (seg == ASEC_NULL)
{
seg = subseg_new (UNWIND_SECTION_NAME, 0);
bfd_set_section_flags (stdoutput, seg,
SEC_READONLY | SEC_HAS_CONTENTS
| SEC_LOAD | SEC_RELOC | SEC_ALLOC | SEC_DATA);
bfd_set_section_alignment (stdoutput, seg, 2);
}
subseg_set (seg, 0);
p = frag_more (16);
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, 0);
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, 0);
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);
subseg_set (save_seg, save_subseg);
}
#endif
static void
pa_callinfo (unused)
int unused ATTRIBUTE_UNUSED;
{
char *name, c, *p;
int temp;
#ifdef OBJ_SOM
pa_check_current_space_and_subspace ();
#endif
if (!within_procedure)
as_bad (_(".callinfo is not within a procedure definition"));
callinfo_found = TRUE;
while (!is_end_of_statement ())
{
name = input_line_pointer;
c = get_symbol_end ();
if ((strncasecmp (name, "frame", 5) == 0))
{
p = input_line_pointer;
*p = c;
input_line_pointer++;
temp = get_absolute_expression ();
if ((temp & 0x3) != 0)
{
as_bad (_("FRAME parameter must be a multiple of 8: %d\n"), temp);
temp = 0;
}
last_call_info->ci_unwind.descriptor.frame_size = temp / 8;
}
else if ((strncasecmp (name, "entry_gr", 8) == 0))
{
p = input_line_pointer;
*p = c;
input_line_pointer++;
temp = get_absolute_expression ();
if (temp < 3 || temp > 18)
as_bad (_("Value for ENTRY_GR must be in the range 3..18\n"));
last_call_info->ci_unwind.descriptor.entry_gr = temp - 2;
}
else if ((strncasecmp (name, "entry_fr", 8) == 0))
{
p = input_line_pointer;
*p = c;
input_line_pointer++;
temp = get_absolute_expression ();
if (temp < 12 || temp > 21)
as_bad (_("Value for ENTRY_FR must be in the range 12..21\n"));
last_call_info->ci_unwind.descriptor.entry_fr = temp - 11;
}
else if ((strncasecmp (name, "entry_sr", 8) == 0))
{
p = input_line_pointer;
*p = c;
input_line_pointer++;
temp = get_absolute_expression ();
if (temp != 3)
as_bad (_("Value for ENTRY_SR must be 3\n"));
}
else if ((strncasecmp (name, "calls", 5) == 0) ||
(strncasecmp (name, "caller", 6) == 0))
{
p = input_line_pointer;
*p = c;
}
else if ((strncasecmp (name, "no_calls", 8) == 0))
{
p = input_line_pointer;
*p = c;
}
else if ((strncasecmp (name, "save_rp", 7) == 0))
{
p = input_line_pointer;
*p = c;
last_call_info->ci_unwind.descriptor.save_rp = 1;
}
else if ((strncasecmp (name, "save_sp", 7) == 0))
{
p = input_line_pointer;
*p = c;
last_call_info->ci_unwind.descriptor.save_sp = 1;
}
else if ((strncasecmp (name, "no_unwind", 9) == 0))
{
p = input_line_pointer;
*p = c;
last_call_info->ci_unwind.descriptor.cannot_unwind = 1;
}
else if ((strncasecmp (name, "hpux_int", 7) == 0))
{
p = input_line_pointer;
*p = c;
last_call_info->ci_unwind.descriptor.hpux_interrupt_marker = 1;
}
else if ((strncasecmp (name, "millicode", 9) == 0))
{
p = input_line_pointer;
*p = c;
last_call_info->ci_unwind.descriptor.millicode = 1;
}
else
{
as_bad (_("Invalid .CALLINFO argument: %s"), name);
*input_line_pointer = c;
}
if (!is_end_of_statement ())
input_line_pointer++;
}
demand_empty_rest_of_line ();
}
#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
static void
pa_text (unused)
int unused ATTRIBUTE_UNUSED;
{
#ifdef OBJ_SOM
current_space = is_defined_space ("$TEXT$");
current_subspace
= pa_subsegment_to_subspace (current_space->sd_seg, 0);
#endif
s_text (0);
pa_undefine_label ();
}
static void
pa_data (unused)
int unused ATTRIBUTE_UNUSED;
{
#ifdef OBJ_SOM
current_space = is_defined_space ("$PRIVATE$");
current_subspace
= pa_subsegment_to_subspace (current_space->sd_seg, 0);
#endif
s_data (0);
pa_undefine_label ();
}
static void
pa_comm (unused)
int unused ATTRIBUTE_UNUSED;
{
unsigned int size;
symbolS *symbol;
label_symbol_struct *label_symbol = pa_get_label ();
if (label_symbol)
symbol = label_symbol->lss_label;
else
symbol = NULL;
SKIP_WHITESPACE ();
size = get_absolute_expression ();
if (symbol)
{
symbol_get_bfdsym (symbol)->flags |= BSF_OBJECT;
S_SET_VALUE (symbol, size);
S_SET_SEGMENT (symbol, bfd_und_section_ptr);
S_SET_EXTERNAL (symbol);
symbol_set_frag (symbol, &zero_address_frag);
}
demand_empty_rest_of_line ();
}
#endif
static void
pa_end (unused)
int unused ATTRIBUTE_UNUSED;
{
demand_empty_rest_of_line ();
}
static void
pa_enter (unused)
int unused ATTRIBUTE_UNUSED;
{
#ifdef OBJ_SOM
pa_check_current_space_and_subspace ();
#endif
as_bad (_("The .ENTER pseudo-op is not supported"));
demand_empty_rest_of_line ();
}
static void
pa_entry (unused)
int unused ATTRIBUTE_UNUSED;
{
#ifdef OBJ_SOM
pa_check_current_space_and_subspace ();
#endif
if (!within_procedure)
as_bad (_("Misplaced .entry. Ignored."));
else
{
if (!callinfo_found)
as_bad (_("Missing .callinfo."));
}
demand_empty_rest_of_line ();
within_entry_exit = TRUE;
#ifdef OBJ_SOM
if (last_call_info->start_symbol != NULL)
{
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, u);
}
#endif
}
static int fudge_reg_expressions;
int
hppa_force_reg_syms_absolute (resultP, op, rightP)
expressionS *resultP;
operatorT op ATTRIBUTE_UNUSED;
expressionS *rightP;
{
if (fudge_reg_expressions
&& rightP->X_op == O_register
&& resultP->X_op == O_register)
{
rightP->X_op = O_constant;
resultP->X_op = O_constant;
}
return 0;
}
static void
pa_equ (reg)
int reg;
{
label_symbol_struct *label_symbol = pa_get_label ();
symbolS *symbol;
if (label_symbol)
{
symbol = label_symbol->lss_label;
if (reg)
{
strict = 1;
if (!pa_parse_number (&input_line_pointer, 0))
as_bad (_(".REG expression must be a register"));
S_SET_VALUE (symbol, pa_number);
S_SET_SEGMENT (symbol, reg_section);
}
else
{
expressionS exp;
segT seg;
fudge_reg_expressions = 1;
seg = expression (&exp);
fudge_reg_expressions = 0;
if (exp.X_op != O_constant
&& exp.X_op != O_register)
{
if (exp.X_op != O_absent)
as_bad (_("bad or irreducible absolute expression; zero assumed"));
exp.X_add_number = 0;
seg = absolute_section;
}
S_SET_VALUE (symbol, (unsigned int) exp.X_add_number);
S_SET_SEGMENT (symbol, seg);
}
}
else
{
if (reg)
as_bad (_(".REG must use a label"));
else
as_bad (_(".EQU must use a label"));
}
pa_undefine_label ();
demand_empty_rest_of_line ();
}
static void
process_exit ()
{
char *where;
where = frag_more (0);
#ifdef OBJ_ELF
hppa_elf_mark_end_of_function ();
pa_build_unwind_subspace (last_call_info);
#else
fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
NULL, (offsetT) 0,
NULL, 0, R_HPPA_EXIT, e_fsel, 0, 0,
UNWIND_HIGH32 (&last_call_info->ci_unwind.descriptor));
#endif
}
static void
pa_exit (unused)
int unused ATTRIBUTE_UNUSED;
{
#ifdef OBJ_SOM
pa_check_current_space_and_subspace ();
#endif
if (!within_procedure)
as_bad (_(".EXIT must appear within a procedure"));
else
{
if (!callinfo_found)
as_bad (_("Missing .callinfo"));
else
{
if (!within_entry_exit)
as_bad (_("No .ENTRY for this .EXIT"));
else
{
within_entry_exit = FALSE;
process_exit ();
}
}
}
demand_empty_rest_of_line ();
}
static void
pa_export (unused)
int unused ATTRIBUTE_UNUSED;
{
char *name, c, *p;
symbolS *symbol;
name = input_line_pointer;
c = get_symbol_end ();
if ((symbol = symbol_find_or_make (name)) == NULL)
{
as_bad (_("Cannot define export symbol: %s\n"), name);
p = input_line_pointer;
*p = c;
input_line_pointer++;
}
else
{
S_SET_EXTERNAL (symbol);
symbol_get_bfdsym (symbol)->flags |= BSF_GLOBAL;
p = input_line_pointer;
*p = c;
if (!is_end_of_statement ())
{
input_line_pointer++;
pa_type_args (symbol, 1);
}
}
demand_empty_rest_of_line ();
}
static void
pa_type_args (symbolP, is_export)
symbolS *symbolP;
int is_export;
{
char *name, c, *p;
unsigned int temp, arg_reloc;
pa_symbol_type type = SYMBOL_TYPE_UNKNOWN;
asymbol *bfdsym = symbol_get_bfdsym (symbolP);
if (strncasecmp (input_line_pointer, "absolute", 8) == 0)
{
input_line_pointer += 8;
bfdsym->flags &= ~BSF_FUNCTION;
S_SET_SEGMENT (symbolP, bfd_abs_section_ptr);
type = SYMBOL_TYPE_ABSOLUTE;
}
else if (strncasecmp (input_line_pointer, "code", 4) == 0)
{
input_line_pointer += 4;
if (S_IS_FUNCTION (symbolP))
{
if (is_export)
as_tsktsk (_("Using ENTRY rather than CODE in export directive for %s"),
S_GET_NAME (symbolP));
bfdsym->flags |= BSF_FUNCTION;
type = SYMBOL_TYPE_ENTRY;
}
else
{
bfdsym->flags &= ~BSF_FUNCTION;
type = SYMBOL_TYPE_CODE;
}
}
else if (strncasecmp (input_line_pointer, "data", 4) == 0)
{
input_line_pointer += 4;
bfdsym->flags &= ~BSF_FUNCTION;
bfdsym->flags |= BSF_OBJECT;
type = SYMBOL_TYPE_DATA;
}
else if ((strncasecmp (input_line_pointer, "entry", 5) == 0))
{
input_line_pointer += 5;
bfdsym->flags |= BSF_FUNCTION;
type = SYMBOL_TYPE_ENTRY;
}
else if (strncasecmp (input_line_pointer, "millicode", 9) == 0)
{
input_line_pointer += 9;
bfdsym->flags |= BSF_FUNCTION;
#ifdef OBJ_ELF
{
elf_symbol_type *elfsym = (elf_symbol_type *) bfdsym;
elfsym->internal_elf_sym.st_info =
ELF_ST_INFO (ELF_ST_BIND (elfsym->internal_elf_sym.st_info),
STT_PARISC_MILLI);
}
#endif
type = SYMBOL_TYPE_MILLICODE;
}
else if (strncasecmp (input_line_pointer, "plabel", 6) == 0)
{
input_line_pointer += 6;
bfdsym->flags &= ~BSF_FUNCTION;
type = SYMBOL_TYPE_PLABEL;
}
else if (strncasecmp (input_line_pointer, "pri_prog", 8) == 0)
{
input_line_pointer += 8;
bfdsym->flags |= BSF_FUNCTION;
type = SYMBOL_TYPE_PRI_PROG;
}
else if (strncasecmp (input_line_pointer, "sec_prog", 8) == 0)
{
input_line_pointer += 8;
bfdsym->flags |= BSF_FUNCTION;
type = SYMBOL_TYPE_SEC_PROG;
}
#ifdef obj_set_symbol_type
obj_set_symbol_type (bfdsym, (int) type);
#endif
while (!is_end_of_statement ())
{
if (*input_line_pointer == ',')
input_line_pointer++;
name = input_line_pointer;
c = get_symbol_end ();
if ((strncasecmp (name, "argw", 4) == 0))
{
p = input_line_pointer;
*p = c;
input_line_pointer++;
temp = atoi (name + 4);
name = input_line_pointer;
c = get_symbol_end ();
arg_reloc = pa_align_arg_reloc (temp, pa_build_arg_reloc (name));
#if defined (OBJ_SOM) || defined (ELF_ARG_RELOC)
symbol_arg_reloc_info (symbolP) |= arg_reloc;
#endif
*input_line_pointer = c;
}
else if ((strncasecmp (name, "rtnval", 6)) == 0)
{
p = input_line_pointer;
*p = c;
input_line_pointer++;
name = input_line_pointer;
c = get_symbol_end ();
arg_reloc = pa_build_arg_reloc (name);
#if defined (OBJ_SOM) || defined (ELF_ARG_RELOC)
symbol_arg_reloc_info (symbolP) |= arg_reloc;
#endif
*input_line_pointer = c;
}
else if ((strncasecmp (name, "priv_lev", 8)) == 0)
{
p = input_line_pointer;
*p = c;
input_line_pointer++;
temp = atoi (input_line_pointer);
#ifdef OBJ_SOM
((obj_symbol_type *) bfdsym)->tc_data.ap.hppa_priv_level = temp;
#endif
c = get_symbol_end ();
*input_line_pointer = c;
}
else
{
as_bad (_("Undefined .EXPORT/.IMPORT argument (ignored): %s"), name);
p = input_line_pointer;
*p = c;
}
if (!is_end_of_statement ())
input_line_pointer++;
}
}
static void
pa_import (unused)
int unused ATTRIBUTE_UNUSED;
{
char *name, c, *p;
symbolS *symbol;
name = input_line_pointer;
c = get_symbol_end ();
symbol = symbol_find (name);
if (symbol == NULL || !S_IS_DEFINED (symbol))
{
symbol = symbol_find_or_make (name);
p = input_line_pointer;
*p = c;
if (!is_end_of_statement ())
{
input_line_pointer++;
pa_type_args (symbol, 0);
}
else
{
if (now_seg == text_section)
symbol_get_bfdsym (symbol)->flags |= BSF_FUNCTION;
S_SET_SEGMENT (symbol, bfd_und_section_ptr);
}
}
else
{
while (!is_end_of_statement ())
input_line_pointer++;
}
demand_empty_rest_of_line ();
}
static void
pa_label (unused)
int unused ATTRIBUTE_UNUSED;
{
char *name, c, *p;
name = input_line_pointer;
c = get_symbol_end ();
if (strlen (name) > 0)
{
colon (name);
p = input_line_pointer;
*p = c;
}
else
{
as_warn (_("Missing label name on .LABEL"));
}
if (!is_end_of_statement ())
{
as_warn (_("extra .LABEL arguments ignored."));
ignore_rest_of_line ();
}
demand_empty_rest_of_line ();
}
static void
pa_leave (unused)
int unused ATTRIBUTE_UNUSED;
{
#ifdef OBJ_SOM
pa_check_current_space_and_subspace ();
#endif
as_bad (_("The .LEAVE pseudo-op is not supported"));
demand_empty_rest_of_line ();
}
static void
pa_level (unused)
int unused ATTRIBUTE_UNUSED;
{
char *level;
level = input_line_pointer;
if (strncmp (level, "1.0", 3) == 0)
{
input_line_pointer += 3;
if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 10))
as_warn (_("could not set architecture and machine"));
}
else if (strncmp (level, "1.1", 3) == 0)
{
input_line_pointer += 3;
if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 11))
as_warn (_("could not set architecture and machine"));
}
else if (strncmp (level, "2.0w", 4) == 0)
{
input_line_pointer += 4;
if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 25))
as_warn (_("could not set architecture and machine"));
}
else if (strncmp (level, "2.0", 3) == 0)
{
input_line_pointer += 3;
if (!bfd_set_arch_mach (stdoutput, bfd_arch_hppa, 20))
as_warn (_("could not set architecture and machine"));
}
else
{
as_bad (_("Unrecognized .LEVEL argument\n"));
ignore_rest_of_line ();
}
demand_empty_rest_of_line ();
}
static void
pa_origin (unused)
int unused ATTRIBUTE_UNUSED;
{
#ifdef OBJ_SOM
pa_check_current_space_and_subspace ();
#endif
s_org (0);
pa_undefine_label ();
}
static void
pa_param (unused)
int unused ATTRIBUTE_UNUSED;
{
char *name, c, *p;
symbolS *symbol;
name = input_line_pointer;
c = get_symbol_end ();
if ((symbol = symbol_find_or_make (name)) == NULL)
{
as_bad (_("Cannot define static symbol: %s\n"), name);
p = input_line_pointer;
*p = c;
input_line_pointer++;
}
else
{
S_CLEAR_EXTERNAL (symbol);
p = input_line_pointer;
*p = c;
if (!is_end_of_statement ())
{
input_line_pointer++;
pa_type_args (symbol, 0);
}
}
demand_empty_rest_of_line ();
}
static void
pa_proc (unused)
int unused ATTRIBUTE_UNUSED;
{
struct call_info *call_info;
#ifdef OBJ_SOM
pa_check_current_space_and_subspace ();
#endif
if (within_procedure)
as_fatal (_("Nested procedures"));
callinfo_found = FALSE;
within_procedure = TRUE;
call_info = (struct call_info *) xmalloc (sizeof (struct call_info));
if (!call_info)
as_fatal (_("Cannot allocate unwind descriptor\n"));
memset (call_info, 0, sizeof (struct call_info));
call_info->ci_next = NULL;
if (call_info_root == NULL)
{
call_info_root = call_info;
last_call_info = call_info;
}
else
{
last_call_info->ci_next = call_info;
last_call_info = call_info;
}
call_info->ci_unwind.descriptor.cannot_unwind = 0;
call_info->ci_unwind.descriptor.region_desc = 1;
call_info->ci_unwind.descriptor.hpux_interrupt_marker = 0;
{
label_symbol_struct *label_symbol = pa_get_label ();
if (label_symbol)
{
if (label_symbol->lss_label)
{
last_call_info->start_symbol = label_symbol->lss_label;
symbol_get_bfdsym (label_symbol->lss_label)->flags |= BSF_FUNCTION;
}
else
as_bad (_("Missing function name for .PROC (corrupted label chain)"));
}
else
last_call_info->start_symbol = NULL;
}
demand_empty_rest_of_line ();
}
static void
pa_procend (unused)
int unused ATTRIBUTE_UNUSED;
{
#ifdef OBJ_SOM
pa_check_current_space_and_subspace ();
#endif
if (within_procedure && last_call_info->start_symbol == NULL)
{
label_symbol_struct *label_symbol = pa_get_label ();
if (label_symbol)
{
if (label_symbol->lss_label)
{
last_call_info->start_symbol = label_symbol->lss_label;
symbol_get_bfdsym (label_symbol->lss_label)->flags
|= BSF_FUNCTION;
#ifdef OBJ_SOM
if (within_entry_exit)
{
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, u);
}
#endif
}
else
as_bad (_("Missing function name for .PROC (corrupted label chain)"));
}
else
as_bad (_("Missing function name for .PROC"));
}
if (!within_procedure)
as_bad (_("misplaced .procend"));
if (!callinfo_found)
as_bad (_("Missing .callinfo for this procedure"));
if (within_entry_exit)
as_bad (_("Missing .EXIT for a .ENTRY"));
#ifdef OBJ_ELF
hppa_elf_mark_end_of_function ();
#endif
within_procedure = FALSE;
demand_empty_rest_of_line ();
pa_undefine_label ();
}
#ifdef OBJ_SOM
static int
exact_log2 (value)
int value;
{
int shift = 0;
while ((1 << shift) != value && shift < 32)
shift++;
if (shift >= 32)
return -1;
else
return shift;
}
static void
pa_check_current_space_and_subspace ()
{
if (current_space == NULL)
as_fatal (_("Not in a space.\n"));
if (current_subspace == NULL)
as_fatal (_("Not in a subspace.\n"));
}
static sd_chain_struct *
pa_parse_space_stmt (space_name, create_flag)
char *space_name;
int create_flag;
{
char *name, *ptemp, c;
char loadable, defined, private, sort;
int spnum;
asection *seg = NULL;
sd_chain_struct *space;
spnum = 0;
sort = 0;
loadable = TRUE;
defined = TRUE;
private = FALSE;
if (strcmp (space_name, "$TEXT$") == 0)
{
seg = pa_def_spaces[0].segment;
defined = pa_def_spaces[0].defined;
private = pa_def_spaces[0].private;
sort = pa_def_spaces[0].sort;
spnum = pa_def_spaces[0].spnum;
}
else if (strcmp (space_name, "$PRIVATE$") == 0)
{
seg = pa_def_spaces[1].segment;
defined = pa_def_spaces[1].defined;
private = pa_def_spaces[1].private;
sort = pa_def_spaces[1].sort;
spnum = pa_def_spaces[1].spnum;
}
if (!is_end_of_statement ())
{
print_errors = FALSE;
ptemp = input_line_pointer + 1;
strict = 0;
pa_parse_number (&ptemp, 0);
if (pa_number >= 0)
{
spnum = pa_number;
input_line_pointer = ptemp;
}
else
{
while (!is_end_of_statement ())
{
input_line_pointer++;
name = input_line_pointer;
c = get_symbol_end ();
if ((strncasecmp (name, "spnum", 5) == 0))
{
*input_line_pointer = c;
input_line_pointer++;
spnum = get_absolute_expression ();
}
else if ((strncasecmp (name, "sort", 4) == 0))
{
*input_line_pointer = c;
input_line_pointer++;
sort = get_absolute_expression ();
}
else if ((strncasecmp (name, "unloadable", 10) == 0))
{
*input_line_pointer = c;
loadable = FALSE;
}
else if ((strncasecmp (name, "notdefined", 10) == 0))
{
*input_line_pointer = c;
defined = FALSE;
}
else if ((strncasecmp (name, "private", 7) == 0))
{
*input_line_pointer = c;
private = TRUE;
}
else
{
as_bad (_("Invalid .SPACE argument"));
*input_line_pointer = c;
if (!is_end_of_statement ())
input_line_pointer++;
}
}
}
print_errors = TRUE;
}
if (create_flag && seg == NULL)
seg = subseg_new (space_name, 0);
if (create_flag)
space = create_new_space (space_name, spnum, loadable, defined,
private, sort, seg, 1);
else
{
space = is_defined_space (space_name);
SPACE_SPNUM (space) = spnum;
SPACE_DEFINED (space) = defined & 1;
SPACE_USER_DEFINED (space) = 1;
}
#ifdef obj_set_section_attributes
obj_set_section_attributes (seg, defined, private, sort, spnum);
#endif
return space;
}
static void
pa_space (unused)
int unused ATTRIBUTE_UNUSED;
{
char *name, c, *space_name, *save_s;
sd_chain_struct *sd_chain;
if (within_procedure)
{
as_bad (_("Can\'t change spaces within a procedure definition. Ignored"));
ignore_rest_of_line ();
}
else
{
if (strncmp (input_line_pointer, "$TEXT$", 6) == 0)
{
input_line_pointer += 6;
sd_chain = is_defined_space ("$TEXT$");
if (sd_chain == NULL)
sd_chain = pa_parse_space_stmt ("$TEXT$", 1);
else if (SPACE_USER_DEFINED (sd_chain) == 0)
sd_chain = pa_parse_space_stmt ("$TEXT$", 0);
current_space = sd_chain;
subseg_set (text_section, sd_chain->sd_last_subseg);
current_subspace
= pa_subsegment_to_subspace (text_section,
sd_chain->sd_last_subseg);
demand_empty_rest_of_line ();
return;
}
if (strncmp (input_line_pointer, "$PRIVATE$", 9) == 0)
{
input_line_pointer += 9;
sd_chain = is_defined_space ("$PRIVATE$");
if (sd_chain == NULL)
sd_chain = pa_parse_space_stmt ("$PRIVATE$", 1);
else if (SPACE_USER_DEFINED (sd_chain) == 0)
sd_chain = pa_parse_space_stmt ("$PRIVATE$", 0);
current_space = sd_chain;
subseg_set (data_section, sd_chain->sd_last_subseg);
current_subspace
= pa_subsegment_to_subspace (data_section,
sd_chain->sd_last_subseg);
demand_empty_rest_of_line ();
return;
}
if (!strncasecmp (input_line_pointer,
GDB_DEBUG_SPACE_NAME,
strlen (GDB_DEBUG_SPACE_NAME)))
{
input_line_pointer += strlen (GDB_DEBUG_SPACE_NAME);
sd_chain = is_defined_space (GDB_DEBUG_SPACE_NAME);
if (sd_chain == NULL)
sd_chain = pa_parse_space_stmt (GDB_DEBUG_SPACE_NAME, 1);
else if (SPACE_USER_DEFINED (sd_chain) == 0)
sd_chain = pa_parse_space_stmt (GDB_DEBUG_SPACE_NAME, 0);
current_space = sd_chain;
{
asection *gdb_section
= bfd_make_section_old_way (stdoutput, GDB_DEBUG_SPACE_NAME);
subseg_set (gdb_section, sd_chain->sd_last_subseg);
current_subspace
= pa_subsegment_to_subspace (gdb_section,
sd_chain->sd_last_subseg);
}
demand_empty_rest_of_line ();
return;
}
print_errors = 0;
save_s = input_line_pointer;
strict = 0;
pa_parse_number (&input_line_pointer, 0);
if (pa_number >= 0)
{
if ((sd_chain = pa_find_space_by_number (pa_number)))
{
current_space = sd_chain;
subseg_set (sd_chain->sd_seg, sd_chain->sd_last_subseg);
current_subspace
= pa_subsegment_to_subspace (sd_chain->sd_seg,
sd_chain->sd_last_subseg);
demand_empty_rest_of_line ();
return;
}
}
print_errors = 1;
input_line_pointer = save_s;
name = input_line_pointer;
c = get_symbol_end ();
space_name = xmalloc (strlen (name) + 1);
strcpy (space_name, name);
*input_line_pointer = c;
sd_chain = pa_parse_space_stmt (space_name, 1);
current_space = sd_chain;
subseg_set (sd_chain->sd_seg, sd_chain->sd_last_subseg);
current_subspace = pa_subsegment_to_subspace (sd_chain->sd_seg,
sd_chain->sd_last_subseg);
demand_empty_rest_of_line ();
}
}
static void
pa_spnum (unused)
int unused ATTRIBUTE_UNUSED;
{
char *name;
char c;
char *p;
sd_chain_struct *space;
name = input_line_pointer;
c = get_symbol_end ();
space = is_defined_space (name);
if (space)
{
p = frag_more (4);
md_number_to_chars (p, SPACE_SPNUM (space), 4);
}
else
as_warn (_("Undefined space: '%s' Assuming space number = 0."), name);
*input_line_pointer = c;
demand_empty_rest_of_line ();
}
static void
pa_subspace (create_new)
int create_new;
{
char *name, *ss_name, c;
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;
asection *section;
if (current_space == NULL)
as_fatal (_("Must be in a space before changing or declaring subspaces.\n"));
if (within_procedure)
{
as_bad (_("Can\'t change subspaces within a procedure definition. Ignored"));
ignore_rest_of_line ();
}
else
{
name = input_line_pointer;
c = get_symbol_end ();
ss_name = xmalloc (strlen (name) + 1);
strcpy (ss_name, name);
*input_line_pointer = c;
sort = 0;
access = 0x7f;
loadable = 1;
comdat = 0;
common = 0;
dup_common = 0;
code_only = 0;
zero = 0;
space_index = ~0;
alignment = 1;
quadrant = 0;
space = current_space;
if (create_new)
ssd = NULL;
else
ssd = is_defined_subspace (ss_name);
if (ssd && SUBSPACE_DEFINED (ssd))
{
subseg_set (ssd->ssd_seg, ssd->ssd_subseg);
current_subspace = ssd;
if (!is_end_of_statement ())
as_warn (_("Parameters of an existing subspace can\'t be modified"));
demand_empty_rest_of_line ();
return;
}
else
{
i = 0;
while (pa_def_subspaces[i].name)
{
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;
zero = pa_def_subspaces[i].zero;
space_index = pa_def_subspaces[i].space_index;
alignment = pa_def_subspaces[i].alignment;
quadrant = pa_def_subspaces[i].quadrant;
access = pa_def_subspaces[i].access;
sort = pa_def_subspaces[i].sort;
break;
}
i++;
}
}
if (!is_end_of_statement ())
{
input_line_pointer++;
while (!is_end_of_statement ())
{
name = input_line_pointer;
c = get_symbol_end ();
if ((strncasecmp (name, "quad", 4) == 0))
{
*input_line_pointer = c;
input_line_pointer++;
quadrant = get_absolute_expression ();
}
else if ((strncasecmp (name, "align", 5) == 0))
{
*input_line_pointer = c;
input_line_pointer++;
alignment = get_absolute_expression ();
if (exact_log2 (alignment) == -1)
{
as_bad (_("Alignment must be a power of 2"));
alignment = 1;
}
}
else if ((strncasecmp (name, "access", 6) == 0))
{
*input_line_pointer = c;
input_line_pointer++;
access = get_absolute_expression ();
}
else if ((strncasecmp (name, "sort", 4) == 0))
{
*input_line_pointer = c;
input_line_pointer++;
sort = get_absolute_expression ();
}
else if ((strncasecmp (name, "code_only", 9) == 0))
{
*input_line_pointer = c;
code_only = 1;
}
else if ((strncasecmp (name, "unloadable", 10) == 0))
{
*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;
common = 1;
}
else if ((strncasecmp (name, "dup_comm", 8) == 0))
{
*input_line_pointer = c;
dup_common = 1;
}
else if ((strncasecmp (name, "zero", 4) == 0))
{
*input_line_pointer = c;
zero = 1;
}
else if ((strncasecmp (name, "first", 5) == 0))
as_bad (_("FIRST not supported as a .SUBSPACE argument"));
else
as_bad (_("Invalid .SUBSPACE argument"));
if (!is_end_of_statement ())
input_line_pointer++;
}
}
applicable = bfd_applicable_section_flags (stdoutput);
flags = 0;
if (loadable)
flags |= (SEC_ALLOC | SEC_LOAD);
if (code_only)
flags |= SEC_CODE;
if (comdat || common || dup_common)
flags |= SEC_LINK_ONCE;
flags |= SEC_RELOC | SEC_HAS_CONTENTS;
if (zero)
flags &= ~(SEC_LOAD | SEC_HAS_CONTENTS);
applicable &= flags;
if (create_new)
section = subseg_force_new (ss_name, 0);
else if (ssd)
section = ssd->ssd_seg;
else
section = subseg_new (ss_name, 0);
if (zero)
seg_info (section)->bss = 1;
bfd_set_section_flags (stdoutput, section, applicable);
record_alignment (section, exact_log2 (alignment));
bfd_set_section_vma (stdoutput, section,
pa_subspace_start (space, quadrant));
if (ssd)
current_subspace = update_subspace (space, ss_name, loadable,
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, comdat, common,
dup_common, zero, sort,
access, space_index,
alignment, quadrant, section);
demand_empty_rest_of_line ();
current_subspace->ssd_seg = section;
subseg_set (current_subspace->ssd_seg, current_subspace->ssd_subseg);
}
SUBSPACE_DEFINED (current_subspace) = 1;
}
static void
pa_spaces_begin ()
{
int i;
space_dict_root = NULL;
space_dict_last = NULL;
i = 0;
while (pa_def_spaces[i].name)
{
char *name;
name = pa_def_spaces[i].name;
pa_def_spaces[i].segment = subseg_new (name, 0);
create_new_space (pa_def_spaces[i].name, pa_def_spaces[i].spnum,
pa_def_spaces[i].loadable, pa_def_spaces[i].defined,
pa_def_spaces[i].private, pa_def_spaces[i].sort,
pa_def_spaces[i].segment, 0);
i++;
}
i = 0;
while (pa_def_subspaces[i].name)
{
char *name;
int applicable, subsegment;
asection *segment = NULL;
sd_chain_struct *space;
name = pa_def_subspaces[i].name;
subsegment = 0;
segment = subseg_new (name, subsegment);
if (!strcmp (pa_def_subspaces[i].name, "$CODE$"))
{
text_section = segment;
applicable = bfd_applicable_section_flags (stdoutput);
bfd_set_section_flags (stdoutput, segment,
applicable & (SEC_ALLOC | SEC_LOAD
| SEC_RELOC | SEC_CODE
| SEC_READONLY
| SEC_HAS_CONTENTS));
}
else if (!strcmp (pa_def_subspaces[i].name, "$DATA$"))
{
data_section = segment;
applicable = bfd_applicable_section_flags (stdoutput);
bfd_set_section_flags (stdoutput, segment,
applicable & (SEC_ALLOC | SEC_LOAD
| SEC_RELOC
| SEC_HAS_CONTENTS));
}
else if (!strcmp (pa_def_subspaces[i].name, "$BSS$"))
{
bss_section = segment;
applicable = bfd_applicable_section_flags (stdoutput);
bfd_set_section_flags (stdoutput, segment,
applicable & SEC_ALLOC);
}
else if (!strcmp (pa_def_subspaces[i].name, "$LIT$"))
{
applicable = bfd_applicable_section_flags (stdoutput);
bfd_set_section_flags (stdoutput, segment,
applicable & (SEC_ALLOC | SEC_LOAD
| SEC_RELOC
| SEC_READONLY
| SEC_HAS_CONTENTS));
}
else if (!strcmp (pa_def_subspaces[i].name, "$MILLICODE$"))
{
applicable = bfd_applicable_section_flags (stdoutput);
bfd_set_section_flags (stdoutput, segment,
applicable & (SEC_ALLOC | SEC_LOAD
| SEC_RELOC
| SEC_READONLY
| SEC_HAS_CONTENTS));
}
else if (!strcmp (pa_def_subspaces[i].name, "$UNWIND$"))
{
applicable = bfd_applicable_section_flags (stdoutput);
bfd_set_section_flags (stdoutput, segment,
applicable & (SEC_ALLOC | SEC_LOAD
| SEC_RELOC
| SEC_READONLY
| SEC_HAS_CONTENTS));
}
space = pa_segment_to_space (pa_def_spaces[pa_def_subspaces[i].
def_space_index].segment);
if (space == NULL)
{
as_fatal (_("Internal error: Unable to find containing space for %s."),
pa_def_subspaces[i].name);
}
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,
pa_def_subspaces[i].sort,
pa_def_subspaces[i].access,
pa_def_subspaces[i].space_index,
pa_def_subspaces[i].alignment,
pa_def_subspaces[i].quadrant,
segment);
i++;
}
}
static sd_chain_struct *
create_new_space (name, spnum, loadable, defined, private,
sort, seg, user_defined)
char *name;
int spnum;
int loadable ATTRIBUTE_UNUSED;
int defined;
int private;
int sort;
asection *seg;
int user_defined;
{
sd_chain_struct *chain_entry;
chain_entry = (sd_chain_struct *) xmalloc (sizeof (sd_chain_struct));
if (!chain_entry)
as_fatal (_("Out of memory: could not allocate new space chain entry: %s\n"),
name);
SPACE_NAME (chain_entry) = (char *) xmalloc (strlen (name) + 1);
strcpy (SPACE_NAME (chain_entry), name);
SPACE_DEFINED (chain_entry) = defined;
SPACE_USER_DEFINED (chain_entry) = user_defined;
SPACE_SPNUM (chain_entry) = spnum;
chain_entry->sd_seg = seg;
chain_entry->sd_last_subseg = -1;
chain_entry->sd_subspaces = NULL;
chain_entry->sd_next = NULL;
if (!space_dict_last)
space_dict_last = chain_entry;
if (space_dict_root == NULL)
space_dict_root = chain_entry;
else
{
sd_chain_struct *chain_pointer;
sd_chain_struct *prev_chain_pointer;
chain_pointer = space_dict_root;
prev_chain_pointer = NULL;
while (chain_pointer)
{
prev_chain_pointer = chain_pointer;
chain_pointer = chain_pointer->sd_next;
}
if (prev_chain_pointer)
{
chain_entry->sd_next = chain_pointer;
prev_chain_pointer->sd_next = chain_entry;
}
else
{
space_dict_root = chain_entry;
chain_entry->sd_next = chain_pointer;
}
if (chain_entry->sd_next == NULL)
space_dict_last = chain_entry;
}
#ifdef obj_set_section_attributes
obj_set_section_attributes (seg, defined, private, sort, spnum);
#endif
return chain_entry;
}
static ssd_chain_struct *
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 ATTRIBUTE_UNUSED;
int code_only ATTRIBUTE_UNUSED;
int comdat, common, dup_common;
int is_zero ATTRIBUTE_UNUSED;
int sort;
int access;
int space_index ATTRIBUTE_UNUSED;
int alignment ATTRIBUTE_UNUSED;
int quadrant;
asection *seg;
{
ssd_chain_struct *chain_entry;
chain_entry = (ssd_chain_struct *) xmalloc (sizeof (ssd_chain_struct));
if (!chain_entry)
as_fatal (_("Out of memory: could not allocate new subspace chain entry: %s\n"), name);
SUBSPACE_NAME (chain_entry) = (char *) xmalloc (strlen (name) + 1);
strcpy (SUBSPACE_NAME (chain_entry), name);
SUBSPACE_DEFINED (chain_entry) = 0;
chain_entry->ssd_subseg = 0;
chain_entry->ssd_seg = seg;
chain_entry->ssd_next = NULL;
if (space->sd_subspaces == NULL)
space->sd_subspaces = chain_entry;
else
{
ssd_chain_struct *chain_pointer;
ssd_chain_struct *prev_chain_pointer;
chain_pointer = space->sd_subspaces;
prev_chain_pointer = NULL;
while (chain_pointer)
{
prev_chain_pointer = chain_pointer;
chain_pointer = chain_pointer->ssd_next;
}
if (prev_chain_pointer)
{
chain_entry->ssd_next = chain_pointer;
prev_chain_pointer->ssd_next = chain_entry;
}
else
{
space->sd_subspaces = chain_entry;
chain_entry->ssd_next = chain_pointer;
}
}
#ifdef obj_set_subsection_attributes
obj_set_subsection_attributes (seg, space->sd_seg, access, sort,
quadrant, comdat, common, dup_common);
#endif
return chain_entry;
}
static ssd_chain_struct *
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 ATTRIBUTE_UNUSED;
int code_only ATTRIBUTE_UNUSED;
int comdat;
int common;
int dup_common;
int zero ATTRIBUTE_UNUSED;
int sort;
int access;
int space_index ATTRIBUTE_UNUSED;
int alignment ATTRIBUTE_UNUSED;
int quadrant;
asection *section;
{
ssd_chain_struct *chain_entry;
chain_entry = is_defined_subspace (name);
#ifdef obj_set_subsection_attributes
obj_set_subsection_attributes (section, space->sd_seg, access, sort,
quadrant, comdat, common, dup_common);
#endif
return chain_entry;
}
static sd_chain_struct *
is_defined_space (name)
char *name;
{
sd_chain_struct *chain_pointer;
for (chain_pointer = space_dict_root;
chain_pointer;
chain_pointer = chain_pointer->sd_next)
{
if (strcmp (SPACE_NAME (chain_pointer), name) == 0)
return chain_pointer;
}
return NULL;
}
static sd_chain_struct *
pa_segment_to_space (seg)
asection *seg;
{
sd_chain_struct *space_chain;
for (space_chain = space_dict_root;
space_chain;
space_chain = space_chain->sd_next)
{
if (space_chain->sd_seg == seg)
return space_chain;
}
return NULL;
}
static ssd_chain_struct *
is_defined_subspace (name)
char *name;
{
sd_chain_struct *space_chain;
ssd_chain_struct *subspace_chain;
for (space_chain = space_dict_root;
space_chain;
space_chain = space_chain->sd_next)
{
for (subspace_chain = space_chain->sd_subspaces;
subspace_chain;
subspace_chain = subspace_chain->ssd_next)
if (strcmp (SUBSPACE_NAME (subspace_chain), name) == 0)
return subspace_chain;
}
return NULL;
}
static ssd_chain_struct *
pa_subsegment_to_subspace (seg, subseg)
asection *seg;
subsegT subseg;
{
sd_chain_struct *space_chain;
ssd_chain_struct *subspace_chain;
for (space_chain = space_dict_root;
space_chain;
space_chain = space_chain->sd_next)
{
if (space_chain->sd_seg == seg)
{
for (subspace_chain = space_chain->sd_subspaces;
subspace_chain;
subspace_chain = subspace_chain->ssd_next)
if (subspace_chain->ssd_subseg == (int) subseg)
return subspace_chain;
}
}
return NULL;
}
static sd_chain_struct *
pa_find_space_by_number (number)
int number;
{
sd_chain_struct *space_chain;
for (space_chain = space_dict_root;
space_chain;
space_chain = space_chain->sd_next)
{
if (SPACE_SPNUM (space_chain) == (unsigned int) number)
return space_chain;
}
return NULL;
}
static unsigned int
pa_subspace_start (space, quadrant)
sd_chain_struct *space;
int quadrant;
{
if ((strcmp (SPACE_NAME (space), "$PRIVATE$") == 0) && quadrant == 1)
return 0x40000000;
else if (space->sd_seg == data_section && quadrant == 1)
return 0x40000000;
else
return 0;
return 0;
}
#endif
static unsigned int
pa_stringer_aux (s)
char *s;
{
unsigned int c = *s & CHAR_MASK;
switch (c)
{
case '\"':
c = NOT_A_CHAR;
break;
default:
break;
}
return c;
}
static void
pa_stringer (append_zero)
int append_zero;
{
char *s, num_buf[4];
unsigned int c;
int i;
#ifdef OBJ_SOM
pa_check_current_space_and_subspace ();
#endif
s = input_line_pointer + 1;
while (is_a_char (c = pa_stringer_aux (s++)))
{
if (c == '\\')
{
c = *s;
switch (c)
{
case 'x':
{
unsigned int number;
int num_digit;
char dg;
char *s_start = s;
s++;
for (num_digit = 0, number = 0, dg = *s;
num_digit < 2
&& (ISDIGIT (dg) || (dg >= 'a' && dg <= 'f')
|| (dg >= 'A' && dg <= 'F'));
num_digit++)
{
if (ISDIGIT (dg))
number = number * 16 + dg - '0';
else if (dg >= 'a' && dg <= 'f')
number = number * 16 + dg - 'a' + 10;
else
number = number * 16 + dg - 'A' + 10;
s++;
dg = *s;
}
if (num_digit > 0)
{
switch (num_digit)
{
case 1:
sprintf (num_buf, "%02o", number);
break;
case 2:
sprintf (num_buf, "%03o", number);
break;
}
for (i = 0; i <= num_digit; i++)
s_start[i] = num_buf[i];
}
break;
}
default:
s++;
break;
}
}
}
stringer (append_zero);
pa_undefine_label ();
}
static void
pa_version (unused)
int unused ATTRIBUTE_UNUSED;
{
obj_version (0);
pa_undefine_label ();
}
#ifdef OBJ_SOM
static void
pa_compiler (unused)
int unused ATTRIBUTE_UNUSED;
{
obj_som_compiler (0);
pa_undefine_label ();
}
#endif
static void
pa_copyright (unused)
int unused ATTRIBUTE_UNUSED;
{
obj_copyright (0);
pa_undefine_label ();
}
static void
pa_cons (nbytes)
int nbytes;
{
cons (nbytes);
pa_undefine_label ();
}
static void
pa_float_cons (float_type)
int float_type;
{
float_cons (float_type);
pa_undefine_label ();
}
static void
pa_fill (unused)
int unused ATTRIBUTE_UNUSED;
{
#ifdef OBJ_SOM
pa_check_current_space_and_subspace ();
#endif
s_fill (0);
pa_undefine_label ();
}
static void
pa_lcomm (needs_align)
int needs_align;
{
#ifdef OBJ_SOM
pa_check_current_space_and_subspace ();
#endif
s_lcomm (needs_align);
pa_undefine_label ();
}
static void
pa_lsym (unused)
int unused ATTRIBUTE_UNUSED;
{
#ifdef OBJ_SOM
pa_check_current_space_and_subspace ();
#endif
s_lsym (0);
pa_undefine_label ();
}
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
if (fixp->fx_r_type == R_HPPA
&& hppa_fix->fx_r_format == 32
&& strncmp (S_GET_NAME (fixp->fx_addsy),
FAKE_LABEL_NAME,
strlen (FAKE_LABEL_NAME)))
return 0;
#endif
#ifdef OBJ_ELF
code = elf_hppa_reloc_final_type (stdoutput, fixp->fx_r_type,
hppa_fix->fx_r_format,
hppa_fix->fx_r_field);
switch (code)
{
case R_PARISC_DIR21L:
case R_PARISC_DLTREL21L:
case R_PARISC_DPREL21L:
case R_PARISC_PLTOFF21L:
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:
case R_PARISC_GNU_VTENTRY:
case R_PARISC_GNU_VTINHERIT:
return 0;
default:
break;
}
#endif
if (fixp->fx_addsy
&& fixp->fx_subsy
&& (hppa_fix->segment->flags & SEC_CODE))
return 0;
if (hppa_fix->fx_r_field == e_lrsel
|| hppa_fix->fx_r_field == e_rrsel
|| hppa_fix->fx_r_field == e_nlrsel)
return 0;
if (hppa_fix->fx_r_field == e_tsel
|| hppa_fix->fx_r_field == e_ltsel
|| hppa_fix->fx_r_field == e_rtsel
|| hppa_fix->fx_r_field == e_psel
|| hppa_fix->fx_r_field == e_rpsel
|| hppa_fix->fx_r_field == e_lpsel)
return 0;
if (hppa_fix->fx_r_type == R_HPPA_ABS_CALL)
return 0;
if (fixp->fx_addsy != 0 && S_IS_FUNCTION (fixp->fx_addsy))
return 0;
return 1;
}
int
hppa_force_relocation (fixp)
struct fix *fixp;
{
struct hppa_fix_struct *hppa_fixp;
hppa_fixp = (struct hppa_fix_struct *) fixp->tc_fix_data;
#ifdef OBJ_SOM
if (fixp->fx_r_type == (int) R_HPPA_ENTRY
|| fixp->fx_r_type == (int) R_HPPA_EXIT
|| fixp->fx_r_type == (int) R_HPPA_BEGIN_BRTAB
|| fixp->fx_r_type == (int) R_HPPA_END_BRTAB
|| fixp->fx_r_type == (int) R_HPPA_BEGIN_TRY
|| fixp->fx_r_type == (int) R_HPPA_END_TRY
|| (fixp->fx_addsy != NULL && fixp->fx_subsy != NULL
&& (hppa_fixp->segment->flags & SEC_CODE) != 0))
return 1;
#endif
#ifdef OBJ_ELF
if (fixp->fx_r_type == (int) R_PARISC_GNU_VTINHERIT
|| fixp->fx_r_type == (int) R_PARISC_GNU_VTENTRY)
return 1;
#endif
assert (fixp->fx_addsy != NULL);
if (S_FORCE_RELOC (fixp->fx_addsy, 1))
return 1;
if (fixp->fx_pcrel
&& arg_reloc_stub_needed (symbol_arg_reloc_info (fixp->fx_addsy),
hppa_fixp->fx_arg_reloc))
return 1;
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;
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;
return 0;
}
#ifdef OBJ_ELF
static void
hppa_elf_mark_end_of_function ()
{
char *name;
if (last_call_info == NULL || last_call_info->start_symbol == NULL)
{
return;
}
name = (char *) xmalloc (strlen ("L$\001end_")
+ strlen (S_GET_NAME (last_call_info->start_symbol))
+ 1);
if (name)
{
symbolS *symbolP;
strcpy (name, "L$\001end_");
strcat (name, S_GET_NAME (last_call_info->start_symbol));
symbolP = symbol_find (name);
if (symbolP)
{
xfree (name);
}
else
{
symbolP = symbol_new (name, now_seg, (valueT) (frag_now_fix () - 4),
frag_now);
assert (symbolP);
S_CLEAR_EXTERNAL (symbolP);
symbol_table_insert (symbolP);
}
if (symbolP)
last_call_info->end_symbol = symbolP;
else
as_bad (_("Symbol '%s' could not be created."), name);
}
else
as_bad (_("No memory for symbol name."));
}
void
elf_hppa_final_processing ()
{
struct call_info *call_info_pointer;
for (call_info_pointer = call_info_root;
call_info_pointer;
call_info_pointer = call_info_pointer->ci_next)
{
elf_symbol_type *esym
= ((elf_symbol_type *)
symbol_get_bfdsym (call_info_pointer->start_symbol));
esym->internal_elf_sym.st_size =
S_GET_VALUE (call_info_pointer->end_symbol)
- S_GET_VALUE (call_info_pointer->start_symbol) + 4;
}
}
static void
pa_vtable_entry (ignore)
int ignore ATTRIBUTE_UNUSED;
{
struct fix *new_fix;
new_fix = obj_elf_vtable_entry (0);
if (new_fix)
{
struct hppa_fix_struct *hppa_fix = (struct hppa_fix_struct *)
obstack_alloc (¬es, sizeof (struct hppa_fix_struct));
hppa_fix->fx_r_type = R_HPPA;
hppa_fix->fx_r_field = e_fsel;
hppa_fix->fx_r_format = 32;
hppa_fix->fx_arg_reloc = 0;
hppa_fix->segment = now_seg;
new_fix->tc_fix_data = (void *) hppa_fix;
new_fix->fx_r_type = (int) R_PARISC_GNU_VTENTRY;
}
}
static void
pa_vtable_inherit (ignore)
int ignore ATTRIBUTE_UNUSED;
{
struct fix *new_fix;
new_fix = obj_elf_vtable_inherit (0);
if (new_fix)
{
struct hppa_fix_struct *hppa_fix = (struct hppa_fix_struct *)
obstack_alloc (¬es, sizeof (struct hppa_fix_struct));
hppa_fix->fx_r_type = R_HPPA;
hppa_fix->fx_r_field = e_fsel;
hppa_fix->fx_r_format = 32;
hppa_fix->fx_arg_reloc = 0;
hppa_fix->segment = now_seg;
new_fix->tc_fix_data = (void *) hppa_fix;
new_fix->fx_r_type = (int) R_PARISC_GNU_VTINHERIT;
}
}
#endif