You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to
- the Free Software Foundation, 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ the Free Software Foundation, 51 Franklin Street - Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/*
TODO:
#endif
#define NELEMS(a) ((int) (sizeof (a)/sizeof ((a)[0])))
+
+/* Some systems define MIN in, e.g., param.h. */
+#undef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define NUM_SLOTS 4
}
md;
+/* These are not const, because they are modified to MMI for non-itanium1
+ targets below. */
+/* MFI bundle of nops. */
+static unsigned char le_nop[16] =
+{
+ 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00
+};
+/* MFI bundle of nops with stop-bit. */
+static unsigned char le_nop_stop[16] =
+{
+ 0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00
+};
+
/* application registers: */
#define AR_K0 0
unwind_record r;
unsigned long slot_number;
fragS *slot_frag;
- unsigned long next_slot_number;
- fragS *next_slot_frag;
struct unw_rec_list *next;
} unw_rec_list;
unsigned int prologue_count;
} label_prologue_count;
+typedef struct proc_pending
+{
+ symbolS *sym;
+ struct proc_pending *next;
+} proc_pending;
+
static struct
{
/* Maintain a list of unwind entries for the current function. */
unw_rec_list *current_entry;
/* These are used to create the unwind table entry for this function. */
- symbolS *proc_start;
+ proc_pending proc_pending;
symbolS *info; /* pointer to unwind info */
symbolS *personality_routine;
segT saved_text_seg;
ptr->next = NULL;
ptr->slot_number = SLOT_NUM_NOT_SET;
ptr->r.type = t;
- ptr->next_slot_number = 0;
- ptr->next_slot_frag = 0;
return ptr;
}
/* Move to the beginning of the next frag. */
first_frag = first_frag->fr_next;
first_addr = (unsigned long) &first_frag->fr_literal;
+
+ /* This can happen if there is section switching in the middle of a
+ function, causing the frag chain for the function to be broken. */
+ if (first_frag == NULL)
+ {
+ /* We get six warnings for one problem, because of the loop in
+ fixup_unw_records, and because fixup_unw_records is called 3
+ times: once before creating the variant frag, once to estimate
+ its size, and once to relax it. This is unreasonable, so we use
+ a static var to make sure we only emit the warning once. */
+ static int warned = 0;
+
+ if (!warned)
+ {
+ as_warn ("Corrupted unwind info due to unsupported section switching");
+ warned = 1;
+ }
+
+ return index;
+ }
}
/* Add in the used part of the last frag. */
dot_radix (dummy)
int dummy ATTRIBUTE_UNUSED;
{
- int radix;
+ char *radix;
+ int ch;
SKIP_WHITESPACE ();
- radix = *input_line_pointer++;
- if (radix != 'C' && !is_end_of_line[(unsigned char) radix])
- {
- as_bad ("Radix `%c' unsupported", *input_line_pointer);
- ignore_rest_of_line ();
- return;
- }
+ if (is_it_end_of_statement ())
+ return;
+ radix = input_line_pointer;
+ ch = get_symbol_end ();
+ ia64_canonicalize_symbol_name (radix);
+ if (strcasecmp (radix, "C"))
+ as_bad ("Radix `%s' unsupported or invalid", radix);
+ *input_line_pointer = ch;
+ demand_empty_rest_of_line ();
}
/* Helper function for .loc directives. If the assembler is not generating
static int
in_procedure (const char *directive)
{
- if (unwind.proc_start
+ if (unwind.proc_pending.sym
&& (!unwind.saved_text_seg || strcmp (directive, "endp") == 0))
return 1;
return unwind_diagnostic ("procedure", directive);
};
static void
-start_unwind_section (const segT text_seg, int sec_index, int linkonce_empty)
+start_unwind_section (const segT text_seg, int sec_index)
{
/*
Use a slightly ugly scheme to derive the unwind section names from
prefix = special_linkonce_name [sec_index - SPECIAL_SECTION_UNWIND];
suffix += sizeof (".gnu.linkonce.t.") - 1;
}
- else if (linkonce_empty)
- return;
prefix_len = strlen (prefix);
suffix_len = strlen (suffix);
sec_name [sec_name_len] = '\0';
/* Handle COMDAT group. */
- if (suffix == text_name && (text_seg->flags & SEC_LINK_ONCE) != 0)
+ if ((text_seg->flags & SEC_LINK_ONCE) != 0
+ && (elf_section_flags (text_seg) & SHF_GROUP) != 0)
{
char *section;
size_t len, group_name_len;
expressionS exp;
bfd_reloc_code_real_type reloc;
- start_unwind_section (text_seg, SPECIAL_SECTION_UNWIND_INFO, 0);
+ start_unwind_section (text_seg, SPECIAL_SECTION_UNWIND_INFO);
/* Make sure the section has 4 byte alignment for ILP32 and
8 byte alignment for LP64. */
unwind.personality_routine = 0;
}
}
- else
- start_unwind_section (text_seg, SPECIAL_SECTION_UNWIND_INFO, 1);
free_saved_prologue_counts ();
unwind.list = unwind.tail = unwind.current_entry = NULL;
{
char *name, *p, c;
symbolS *sym;
+ proc_pending *pending, *last_pending;
+
+ if (unwind.proc_pending.sym)
+ {
+ (md.unwind_check == unwind_check_warning
+ ? as_warn
+ : as_bad) ("Missing .endp after previous .proc");
+ while (unwind.proc_pending.next)
+ {
+ pending = unwind.proc_pending.next;
+ unwind.proc_pending.next = pending->next;
+ free (pending);
+ }
+ }
+ last_pending = NULL;
- unwind.proc_start = 0;
/* Parse names of main and alternate entry points and mark them as
function symbols: */
while (1)
sym = symbol_find_or_make (name);
if (S_IS_DEFINED (sym))
as_bad ("`%s' was already defined", name);
- else if (unwind.proc_start == 0)
+ else if (!last_pending)
+ {
+ unwind.proc_pending.sym = sym;
+ last_pending = &unwind.proc_pending;
+ }
+ else
{
- unwind.proc_start = sym;
+ pending = xmalloc (sizeof (*pending));
+ pending->sym = sym;
+ last_pending = last_pending->next = pending;
}
symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
}
break;
++input_line_pointer;
}
- if (unwind.proc_start == 0)
- unwind.proc_start = expr_build_dot ();
+ if (!last_pending)
+ {
+ unwind.proc_pending.sym = expr_build_dot ();
+ last_pending = &unwind.proc_pending;
+ }
+ last_pending->next = NULL;
demand_empty_rest_of_line ();
ia64_do_align (16);
int dummy ATTRIBUTE_UNUSED;
{
expressionS e;
- char *ptr;
int bytes_per_address;
long where;
segT saved_seg;
subsegT saved_subseg;
- char *name, *default_name, *p, c;
- symbolS *sym;
+ proc_pending *pending;
int unwind_check = md.unwind_check;
md.unwind_check = unwind_check_error;
subseg_set (md.last_text_seg, 0);
proc_end = expr_build_dot ();
- start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND, 0);
+ start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND);
/* Make sure that section has 4 byte alignment for ILP32 and
8 byte alignment for LP64. */
/* Need space for 3 pointers for procedure start, procedure end,
and unwind info. */
- ptr = frag_more (3 * md.pointer_size);
+ memset (frag_more (3 * md.pointer_size), 0, 3 * md.pointer_size);
where = frag_now_fix () - (3 * md.pointer_size);
bytes_per_address = bfd_arch_bits_per_address (stdoutput) / 8;
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 = unwind.proc_start;
+ if (!S_IS_LOCAL (unwind.proc_pending.sym)
+ && S_IS_DEFINED (unwind.proc_pending.sym))
+ e.X_add_symbol = symbol_temp_new (S_GET_SEGMENT (unwind.proc_pending.sym),
+ S_GET_VALUE (unwind.proc_pending.sym),
+ 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);
e.X_op = O_pseudo_fixup;
ia64_cons_fix_new (frag_now, where + (bytes_per_address * 2),
bytes_per_address, &e);
}
- else
- md_number_to_chars (ptr + (bytes_per_address * 2), 0,
- bytes_per_address);
-
}
- else
- start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND, 1);
-
subseg_set (saved_seg, saved_subseg);
- if (unwind.proc_start)
- default_name = (char *) S_GET_NAME (unwind.proc_start);
- else
- default_name = NULL;
-
- /* Parse names of main and alternate entry points and set symbol sizes. */
- while (1)
+ /* Set symbol sizes. */
+ pending = &unwind.proc_pending;
+ if (S_GET_NAME (pending->sym))
{
- SKIP_WHITESPACE ();
- name = input_line_pointer;
- c = get_symbol_end ();
- p = input_line_pointer;
- if (!*name)
+ do
{
- if (md.unwind_check == unwind_check_warning)
- {
- if (default_name)
- {
- as_warn ("Empty argument of .endp. Use the default name `%s'",
- default_name);
- name = default_name;
- }
- else
- as_warn ("Empty argument of .endp");
- }
- else
- as_bad ("Empty argument of .endp");
- }
- if (*name)
- {
- sym = symbol_find (name);
- if (!sym
- && md.unwind_check == unwind_check_warning
- && default_name
- && default_name != name)
- {
- /* We have a bad name. Try the default one if needed. */
- as_warn ("`%s' was not defined within procedure. Use the default name `%s'",
- name, default_name);
- name = default_name;
- sym = symbol_find (name);
- }
- if (!sym || !S_IS_DEFINED (sym))
- as_bad ("`%s' was not defined within procedure", name);
- else if (unwind.proc_start
- && (symbol_get_bfdsym (sym)->flags & BSF_FUNCTION)
- && S_GET_SIZE (sym) == 0 && symbol_get_obj (sym)->size == NULL)
+ symbolS *sym = pending->sym;
+
+ if (!S_IS_DEFINED (sym))
+ as_bad ("`%s' was not defined within procedure", S_GET_NAME (sym));
+ else if (S_GET_SIZE (sym) == 0
+ && symbol_get_obj (sym)->size == NULL)
{
- fragS *fr = symbol_get_frag (unwind.proc_start);
fragS *frag = symbol_get_frag (sym);
- /* Check whether the function label is at or beyond last
- .proc directive. */
- while (fr && fr != frag)
- fr = fr->fr_next;
- if (fr)
+ if (frag)
{
if (frag == frag_now && SEG_NORMAL (now_seg))
S_SET_SIZE (sym, frag_now_fix () - S_GET_VALUE (sym));
}
}
}
+ } while ((pending = pending->next) != NULL);
+ }
+
+ /* Parse names of main and alternate entry points. */
+ while (1)
+ {
+ char *name, *p, c;
+
+ SKIP_WHITESPACE ();
+ name = input_line_pointer;
+ c = get_symbol_end ();
+ p = input_line_pointer;
+ if (!*name)
+ (md.unwind_check == unwind_check_warning
+ ? as_warn
+ : as_bad) ("Empty argument of .endp");
+ else
+ {
+ symbolS *sym = symbol_find (name);
+
+ for (pending = &unwind.proc_pending; pending; pending = pending->next)
+ {
+ if (sym == pending->sym)
+ {
+ pending->sym = NULL;
+ break;
+ }
+ }
+ if (!sym || !pending)
+ as_warn ("`%s' was not specified with previous .proc", name);
}
*p = c;
SKIP_WHITESPACE ();
++input_line_pointer;
}
demand_empty_rest_of_line ();
- unwind.proc_start = unwind.info = 0;
+
+ /* Deliberately only checking for the main entry point here; the
+ language spec even says all arguments to .endp are ignored. */
+ if (unwind.proc_pending.sym
+ && S_GET_NAME (unwind.proc_pending.sym)
+ && strcmp (S_GET_NAME (unwind.proc_pending.sym), FAKE_LABEL_NAME))
+ as_warn ("`%s' should be an operand to this .endp",
+ S_GET_NAME (unwind.proc_pending.sym));
+ while (unwind.proc_pending.next)
+ {
+ pending = unwind.proc_pending.next;
+ unwind.proc_pending.next = pending->next;
+ free (pending);
+ }
+ unwind.proc_pending.sym = unwind.info = NULL;
}
static void
case O_symbol:
fix = CURR_SLOT.fixup + CURR_SLOT.num_fixups;
/* There are no external relocs for TAG13/TAG13b fields, so we
- create a dummy reloc. This will not live past md_apply_fix3. */
+ create a dummy reloc. This will not live past md_apply_fix. */
fix->code = BFD_RELOC_UNUSED;
fix->code = ia64_gen_real_reloc_type (e->X_op_symbol, fix->code);
fix->opnd = idesc->operands[index];
struct ia64_opcode *idesc;
int end_of_insn_group = 0, user_template = -1;
int n, i, j, first, curr, last_slot;
- unw_rec_list *ptr, *last_ptr, *end_ptr;
bfd_vma t0 = 0, t1 = 0;
struct label_fix *lfix;
struct insn_fix *ifix;
for (i = 0; i < 3 && md.num_slots_in_use > 0; ++i)
{
/* If we have unwind records, we may need to update some now. */
- ptr = md.slot[curr].unwind_record;
+ unw_rec_list *ptr = md.slot[curr].unwind_record;
+ unw_rec_list *end_ptr = NULL;
+
if (ptr)
{
/* Find the last prologue/body record in the list for the current
issued. This matters because there may have been nops emitted
meanwhile. Any non-prologue non-body record followed by a
prologue/body record must also refer to the current point. */
- last_ptr = NULL;
- end_ptr = md.slot[(curr + 1) % NUM_SLOTS].unwind_record;
- for (; ptr != end_ptr; ptr = ptr->next)
+ unw_rec_list *last_ptr;
+
+ for (j = 1; end_ptr == NULL && j < md.num_slots_in_use; ++j)
+ end_ptr = md.slot[(curr + j) % NUM_SLOTS].unwind_record;
+ for (last_ptr = NULL; ptr != end_ptr; ptr = ptr->next)
if (ptr->r.type == prologue || ptr->r.type == prologue_gr
|| ptr->r.type == body)
last_ptr = ptr;
/* Set slot numbers for all remaining unwind records belonging to the
current insn. There can not be any prologue/body unwind records
here. */
- end_ptr = md.slot[(curr + 1) % NUM_SLOTS].unwind_record;
for (; ptr != end_ptr; ptr = ptr->next)
{
ptr->slot_number = (unsigned long) f + i;
number_to_chars_littleendian (f + 0, t0, 8);
number_to_chars_littleendian (f + 8, t1, 8);
-
- if (unwind.list)
- {
- unwind.list->next_slot_number = (unsigned long) f + 16;
- unwind.list->next_slot_frag = frag_now;
- }
}
int
return result;
}
-/* Add a bit of extra goodness if a nop of type F or B would fit
- in TEMPL at SLOT. */
+/* For Itanium 1, add a bit of extra goodness if a nop of type F or B would fit
+ in TEMPL at SLOT. For Itanium 2, add a bit of extra goodness if a nop of
+ type M or I would fit in TEMPL at SLOT. */
static inline int
extra_goodness (int templ, int slot)
symbol_new (".<iplt>", undefined_section, FUNC_IPLT_RELOC,
&zero_address_frag);
+ if (md.tune != itanium1)
+ {
+ /* Convert MFI NOPs bundles into MMI NOPs bundles. */
+ le_nop[0] = 0x8;
+ le_nop_stop[0] = 0x9;
+ }
+
/* Compute the table of best templates. We compute goodness as a
base 4 value, in which each match counts for 3. Match-failures
result in NOPs and we use extra_goodness() to pick the execution
{
if (match (t, j, 1))
{
- if (match (t, k, 2))
+ if ((t == 2 && j == IA64_TYPE_X) || match (t, k, 2))
goodness = 3 + 3 + 3;
else
goodness = 3 + 3 + extra_goodness (t, 2);
}
else if (match (t, i, 1))
{
- if (match (t, j, 2))
+ if ((t == 2 && i == IA64_TYPE_X) || match (t, j, 2))
goodness = 3 + 3;
else
goodness = 3 + extra_goodness (t, 2);
}
}
+#ifdef DEBUG_TEMPLATES
+ /* For debugging changes to the best_template calculations. We don't care
+ about combinations with invalid instructions, so start the loops at 1. */
+ for (i = 0; i < IA64_NUM_TYPES; ++i)
+ for (j = 0; j < IA64_NUM_TYPES; ++j)
+ for (k = 0; k < IA64_NUM_TYPES; ++k)
+ {
+ char type_letter[IA64_NUM_TYPES] = { 'n', 'a', 'i', 'm', 'b', 'f',
+ 'x', 'd' };
+ fprintf (stderr, "%c%c%c %s\n", type_letter[i], type_letter[j],
+ type_letter[k],
+ ia64_templ_desc[best_template[i][j][k]].name);
+ }
+#endif
+
for (i = 0; i < NUM_SLOTS; ++i)
md.slot[i].user_template = -1;
{
if (full > 0)
as_bad ("Standalone `#' is illegal");
- else
- as_bad ("Zero-length symbol is illegal");
}
else if (len < full - 1)
as_warn ("Redundant `#' suffix operators");
tmpl.qp_regno = CURR_SLOT.qp_regno;
tmpl.link_to_qp_branch = 1;
tmpl.mem_offset.hint = 0;
+ tmpl.mem_offset.offset = 0;
+ tmpl.mem_offset.base = 0;
tmpl.specific = 1;
tmpl.index = -1;
tmpl.cmp_type = CMP_NONE;
+ tmpl.depind = 0;
+ tmpl.file = NULL;
+ tmpl.line = 0;
+ tmpl.path = 0;
#define UNHANDLED \
as_warn (_("Unhandled dependency %s for %s (%s), note %d"), \
else if (ar_is_only_in_memory_unit (CURR_SLOT.opnd[rop].X_add_number))
unit = 'm';
if (unit != 'a' && unit != idesc->name [4])
- as_bad ("AR %d cannot be accessed by %c-unit",
+ as_bad ("AR %d can only be accessed by %c-unit",
(int) (CURR_SLOT.opnd[rop].X_add_number - REG_AR),
TOUPPER (unit));
}
CURR_SLOT.unwind_record = unwind.current_entry;
unwind.current_entry = NULL;
}
- if (unwind.proc_start && S_IS_DEFINED (unwind.proc_start))
+ if (unwind.proc_pending.sym && S_IS_DEFINED (unwind.proc_pending.sym))
unwind.insn = 1;
/* Check for dependency violations. */
fixS *fix;
{
/* Prevent all adjustments to global symbols */
- if (S_IS_EXTERN (fix->fx_addsy) || S_IS_WEAK (fix->fx_addsy))
+ if (S_IS_EXTERNAL (fix->fx_addsy) || S_IS_WEAK (fix->fx_addsy))
return 0;
switch (fix->fx_r_type)
fix = fix_new_exp (f, where, nbytes, exp, 0, code);
/* We need to store the byte order in effect in case we're going
to fix an 8 or 16 bit relocation (for which there no real
- relocs available). See md_apply_fix3(). */
+ relocs available). See md_apply_fix(). */
fix->tc_fix_data.bigendian = target_big_endian;
}
case BFD_RELOC_IA64_DIR32LSB: width = 32; suffix = "LSB"; break;
case BFD_RELOC_IA64_DIR64MSB: width = 64; suffix = "MSB"; break;
case BFD_RELOC_IA64_DIR64LSB: width = 64; suffix = "LSB"; break;
+ case BFD_RELOC_UNUSED: width = 13; break;
case BFD_RELOC_IA64_IMM14: width = 14; break;
case BFD_RELOC_IA64_IMM22: width = 22; break;
case BFD_RELOC_IA64_IMM64: width = 64; suffix = "I"; break;
(if possible). */
void
-md_apply_fix3 (fix, valP, seg)
+md_apply_fix (fix, valP, seg)
fixS *fix;
valueT *valP;
segT seg ATTRIBUTE_UNUSED;
ia64_handle_align (fragp)
fragS *fragp;
{
- /* Use mfi bundle of nops with no stop bits. */
- static const unsigned char le_nop[]
- = { 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00};
- static const unsigned char le_nop_stop[]
- = { 0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00};
-
int bytes;
char *p;
const unsigned char *nop;