/* tc-hppa.c -- Assemble for the PA
- Copyright 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ Copyright (C) 1989-2019 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
GAS is distributed in the hope that it will be useful,
/* HP PA-RISC support was contributed by the Center for Software Science
at the University of Utah. */
-#include <stdio.h>
-
#include "as.h"
#include "safe-ctype.h"
#include "subsegs.h"
+#include "dw2gencfi.h"
#include "bfd/libhppa.h"
struct default_subspace_dict
{
/* Name of the subspace. */
- char *name;
+ const char *name;
/* FIXME. Is this still needed? */
char defined;
struct default_space_dict
{
/* Name of the space. */
- char *name;
+ const char *name;
/* Space number. It is possible to identify spaces within
assembly code numerically! */
struct pd_reg
{
- char *name;
+ const char *name;
int value;
};
to a condition number which can be recorded in an instruction. */
struct fp_cond_map
{
- char *string;
+ const char *string;
int cond;
};
string to a field selector type. */
struct selector_entry
{
- char *prefix;
+ const char *prefix;
int field_selector;
};
static void pa_space (int);
static void pa_spnum (int);
static void pa_subspace (int);
-static sd_chain_struct *create_new_space (char *, int, int,
- int, int, int,
- asection *, int);
+static sd_chain_struct *create_new_space (const char *, int, int,
+ int, int, int,
+ asection *, int);
static ssd_chain_struct *create_new_subspace (sd_chain_struct *,
- char *, int, int,
- int, int, int, int,
- int, int, int, int,
- int, asection *);
+ const char *, int, int,
+ int, int, int, int,
+ int, int, int, int,
+ int, asection *);
static ssd_chain_struct *update_subspace (sd_chain_struct *,
- char *, int, int, int,
- int, int, int, int,
- int, int, int, int,
- asection *);
-static sd_chain_struct *is_defined_space (char *);
-static ssd_chain_struct *is_defined_subspace (char *);
+ char *, int, int, int,
+ int, int, int, int,
+ int, int, int, int,
+ asection *);
+static sd_chain_struct *is_defined_space (const char *);
+static ssd_chain_struct *is_defined_subspace (const char *);
static sd_chain_struct *pa_segment_to_space (asection *);
static ssd_chain_struct *pa_subsegment_to_subspace (asection *,
subsegT);
static sd_chain_struct *pa_find_space_by_number (int);
static unsigned int pa_subspace_start (sd_chain_struct *, int);
-static sd_chain_struct *pa_parse_space_stmt (char *, int);
+static sd_chain_struct *pa_parse_space_stmt (const char *, int);
#endif
/* File and globally scoped variable declarations. */
As in 0f12.456 or 0d1.2345e12.
Be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
- changed in read.c. Ideally it shouldn't hae to know abou it at
- all, but nothing is ideal around here. */
+ changed in read.c. Ideally it shouldn't have to know about it
+ at all, but nothing is ideal around here. */
const char FLT_CHARS[] = "rRsSfFdDxXpP";
static struct pa_it the_insn;
seen in each subspace. */
static label_symbol_struct *label_symbols_rootp = NULL;
-/* Holds the last field selector. */
-static int hppa_field_selector;
+/* Last label symbol */
+static label_symbol_struct last_label_symbol;
/* Nonzero when strict matching is enabled. Zero otherwise.
#ifdef OBJ_SOM
/* default space and subspace dictionaries */
-#define GDB_SYMBOLS GDB_SYMBOLS_SUBSPACE_NAME
-#define GDB_STRINGS GDB_STRINGS_SUBSPACE_NAME
+#define GDB_SYMBOLS GDB_SYMBOLS_SUBSPACE_NAME
+#define GDB_STRINGS GDB_STRINGS_SUBSPACE_NAME
/* pre-defined subsegments (subspaces) for the HPPA. */
#define SUBSEG_CODE 0
#define IS_R_SELECT(S) (*(S) == 'R' || *(S) == 'r')
#define IS_L_SELECT(S) (*(S) == 'L' || *(S) == 'l')
+/* Store immediate values of shift/deposit/extract functions. */
+
+#define SAVE_IMMEDIATE(VALUE) \
+ { \
+ if (immediate_check) \
+ { \
+ if (pos == -1) \
+ pos = (VALUE); \
+ else if (len == -1) \
+ len = (VALUE); \
+ } \
+ }
+
/* Insert FIELD into OPCODE starting at bit START. Continue pa_ip
main loop after insertion. */
if ((FIELD) > (HIGH) || (FIELD) < (LOW)) \
{ \
if (! IGNORE) \
- as_bad (_("Field out of range [%d..%d] (%d)."), (LOW), (HIGH), \
+ as_bad (_("Field out of range [%d..%d] (%d)."), (LOW), (HIGH), \
(int) (FIELD));\
- break; \
+ break; \
} \
}
{ \
if ((FIELD) > (HIGH) || (FIELD) < (LOW)) \
{ \
- as_bad_where ((FILENAME), (LINE), \
+ as_bad_where ((FILENAME), (LINE), \
_("Field out of range [%d..%d] (%d)."), (LOW), (HIGH), \
(int) (FIELD));\
- break; \
+ break; \
} \
}
if ((FIELD) & ((ALIGN) - 1)) \
{ \
if (! IGNORE) \
- as_bad (_("Field not properly aligned [%d] (%d)."), (ALIGN), \
+ as_bad (_("Field not properly aligned [%d] (%d)."), (ALIGN), \
(int) (FIELD));\
- break; \
+ break; \
} \
}
((exp).X_op == O_subtract \
&& strcmp (S_GET_NAME ((exp).X_op_symbol), "$global$") == 0)
+#define is_SB_relative(exp) \
+ ((exp).X_op == O_subtract \
+ && strcmp (S_GET_NAME ((exp).X_op_symbol), "$segrel$") == 0)
+
#define is_PC_relative(exp) \
((exp).X_op == O_subtract \
&& strcmp (S_GET_NAME ((exp).X_op_symbol), "$PIC_pcrel$0") == 0)
static label_symbol_struct *
pa_get_label (void)
{
- label_symbol_struct *label_chain;
+ label_symbol_struct *label_chain = label_symbols_rootp;
- for (label_chain = label_symbols_rootp;
- label_chain;
- label_chain = label_chain->lss_next)
+ if (label_chain)
{
#ifdef OBJ_SOM
- if (current_space == label_chain->lss_space && label_chain->lss_label)
- return label_chain;
+ 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;
+ if (now_seg == label_chain->lss_segment && label_chain->lss_label)
+ return label_chain;
#endif
}
void
pa_define_label (symbolS *symbol)
{
- label_symbol_struct *label_chain = pa_get_label ();
+ label_symbol_struct *label_chain = label_symbols_rootp;
- if (label_chain)
- label_chain->lss_label = symbol;
- else
- {
- /* Create a new label entry and add it to the head of the chain. */
- label_chain = xmalloc (sizeof (label_symbol_struct));
- label_chain->lss_label = symbol;
+ if (!label_chain)
+ label_chain = &last_label_symbol;
+
+ label_chain->lss_label = symbol;
#ifdef OBJ_SOM
- label_chain->lss_space = current_space;
+ label_chain->lss_space = current_space;
#endif
#ifdef OBJ_ELF
- label_chain->lss_segment = now_seg;
+ label_chain->lss_segment = now_seg;
#endif
- label_chain->lss_next = NULL;
- if (label_symbols_rootp)
- label_chain->lss_next = label_symbols_rootp;
+ /* Not used. */
+ label_chain->lss_next = NULL;
- label_symbols_rootp = label_chain;
- }
+ label_symbols_rootp = label_chain;
#ifdef OBJ_ELF
dwarf2_emit_label (symbol);
static void
pa_undefine_label (void)
{
- label_symbol_struct *label_chain;
- label_symbol_struct *prev_label_chain = NULL;
-
- for (label_chain = label_symbols_rootp;
- label_chain;
- label_chain = label_chain->lss_next)
- {
- if (1
-#ifdef OBJ_SOM
- && current_space == label_chain->lss_space && label_chain->lss_label
-#endif
-#ifdef OBJ_ELF
- && now_seg == label_chain->lss_segment && label_chain->lss_label
-#endif
- )
- {
- /* Remove the label from the chain and free its memory. */
- if (prev_label_chain)
- prev_label_chain->lss_next = label_chain->lss_next;
- else
- label_symbols_rootp = label_chain->lss_next;
-
- free (label_chain);
- break;
- }
- prev_label_chain = label_chain;
- }
+ label_symbols_rootp = NULL;
}
/* An HPPA-specific version of fix_new. This is required because the HPPA
int unwind_bits ATTRIBUTE_UNUSED)
{
fixS *new_fix;
- struct hppa_fix_struct *hppa_fix = obstack_alloc (¬es, sizeof (struct hppa_fix_struct));
+ struct hppa_fix_struct *hppa_fix = XOBNEW (¬es, struct hppa_fix_struct);
if (exp != NULL)
new_fix = fix_new_exp (frag, where, size, exp, pcrel, r_type);
it now so as not to confuse write.c. Ditto for $PIC_pcrel$0. */
if (new_fix->fx_subsy
&& (strcmp (S_GET_NAME (new_fix->fx_subsy), "$global$") == 0
+ || strcmp (S_GET_NAME (new_fix->fx_subsy), "$segrel$") == 0
|| strcmp (S_GET_NAME (new_fix->fx_subsy), "$PIC_pcrel$0") == 0
|| strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_gdidx$") == 0
|| strcmp (S_GET_NAME (new_fix->fx_subsy), "$tls_ldidx$") == 0
hppa_field_selector is set by the parse_cons_expression_hppa. */
void
-cons_fix_new_hppa (fragS *frag, int where, int size, expressionS *exp)
+cons_fix_new_hppa (fragS *frag, int where, int size, expressionS *exp,
+ int hppa_field_selector)
{
unsigned int rel_type;
else if (is_PC_relative (*exp))
rel_type = R_HPPA_PCREL_CALL;
#ifdef OBJ_ELF
+ else if (is_SB_relative (*exp))
+ rel_type = R_PARISC_SEGREL32;
else if (is_tls_gdidx (*exp))
rel_type = R_PARISC_TLS_GD21L;
else if (is_tls_ldidx (*exp))
fix_new_hppa (frag, where, size,
(symbolS *) NULL, (offsetT) 0, exp, 0, rel_type,
hppa_field_selector, size * 8, 0, 0);
-
- /* Reset field selector to its default state. */
- hppa_field_selector = 0;
}
/* Mark (via expr_end) the end of an expression (I think). FIXME. */
return nullif;
}
-/* Turn a string in input_line_pointer into a floating point constant of type
- type, and store the appropriate bytes in *litP. The number of LITTLENUMS
- emitted is stored in *sizeP . An error message or NULL is returned. */
-
-#define MAX_LITTLENUMS 6
-
-char *
+const char *
md_atof (int 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;
+ return ieee_md_atof (type, litP, sizeP, TRUE);
}
/* Write out big-endian. */
if (fixp->fx_addsy == 0)
return &no_relocs;
- assert (hppa_fixp != 0);
- assert (section != 0);
+ gas_assert (hppa_fixp != 0);
+ gas_assert (section != 0);
- reloc = xmalloc (sizeof (arelent));
+ reloc = XNEW (arelent);
- reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+ reloc->sym_ptr_ptr = XNEW (asymbol *);
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+
+ /* Allow fixup_segment to recognize hand-written pc-relative relocations.
+ When we went through cons_fix_new_hppa, we classified them as complex. */
+ /* ??? It might be better to hide this +8 stuff in tc_cfi_emit_pcrel_expr,
+ undefine DIFF_EXPR_OK, and let these sorts of complex expressions fail
+ when R_HPPA_COMPLEX == R_PARISC_UNIMPLEMENTED. */
+ if (fixp->fx_r_type == (bfd_reloc_code_real_type) R_HPPA_COMPLEX
+ && fixp->fx_pcrel)
+ {
+ fixp->fx_r_type = R_HPPA_PCREL_CALL;
+ fixp->fx_offset += 8;
+ }
+
codes = hppa_gen_reloc_type (stdoutput,
fixp->fx_r_type,
hppa_fixp->fx_r_format,
for (n_relocs = 0; codes[n_relocs]; n_relocs++)
;
- relocs = xmalloc (sizeof (arelent *) * n_relocs + 1);
- reloc = xmalloc (sizeof (arelent) * n_relocs);
+ relocs = XNEWVEC (arelent *, n_relocs + 1);
+ reloc = XNEWVEC (arelent, n_relocs);
for (i = 0; i < n_relocs; i++)
relocs[i] = &reloc[i];
switch (fixp->fx_r_type)
{
default:
- assert (n_relocs == 1);
+ gas_assert (n_relocs == 1);
code = *codes[0];
/* Facilitate hand-crafted unwind info. */
if (strcmp (section->name, UNWIND_SECTION_NAME) == 0)
code = R_PARISC_SEGREL32;
- /* Fall thru */
+ /* Fallthru */
default:
reloc->addend = fixp->fx_offset;
break;
}
- reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+ reloc->sym_ptr_ptr = XNEW (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);
+ gas_assert (reloc->howto && (unsigned int) code == reloc->howto->type);
break;
}
#else /* OBJ_SOM */
{
code = *codes[i];
- relocs[i]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+ relocs[i]->sym_ptr_ptr = XNEW (asymbol *);
*relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
relocs[i]->howto =
bfd_reloc_type_lookup (stdoutput,
/* The only time we ever use a R_COMP2 fixup is for the difference
of two symbols. With that in mind we fill in all four
relocs now and break out of the loop. */
- assert (i == 1);
+ gas_assert (i == 1);
relocs[0]->sym_ptr_ptr
= (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr;
relocs[0]->howto
(bfd_reloc_code_real_type) *codes[0]);
relocs[0]->address = fixp->fx_frag->fr_address + fixp->fx_where;
relocs[0]->addend = 0;
- relocs[1]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+ relocs[1]->sym_ptr_ptr = XNEW (asymbol *);
*relocs[1]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
relocs[1]->howto
= bfd_reloc_type_lookup (stdoutput,
(bfd_reloc_code_real_type) *codes[1]);
relocs[1]->address = fixp->fx_frag->fr_address + fixp->fx_where;
relocs[1]->addend = 0;
- relocs[2]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+ relocs[2]->sym_ptr_ptr = XNEW (asymbol *);
*relocs[2]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
relocs[2]->howto
= bfd_reloc_type_lookup (stdoutput,
case R_N0SEL:
case R_N1SEL:
/* There is no symbol or addend associated with these fixups. */
- relocs[i]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+ relocs[i]->sym_ptr_ptr = XNEW (asymbol *);
*relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
relocs[i]->addend = 0;
break;
case R_ENTRY:
case R_EXIT:
/* There is no symbol associated with these fixups. */
- relocs[i]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+ relocs[i]->sym_ptr_ptr = XNEW (asymbol *);
*relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
relocs[i]->addend = fixp->fx_offset;
break;
valueT
md_section_align (asection *segment, valueT size)
{
- int align = bfd_get_section_alignment (stdoutput, segment);
+ int align = bfd_section_alignment (segment);
int align2 = (1 << align) - 1;
return (size + align2) & ~align2;
size_t md_longopts_size = sizeof (md_longopts);
int
-md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
+md_parse_option (int c, const char *arg ATTRIBUTE_UNUSED)
{
switch (c)
{
case R_PARISC_TLS_LE14R:
case R_PARISC_TLS_IE21L:
case R_PARISC_TLS_IE14R:
- if (fixP->fx_addsy)
+ if (fixP->fx_addsy)
S_SET_THREAD_LOCAL (fixP->fx_addsy);
break;
default:
p++;
c = *p;
/* Tege hack: Special case for general registers as the general
- code makes a binary search with case translation, and is VERY
- slow. */
+ code makes a binary search with case translation, and is VERY
+ slow. */
if (c == 'r')
{
p++;
else
{
/* And finally, it could be a symbol in the absolute section which
- is effectively a constant, or a register alias symbol. */
+ is effectively a constant, or a register alias symbol. */
name = p;
c = *p;
while (is_part_of_name (c))
register, so... */
have_prefix = TRUE;
}
- else if (S_GET_SEGMENT (sym) == &bfd_abs_section)
+ else if (S_GET_SEGMENT (sym) == bfd_abs_section_ptr)
num = S_GET_VALUE (sym);
else if (!strict)
{
/* Parse a .byte, .word, .long expression for the HPPA. Called by
cons via the TC_PARSE_CONS_EXPRESSION macro. */
-void
+int
parse_cons_expression_hppa (expressionS *exp)
{
- hppa_field_selector = pa_chk_field_selector (&input_line_pointer);
+ int hppa_field_selector = pa_chk_field_selector (&input_line_pointer);
expression (exp);
+ return hppa_field_selector;
}
/* Evaluate an absolute expression EXP which may be modified by
save_in = input_line_pointer;
input_line_pointer = *strp;
expression (&insn->exp);
- /* This is not perfect, but is a huge improvement over doing nothing.
+ expr_end = input_line_pointer;
+ input_line_pointer = save_in;
+ if (insn->exp.X_op != O_constant)
+ {
+ /* We have a non-match in strict mode. */
+ if (!strict)
+ as_bad (_("Bad segment (should be absolute)."));
+ return 0;
+ }
+ return evaluate_absolute (insn);
+}
+
+/* Get an absolute number. The input string is terminated at the
+ first whitespace character. */
+
+static int
+pa_get_number (struct pa_it *insn, char **strp)
+{
+ char *save_in;
+ char *s, c;
+ int result;
- The PA assembly syntax is ambiguous in a variety of ways. Consider
+ save_in = input_line_pointer;
+ input_line_pointer = *strp;
+
+ /* The PA assembly syntax is ambiguous in a variety of ways. Consider
this string "4 %r5" Is that the number 4 followed by the register
- r5, or is that 4 MOD r5?
+ r5, or is that 4 MOD r5? This situation occurs for example in the
+ coprocessor load and store instructions. Previously, calling
+ pa_get_absolute_expression directly results in r5 being entered
+ in the symbol table.
- If we get a modulo expression when looking for an absolute, we try
- again cutting off the input string at the first whitespace character. */
- if (insn->exp.X_op == O_modulus)
- {
- char *s, c;
- int retval;
+ So, when looking for an absolute number, we cut off the input string
+ at the first whitespace character. Thus, expressions should generally
+ contain no whitespace. */
- input_line_pointer = *strp;
- s = *strp;
- while (*s != ',' && *s != ' ' && *s != '\t')
- s++;
+ s = *strp;
+ while (*s != ',' && *s != ' ' && *s != '\t')
+ s++;
- c = *s;
- *s = 0;
+ c = *s;
+ *s = 0;
- retval = pa_get_absolute_expression (insn, strp);
+ result = pa_get_absolute_expression (insn, strp);
- input_line_pointer = save_in;
- *s = c;
- return evaluate_absolute (insn);
- }
- /* When in strict mode we have a non-match, fix up the pointers
- and return to our caller. */
- if (insn->exp.X_op != O_constant && strict)
- {
- expr_end = input_line_pointer;
- input_line_pointer = save_in;
- return 0;
- }
- if (insn->exp.X_op != O_constant)
- {
- as_bad (_("Bad segment (should be absolute)."));
- 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);
+ *s = c;
+ return result;
}
/* Given an argument location specification return the associated
cmpltr = 7;
}
/* If we have something like addb,n then there is no condition
- completer. */
+ completer. */
else if (strcasecmp (name, "n") == 0)
{
cmpltr = 0;
cmpltr = 7;
}
/* If we have something like addb,n then there is no condition
- completer. */
+ completer. */
else if (strcasecmp (name, "n") == 0)
{
cmpltr = 0;
cmpltr = 7;
}
/* If we have something like addb,n then there is no condition
- completer. */
+ completer. */
else if (strcasecmp (name, "n") == 0)
{
cmpltr = 0;
cmpltr = 7;
}
/* If we have something like addb,n then there is no condition
- completer. */
+ completer. */
else if (strcasecmp (name, "n") == 0)
{
cmpltr = 0;
cmpltr = 15;
}
/* If we have something like addb,n then there is no condition
- completer. */
+ completer. */
else if (strcasecmp (name, "n") == 0)
{
cmpltr = 0;
static void
pa_ip (char *str)
{
- char *error_message = "";
+ const 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;
+ int cmpltr, nullif, flag, cond, need_cond, num;
+ int immediate_check = 0, pos = -1, len = -1;
unsigned long opcode;
struct pa_opcode *insn;
return;
}
- /* Look up the opcode in the has table. */
+ /* Look up the opcode in the hash table. */
if ((insn = (struct pa_opcode *) hash_find (op_hash, str)) == NULL)
{
- as_bad ("Unknown opcode: `%s'", str);
+ as_bad (_("Unknown opcode: `%s'"), str);
return;
}
opcode = insn->match;
strict = (insn->flags & FLAG_STRICT);
memset (&the_insn, 0, sizeof (the_insn));
+ need_cond = 1;
the_insn.reloc = R_HPPA_NONE;
goto failed;
/* Build the opcode, checking as we go to make
- sure that the operands match. */
+ sure that the operands match. */
for (args = insn->args;; ++args)
{
/* Absorb white space in instruction. */
s = s + 1;
if (!strncasecmp (s, "%sar", 4))
- {
+ {
s += 4;
continue;
}
else if (!strncasecmp (s, "%cr11", 5))
- {
+ {
s += 5;
continue;
}
break;
s = expr_end;
CHECK_FIELD (num, 32, 1, 0);
+ SAVE_IMMEDIATE(num);
INSERT_FIELD_AND_CONTINUE (opcode, 32 - num, 0);
/* Handle a 5 bit immediate at 15. */
}
else if (*args == 'J')
{
- /* M bit is explicit in the major opcode. */
+ /* M bit is explicit in the major opcode. */
INSERT_FIELD_AND_CONTINUE (opcode, a, 2);
}
- else if (*args == 'e')
+ else
{
+ gas_assert (*args == 'e');
/* Stash the ma/mb flag temporarily in the
instruction. We will use (and remove it)
later when handling 'J', 'K', '<' & '>'. */
else
break;
+ /* Condition is not required with "dc". */
+ need_cond = 0;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
/* Handle 32 bit carry for ADD. */
else
break;
+ /* Condition is not required with "db". */
+ need_cond = 0;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 11);
/* Handle 32 bit borrow for SUB. */
permloc[2] = 8;
permloc[3] = 6;
for (; i < 4; i++)
- {
+ {
switch (*s++)
{
case '0':
as_bad (_("Invalid Add Condition: %s"), name);
*s = c;
}
+ /* Except with "dc", we have a match failure with
+ 'A' if we don't have a doubleword condition. */
+ else if (*args == 'A' && need_cond)
+ break;
+
opcode |= cmpltr << 13;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
s += 2;
}
else
- as_bad (_("Invalid Bit Branch Condition: %c"), *s);
+ as_bad (_("Invalid Branch On Bit Condition: %c"), *s);
}
+ else
+ as_bad (_("Missing Branch On Bit Condition"));
+
INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 15);
/* Handle a compare/subtract condition. */
name);
*s = c;
}
+ /* Except with "db", we have a match failure with
+ 'S' if we don't have a doubleword condition. */
+ else if (*args == 'S' && need_cond)
+ break;
+
opcode |= cmpltr << 13;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
- /* Handle a logical instruction condition. */
+ /* Handle a logical instruction condition. */
case 'L':
case 'l':
cmpltr = 0;
as_bad (_("Invalid Logical Instruction Condition."));
*s = c;
}
+ /* 32-bit is default for no condition. */
+ else if (*args == 'L')
+ break;
+
opcode |= cmpltr << 13;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
case 'x':
case 'y':
cmpltr = 0;
+ /* Check immediate values in shift/extract/deposit
+ * instructions if they will give undefined behaviour. */
+ immediate_check = 1;
if (*s == ',')
{
save_s = s++;
as_bad (_("Invalid Shift/Extract/Deposit Condition."));
*s = c;
}
+
INSERT_FIELD_AND_CONTINUE (opcode, cmpltr, 13);
/* Handle a unit instruction condition. */
flag = 0;
if (*s == ',')
{
+ int uxor;
s++;
/* 64 bit conditions. */
else if (*s == '*')
break;
+ /* The uxor instruction only supports unit conditions
+ not involving carries. */
+ uxor = (opcode & 0xfc000fc0) == 0x08000380;
if (strncasecmp (s, "sbz", 3) == 0)
{
cmpltr = 2;
cmpltr = 3;
s += 3;
}
- else if (strncasecmp (s, "sdc", 3) == 0)
+ else if (!uxor && strncasecmp (s, "sdc", 3) == 0)
{
cmpltr = 4;
s += 3;
}
- else if (strncasecmp (s, "sbc", 3) == 0)
+ else if (!uxor && strncasecmp (s, "sbc", 3) == 0)
{
cmpltr = 6;
s += 3;
}
- else if (strncasecmp (s, "shc", 3) == 0)
+ else if (!uxor && strncasecmp (s, "shc", 3) == 0)
{
cmpltr = 7;
s += 3;
flag = 1;
s += 3;
}
- else if (strncasecmp (s, "ndc", 3) == 0)
+ else if (!uxor && strncasecmp (s, "ndc", 3) == 0)
{
cmpltr = 4;
flag = 1;
s += 3;
}
- else if (strncasecmp (s, "nbc", 3) == 0)
+ else if (!uxor && strncasecmp (s, "nbc", 3) == 0)
{
cmpltr = 6;
flag = 1;
s += 3;
}
- else if (strncasecmp (s, "nhc", 3) == 0)
+ else if (!uxor && strncasecmp (s, "nhc", 3) == 0)
{
cmpltr = 7;
flag = 1;
flag = 0;
s += 3;
}
- else if (strncasecmp (s, "swc", 3) == 0)
+ else if (!uxor && strncasecmp (s, "swc", 3) == 0)
{
cmpltr = 5;
flag = 0;
flag = 1;
s += 3;
}
- else if (strncasecmp (s, "nwc", 3) == 0)
+ else if (!uxor && strncasecmp (s, "nwc", 3) == 0)
{
cmpltr = 5;
flag = 1;
else if (*args != 'U' || (*s != ' ' && *s != '\t'))
as_bad (_("Invalid Unit Instruction Condition."));
}
+ /* 32-bit is default for no condition. */
+ else if (*args == 'U')
+ break;
+
opcode |= cmpltr << 13;
INSERT_FIELD_AND_CONTINUE (opcode, flag, 12);
continue;
}
else
- break;
+ break;
/* Handle '%sr0,%r31' implicit operand of be,l instruction. */
case 'Y':
break;
s = expr_end;
CHECK_FIELD (num, 31, 0, strict);
+ SAVE_IMMEDIATE(num);
INSERT_FIELD_AND_CONTINUE (opcode, 31 - num, 5);
/* Handle a 6 bit shift count at 20,22:26. */
break;
s = expr_end;
CHECK_FIELD (num, 63, 0, strict);
+ SAVE_IMMEDIATE(num);
num = 63 - num;
opcode |= (num & 0x20) << 6;
INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 5);
break;
s = expr_end;
CHECK_FIELD (num, 64, 1, strict);
+ SAVE_IMMEDIATE(num);
num--;
opcode |= (num & 0x20) << 3;
num = 31 - (num & 0x1f);
break;
s = expr_end;
CHECK_FIELD (num, 64, 1, strict);
+ SAVE_IMMEDIATE(num);
num--;
opcode |= (num & 0x20) << 7;
num = 31 - (num & 0x1f);
break;
s = expr_end;
CHECK_FIELD (num, 31, 0, strict);
+ SAVE_IMMEDIATE(num);
INSERT_FIELD_AND_CONTINUE (opcode, num, 5);
/* Handle a 6 bit bit position at 20,22:26. */
break;
s = expr_end;
CHECK_FIELD (num, 63, 0, strict);
+ SAVE_IMMEDIATE(num);
opcode |= (num & 0x20) << 6;
INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 5);
s = expr_end;
CHECK_FIELD (num, 63, 0, strict);
if (num & 0x20)
- ;
- else
- opcode |= (1 << 13);
+ opcode &= ~(1 << 13);
INSERT_FIELD_AND_CONTINUE (opcode, num & 0x1f, 21);
/* Handle a 5 bit immediate at 10. */
case 'v':
if (*s++ != ',')
as_bad (_("Invalid SFU identifier"));
- num = pa_get_absolute_expression (&the_insn, &s);
+ num = pa_get_number (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
/* Handle a 20 bit SOP field for spop0. */
case 'O':
- num = pa_get_absolute_expression (&the_insn, &s);
+ num = pa_get_number (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
/* Handle a 15bit SOP field for spop1. */
case 'o':
- num = pa_get_absolute_expression (&the_insn, &s);
+ num = pa_get_number (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
/* Handle a 10bit SOP field for spop3. */
case '0':
- num = pa_get_absolute_expression (&the_insn, &s);
+ num = pa_get_number (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
/* Handle a 15 bit SOP field for spop2. */
case '1':
- num = pa_get_absolute_expression (&the_insn, &s);
+ num = pa_get_number (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
case 'u':
if (*s++ != ',')
as_bad (_("Invalid COPR identifier"));
- num = pa_get_absolute_expression (&the_insn, &s);
+ num = pa_get_number (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
/* Handle a 22bit SOP field for copr. */
case '2':
- num = pa_get_absolute_expression (&the_insn, &s);
+ num = pa_get_number (&the_insn, &s);
if (strict && the_insn.exp.X_op != O_constant)
break;
s = expr_end;
{
case SGL:
opcode |= 0x20;
+ /* Fall through. */
case DBL:
the_insn.fpof1 = flag;
continue;
/* Handle all floating point registers. */
case 'f':
switch (*++args)
- {
+ {
/* Float target register. */
case 't':
if (!pa_parse_number (&s, 3))
break;
- num = (pa_number & ~FP_REG_RSEL) - FP_REG_BASE;
+ /* RSEL should not be set. */
+ if (pa_number & FP_REG_RSEL)
+ break;
+ num = pa_number - FP_REG_BASE;
CHECK_FIELD (num, 31, 0, 0);
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
CHECK_FIELD (num, 31, 0, 0);
if (the_insn.fpof1 == SGL)
{
- if (num < 16)
- {
+ 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);
+ }
+ num &= 0xF;
+ num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
}
INSERT_FIELD_AND_CONTINUE (opcode, num, 16);
}
CHECK_FIELD (num, 31, 0, 0);
if (the_insn.fpof1 == SGL)
{
- if (num < 16)
- {
+ 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);
+ }
+ num &= 0xF;
+ num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
}
INSERT_FIELD_AND_CONTINUE (opcode, num, 0);
}
CHECK_FIELD (num, 31, 0, 0);
if (the_insn.fpof1 == SGL)
{
- if (num < 16)
- {
+ 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);
+ }
+ num &= 0xF;
+ num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
}
INSERT_FIELD_AND_CONTINUE (opcode, num, 6);
}
CHECK_FIELD (num, 31, 0, 0);
if (the_insn.fpof1 == SGL)
{
- if (num < 16)
- {
+ 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);
+ }
+ num &= 0xF;
+ num |= (pa_number & FP_REG_RSEL ? 1 << 4 : 0);
}
INSERT_FIELD_AND_CONTINUE (opcode, num, 11);
}
/* If this instruction is specific to a particular architecture,
then set a new architecture. This automatic promotion crud is
for compatibility with HP's old assemblers only. */
- if (match == TRUE
+ if (match
&& bfd_get_mach (stdoutput) < insn->arch
&& !bfd_set_arch_mach (stdoutput, bfd_arch_hppa, insn->arch))
{
break;
}
+ if (immediate_check)
+ {
+ if (pos != -1 && len != -1 && pos < len - 1)
+ as_warn (_("Immediates %d and %d will give undefined behavior."),
+ pos, len);
+ }
+
the_insn.opcode = opcode;
}
char *to;
/* The had better be something to assemble. */
- assert (str);
+ gas_assert (str);
/* If we are within a procedure definition, make sure we've
defined a label for the procedure; handle case where the
static void
pa_call_args (struct call_desc *call_desc)
{
- char *name, c, *p;
+ char *name, c;
unsigned int temp, arg_reloc;
while (!is_end_of_statement ())
{
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
/* Process a source argument. */
if ((strncasecmp (name, "argw", 4) == 0))
{
temp = atoi (name + 4);
- p = input_line_pointer;
- *p = c;
+ (void) restore_line_pointer (c);
input_line_pointer++;
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
arg_reloc = pa_build_arg_reloc (name);
call_desc->arg_reloc |= pa_align_arg_reloc (temp, arg_reloc);
}
/* Process a return value. */
else if ((strncasecmp (name, "rtnval", 6) == 0))
{
- p = input_line_pointer;
- *p = c;
+ (void) restore_line_pointer (c);
input_line_pointer++;
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
arg_reloc = pa_build_arg_reloc (name);
call_desc->arg_reloc |= (arg_reloc & 0x3);
}
{
as_bad (_("Invalid .CALL argument: %s"), name);
}
- p = input_line_pointer;
- *p = c;
+
+ (void) restore_line_pointer (c);
if (!is_end_of_statement ())
input_line_pointer++;
}
demand_empty_rest_of_line ();
}
-/* Return TRUE if FRAG1 and FRAG2 are the same. */
-
-static bfd_boolean
-is_same_frag (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
/* Build an entry in the UNWIND subspace from the given function
attributes in CALL_INFO. This is not needed for SOM as using
subsegT save_subseg;
unsigned int unwind;
int reloc;
- char *p;
+ char *name, *p;
+ symbolS *symbolP;
- if ((bfd_get_section_flags (stdoutput, now_seg)
+ if ((bfd_section_flags (now_seg)
& (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
!= (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
return;
+ if (call_info->start_symbol == NULL)
+ /* This can happen if there were errors earlier on in the assembly. */
+ return;
+
+ /* Replace the start symbol with a local symbol that will be reduced
+ to a section offset. This avoids problems with weak functions with
+ multiple definitions, etc. */
+ name = concat ("L$\001start_", S_GET_NAME (call_info->start_symbol),
+ (char *) NULL);
+
+ /* If we have a .procend preceded by a .exit, then the symbol will have
+ already been defined. In that case, we don't want another unwind
+ entry. */
+ symbolP = symbol_find (name);
+ if (symbolP)
+ {
+ xfree (name);
+ return;
+ }
+ else
+ {
+ symbolP = symbol_new (name, now_seg,
+ S_GET_VALUE (call_info->start_symbol),
+ symbol_get_frag (call_info->start_symbol));
+ gas_assert (symbolP);
+ S_CLEAR_EXTERNAL (symbolP);
+ symbol_table_insert (symbolP);
+ }
+
reloc = R_PARISC_SEGREL32;
save_seg = now_seg;
save_subseg = now_subseg;
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);
+ bfd_set_section_flags (seg, (SEC_READONLY | SEC_HAS_CONTENTS | SEC_LOAD
+ | SEC_RELOC | SEC_ALLOC | SEC_DATA));
+ bfd_set_section_alignment (seg, 2);
}
subseg_set (seg, 0);
/* Relocation info. for start offset of the function. */
md_number_to_chars (p, 0, 4);
fix_new_hppa (frag_now, p - frag_now->fr_literal, 4,
- call_info->start_symbol, (offsetT) 0,
+ symbolP, (offsetT) 0,
(expressionS *) NULL, 0, reloc,
e_fsel, 32, 0, 0);
static void
pa_callinfo (int unused ATTRIBUTE_UNUSED)
{
- char *name, c, *p;
+ char *name, c;
int temp;
#ifdef OBJ_SOM
/* Iterate over the .CALLINFO arguments. */
while (!is_end_of_statement ())
{
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
/* Frame size specification. */
if ((strncasecmp (name, "frame", 5) == 0))
{
- p = input_line_pointer;
- *p = c;
+ (void) restore_line_pointer (c);
input_line_pointer++;
temp = get_absolute_expression ();
if ((temp & 0x3) != 0)
/* callinfo is in bytes and unwind_desc is in 8 byte units. */
last_call_info->ci_unwind.descriptor.frame_size = temp / 8;
-
}
/* Entry register (GR, GR and SR) specifications. */
else if ((strncasecmp (name, "entry_gr", 8) == 0))
{
- p = input_line_pointer;
- *p = c;
+ (void) restore_line_pointer (c);
input_line_pointer++;
temp = get_absolute_expression ();
/* The HP assembler accepts 19 as the high bound for ENTRY_GR
}
else if ((strncasecmp (name, "entry_fr", 8) == 0))
{
- p = input_line_pointer;
- *p = c;
+ (void) restore_line_pointer (c);
input_line_pointer++;
temp = get_absolute_expression ();
/* Similarly the HP assembler takes 31 as the high bound even
}
else if ((strncasecmp (name, "entry_sr", 8) == 0))
{
- p = input_line_pointer;
- *p = c;
+ (void) restore_line_pointer (c);
input_line_pointer++;
temp = get_absolute_expression ();
if (temp != 3)
as_bad (_("Value for ENTRY_SR must be 3\n"));
}
/* Note whether or not this function performs any calls. */
- else if ((strncasecmp (name, "calls", 5) == 0) ||
- (strncasecmp (name, "caller", 6) == 0))
+ else if ((strncasecmp (name, "calls", 5) == 0)
+ || (strncasecmp (name, "caller", 6) == 0))
{
- p = input_line_pointer;
- *p = c;
+ (void) restore_line_pointer (c);
}
else if ((strncasecmp (name, "no_calls", 8) == 0))
{
- p = input_line_pointer;
- *p = c;
+ (void) restore_line_pointer (c);
}
/* Should RP be saved into the stack. */
else if ((strncasecmp (name, "save_rp", 7) == 0))
{
- p = input_line_pointer;
- *p = c;
+ (void) restore_line_pointer (c);
last_call_info->ci_unwind.descriptor.save_rp = 1;
}
/* Likewise for SP. */
else if ((strncasecmp (name, "save_sp", 7) == 0))
{
- p = input_line_pointer;
- *p = c;
+ (void) restore_line_pointer (c);
last_call_info->ci_unwind.descriptor.save_sp = 1;
}
/* Is this an unwindable procedure. If so mark it so
- in the unwind descriptor. */
+ in the unwind descriptor. */
else if ((strncasecmp (name, "no_unwind", 9) == 0))
{
- p = input_line_pointer;
- *p = c;
+ (void) restore_line_pointer (c);
last_call_info->ci_unwind.descriptor.cannot_unwind = 1;
}
/* Is this an interrupt routine. If so mark it in the
- unwind descriptor. */
+ unwind descriptor. */
else if ((strncasecmp (name, "hpux_int", 7) == 0))
{
- p = input_line_pointer;
- *p = c;
+ (void) restore_line_pointer (c);
last_call_info->ci_unwind.descriptor.hpux_interrupt_marker = 1;
}
/* Is this a millicode routine. "millicode" isn't in my
to drop the information, so we'll accept it too. */
else if ((strncasecmp (name, "millicode", 9) == 0))
{
- p = input_line_pointer;
- *p = c;
+ (void) restore_line_pointer (c);
last_call_info->ci_unwind.descriptor.millicode = 1;
}
else
{
as_bad (_("Invalid .CALLINFO argument: %s"), name);
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
}
+
if (!is_end_of_statement ())
input_line_pointer++;
}
}
/* This is different than the standard GAS s_comm(). On HP9000/800 machines,
- the .comm pseudo-op has the following symtax:
+ the .comm pseudo-op has the following syntax:
<label> .comm <length>
S_SET_EXTERNAL (symbol);
/* colon() has already set the frag to the current location in the
- current subspace; we need to reset the fragment to the zero address
- fragment. We also need to reset the segment pointer. */
+ current subspace; we need to reset the fragment to the zero address
+ fragment. We also need to reset the segment pointer. */
symbol_set_frag (symbol, &zero_address_frag);
}
demand_empty_rest_of_line ();
/* ELF does not have EXIT relocations. All we do is create a
temporary symbol marking the end of the function. */
char *name;
+ symbolS *symbolP;
if (last_call_info == NULL || last_call_info->start_symbol == NULL)
{
return;
}
- name = 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));
-
- /* If we have a .exit followed by a .procend, then the
- symbol will have already been defined. */
- symbolP = symbol_find (name);
- if (symbolP)
- {
- /* The symbol has already been defined! This can
- happen if we have a .exit followed by a .procend.
-
- This is *not* an error. All we want to do is free
- the memory we just allocated for the name and continue. */
- xfree (name);
- }
- else
- {
- /* symbol value should be the offset of the
- last instruction of the function */
- symbolP = symbol_new (name, now_seg, (valueT) (frag_now_fix () - 4),
- frag_now);
+ name = concat ("L$\001end_", S_GET_NAME (last_call_info->start_symbol),
+ (char *) NULL);
- 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);
+ /* If we have a .exit followed by a .procend, then the
+ symbol will have already been defined. */
+ symbolP = symbol_find (name);
+ if (symbolP)
+ {
+ /* The symbol has already been defined! This can
+ happen if we have a .exit followed by a .procend.
+ This is *not* an error. All we want to do is free
+ the memory we just allocated for the name and continue. */
+ xfree (name);
}
else
- as_bad (_("No memory for symbol name."));
+ {
+ /* symbol value should be the offset of the
+ last instruction of the function */
+ symbolP = symbol_new (name, now_seg, (valueT) (frag_now_fix () - 4),
+ frag_now);
+
+ gas_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);
}
#endif
/* Mark the end of the function, stuff away the location of the frag
for the end of the function, and finally call pa_build_unwind_subspace
to add an entry in the unwind table. */
+ (void) where;
hppa_elf_mark_end_of_function ();
pa_build_unwind_subspace (last_call_info);
#else
static void
pa_type_args (symbolS *symbolP, int is_export)
{
- char *name, c, *p;
+ char *name, c;
unsigned int temp, arg_reloc;
pa_symbol_type type = SYMBOL_TYPE_UNKNOWN;
asymbol *bfdsym = symbol_get_bfdsym (symbolP);
{
input_line_pointer += 4;
/* IMPORTing/EXPORTing CODE types for functions is meaningless for SOM,
- instead one should be IMPORTing/EXPORTing ENTRY types.
+ instead one should be IMPORTing/EXPORTing ENTRY types.
- Complain if one tries to EXPORT a CODE type since that's never
- done. Both GCC and HP C still try to IMPORT CODE types, so
- silently fix them to be ENTRY types. */
+ Complain if one tries to EXPORT a CODE type since that's never
+ done. Both GCC and HP C still try to IMPORT CODE types, so
+ silently fix them to be ENTRY types. */
if (S_IS_FUNCTION (symbolP))
{
if (is_export)
to the SOM BFD backend. */
#ifdef obj_set_symbol_type
obj_set_symbol_type (bfdsym, (int) type);
+#else
+ (void) type;
#endif
/* Now that the type of the exported symbol has been handled,
{
if (*input_line_pointer == ',')
input_line_pointer++;
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
/* Argument sources. */
if ((strncasecmp (name, "argw", 4) == 0))
{
- p = input_line_pointer;
- *p = c;
+ (void) restore_line_pointer (c);
input_line_pointer++;
temp = atoi (name + 4);
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
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;
+#else
+ (void) arg_reloc;
#endif
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
}
/* The return value. */
else if ((strncasecmp (name, "rtnval", 6)) == 0)
{
- p = input_line_pointer;
- *p = c;
+ (void) restore_line_pointer (c);
input_line_pointer++;
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
arg_reloc = pa_build_arg_reloc (name);
#if defined (OBJ_SOM) || defined (ELF_ARG_RELOC)
symbol_arg_reloc_info (symbolP) |= arg_reloc;
+#else
+ (void) arg_reloc;
#endif
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
}
/* Privilege level. */
else if ((strncasecmp (name, "priv_lev", 8)) == 0)
{
- p = input_line_pointer;
- *p = c;
+ char *priv;
+
+ (void) restore_line_pointer (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;
+ c = get_symbol_name (&priv);
+ (void) restore_line_pointer (c);
}
else
{
as_bad (_("Undefined .EXPORT/.IMPORT argument (ignored): %s"), name);
- p = input_line_pointer;
- *p = c;
+ (void) restore_line_pointer (c);
}
+
if (!is_end_of_statement ())
input_line_pointer++;
}
static void
pa_export (int unused ATTRIBUTE_UNUSED)
{
- char *name, c, *p;
+ char *name, c;
symbolS *symbol;
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
/* Make sure the given symbol exists. */
if ((symbol = symbol_find_or_make (name)) == NULL)
{
as_bad (_("Cannot define export symbol: %s\n"), name);
- p = input_line_pointer;
- *p = c;
+ restore_line_pointer (c);
input_line_pointer++;
}
else
{
/* OK. Set the external bits and process argument relocations.
- For the HP, weak and global are not mutually exclusive.
- S_SET_EXTERNAL will not set BSF_GLOBAL if WEAK is set.
- Call S_SET_EXTERNAL to get the other processing. Manually
- set BSF_GLOBAL when we get back. */
+ For the HP, weak and global are not mutually exclusive.
+ S_SET_EXTERNAL will not set BSF_GLOBAL if WEAK is set.
+ Call S_SET_EXTERNAL to get the other processing. Manually
+ set BSF_GLOBAL when we get back. */
S_SET_EXTERNAL (symbol);
symbol_get_bfdsym (symbol)->flags |= BSF_GLOBAL;
- p = input_line_pointer;
- *p = c;
+ (void) restore_line_pointer (c);
if (!is_end_of_statement ())
{
input_line_pointer++;
static void
pa_import (int unused ATTRIBUTE_UNUSED)
{
- char *name, c, *p;
+ char *name, c;
symbolS *symbol;
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
symbol = symbol_find (name);
/* Ugh. We might be importing a symbol defined earlier in the file,
if (symbol == NULL || !S_IS_DEFINED (symbol))
{
symbol = symbol_find_or_make (name);
- p = input_line_pointer;
- *p = c;
+ (void) restore_line_pointer (c);
if (!is_end_of_statement ())
{
static void
pa_label (int unused ATTRIBUTE_UNUSED)
{
- char *name, c, *p;
+ char *name, c;
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
if (strlen (name) > 0)
{
colon (name);
- p = input_line_pointer;
- *p = c;
+ (void) restore_line_pointer (c);
}
else
{
static void
pa_param (int unused ATTRIBUTE_UNUSED)
{
- char *name, c, *p;
+ char *name, c;
symbolS *symbol;
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
if ((symbol = symbol_find_or_make (name)) == NULL)
{
as_bad (_("Cannot define static symbol: %s\n"), name);
- p = input_line_pointer;
- *p = c;
+ (void) restore_line_pointer (c);
input_line_pointer++;
}
else
{
S_CLEAR_EXTERNAL (symbol);
- p = input_line_pointer;
- *p = c;
+ (void) restore_line_pointer (c);
if (!is_end_of_statement ())
{
input_line_pointer++;
within_procedure = TRUE;
/* Create another call_info structure. */
- call_info = xmalloc (sizeof (struct call_info));
+ call_info = XNEW (struct call_info);
if (!call_info)
as_fatal (_("Cannot allocate unwind descriptor\n"));
#ifdef OBJ_ELF
/* ELF needs to mark the end of each function so that it can compute
- the size of the function (apparently its needed in the symbol table). */
+ the size of the function (apparently it's needed in the symbol table). */
hppa_elf_mark_end_of_function ();
#endif
by the parameters to the .SPACE directive. */
static sd_chain_struct *
-pa_parse_space_stmt (char *space_name, int create_flag)
+pa_parse_space_stmt (const char *space_name, int create_flag)
{
char *name, *ptemp, c;
char loadable, defined, private, sort;
print_errors = FALSE;
ptemp = input_line_pointer + 1;
/* First see if the space was specified as a number rather than
- as a name. According to the PA assembly manual the rest of
- the line should be ignored. */
+ as a name. According to the PA assembly manual the rest of
+ the line should be ignored. */
strict = 0;
pa_parse_number (&ptemp, 0);
if (pa_number >= 0)
while (!is_end_of_statement ())
{
input_line_pointer++;
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
if ((strncasecmp (name, "spnum", 5) == 0))
{
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
input_line_pointer++;
spnum = get_absolute_expression ();
}
else if ((strncasecmp (name, "sort", 4) == 0))
{
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
input_line_pointer++;
sort = get_absolute_expression ();
}
else if ((strncasecmp (name, "unloadable", 10) == 0))
{
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
loadable = FALSE;
}
else if ((strncasecmp (name, "notdefined", 10) == 0))
{
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
defined = FALSE;
}
else if ((strncasecmp (name, "private", 7) == 0))
{
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
private = TRUE;
}
else
{
as_bad (_("Invalid .SPACE argument"));
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
if (!is_end_of_statement ())
input_line_pointer++;
}
else
{
/* Check for some of the predefined spaces. FIXME: most of the code
- below is repeated several times, can we extract the common parts
- and place them into a subroutine or something similar? */
+ below is repeated several times, can we extract the common parts
+ and place them into a subroutine or something similar? */
/* FIXME Is this (and the next IF stmt) really right?
What if INPUT_LINE_POINTER points to "$TEXT$FOO"? */
if (strncmp (input_line_pointer, "$TEXT$", 6) == 0)
/* Not a number, attempt to create a new space. */
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;
+ c = get_symbol_name (&name);
+ space_name = xstrdup (name);
+ (void) restore_line_pointer (c);
sd_chain = pa_parse_space_stmt (space_name, 1);
current_space = sd_chain;
char *p;
sd_chain_struct *space;
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
space = is_defined_space (name);
if (space)
{
else
as_warn (_("Undefined space: '%s' Assuming space number = 0."), name);
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
demand_empty_rest_of_line ();
}
{
char *name, *ss_name, c;
char loadable, code_only, comdat, common, dup_common, zero, sort;
- int i, access, space_index, alignment, quadrant, applicable, flags;
+ int i, access_ctr, space_index, alignment, quadrant, applicable, flags;
sd_chain_struct *space;
ssd_chain_struct *ssd;
asection *section;
}
else
{
- name = input_line_pointer;
- c = get_symbol_end ();
- ss_name = xmalloc (strlen (name) + 1);
- strcpy (ss_name, name);
- *input_line_pointer = c;
+ c = get_symbol_name (&name);
+ ss_name = xstrdup (name);
+ (void) restore_line_pointer (c);
/* Load default values. */
sort = 0;
- access = 0x7f;
+ access_ctr = 0x7f;
loadable = 1;
comdat = 0;
common = 0;
else
ssd = is_defined_subspace (ss_name);
/* Allow user to override the builtin attributes of subspaces. But
- only allow the attributes to be changed once! */
+ only allow the attributes to be changed once! */
if (ssd && SUBSPACE_DEFINED (ssd))
{
subseg_set (ssd->ssd_seg, ssd->ssd_subseg);
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;
+ access_ctr = pa_def_subspaces[i].access;
sort = pa_def_subspaces[i].sort;
break;
}
}
/* We should be working with a new subspace now. Fill in
- any information as specified by the user. */
+ any information as specified by the user. */
if (!is_end_of_statement ())
{
input_line_pointer++;
while (!is_end_of_statement ())
{
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
if ((strncasecmp (name, "quad", 4) == 0))
{
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
input_line_pointer++;
quadrant = get_absolute_expression ();
}
else if ((strncasecmp (name, "align", 5) == 0))
{
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
input_line_pointer++;
alignment = get_absolute_expression ();
if (exact_log2 (alignment) == -1)
}
else if ((strncasecmp (name, "access", 6) == 0))
{
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
input_line_pointer++;
- access = get_absolute_expression ();
+ access_ctr = get_absolute_expression ();
}
else if ((strncasecmp (name, "sort", 4) == 0))
{
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
input_line_pointer++;
sort = get_absolute_expression ();
}
else if ((strncasecmp (name, "code_only", 9) == 0))
{
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
code_only = 1;
}
else if ((strncasecmp (name, "unloadable", 10) == 0))
{
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
loadable = 0;
}
else if ((strncasecmp (name, "comdat", 6) == 0))
{
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
comdat = 1;
}
else if ((strncasecmp (name, "common", 6) == 0))
{
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
common = 1;
}
else if ((strncasecmp (name, "dup_comm", 8) == 0))
{
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
dup_common = 1;
}
else if ((strncasecmp (name, "zero", 4) == 0))
{
- *input_line_pointer = c;
+ (void) restore_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++;
}
}
/* Compute a reasonable set of BFD flags based on the information
- in the .subspace directive. */
+ in the .subspace directive. */
applicable = bfd_applicable_section_flags (stdoutput);
flags = 0;
if (loadable)
applicable &= flags;
/* If this is an existing subspace, then we want to use the
- segment already associated with the subspace.
+ segment already associated with the subspace.
- FIXME NOW! ELF BFD doesn't appear to be ready to deal with
- lots of sections. It might be a problem in the PA ELF
- code, I do not know yet. For now avoid creating anything
- but the "standard" sections for ELF. */
+ FIXME NOW! ELF BFD doesn't appear to be ready to deal with
+ lots of sections. It might be a problem in the PA ELF
+ code, I do not know yet. For now avoid creating anything
+ but the "standard" sections for ELF. */
if (create_new)
section = subseg_force_new (ss_name, 0);
else if (ssd)
seg_info (section)->bss = 1;
/* Now set the flags. */
- bfd_set_section_flags (stdoutput, section, applicable);
+ bfd_set_section_flags (section, applicable);
/* Record any alignment request for this section. */
record_alignment (section, exact_log2 (alignment));
/* Set the starting offset for this section. */
- bfd_set_section_vma (stdoutput, section,
- pa_subspace_start (space, quadrant));
+ bfd_set_section_vma (section, pa_subspace_start (space, quadrant));
/* Now that all the flags are set, update an existing subspace,
- or create a new one. */
+ or create a new one. */
if (ssd)
current_subspace = update_subspace (space, ss_name, loadable,
code_only, comdat, common,
- dup_common, sort, zero, access,
+ dup_common, sort, zero, access_ctr,
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,
+ access_ctr, space_index,
alignment, quadrant, section);
demand_empty_rest_of_line ();
i = 0;
while (pa_def_spaces[i].name)
{
- char *name;
+ const char *name;
/* Pick the right name to use for the new section. */
name = pa_def_spaces[i].name;
i = 0;
while (pa_def_subspaces[i].name)
{
- char *name;
+ const char *name;
int applicable, subsegment;
asection *segment = NULL;
sd_chain_struct *space;
/* Pick the right name for the new section and pick the right
- subsegment number. */
+ subsegment number. */
name = pa_def_subspaces[i].name;
subsegment = 0;
segment = subseg_new (name, subsegment);
/* For SOM we want to replace the standard .text, .data, and .bss
- sections with our own. We also want to set BFD flags for
+ sections with our own. We also want to set BFD flags for
all the built-in subspaces. */
if (!strcmp (pa_def_subspaces[i].name, "$CODE$"))
{
text_section = segment;
applicable = bfd_applicable_section_flags (stdoutput);
- bfd_set_section_flags (stdoutput, segment,
+ bfd_set_section_flags (segment,
applicable & (SEC_ALLOC | SEC_LOAD
| SEC_RELOC | SEC_CODE
| SEC_READONLY
{
data_section = segment;
applicable = bfd_applicable_section_flags (stdoutput);
- bfd_set_section_flags (stdoutput, segment,
+ bfd_set_section_flags (segment,
applicable & (SEC_ALLOC | SEC_LOAD
| SEC_RELOC
| SEC_HAS_CONTENTS));
{
bss_section = segment;
applicable = bfd_applicable_section_flags (stdoutput);
- bfd_set_section_flags (stdoutput, segment,
+ bfd_set_section_flags (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,
+ bfd_set_section_flags (segment,
applicable & (SEC_ALLOC | SEC_LOAD
| SEC_RELOC
| SEC_READONLY
else if (!strcmp (pa_def_subspaces[i].name, "$MILLICODE$"))
{
applicable = bfd_applicable_section_flags (stdoutput);
- bfd_set_section_flags (stdoutput, segment,
+ bfd_set_section_flags (segment,
applicable & (SEC_ALLOC | SEC_LOAD
| SEC_RELOC
| SEC_READONLY
else if (!strcmp (pa_def_subspaces[i].name, "$UNWIND$"))
{
applicable = bfd_applicable_section_flags (stdoutput);
- bfd_set_section_flags (stdoutput, segment,
+ bfd_set_section_flags (segment,
applicable & (SEC_ALLOC | SEC_LOAD
| SEC_RELOC
| SEC_READONLY
by the given parameters. */
static sd_chain_struct *
-create_new_space (char *name,
+create_new_space (const char *name,
int spnum,
int loadable ATTRIBUTE_UNUSED,
int defined,
{
sd_chain_struct *chain_entry;
- chain_entry = 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) = xmalloc (strlen (name) + 1);
- strcpy (SPACE_NAME (chain_entry), name);
+ chain_entry = XNEW (sd_chain_struct);
+ SPACE_NAME (chain_entry) = xstrdup (name);
SPACE_DEFINED (chain_entry) = defined;
SPACE_USER_DEFINED (chain_entry) = user_defined;
SPACE_SPNUM (chain_entry) = spnum;
}
/* At this point we've found the correct place to add the new
- entry. So add it and update the linked lists as appropriate. */
+ entry. So add it and update the linked lists as appropriate. */
if (prev_chain_pointer)
{
chain_entry->sd_next = chain_pointer;
static ssd_chain_struct *
create_new_subspace (sd_chain_struct *space,
- char *name,
+ const char *name,
int loadable ATTRIBUTE_UNUSED,
int code_only ATTRIBUTE_UNUSED,
int comdat,
int dup_common,
int is_zero ATTRIBUTE_UNUSED,
int sort,
- int access,
+ int access_ctr,
int space_index ATTRIBUTE_UNUSED,
int alignment ATTRIBUTE_UNUSED,
int quadrant,
{
ssd_chain_struct *chain_entry;
- chain_entry = 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) = xmalloc (strlen (name) + 1);
- strcpy (SUBSPACE_NAME (chain_entry), name);
+ chain_entry = XNEW (ssd_chain_struct);
+ SUBSPACE_NAME (chain_entry) = xstrdup (name);
/* Initialize subspace_defined. When we hit a .subspace directive
we'll set it to 1 which "locks-in" the subspace attributes. */
}
/* Now we have somewhere to put the new entry. Insert it and update
- the links. */
+ the links. */
if (prev_chain_pointer)
{
chain_entry->ssd_next = chain_pointer;
}
#ifdef obj_set_subsection_attributes
- obj_set_subsection_attributes (seg, space->sd_seg, access, sort,
+ obj_set_subsection_attributes (seg, space->sd_seg, access_ctr, sort,
quadrant, comdat, common, dup_common);
#endif
int dup_common,
int sort,
int zero ATTRIBUTE_UNUSED,
- int access,
+ int access_ctr,
int space_index ATTRIBUTE_UNUSED,
int alignment ATTRIBUTE_UNUSED,
int quadrant,
chain_entry = is_defined_subspace (name);
#ifdef obj_set_subsection_attributes
- obj_set_subsection_attributes (section, space->sd_seg, access, sort,
+ obj_set_subsection_attributes (section, space->sd_seg, access_ctr, sort,
quadrant, comdat, common, dup_common);
#endif
NULL if no such space exists. */
static sd_chain_struct *
-is_defined_space (char *name)
+is_defined_space (const char *name)
{
sd_chain_struct *chain_pointer;
own subspace. */
static ssd_chain_struct *
-is_defined_subspace (char *name)
+is_defined_subspace (const char *name)
{
sd_chain_struct *space_chain;
ssd_chain_struct *subspace_chain;
}
}
}
- stringer (append_zero);
+ stringer (8 + append_zero);
pa_undefine_label ();
}
dummy_symbol = symbol_find_or_make ("L$dummy");
S_SET_SEGMENT (dummy_symbol, text_section);
/* Force the symbol to be converted to a real symbol. */
- (void) symbol_get_bfdsym (dummy_symbol);
+ symbol_get_bfdsym (dummy_symbol)->flags |= BSF_KEEP;
#endif
}
return 1;
#endif
- assert (fixp->fx_addsy != NULL);
+ gas_assert (fixp->fx_addsy != NULL);
/* Ensure we emit a relocation for global symbols so that dynamic
linking works. */
{
struct fix *new_fix;
- new_fix = obj_elf_vtable_entry (0);
+ new_fix = obj_elf_get_vtable_entry ();
if (new_fix)
{
- struct hppa_fix_struct * hppa_fix = obstack_alloc (¬es, sizeof (struct hppa_fix_struct));
+ struct hppa_fix_struct * hppa_fix = XOBNEW (¬es, struct hppa_fix_struct);
hppa_fix->fx_r_type = R_HPPA;
hppa_fix->fx_r_field = e_fsel;
{
struct fix *new_fix;
- new_fix = obj_elf_vtable_inherit (0);
+ new_fix = obj_elf_get_vtable_inherit ();
if (new_fix)
{
- struct hppa_fix_struct * hppa_fix = obstack_alloc (¬es, sizeof (struct hppa_fix_struct));
+ struct hppa_fix_struct * hppa_fix = XOBNEW (¬es, struct hppa_fix_struct);
hppa_fix->fx_r_type = R_HPPA;
hppa_fix->fx_r_field = e_fsel;
{"word", pa_cons, 4},
{NULL, 0, 0}
};
+
+#ifdef OBJ_ELF
+void
+hppa_cfi_frame_initial_instructions (void)
+{
+ cfi_add_CFA_def_cfa (30, 0);
+}
+
+int
+hppa_regname_to_dw2regnum (char *regname)
+{
+ unsigned int regnum = -1;
+ unsigned int i;
+ const char *p;
+ char *q;
+ static struct { const char *name; int dw2regnum; } regnames[] =
+ {
+ { "sp", 30 }, { "rp", 2 },
+ };
+
+ for (i = 0; i < ARRAY_SIZE (regnames); ++i)
+ if (strcmp (regnames[i].name, regname) == 0)
+ return regnames[i].dw2regnum;
+
+ if (regname[0] == 'r')
+ {
+ p = regname + 1;
+ regnum = strtoul (p, &q, 10);
+ if (p == q || *q || regnum >= 32)
+ return -1;
+ }
+ else if (regname[0] == 'f' && regname[1] == 'r')
+ {
+ p = regname + 2;
+ regnum = strtoul (p, &q, 10);
+#if TARGET_ARCH_SIZE == 64
+ if (p == q || *q || regnum <= 4 || regnum >= 32)
+ return -1;
+ regnum += 32 - 4;
+#else
+ if (p == q
+ || (*q && ((*q != 'L' && *q != 'R') || *(q + 1)))
+ || regnum <= 4 || regnum >= 32)
+ return -1;
+ regnum = (regnum - 4) * 2 + 32;
+ if (*q == 'R')
+ regnum++;
+#endif
+ }
+ return regnum;
+}
+#endif