/* tc-ia64.c -- Assembler for the HP/Intel IA-64 architecture.
- Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
- 2008, 2009, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1998-2015 Free Software Foundation, Inc.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of GAS, the GNU Assembler.
REG_FR = (REG_GR + 128),
REG_AR = (REG_FR + 128),
REG_CR = (REG_AR + 128),
- REG_P = (REG_CR + 128),
+ REG_DAHR = (REG_CR + 128),
+ REG_P = (REG_DAHR + 8),
REG_BR = (REG_P + 64),
REG_IP = (REG_BR + 8),
REG_CFM,
IND_PKR,
IND_PMC,
IND_PMD,
+ IND_DAHR,
IND_RR,
/* The following pseudo-registers are used for unwind directives only: */
REG_PSP,
{ "pkr", IND_PKR },
{ "pmc", IND_PMC },
{ "pmd", IND_PMD },
+ { "dahr", IND_DAHR },
{ "rr", IND_RR },
};
/* hint constants: */
{ "pause", PSEUDO_FUNC_CONST, { 0x0 } },
+ { "priority", PSEUDO_FUNC_CONST, { 0x1 } },
+
+ /* tf constants: */
+ { "clz", PSEUDO_FUNC_CONST, { 32 } },
+ { "mpy", PSEUDO_FUNC_CONST, { 33 } },
+ { "datahints", PSEUDO_FUNC_CONST, { 34 } },
/* unwind-related constants: */
{ "svr4", PSEUDO_FUNC_CONST, { ELFOSABI_NONE } },
return reg >= 64 && reg <= 111;
}
-/* Determine if application register REGNUM resides only in the memory
+/* Determine if application register REGNUM resides only in the memory
unit (as opposed to the integer unit). */
static int
ar_is_only_in_memory_unit (int reg)
}
}
+#ifdef TE_VMS
+
+/* .vms_common section, symbol, size, alignment */
+
+static void
+obj_elf_vms_common (int ignore ATTRIBUTE_UNUSED)
+{
+ char *sec_name;
+ char *sym_name;
+ char c;
+ offsetT size;
+ offsetT cur_size;
+ offsetT temp;
+ symbolS *symbolP;
+ segT current_seg = now_seg;
+ subsegT current_subseg = now_subseg;
+ offsetT log_align;
+
+ /* Section name. */
+ sec_name = obj_elf_section_name ();
+ if (sec_name == NULL)
+ return;
+
+ /* Symbol name. */
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer == ',')
+ {
+ input_line_pointer++;
+ SKIP_WHITESPACE ();
+ }
+ else
+ {
+ as_bad (_("expected ',' after section name"));
+ ignore_rest_of_line ();
+ return;
+ }
+
+ sym_name = input_line_pointer;
+ c = get_symbol_end ();
+
+ if (input_line_pointer == sym_name)
+ {
+ *input_line_pointer = c;
+ as_bad (_("expected symbol name"));
+ ignore_rest_of_line ();
+ return;
+ }
+
+ symbolP = symbol_find_or_make (sym_name);
+ *input_line_pointer = c;
+
+ if ((S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP))
+ && !S_IS_COMMON (symbolP))
+ {
+ as_bad (_("Ignoring attempt to re-define symbol"));
+ ignore_rest_of_line ();
+ return;
+ }
+
+ /* Symbol size. */
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer == ',')
+ {
+ input_line_pointer++;
+ SKIP_WHITESPACE ();
+ }
+ else
+ {
+ as_bad (_("expected ',' after symbol name"));
+ ignore_rest_of_line ();
+ return;
+ }
+
+ temp = get_absolute_expression ();
+ size = temp;
+ size &= ((offsetT) 2 << (stdoutput->arch_info->bits_per_address - 1)) - 1;
+ if (temp != size)
+ {
+ as_warn (_("size (%ld) out of range, ignored"), (long) temp);
+ ignore_rest_of_line ();
+ return;
+ }
+
+ /* Alignment. */
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer == ',')
+ {
+ input_line_pointer++;
+ SKIP_WHITESPACE ();
+ }
+ else
+ {
+ as_bad (_("expected ',' after symbol size"));
+ ignore_rest_of_line ();
+ return;
+ }
+
+ log_align = get_absolute_expression ();
+
+ demand_empty_rest_of_line ();
+
+ obj_elf_change_section
+ (sec_name, SHT_NOBITS,
+ SHF_ALLOC | SHF_WRITE | SHF_IA_64_VMS_OVERLAID | SHF_IA_64_VMS_GLOBAL,
+ 0, NULL, 1, 0);
+
+ S_SET_VALUE (symbolP, 0);
+ S_SET_SIZE (symbolP, size);
+ S_SET_EXTERNAL (symbolP);
+ S_SET_SEGMENT (symbolP, now_seg);
+
+ symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT;
+
+ record_alignment (now_seg, log_align);
+
+ cur_size = bfd_section_size (stdoutput, now_seg);
+ if ((int) size > cur_size)
+ {
+ char *pfrag
+ = frag_var (rs_fill, 1, 1, (relax_substateT)0, NULL,
+ (valueT)size - (valueT)cur_size, NULL);
+ *pfrag = 0;
+ bfd_section_size (stdoutput, now_seg) = size;
+ }
+
+ /* Switch back to current segment. */
+ subseg_set (current_seg, current_subseg);
+
+#ifdef md_elf_section_change_hook
+ md_elf_section_change_hook ();
+#endif
+}
+
+#endif /* TE_VMS */
+
/* Output COUNT bytes to a memory location. */
static char *vbyte_mem_ptr = NULL;
}
/* This function converts a rs_machine_dependent variant frag into a
- normal fill frag with the unwind image from the the record list. */
+ normal fill frag with the unwind image from the record list. */
void
ia64_convert_frag (fragS *frag)
{
/* Set expression which points to start of unwind descriptor area. */
unwind.info = expr_build_dot ();
-
+
frag_var (rs_machine_dependent, size, size, 0, 0,
(offsetT) (long) unwind.personality_routine,
(char *) list);
symbol_get_frag (unwind.proc_pending.sym));
else
e.X_add_symbol = unwind.proc_pending.sym;
- ia64_cons_fix_new (frag_now, where, bytes_per_address, &e);
+ ia64_cons_fix_new (frag_now, where, bytes_per_address, &e,
+ BFD_RELOC_NONE);
e.X_op = O_pseudo_fixup;
e.X_op_symbol = pseudo_func[FUNC_SEG_RELATIVE].u.sym;
e.X_add_number = 0;
e.X_add_symbol = proc_end;
ia64_cons_fix_new (frag_now, where + bytes_per_address,
- bytes_per_address, &e);
+ bytes_per_address, &e, BFD_RELOC_NONE);
if (unwind.info)
{
e.X_add_number = 0;
e.X_add_symbol = unwind.info;
ia64_cons_fix_new (frag_now, where + (bytes_per_address * 2),
- bytes_per_address, &e);
+ bytes_per_address, &e, BFD_RELOC_NONE);
}
}
subseg_set (saved_seg, saved_subseg);
{"4byte", stmt_cons_ua, 4},
{"8byte", stmt_cons_ua, 8},
+#ifdef TE_VMS
+ {"vms_common", obj_elf_vms_common, 0},
+#endif
+
{ NULL, 0, 0 }
};
return OPERAND_MATCH;
break;
+ case IA64_OPND_DAHR3:
+ if (e->X_op == O_register && e->X_add_number >= REG_DAHR
+ && e->X_add_number < REG_DAHR + 8)
+ return OPERAND_MATCH;
+ break;
+
case IA64_OPND_F1:
case IA64_OPND_F2:
case IA64_OPND_F3:
case IA64_OPND_PKR_R3:
case IA64_OPND_PMC_R3:
case IA64_OPND_PMD_R3:
+ case IA64_OPND_DAHR_R3:
case IA64_OPND_RR_R3:
if (e->X_op == O_index && e->X_op_symbol
&& (S_GET_VALUE (e->X_op_symbol) - IND_CPUID
case IA64_OPND_IMMU2:
case IA64_OPND_IMMU7a:
case IA64_OPND_IMMU7b:
+ case IA64_OPND_IMMU16:
+ case IA64_OPND_IMMU19:
case IA64_OPND_IMMU21:
case IA64_OPND_IMMU24:
case IA64_OPND_MBTYPE4:
++CURR_SLOT.num_fixups;
return OPERAND_MATCH;
+ case IA64_OPND_STRD5b:
+ if (e->X_op == O_constant)
+ {
+ /* 5-bit signed scaled by 64 */
+ if ((e->X_add_number <= ( 0xf << 6 ))
+ && (e->X_add_number >= -( 0x10 << 6 )))
+ {
+
+ /* Must be a multiple of 64 */
+ if ((e->X_add_number & 0x3f) != 0)
+ as_warn (_("stride must be a multiple of 64; lower 6 bits ignored"));
+
+ e->X_add_number &= ~ 0x3f;
+ return OPERAND_MATCH;
+ }
+ else
+ return OPERAND_OUT_OF_RANGE;
+ }
+ break;
+ case IA64_OPND_CNT6a:
+ if (e->X_op == O_constant)
+ {
+ /* 6-bit unsigned biased by 1 -- count 0 is meaningless */
+ if ((e->X_add_number <= 64)
+ && (e->X_add_number > 0) )
+ {
+ return OPERAND_MATCH;
+ }
+ else
+ return OPERAND_OUT_OF_RANGE;
+ }
+ break;
+
default:
break;
}
for (; ; ++i)
{
- if (i < NELEMS (CURR_SLOT.opnd))
+ if (i < NELEMS (CURR_SLOT.opnd))
{
sep = parse_operand_maybe_eval (CURR_SLOT.opnd + i, '=',
idesc->operands[i]);
val -= REG_CR;
break;
+ case IA64_OPND_DAHR3:
+ val -= REG_DAHR;
+ break;
+
case IA64_OPND_F1:
case IA64_OPND_F2:
case IA64_OPND_F3:
case IA64_OPND_PKR_R3:
case IA64_OPND_PMC_R3:
case IA64_OPND_PMD_R3:
+ case IA64_OPND_DAHR_R3:
case IA64_OPND_RR_R3:
val -= REG_GR;
break;
md.slot[curr].unwind_record = NULL;
}
- if (required_unit == IA64_UNIT_L)
- {
- know (i == 1);
- /* skip one slot for long/X-unit instructions */
- ++i;
- }
- --md.num_slots_in_use;
- last_slot = i;
-
for (j = 0; j < md.slot[curr].num_fixups; ++j)
{
ifix = md.slot[curr].fixup + j;
end_of_insn_group = md.slot[curr].end_of_insn_group;
+ /* This adjustment to "i" must occur after the fix, otherwise the fix
+ is assigned to the wrong slot, and the VMS linker complains. */
+ if (required_unit == IA64_UNIT_L)
+ {
+ know (i == 1);
+ /* skip one slot for long/X-unit instructions */
+ ++i;
+ }
+ --md.num_slots_in_use;
+ last_slot = i;
+
/* clear slot: */
ia64_free_opcode (md.slot[curr].idesc);
memset (md.slot + curr, 0, sizeof (md.slot[curr]));
as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
_("Missing '}' at end of file"));
}
-
+
know (md.num_slots_in_use < NUM_SLOTS);
t0 = end_of_insn_group | (template_val << 1) | (insn[0] << 5) | (insn[1] << 46);
for (i = 0; i < NELEMS (cr); ++i)
declare_register (cr[i].name, REG_CR + cr[i].regnum);
+ /* dahr registers: */
+ declare_register_set ("dahr", 8, REG_DAHR);
+
declare_register ("ip", REG_IP);
declare_register ("cfm", REG_CFM);
declare_register ("psr", REG_PSR);
int
ia64_frob_symbol (struct symbol *sym)
{
- if ((S_GET_SEGMENT (sym) == &bfd_und_section && ! symbol_used_p (sym) &&
+ if ((S_GET_SEGMENT (sym) == bfd_und_section_ptr && ! symbol_used_p (sym) &&
ELF_ST_VISIBILITY (S_GET_OTHER (sym)) == STV_DEFAULT)
- || (S_GET_SEGMENT (sym) == &bfd_abs_section
+ || (S_GET_SEGMENT (sym) == bfd_abs_section_ptr
&& ! S_IS_EXTERNAL (sym)))
return 1;
return 0;
}
break;
+ case IA64_RS_DAHR:
+ if (note == 0)
+ {
+ if (idesc->operands[!rsrc_write] == IA64_OPND_DAHR3)
+ {
+ specs[count] = tmpl;
+ specs[count++].index =
+ CURR_SLOT.opnd[!rsrc_write].X_add_number - REG_DAHR;
+ }
+ }
+ else
+ {
+ UNHANDLED;
+ }
+ break;
+
case IA64_RS_FR:
case IA64_RS_FRb:
if (note != 1)
|| idesc->operands[i] == IA64_OPND_PKR_R3
|| idesc->operands[i] == IA64_OPND_PMC_R3
|| idesc->operands[i] == IA64_OPND_PMD_R3
+ || idesc->operands[i] == IA64_OPND_DAHR_R3
|| idesc->operands[i] == IA64_OPND_RR_R3
|| ((i >= idesc->num_outputs)
&& (idesc->operands[i] == IA64_OPND_R1
print_prmask (qp_mutexes[i].prmask);
fprintf (stderr, "\n");
}
-
+
/* Deal with the old mutex with more than 3+ PRs only if
the new mutex on the same execution path with it.
if (add == 0
&& (qp_mutexes[i].prmask & mask) == mask)
add = 1;
-
+
qp_mutexes[i].prmask &= ~mask;
if (qp_mutexes[i].prmask & (qp_mutexes[i].prmask - 1))
{
i++;
}
}
-
+
if (keep == 0)
/* Remove the mutex. */
qp_mutexes[i] = qp_mutexes[--qp_mutexeslen];
{
enum ia64_opnd opnd1, opnd2;
int rop;
-
+
opnd1 = idesc->operands[0];
opnd2 = idesc->operands[1];
if (opnd1 == IA64_OPND_AR3)
fixup. We pick the right reloc code depending on the byteorder
currently in effect. */
void
-ia64_cons_fix_new (fragS *f, int where, int nbytes, expressionS *exp)
+ia64_cons_fix_new (fragS *f, int where, int nbytes, expressionS *exp,
+ bfd_reloc_code_real_type code)
{
- bfd_reloc_code_real_type code;
fixS *fix;
switch (nbytes)
bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
p = fragp->fr_literal + fragp->fr_fix;
- /* If no paddings are needed, we check if we need a stop bit. */
+ /* If no paddings are needed, we check if we need a stop bit. */
if (!bytes && fragp->tc_frag_data)
{
if (fragp->fr_fix < 16)
h = (struct alias *) xmalloc (sizeof (struct alias));
as_where (&h->file, &h->line);
h->name = name;
-
+
error_string = hash_jam (ahash, alias, (void *) h);
if (error_string)
{
bname = xstrdup (lbasename (out_file_name));
if ((p = strrchr (bname, '.')))
*p = '\0';
-
+
/* VMS note header is 24 bytes long. */
p = frag_more (8 + 8 + 8);
number_to_chars_littleendian (p + 0, 8, 8);