/* tc-ia64.c -- Assembler for the HP/Intel IA-64 architecture.
- Copyright 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of GAS, the GNU Assembler.
FUNC_FPTR_RELATIVE,
FUNC_GP_RELATIVE,
FUNC_LT_RELATIVE,
+ FUNC_LT_RELATIVE_X,
FUNC_PC_RELATIVE,
FUNC_PLT_RELATIVE,
FUNC_SEC_RELATIVE,
extern int target_big_endian;
+void (*ia64_number_to_chars) PARAMS ((char *, valueT, int));
+
+static void ia64_float_to_chars_bigendian
+ PARAMS ((char *, LITTLENUM_TYPE *, int));
+static void ia64_float_to_chars_littleendian
+ PARAMS ((char *, LITTLENUM_TYPE *, int));
+static void (*ia64_float_to_chars)
+ PARAMS ((char *, LITTLENUM_TYPE *, int));
+
/* Characters which always start a comment. */
const char comment_chars[] = "";
{ "fptr", PSEUDO_FUNC_RELOC, { 0 } },
{ "gprel", PSEUDO_FUNC_RELOC, { 0 } },
{ "ltoff", PSEUDO_FUNC_RELOC, { 0 } },
+ { "ltoffx", PSEUDO_FUNC_RELOC, { 0 } },
{ "pcrel", PSEUDO_FUNC_RELOC, { 0 } },
{ "pltoff", PSEUDO_FUNC_RELOC, { 0 } },
{ "secrel", PSEUDO_FUNC_RELOC, { 0 } },
{ "natval", PSEUDO_FUNC_CONST, { 0x100 } }, /* old usage */
+ /* hint constants: */
+ { "pause", PSEUDO_FUNC_CONST, { 0x0 } },
+
/* unwind-related constants: */
{ "svr4", PSEUDO_FUNC_CONST, { 0 } },
{ "hpux", PSEUDO_FUNC_CONST, { 1 } },
{
if (letter == 's')
return SHF_IA_64_SHORT;
+ else if (letter == 'o')
+ return SHF_LINK_ORDER;
- *ptr_msg = _("Bad .section directive: want a,s,w,x,M,S,G,T in string");
- return 0;
+ *ptr_msg = _("Bad .section directive: want a,o,s,w,x,M,S,G,T in string");
+ return -1;
}
/* Map SHF_IA_64_SHORT to SEC_SMALL_DATA. */
if (STREQ (ELF_STRING_ia64_unwind_once))
return SHT_IA_64_UNWIND;
+ if (STREQ ("unwind"))
+ return SHT_IA_64_UNWIND;
+
if (STREQ ("init_array"))
return SHT_INIT_ARRAY;
add_unwind_entry (output_psp_sprel (e.X_add_number));
}
else
- as_bad ("First operand to .vframesp must be a general register");
+ as_bad ("Operand to .vframesp must be a constant (sp-relative offset)");
}
static void
add_unwind_entry (output_psp_sprel (e.X_add_number));
}
else
- as_bad ("First operand to .vframepsp must be a general register");
+ as_bad ("Operand to .vframepsp must be a constant (psp-relative offset)");
}
static void
const char *text_name;
{
int size;
- unsigned char *unw_rec;
+ void *unw_rec;
/* Force out pending instructions, to make sure all unwind records have
a valid slot_number field. */
ia64_flush_insns ();
/* Generate the unwind record. */
- size = output_unw_records (unwind.list, (void **) &unw_rec);
+ size = output_unw_records (unwind.list, &unw_rec);
if (size % md.pointer_size != 0)
as_bad ("Unwind record is not a multiple of %d bytes.", md.pointer_size);
dot_byteorder (byteorder)
int byteorder;
{
- target_big_endian = byteorder;
+ segment_info_type *seginfo = seg_info (now_seg);
+
+ if (byteorder == -1)
+ {
+ if (seginfo->tc_segment_info_data.endian == 0)
+ seginfo->tc_segment_info_data.endian
+ = TARGET_BYTES_BIG_ENDIAN ? 1 : 2;
+ byteorder = seginfo->tc_segment_info_data.endian == 1;
+ }
+ else
+ seginfo->tc_segment_info_data.endian = byteorder ? 1 : 2;
+
+ if (target_big_endian != byteorder)
+ {
+ target_big_endian = byteorder;
+ if (target_big_endian)
+ {
+ ia64_number_to_chars = number_to_chars_bigendian;
+ ia64_float_to_chars = ia64_float_to_chars_bigendian;
+ }
+ else
+ {
+ ia64_number_to_chars = number_to_chars_littleendian;
+ ia64_float_to_chars = ia64_float_to_chars_littleendian;
+ }
+ }
}
static void
stmt_float_cons (kind)
int kind;
{
- size_t size;
+ size_t alignment;
switch (kind)
{
- case 'd': size = 8; break;
- case 'x': size = 10; break;
+ case 'd':
+ alignment = 8;
+ break;
+
+ case 'x':
+ case 'X':
+ alignment = 16;
+ break;
case 'f':
default:
- size = 4;
+ alignment = 4;
break;
}
- ia64_do_align (size);
+ ia64_do_align (alignment);
float_cons (kind);
}
{ "xreal4", dot_xfloat_cons, 'f' },
{ "xreal8", dot_xfloat_cons, 'd' },
{ "xreal10", dot_xfloat_cons, 'x' },
+ { "xreal16", dot_xfloat_cons, 'X' },
{ "xstring", dot_xstringer, 0 },
{ "xstringz", dot_xstringer, 1 },
{ "xreal4.ua", dot_xfloat_cons_ua, 'f' },
{ "xreal8.ua", dot_xfloat_cons_ua, 'd' },
{ "xreal10.ua", dot_xfloat_cons_ua, 'x' },
+ { "xreal16.ua", dot_xfloat_cons_ua, 'X' },
/* annotations/DV checking support */
{ "entry", dot_entry, 0 },
{ "real4", stmt_float_cons, 'f' },
{ "real8", stmt_float_cons, 'd' },
{ "real10", stmt_float_cons, 'x' },
+ { "real16", stmt_float_cons, 'X' },
{ "string", stringer, 0 },
{ "stringz", stringer, 1 },
{ "real4.ua", float_cons, 'f' },
{ "real8.ua", float_cons, 'd' },
{ "real10.ua", float_cons, 'x' },
+ { "real16.ua", float_cons, 'X' },
};
/* Declare a register by creating a symbol for it and entering it in
return OPERAND_MATCH;
break;
+ case IA64_OPND_AR_CSD:
+ if (e->X_op == O_register && e->X_add_number == REG_AR + 25)
+ return OPERAND_MATCH;
+ break;
+
case IA64_OPND_AR_PFS:
if (e->X_op == O_register && e->X_add_number == REG_AR + 64)
return OPERAND_MATCH;
}
break;
+ case IA64_OPND_LDXMOV:
+ fix = CURR_SLOT.fixup + CURR_SLOT.num_fixups;
+ fix->code = BFD_RELOC_IA64_LDXMOV;
+ fix->opnd = idesc->operands[index];
+ fix->expr = *e;
+ fix->is_pcrel = 0;
+ ++CURR_SLOT.num_fixups;
+ return OPERAND_MATCH;
+
default:
break;
}
}
required_unit = ia64_templ_desc[template].exec_unit[i];
- /* resolve dynamic opcodes such as "break" and "nop": */
+ /* resolve dynamic opcodes such as "break", "hint", and "nop": */
if (idesc->type == IA64_TYPE_DYN)
{
if ((strcmp (idesc->name, "nop") == 0)
+ || (strcmp (idesc->name, "hint") == 0)
|| (strcmp (idesc->name, "break") == 0))
insn_unit = required_unit;
else if (strcmp (idesc->name, "chk.s") == 0)
bfd_set_section_alignment (stdoutput, text_section, 4);
- target_big_endian = TARGET_BYTES_BIG_ENDIAN;
+ /* Make sure fucntion pointers get initialized. */
+ target_big_endian = -1;
+ dot_byteorder (TARGET_BYTES_BIG_ENDIAN);
+
pseudo_func[FUNC_DTP_MODULE].u.sym =
symbol_new (".<dtpmod>", undefined_section, FUNC_DTP_MODULE,
&zero_address_frag);
symbol_new (".<ltoff>", undefined_section, FUNC_LT_RELATIVE,
&zero_address_frag);
+ pseudo_func[FUNC_LT_RELATIVE_X].u.sym =
+ symbol_new (".<ltoffx>", undefined_section, FUNC_LT_RELATIVE_X,
+ &zero_address_frag);
+
pseudo_func[FUNC_PC_RELATIVE].u.sym =
symbol_new (".<pcrel>", undefined_section, FUNC_PC_RELATIVE,
&zero_address_frag);
case BFD_RELOC_IA64_PLTOFF64I:
case BFD_RELOC_IA64_PLTOFF64MSB:
case BFD_RELOC_IA64_PLTOFF64LSB:
+
+ case BFD_RELOC_IA64_LTOFF22X:
+ case BFD_RELOC_IA64_LDXMOV:
return 1;
default:
break;
}
- return S_FORCE_RELOC (fix->fx_addsy);
+ return generic_force_reloc (fix);
}
/* Decide from what point a pc-relative relocation is relative to,
return off;
}
+
+/* Used to emit section-relative relocs for the dwarf2 debug data. */
+void
+ia64_dwarf2_emit_offset (symbolS *symbol, unsigned int size)
+{
+ expressionS expr;
+
+ expr.X_op = O_pseudo_fixup;
+ expr.X_op_symbol = pseudo_func[FUNC_SEC_RELATIVE].u.sym;
+ expr.X_add_number = 0;
+ expr.X_add_symbol = symbol;
+ emit_expr (&expr, size);
+}
+
/* This is called whenever some data item (not an instruction) needs a
fixup. We pick the right reloc code depending on the byteorder
currently in effect. */
code = BFD_RELOC_IA64_IPLTMSB;
else
code = BFD_RELOC_IA64_IPLTLSB;
-
exp->X_op = O_symbol;
break;
}
ignore_rest_of_line ();
return;
}
+
if (exp->X_op == O_pseudo_fixup)
{
- /* ??? */
exp->X_op = O_symbol;
code = ia64_gen_real_reloc_type (exp->X_op_symbol, code);
+ /* ??? If code unchanged, unsupported. */
}
fix = fix_new_exp (f, where, nbytes, exp, 0, code);
}
break;
+ case FUNC_LT_RELATIVE_X:
+ switch (r_type)
+ {
+ case BFD_RELOC_IA64_IMM22: new = BFD_RELOC_IA64_LTOFF22X; break;
+ default: break;
+ }
+ break;
+
case FUNC_PC_RELATIVE:
switch (r_type)
{
case FUNC_DTP_RELATIVE:
switch (r_type)
{
+ case BFD_RELOC_IA64_DIR64MSB:
+ new = BFD_RELOC_IA64_DTPREL64MSB; break;
+ case BFD_RELOC_IA64_DIR64LSB:
+ new = BFD_RELOC_IA64_DTPREL64LSB; break;
case BFD_RELOC_IA64_IMM14:
new = BFD_RELOC_IA64_DTPREL14; break;
case BFD_RELOC_IA64_IMM22:
default:
abort ();
}
+
/* Hmmmm. Should this ever occur? */
if (new)
return new;
{
char *fixpos;
valueT value = *valP;
- int adjust = 0;
fixpos = fix->fx_frag->fr_literal + fix->fx_where;
{
case BFD_RELOC_IA64_DIR32MSB:
fix->fx_r_type = BFD_RELOC_IA64_PCREL32MSB;
- adjust = 1;
break;
case BFD_RELOC_IA64_DIR32LSB:
fix->fx_r_type = BFD_RELOC_IA64_PCREL32LSB;
- adjust = 1;
break;
case BFD_RELOC_IA64_DIR64MSB:
fix->fx_r_type = BFD_RELOC_IA64_PCREL64MSB;
- adjust = 1;
break;
case BFD_RELOC_IA64_DIR64LSB:
fix->fx_r_type = BFD_RELOC_IA64_PCREL64LSB;
- adjust = 1;
break;
default:
default:
break;
}
-
- /* ??? This is a hack copied from tc-i386.c to make PCREL relocs
- work. There should be a better way to handle this. */
- if (adjust)
- fix->fx_offset += fix->fx_where + fix->fx_frag->fr_address;
}
else if (fix->tc_fix_data.opnd == IA64_OPND_NIL)
{
int *size;
{
LITTLENUM_TYPE words[MAX_LITTLENUMS];
- LITTLENUM_TYPE *word;
char *t;
int prec;
t = atof_ieee (input_line_pointer, type, words);
if (t)
input_line_pointer = t;
- *size = prec * sizeof (LITTLENUM_TYPE);
- for (word = words + prec - 1; prec--;)
+ (*ia64_float_to_chars) (lit, words, prec);
+
+ if (type == 'X')
{
- md_number_to_chars (lit, (long) (*word--), sizeof (LITTLENUM_TYPE));
- lit += sizeof (LITTLENUM_TYPE);
+ /* It is 10 byte floating point with 6 byte padding. */
+ memset (&lit [10], 0, 6);
+ *size = 8 * sizeof (LITTLENUM_TYPE);
}
- return 0;
-}
-
-/* Round up a section's size to the appropriate boundary. */
-valueT
-md_section_align (seg, size)
- segT seg;
- valueT size;
-{
- int align = bfd_get_section_alignment (stdoutput, seg);
- valueT mask = ((valueT) 1 << align) - 1;
+ else
+ *size = prec * sizeof (LITTLENUM_TYPE);
- return (size + mask) & ~mask;
+ return 0;
}
/* Handle ia64 specific semantics of the align directive. */
memcpy (p, (target_big_endian ? be_nop : le_nop), 16);
fragp->fr_var = 16;
}
+
+static void
+ia64_float_to_chars_bigendian (char *lit, LITTLENUM_TYPE *words,
+ int prec)
+{
+ while (prec--)
+ {
+ number_to_chars_bigendian (lit, (long) (*words++),
+ sizeof (LITTLENUM_TYPE));
+ lit += sizeof (LITTLENUM_TYPE);
+ }
+}
+
+static void
+ia64_float_to_chars_littleendian (char *lit, LITTLENUM_TYPE *words,
+ int prec)
+{
+ while (prec--)
+ {
+ number_to_chars_littleendian (lit, (long) (words[prec]),
+ sizeof (LITTLENUM_TYPE));
+ lit += sizeof (LITTLENUM_TYPE);
+ }
+}
+
+void
+ia64_elf_section_change_hook (void)
+{
+ dot_byteorder (-1);
+}
+
+/* Check if a label should be made global. */
+void
+ia64_check_label (symbolS *label)
+{
+ if (*input_line_pointer == ':')
+ {
+ S_SET_EXTERNAL (label);
+ input_line_pointer++;
+ }
+}