/* tc-hppa.c -- Assemble for the PA
Copyright 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- 2002 Free Software Foundation, Inc.
+ 2002, 2003 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
#ifdef OBJ_ELF
#include "dwarf2dbg.h"
-/* A "convient" place to put object file dependencies which do
+/* A "convenient" place to put object file dependencies which do
not need to be seen outside of tc-hppa.c. */
/* Object file formats specify relocation types. */
static void pa_check_current_space_and_subspace PARAMS ((void));
#endif
-#if !(defined (OBJ_ELF) && defined (TE_LINUX))
+#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
static void pa_text PARAMS ((int));
static void pa_data PARAMS ((int));
static void pa_comm PARAMS ((int));
static void pa_vtable_inherit PARAMS ((int));
#endif
-/* File and gloally scoped variable declarations. */
+/* File and globally scoped variable declarations. */
#ifdef OBJ_SOM
/* Root and final entry in the space chain. */
/* handle of the OPCODE hash table */
static struct hash_control *op_hash = NULL;
+/* These characters can be suffixes of opcode names and they may be
+ followed by meaningful whitespace. We don't include `,' and `!'
+ as they never appear followed by meaningful whitespace. */
+const char hppa_symbol_chars[] = "*?=<>";
+
/* Table of pseudo ops for the PA. FIXME -- how many of these
are now redundant with the overall GAS and the object file
dependent tables? */
{"byte", pa_cons, 1},
{"call", pa_call, 0},
{"callinfo", pa_callinfo, 0},
-#if defined (OBJ_ELF) && defined (TE_LINUX)
+#if defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD))
{"code", obj_elf_text, 0},
#else
{"code", pa_text, 0},
{"compiler", pa_compiler, 0},
#endif
{"copyright", pa_copyright, 0},
-#if !(defined (OBJ_ELF) && defined (TE_LINUX))
+#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
{"data", pa_data, 0},
#endif
{"double", pa_float_cons, 'd'},
{"dword", pa_cons, 8},
{"end", pa_end, 0},
{"end_brtab", pa_brtab, 0},
-#if !(defined (OBJ_ELF) && defined (TE_LINUX))
+#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
{"end_try", pa_try, 0},
#endif
{"enter", pa_enter, 0},
{"equ", pa_equ, 0},
{"exit", pa_exit, 0},
{"export", pa_export, 0},
-#ifdef OBJ_ELF
- {"file", dwarf2_directive_file, 0 },
-#endif
{"fill", pa_fill, 0},
{"float", pa_float_cons, 'f'},
{"half", pa_cons, 2},
{"lcomm", pa_lcomm, 0},
{"leave", pa_leave, 0},
{"level", pa_level, 0},
-#ifdef OBJ_ELF
- {"loc", dwarf2_directive_loc, 0 },
-#endif
{"long", pa_cons, 4},
{"lsym", pa_lsym, 0},
#ifdef OBJ_SOM
#ifdef OBJ_SOM
{"subspa", pa_subspace, 0},
#endif
-#if !(defined (OBJ_ELF) && defined (TE_LINUX))
+#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
{"text", pa_text, 0},
#endif
{"version", pa_version, 0},
static struct pa_it the_insn;
-/* Points to the end of an expression just parsed by get_expressoin
+/* Points to the end of an expression just parsed by get_expression
and friends. FIXME. This shouldn't be handled with a file-global
variable. */
static char *expr_end;
{"%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},
{"%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},
{"%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},
continue; \
}
-/* Simple range checking for FIELD againt HIGH and LOW bounds.
+/* Simple range checking for FIELD against HIGH and LOW bounds.
IGNORE is used to suppress the error message. */
#define CHECK_FIELD(FIELD, HIGH, LOW, IGNORE) \
} \
}
-/* Simple alignment checking for FIELD againt ALIGN (a power of two).
+/* Simple alignment checking for FIELD against ALIGN (a power of two).
IGNORE is used to suppress the error message. */
#define CHECK_ALIGN(FIELD, ALIGN, IGNORE) \
{
if (1
#ifdef OBJ_SOM
- && current_space == label_chain->lss_space && label_chain->lss_label
+ && current_space == label_chain->lss_space && label_chain->lss_label
#endif
#ifdef OBJ_ELF
- && now_seg == label_chain->lss_segment && label_chain->lss_label
+ && now_seg == label_chain->lss_segment && label_chain->lss_label
#endif
)
{
/* Assemble the instruction. Results are saved into "the_insn". */
pa_ip (str);
- /* Get somewhere to put the assembled instrution. */
+ /* Get somewhere to put the assembled instruction. */
to = frag_more (4);
/* Output the opcode. */
/* If this instruction is specific to a particular architecture,
then set a new architecture. */
/* But do not automatically promote to pa2.0. The automatic promotion
- crud is for compatability with HP's old assemblers only. */
+ crud is for compatibility with HP's old assemblers only. */
if (insn->arch < 20
&& bfd_get_mach (stdoutput) < insn->arch)
{
args++;
switch (*args)
{
- /* Handle FP compare conditions. */
- case 'f':
- cond = pa_parse_fp_cmp_cond (&s);
- INSERT_FIELD_AND_CONTINUE (opcode, cond, 0);
+ /* Handle FP compare conditions. */
+ case 'f':
+ cond = pa_parse_fp_cmp_cond (&s);
+ INSERT_FIELD_AND_CONTINUE (opcode, cond, 0);
/* Handle an add condition. */
case 'A':
case 'a':
- cmpltr = 0;
- flag = 0;
+ cmpltr = 0;
+ flag = 0;
if (*s == ',')
{
s++;
}
else if (*s == '*')
break;
- name = s;
name = s;
while (*s != ',' && *s != ' ' && *s != '\t')
flag = 1;
}
/* ",*" is a valid condition. */
- else if (*args == 'a')
+ else if (*args == 'a' || *name)
as_bad (_("Invalid Add Condition: %s"), name);
*s = c;
}
}
else if (*s == '*')
break;
- name = s;
name = s;
while (*s != ',' && *s != ' ' && *s != '\t')
flag = 1;
}
/* ",*" is a valid condition. */
- else if (*args != 'S')
+ else if (*args != 'S' || *name)
as_bad (_("Invalid Compare/Subtract Condition: %s"),
name);
*s = c;
flag = 1;
}
/* ",*" is a valid condition. */
- else if (*args != 'L')
+ else if (*args != 'L' || *name)
as_bad (_("Invalid Logical Instruction Condition."));
*s = c;
}
continue;
}
/* ",*" is a valid condition. */
- else if (*args != 'X')
+ else if (*args != 'X' || *name)
as_bad (_("Invalid Shift/Extract/Deposit Condition."));
*s = c;
}
s += 3;
}
/* ",*" is a valid condition. */
- else if (*args != 'U')
+ else if (*args != 'U' || (*s != ' ' && *s != '\t'))
as_bad (_("Invalid Unit Instruction Condition."));
}
opcode |= cmpltr << 13;
the_insn.pcrel = 1;
if (!the_insn.exp.X_add_symbol
|| !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
- "L$0\001"))
+ FAKE_LABEL_NAME))
{
num = evaluate_absolute (&the_insn);
if (num % 4)
the_insn.pcrel = 1;
if (!the_insn.exp.X_add_symbol
|| !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
- "L$0\001"))
+ FAKE_LABEL_NAME))
{
num = evaluate_absolute (&the_insn);
if (num % 4)
the_insn.pcrel = 1;
if (!the_insn.exp.X_add_symbol
|| !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
- "L$0\001"))
+ FAKE_LABEL_NAME))
{
num = evaluate_absolute (&the_insn);
if (num % 4)
the_insn.pcrel = 0;
if (!the_insn.exp.X_add_symbol
|| !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol),
- "L$0\001"))
+ FAKE_LABEL_NAME))
{
num = evaluate_absolute (&the_insn);
if (num % 4)
failed:
/* Check if the args matched. */
- if (match == FALSE)
+ if (!match)
{
if (&insn[1] - pa_opcodes < (int) NUMOPCODES
&& !strcmp (insn->name, insn[1].name))
case R_N0SEL:
case R_N1SEL:
/* There is no symbol or addend associated with these fixups. */
- relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
- *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
+ relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
relocs[i]->addend = 0;
break;
case R_ENTRY:
case R_EXIT:
/* There is no symbol associated with these fixups. */
- relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
- *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
+ relocs[i]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ *relocs[i]->sym_ptr_ptr = symbol_get_bfdsym (dummy_symbol);
relocs[i]->addend = fixp->fx_offset;
break;
offsetT new_val;
int insn, val, fmt;
- if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
- fixP->fx_done = 1;
-
/* SOM uses R_HPPA_ENTRY and R_HPPA_EXIT relocations which can
never be "applied" (they are just markers). Likewise for
R_HPPA_BEGIN_BRTAB and R_HPPA_END_BRTAB. */
return;
#endif
+ if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
+ fixP->fx_done = 1;
+
/* There should have been an HPPA specific fixup associated
with the GAS fixup. */
hppa_fixP = (struct hppa_fix_struct *) fixP->tc_fix_data;
|| hppa_fixP->fx_r_field == e_rtsel
|| hppa_fixP->fx_r_field == e_ltsel)
new_val = ((fmt == 12 || fmt == 17 || fmt == 22) ? 8 : 0);
- /* This is truly disgusting. The machine independent code blindly
- adds in the value of the symbol being relocated against. Damn! */
- else if (fmt == 32
- && fixP->fx_addsy != NULL
- && S_GET_SEGMENT (fixP->fx_addsy) != bfd_com_section_ptr)
- new_val = hppa_field_adjust (* valP - S_GET_VALUE (fixP->fx_addsy),
- 0, hppa_fixP->fx_r_field);
#endif
else
new_val = hppa_field_adjust (* valP, 0, hppa_fixP->fx_r_field);
symbolS *sym;
int status;
char *p = *s;
- boolean have_prefix;
+ bfd_boolean have_prefix;
/* Skip whitespace before the number. */
while (*p == ' ' || *p == '\t')
num = S_GET_VALUE (sym);
/* Well, we don't really have one, but we do have a
register, so... */
- have_prefix = true;
+ have_prefix = TRUE;
}
else if (S_GET_SEGMENT (sym) == &bfd_abs_section)
num = S_GET_VALUE (sym);
/* There is where we'd come for an undefined symbol
or for an empty string. For an empty string we
will return zero. That's a concession made for
- compatability with the braindamaged HP assemblers. */
+ compatibility with the braindamaged HP assemblers. */
if (*name == 0)
num = 0;
else
expression (&insn->exp);
/* This is not perfect, but is a huge improvement over doing nothing.
- The PA assembly syntax is ambigious in a variety of ways. Consider
+ The PA assembly syntax is ambiguous in a variety of ways. Consider
this string "4 %r5" Is that the number 4 followed by the register
r5, or is that 4 MOD r5?
- If we get a modulo expresion When looking for an absolute, we try
+ If we get a modulo expression when looking for an absolute, we try
again cutting off the input string at the first whitespace character. */
if (insn->exp.X_op == O_modulus)
{
input_line_pointer = *strp;
s = *strp;
while (*s != ',' && *s != ' ' && *s != '\t')
- s++;
+ s++;
c = *s;
*s = 0;
}
/* Parse a non-negated compare/subtract completer returning the
- number (for encoding in instrutions) of the given completer. */
+ number (for encoding in instructions) of the given completer. */
static int
pa_parse_nonneg_cmpsub_cmpltr (s)
}
/* Parse a negated compare/subtract completer returning the
- number (for encoding in instrutions) of the given completer. */
+ number (for encoding in instructions) of the given completer. */
static int
pa_parse_neg_cmpsub_cmpltr (s)
}
/* Parse a 64 bit compare and branch completer returning the number (for
- encoding in instrutions) of the given completer.
+ encoding in instructions) of the given completer.
Nonnegated comparisons are returned as 0-7, negated comparisons are
returned as 8-15. */
}
/* Parse a 64 bit compare immediate and branch completer returning the number
- (for encoding in instrutions) of the given completer. */
+ (for encoding in instructions) of the given completer. */
static int
pa_parse_cmpib_64_cmpltr (s)
}
/* Parse a non-negated addition completer returning the number
- (for encoding in instrutions) of the given completer. */
+ (for encoding in instructions) of the given completer. */
static int
pa_parse_nonneg_add_cmpltr (s)
}
/* Parse a negated addition completer returning the number
- (for encoding in instrutions) of the given completer. */
+ (for encoding in instructions) of the given completer. */
static int
pa_parse_neg_add_cmpltr (s)
}
/* Parse a 64 bit wide mode add and branch completer returning the number (for
- encoding in instrutions) of the given completer. */
+ encoding in instructions) of the given completer. */
static int
pa_parse_addb_64_cmpltr (s)
{
#ifdef OBJ_SOM
- /* The BRTAB relocations are only availble in SOM (to denote
+ /* The BRTAB relocations are only available in SOM (to denote
the beginning and end of branch tables). */
char *where = frag_more (0);
if (! begin)
expression (&exp);
- /* The TRY relocations are only availble in SOM (to denote
+ /* The TRY relocations are only available in SOM (to denote
the beginning and end of exception handling regions). */
fix_new_hppa (frag_now, where - frag_now->fr_literal, 0,
demand_empty_rest_of_line ();
}
-#if !(defined (OBJ_ELF) && defined (TE_LINUX))
+#if !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD)))
/* Switch to the text space. Like s_text, but delete our
label when finished. */
static void
}
demand_empty_rest_of_line ();
}
-#endif /* !(defined (OBJ_ELF) && defined (TE_LINUX)) */
+#endif /* !(defined (OBJ_ELF) && (defined (TE_LINUX) || defined (TE_NetBSD))) */
/* Process a .END pseudo-op. */
}
/* Process a .ENTRY pseudo-op. .ENTRY marks the beginning of the
- procesure. */
+ procedure. */
static void
pa_entry (unused)
int unused ATTRIBUTE_UNUSED;
#endif
*input_line_pointer = c;
}
- /* Privelege level. */
+ /* Privilege level. */
else if ((strncasecmp (name, "priv_lev", 8)) == 0)
{
p = input_line_pointer;
}
else
{
- /* Sigh. To be compatable with the HP assembler and to help
+ /* Sigh. To be compatible with the HP assembler and to help
poorly written assembly code, we assign a type based on
the current segment. Note only BSF_FUNCTION really
matters, we do not need to set the full SYMBOL_TYPE_* info. */
demand_empty_rest_of_line ();
}
-/* Process the syntatical end of a procedure. Make sure all the
+/* Process the syntactical end of a procedure. Make sure all the
appropriate pseudo-ops were found within the procedure. */
static void
/* If create_flag is nonzero, then create the new space with
the attributes computed above. Else set the values in
an already existing space -- this can only happen for
- the first occurence of a built-in space. */
+ the first occurrence of a built-in space. */
if (create_flag)
space = create_new_space (space_name, spnum, loadable, defined,
private, sort, seg, 1);
}
#endif
- if (fixp->fx_addsy && (S_IS_EXTERNAL (fixp->fx_addsy)
- || S_IS_WEAK (fixp->fx_addsy)))
- return 0;
-
/* Reject reductions of symbols in sym1-sym2 expressions when
the fixup will occur in a CODE subspace.
if (fixp->fx_addsy
&& fixp->fx_subsy
&& (hppa_fix->segment->flags & SEC_CODE))
- {
- /* Apparently sy_used_in_reloc never gets set for sub symbols. */
- symbol_mark_used_in_reloc (fixp->fx_subsy);
- return 0;
- }
+ return 0;
/* We can't adjust any relocs that use LR% and RR% field selectors.
. RR%sect+4092 == (R%sect)+4092
. RR%sect+4096 == (R%sect)-4096
and the last address loses because rounding the addend to 8k
- mutiples takes us up to 8192 with an offset of -4096.
+ multiples takes us up to 8192 with an offset of -4096.
In cases where the LR% expression is identical to the RR% one we
will never have a problem, but is so happens that gcc rounds
/* Ensure we emit a relocation for global symbols so that dynamic
linking works. */
- if (S_IS_EXTERNAL (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy))
+ if (S_FORCE_RELOC (fixp->fx_addsy, 1))
return 1;
/* It is necessary to force PC-relative calls/jumps to have a relocation
/* Now check to see if we're going to need a long-branch stub. */
if (fixp->fx_r_type == (int) R_HPPA_PCREL_CALL)
{
- valueT distance;
+ long pc = md_pcrel_from (fixp);
+ valueT distance, min_stub_distance;
- distance = (fixp->fx_offset + S_GET_VALUE (fixp->fx_addsy)
- - md_pcrel_from (fixp) - 8);
- if (distance + 8388608 >= 16777216
- || (hppa_fixp->fx_r_format == 17 && distance + 262144 >= 524288)
-#ifdef OBJ_ELF
- || (hppa_fixp->fx_r_format == 12 && distance + 8192 >= 16384)
+ distance = fixp->fx_offset + S_GET_VALUE (fixp->fx_addsy) - pc - 8;
+
+ /* Distance to the closest possible stub. This will detect most
+ but not all circumstances where a stub will not work. */
+ min_stub_distance = pc + 16;
+#ifdef OBJ_SOM
+ if (last_call_info != NULL)
+ min_stub_distance -= S_GET_VALUE (last_call_info->start_symbol);
#endif
+
+ if ((distance + 8388608 >= 16777216
+ && min_stub_distance <= 8388608)
+ || (hppa_fixp->fx_r_format == 17
+ && distance + 262144 >= 524288
+ && min_stub_distance <= 262144)
+ || (hppa_fixp->fx_r_format == 12
+ && distance + 8192 >= 16384
+ && min_stub_distance <= 8192)
)
return 1;
}
/* Now for some ELF specific code. FIXME. */
#ifdef OBJ_ELF
/* Mark the end of a function so that it's possible to compute
- the size of the function in hppa_elf_final_processing. */
+ the size of the function in elf_hppa_final_processing. */
static void
hppa_elf_mark_end_of_function ()