summaryrefslogtreecommitdiffstats
path: root/contrib/binutils/gas/config/tc-ia64.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/binutils/gas/config/tc-ia64.c')
-rw-r--r--contrib/binutils/gas/config/tc-ia64.c432
1 files changed, 336 insertions, 96 deletions
diff --git a/contrib/binutils/gas/config/tc-ia64.c b/contrib/binutils/gas/config/tc-ia64.c
index 0e1c578..701752f 100644
--- a/contrib/binutils/gas/config/tc-ia64.c
+++ b/contrib/binutils/gas/config/tc-ia64.c
@@ -1,5 +1,5 @@
/* tc-ia64.c -- Assembler for the HP/Intel IA-64 architecture.
- Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ Copyright 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of GAS, the GNU Assembler.
@@ -43,6 +43,7 @@
*/
#include "as.h"
+#include "safe-ctype.h"
#include "dwarf2dbg.h"
#include "subsegs.h"
@@ -61,13 +62,17 @@
enum special_section
{
+ /* IA-64 ABI section pseudo-ops. */
SPECIAL_SECTION_BSS = 0,
SPECIAL_SECTION_SBSS,
SPECIAL_SECTION_SDATA,
SPECIAL_SECTION_RODATA,
SPECIAL_SECTION_COMMENT,
SPECIAL_SECTION_UNWIND,
- SPECIAL_SECTION_UNWIND_INFO
+ SPECIAL_SECTION_UNWIND_INFO,
+ /* HPUX specific section pseudo-ops. */
+ SPECIAL_SECTION_INIT_ARRAY,
+ SPECIAL_SECTION_FINI_ARRAY,
};
enum reloc_func
@@ -81,6 +86,7 @@ enum reloc_func
FUNC_SEG_RELATIVE,
FUNC_LTV_RELATIVE,
FUNC_LT_FPTR_RELATIVE,
+ FUNC_IPLT_RELOC,
};
enum reg_symbol
@@ -279,6 +285,9 @@ static struct
int g_reg_set_conditionally[128];
} last_groups[3];
int group_idx;
+
+ int pointer_size; /* size in bytes of a pointer */
+ int pointer_size_shift; /* shift size of a pointer for alignment */
}
md;
@@ -476,6 +485,7 @@ pseudo_func[] =
{ "segrel", PSEUDO_FUNC_RELOC, { 0 } },
{ "ltv", PSEUDO_FUNC_RELOC, { 0 } },
{ "", 0, { 0 } }, /* placeholder for FUNC_LT_FPTR_RELATIVE */
+ { "iplt", PSEUDO_FUNC_RELOC, { 0 } },
/* mbtype4 constants: */
{ "alt", PSEUDO_FUNC_CONST, { 0xa } },
@@ -523,7 +533,13 @@ static const bfd_vma nop[IA64_NUM_UNITS] =
static char special_section_name[][20] =
{
{".bss"}, {".sbss"}, {".sdata"}, {".rodata"}, {".comment"},
- {".IA_64.unwind"}, {".IA_64.unwind_info"}
+ {".IA_64.unwind"}, {".IA_64.unwind_info"},
+ {".init_array"}, {".fini_array"}
+ };
+
+static char *special_linkonce_name[] =
+ {
+ ".gnu.linkonce.ia64unw.", ".gnu.linkonce.ia64unwi."
};
/* The best template for a particular sequence of up to three
@@ -703,6 +719,7 @@ static enum operand_match_result operand_match PARAMS ((const struct ia64_opcode
expressionS *e));
static int parse_operand PARAMS ((expressionS *e));
static struct ia64_opcode * parse_operands PARAMS ((struct ia64_opcode *));
+static int errata_nop_necessary_p PARAMS ((struct slot *, enum ia64_unit));
static void build_insn PARAMS ((struct slot *, bfd_vma *));
static void emit_one_bundle PARAMS ((void));
static void fix_insn PARAMS ((fixS *, const struct ia64_operand *, valueT));
@@ -716,6 +733,7 @@ static void add_qp_imply PARAMS((int p1, int p2));
static void clear_qp_branch_flag PARAMS((valueT mask));
static void clear_qp_mutex PARAMS((valueT mask));
static void clear_qp_implies PARAMS((valueT p1_mask, valueT p2_mask));
+static int has_suffix_p PARAMS((const char *, const char *));
static void clear_register_values PARAMS ((void));
static void print_dependency PARAMS ((const char *action, int depind));
static void instruction_serialization PARAMS ((void));
@@ -851,12 +869,21 @@ static int generate_unwind_image PARAMS ((const char *));
stack, so this must be a macro... */
#define make_unw_section_name(special, text_name, result) \
{ \
- char *_prefix = special_section_name[special]; \
- size_t _prefix_len = strlen (_prefix), _text_len = strlen (text_name); \
- char *_result = alloca (_prefix_len + _text_len + 1); \
- memcpy(_result, _prefix, _prefix_len); \
- memcpy(_result + _prefix_len, text_name, _text_len); \
- _result[_prefix_len + _text_len] = '\0'; \
+ const char *_prefix = special_section_name[special]; \
+ const char *_suffix = text_name; \
+ size_t _prefix_len, _suffix_len; \
+ char *_result; \
+ if (strncmp (text_name, ".gnu.linkonce.t.", \
+ sizeof (".gnu.linkonce.t.") - 1) == 0) \
+ { \
+ _prefix = special_linkonce_name[special - SPECIAL_SECTION_UNWIND]; \
+ _suffix += sizeof (".gnu.linkonce.t.") - 1; \
+ } \
+ _prefix_len = strlen (_prefix), _suffix_len = strlen (_suffix); \
+ _result = alloca (_prefix_len + _suffix_len + 1); \
+ memcpy (_result, _prefix, _prefix_len); \
+ memcpy (_result + _prefix_len, _suffix, _suffix_len); \
+ _result[_prefix_len + _suffix_len] = '\0'; \
result = _result; \
} \
while (0)
@@ -892,6 +919,20 @@ set_section (name)
input_line_pointer = saved_input_line_pointer;
}
+/* Map 's' to SHF_IA_64_SHORT. */
+
+int
+ia64_elf_section_letter (letter, ptr_msg)
+ int letter;
+ char **ptr_msg;
+{
+ if (letter == 's')
+ return SHF_IA_64_SHORT;
+
+ *ptr_msg = _("Bad .section directive: want a,s,w,x,M,S in string");
+ return 0;
+}
+
/* Map SHF_IA_64_SHORT to SEC_SMALL_DATA. */
flagword
@@ -909,15 +950,28 @@ ia64_elf_section_type (str, len)
const char *str;
size_t len;
{
- len = sizeof (ELF_STRING_ia64_unwind_info) - 1;
- if (strncmp (str, ELF_STRING_ia64_unwind_info, len) == 0)
+#define STREQ(s) ((len == sizeof (s) - 1) && (strncmp (str, s, sizeof (s) - 1) == 0))
+
+ if (STREQ (ELF_STRING_ia64_unwind_info))
return SHT_PROGBITS;
- len = sizeof (ELF_STRING_ia64_unwind) - 1;
- if (strncmp (str, ELF_STRING_ia64_unwind, len) == 0)
+ if (STREQ (ELF_STRING_ia64_unwind_info_once))
+ return SHT_PROGBITS;
+
+ if (STREQ (ELF_STRING_ia64_unwind))
+ return SHT_IA_64_UNWIND;
+
+ if (STREQ (ELF_STRING_ia64_unwind_once))
return SHT_IA_64_UNWIND;
+ if (STREQ ("init_array"))
+ return SHT_INIT_ARRAY;
+
+ if (STREQ ("fini_array"))
+ return SHT_FINI_ARRAY;
+
return -1;
+#undef STREQ
}
static unsigned int
@@ -2735,6 +2789,47 @@ fixup_unw_records (list)
}
}
+/* Helper routine for output_unw_records. Emits the header for the unwind
+ info. */
+
+static int
+setup_unwind_header (int size, unsigned char **mem)
+{
+ int x, extra = 0;
+ valueT flag_value;
+
+ /* pad to pointer-size boundry. */
+ x = size % md.pointer_size;
+ if (x != 0)
+ extra = md.pointer_size - x;
+
+ /* Add 8 for the header + a pointer for the
+ personality offset. */
+ *mem = xmalloc (size + extra + 8 + md.pointer_size);
+
+ /* Clear the padding area and personality. */
+ memset (*mem + 8 + size, 0 , extra + md.pointer_size);
+
+ /* Initialize the header area. */
+ if (unwind.personality_routine)
+ {
+ if (md.flags & EF_IA_64_ABI64)
+ flag_value = (bfd_vma) 3 << 32;
+ else
+ /* 32-bit unwind info block. */
+ flag_value = (bfd_vma) 0x1003 << 32;
+ }
+ else
+ flag_value = 0;
+
+ md_number_to_chars (*mem, (((bfd_vma) 1 << 48) /* Version. */
+ | flag_value /* U & E handler flags. */
+ | ((size + extra) / md.pointer_size)), /* Length. */
+ 8);
+
+ return extra;
+}
+
/* Generate an unwind image from a record list. Returns the number of
bytes in the resulting image. The memory image itselof is returned
in the 'ptr' parameter. */
@@ -2743,7 +2838,7 @@ output_unw_records (list, ptr)
unw_rec_list *list;
void **ptr;
{
- int size, x, extra = 0;
+ int size, extra;
unsigned char *mem;
*ptr = NULL;
@@ -2752,35 +2847,17 @@ output_unw_records (list, ptr)
fixup_unw_records (list);
size = calc_record_size (list);
- /* pad to 8 byte boundry. */
- x = size % 8;
- if (x != 0)
- extra = 8 - x;
-
if (size > 0 || unwind.force_unwind_entry)
{
unwind.force_unwind_entry = 0;
-
- /* Add 8 for the header + 8 more bytes for the personality offset. */
- mem = xmalloc (size + extra + 16);
+ extra = setup_unwind_header (size, &mem);
vbyte_mem_ptr = mem + 8;
- /* Clear the padding area and personality. */
- memset (mem + 8 + size, 0 , extra + 8);
- /* Initialize the header area. */
- md_number_to_chars (mem,
- (((bfd_vma) 1 << 48) /* version */
- | (unwind.personality_routine
- ? ((bfd_vma) 3 << 32) /* U & E handler flags */
- : 0)
- | ((size + extra) / 8)), /* length (dwords) */
- 8);
-
process_unw_records (list, output_vbyte_mem);
*ptr = mem;
- size += extra + 16;
+ size += extra + 8 + md.pointer_size;
}
return size;
}
@@ -3149,24 +3226,26 @@ generate_unwind_image (text_name)
/* Generate the unwind record. */
size = output_unw_records (unwind.list, (void **) &unw_rec);
- if (size % 8 != 0)
- as_bad ("Unwind record is not a multiple of 8 bytes.");
-
+ if (size % md.pointer_size != 0)
+ as_bad ("Unwind record is not a multiple of %d bytes.", md.pointer_size);
+
/* If there are unwind records, switch sections, and output the info. */
if (size != 0)
{
unsigned char *where;
char *sec_name;
expressionS exp;
+ bfd_reloc_code_real_type reloc;
make_unw_section_name (SPECIAL_SECTION_UNWIND_INFO, text_name, sec_name);
set_section (sec_name);
bfd_set_section_flags (stdoutput, now_seg,
SEC_LOAD | SEC_ALLOC | SEC_READONLY);
- /* Make sure the section has 8 byte alignment. */
- frag_align (3, 0, 0);
- record_alignment (now_seg, 3);
+ /* Make sure the section has 4 byte alignment for ILP32 and
+ 8 byte alignment for LP64. */
+ frag_align (md.pointer_size_shift, 0, 0);
+ record_alignment (now_seg, md.pointer_size_shift);
/* Set expression which points to start of unwind descriptor area. */
unwind.info = expr_build_dot ();
@@ -3186,8 +3265,24 @@ generate_unwind_image (text_name)
exp.X_op = O_symbol;
exp.X_add_symbol = unwind.personality_routine;
exp.X_add_number = 0;
- fix_new_exp (frag_now, frag_now_fix () - 8, 8,
- &exp, 0, BFD_RELOC_IA64_LTOFF_FPTR64LSB);
+
+ if (md.flags & EF_IA_64_BE)
+ {
+ if (md.flags & EF_IA_64_ABI64)
+ reloc = BFD_RELOC_IA64_LTOFF_FPTR64MSB;
+ else
+ reloc = BFD_RELOC_IA64_LTOFF_FPTR32MSB;
+ }
+ else
+ {
+ if (md.flags & EF_IA_64_ABI64)
+ reloc = BFD_RELOC_IA64_LTOFF_FPTR64LSB;
+ else
+ reloc = BFD_RELOC_IA64_LTOFF_FPTR32LSB;
+ }
+
+ fix_new_exp (frag_now, frag_now_fix () - md.pointer_size,
+ md.pointer_size, & exp, 0, reloc);
unwind.personality_routine = 0;
}
}
@@ -3797,6 +3892,8 @@ dot_endp (dummy)
segT saved_seg;
subsegT saved_subseg;
const char *sec_name, *text_name;
+ char *name, *p, c;
+ symbolS *sym;
if (unwind.saved_text_seg)
{
@@ -3820,6 +3917,8 @@ dot_endp (dummy)
.text .IA_64.unwind
.text.foo .IA_64.unwind.text.foo
.foo .IA_64.unwind.foo
+ .gnu.linkonce.t.foo
+ .gnu.linkonce.ia64unw.foo
_info .IA_64.unwind_info gas issues error message (ditto)
_infoFOO .IA_64.unwind_infoFOO gas issues error message (ditto)
@@ -3851,9 +3950,6 @@ dot_endp (dummy)
if (strcmp (text_name, ".text") == 0)
text_name = "";
- expression (&e);
- demand_empty_rest_of_line ();
-
insn_group_break (1, 0, 0);
/* If there wasn't a .handlerdata, we haven't generated an image yet. */
@@ -3870,11 +3966,14 @@ dot_endp (dummy)
bfd_set_section_flags (stdoutput, now_seg,
SEC_LOAD | SEC_ALLOC | SEC_READONLY);
- /* Make sure the section has 8 byte alignment. */
- record_alignment (now_seg, 3);
+ /* Make sure that section has 4 byte alignment for ILP32 and
+ 8 byte alignment for LP64. */
+ record_alignment (now_seg, md.pointer_size_shift);
- ptr = frag_more (24);
- where = frag_now_fix () - 24;
+ /* Need space for 3 pointers for procedure start, procedure end,
+ and unwind info. */
+ ptr = frag_more (3 * md.pointer_size);
+ where = frag_now_fix () - (3 * md.pointer_size);
bytes_per_address = bfd_arch_bits_per_address (stdoutput) / 8;
/* Issue the values of a) Proc Begin, b) Proc End, c) Unwind Record. */
@@ -3906,6 +4005,50 @@ dot_endp (dummy)
}
subseg_set (saved_seg, saved_subseg);
+
+ /* Parse names of main and alternate entry points and set symbol sizes. */
+ while (1)
+ {
+ SKIP_WHITESPACE ();
+ name = input_line_pointer;
+ c = get_symbol_end ();
+ p = input_line_pointer;
+ sym = symbol_find (name);
+ if (sym && unwind.proc_start
+ && (symbol_get_bfdsym (sym)->flags & BSF_FUNCTION)
+ && 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 == frag_now && SEG_NORMAL (now_seg))
+ S_SET_SIZE (sym, frag_now_fix () - S_GET_VALUE (sym));
+ else
+ {
+ symbol_get_obj (sym)->size =
+ (expressionS *) xmalloc (sizeof (expressionS));
+ symbol_get_obj (sym)->size->X_op = O_subtract;
+ symbol_get_obj (sym)->size->X_add_symbol
+ = symbol_new (FAKE_LABEL_NAME, now_seg,
+ frag_now_fix (), frag_now);
+ symbol_get_obj (sym)->size->X_op_symbol = sym;
+ symbol_get_obj (sym)->size->X_add_number = 0;
+ }
+ }
+ }
+ *p = c;
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer != ',')
+ break;
+ ++input_line_pointer;
+ }
+ demand_empty_rest_of_line ();
unwind.proc_start = unwind.proc_end = unwind.info = 0;
}
@@ -4406,7 +4549,7 @@ dot_pred_rel (type)
valueT bit = 1;
int regno;
- if (toupper (*input_line_pointer) != 'P'
+ if (TOUPPER (*input_line_pointer) != 'P'
|| (regno = atoi (++input_line_pointer)) < 0
|| regno > 63)
{
@@ -4414,7 +4557,7 @@ dot_pred_rel (type)
ignore_rest_of_line ();
return;
}
- while (isdigit (*input_line_pointer))
+ while (ISDIGIT (*input_line_pointer))
++input_line_pointer;
if (p1 == -1)
p1 = regno;
@@ -4431,7 +4574,7 @@ dot_pred_rel (type)
valueT stop = 1;
++input_line_pointer;
- if (toupper (*input_line_pointer) != 'P'
+ if (TOUPPER (*input_line_pointer) != 'P'
|| (regno = atoi (++input_line_pointer)) < 0
|| regno > 63)
{
@@ -4439,7 +4582,7 @@ dot_pred_rel (type)
ignore_rest_of_line ();
return;
}
- while (isdigit (*input_line_pointer))
+ while (ISDIGIT (*input_line_pointer))
++input_line_pointer;
stop <<= regno;
if (bit >= stop)
@@ -4582,6 +4725,8 @@ const pseudo_typeS md_pseudo_table[] =
{ "comment", dot_special_section, SPECIAL_SECTION_COMMENT },
{ "ia_64.unwind", dot_special_section, SPECIAL_SECTION_UNWIND },
{ "ia_64.unwind_info", dot_special_section, SPECIAL_SECTION_UNWIND_INFO },
+ { "init_array", dot_special_section, SPECIAL_SECTION_INIT_ARRAY },
+ { "fini_array", dot_special_section, SPECIAL_SECTION_FINI_ARRAY },
{ "proc", dot_proc, 0 },
{ "body", dot_body, 0 },
{ "prologue", dot_prologue, 0 },
@@ -4677,6 +4822,15 @@ const pseudo_typeS md_pseudo_table[] =
{ "explicit", dot_dv_mode, 'e' },
{ "default", dot_dv_mode, 'd' },
+ /* ??? These are needed to make gas/testsuite/gas/elf/ehopt.s work.
+ IA-64 aligns data allocation pseudo-ops by default, so we have to
+ tell it that these ones are supposed to be unaligned. Long term,
+ should rewrite so that only IA-64 specific data allocation pseudo-ops
+ are aligned by default. */
+ {"2byte", stmt_cons_ua, 2},
+ {"4byte", stmt_cons_ua, 4},
+ {"8byte", stmt_cons_ua, 8},
+
{ NULL, 0, 0 }
};
@@ -4693,6 +4847,7 @@ pseudo_opcode[] =
{ "data2", cons, 2 },
{ "data4", cons, 4 },
{ "data8", cons, 8 },
+ { "data16", cons, 16 },
{ "real4", stmt_float_cons, 'f' },
{ "real8", stmt_float_cons, 'd' },
{ "real10", stmt_float_cons, 'x' },
@@ -4703,6 +4858,7 @@ pseudo_opcode[] =
{ "data2.ua", stmt_cons_ua, 2 },
{ "data4.ua", stmt_cons_ua, 4 },
{ "data8.ua", stmt_cons_ua, 8 },
+ { "data16.ua", stmt_cons_ua, 16 },
{ "real4.ua", float_cons, 'f' },
{ "real8.ua", float_cons, 'd' },
{ "real10.ua", float_cons, 'x' },
@@ -5256,7 +5412,10 @@ operand_match (idesc, index, e)
case O_symbol:
fix = CURR_SLOT.fixup + CURR_SLOT.num_fixups;
- fix->code = ia64_gen_real_reloc_type (e->X_op_symbol, 0);
+ /* There are no external relocs for TAG13/TAG13b fields, so we
+ create a dummy reloc. This will not live past md_apply_fix3. */
+ fix->code = BFD_RELOC_UNUSED;
+ fix->code = ia64_gen_real_reloc_type (e->X_op_symbol, fix->code);
fix->opnd = idesc->operands[index];
fix->expr = *e;
fix->is_pcrel = 1;
@@ -6058,6 +6217,7 @@ md_parse_option (c, arg)
int c;
char *arg;
{
+
switch (c)
{
/* Switches from the Intel assembler. */
@@ -6184,6 +6344,13 @@ IA-64 options:\n\
stream);
}
+void
+ia64_after_parse_args ()
+{
+ if (debug_type == DEBUG_STABS)
+ as_fatal (_("--gstabs is not supported for ia64"));
+}
+
/* Return true if TYPE fits in TEMPL at SLOT. */
static int
@@ -6274,6 +6441,10 @@ md_begin ()
symbol_new (".<ltoff.fptr>", undefined_section, FUNC_LT_FPTR_RELATIVE,
&zero_address_frag);
+ pseudo_func[FUNC_IPLT_RELOC].u.sym =
+ symbol_new (".<iplt>", undefined_section, FUNC_IPLT_RELOC,
+ &zero_address_frag);
+
/* Compute the table of best templates. We compute goodness as a
base 4 value, in which each match counts for 3, each F counts
for 2, each B counts for 1. This should maximize the number of
@@ -6446,6 +6617,19 @@ md_begin ()
if (! ok)
as_warn (_("Could not set architecture and machine"));
+ /* Set the pointer size and pointer shift size depending on md.flags */
+
+ if (md.flags & EF_IA_64_ABI64)
+ {
+ md.pointer_size = 8; /* pointers are 8 bytes */
+ md.pointer_size_shift = 3; /* alignment is 8 bytes = 2^2 */
+ }
+ else
+ {
+ md.pointer_size = 4; /* pointers are 4 bytes */
+ md.pointer_size_shift = 2; /* alignment is 4 bytes = 2^2 */
+ }
+
md.mem_offset.hint = 0;
md.path = 0;
md.maxpaths = 0;
@@ -6462,9 +6646,7 @@ ia64_init (argc, argv)
int argc ATTRIBUTE_UNUSED;
char **argv ATTRIBUTE_UNUSED;
{
- md.flags = EF_IA_64_ABI64;
- if (TARGET_BYTES_BIG_ENDIAN)
- md.flags |= EF_IA_64_BE;
+ md.flags = MD_FLAGS_DEFAULT;
}
/* Return a string for the target object file format. */
@@ -6477,16 +6659,36 @@ ia64_target_format ()
if (md.flags & EF_IA_64_BE)
{
if (md.flags & EF_IA_64_ABI64)
+#if defined(TE_AIX50)
+ return "elf64-ia64-aix-big";
+#elif defined(TE_HPUX)
+ return "elf64-ia64-hpux-big";
+#else
return "elf64-ia64-big";
+#endif
else
+#if defined(TE_AIX50)
+ return "elf32-ia64-aix-big";
+#elif defined(TE_HPUX)
+ return "elf32-ia64-hpux-big";
+#else
return "elf32-ia64-big";
+#endif
}
else
{
if (md.flags & EF_IA_64_ABI64)
+#ifdef TE_AIX50
+ return "elf64-ia64-aix-little";
+#else
return "elf64-ia64-little";
+#endif
else
+#ifdef TE_AIX50
+ return "elf32-ia64-aix-little";
+#else
return "elf32-ia64-little";
+#endif
}
}
else
@@ -6621,10 +6823,10 @@ ia64_unrecognized_line (ch)
c = get_symbol_end ();
}
else if (LOCAL_LABELS_FB
- && isdigit ((unsigned char) *input_line_pointer))
+ && ISDIGIT (*input_line_pointer))
{
temp = 0;
- while (isdigit ((unsigned char) *input_line_pointer))
+ while (ISDIGIT (*input_line_pointer))
temp = (temp * 10) + *input_line_pointer++ - '0';
fb_label_instance_inc (temp);
s = fb_label_name (temp, 0);
@@ -6797,7 +6999,7 @@ ia64_parse_name (name, e)
switch (name[0])
{
case 'i':
- if (name[1] == 'n' && isdigit (name[2]))
+ if (name[1] == 'n' && ISDIGIT (name[2]))
{
dr = &md.in;
name += 2;
@@ -6805,7 +7007,7 @@ ia64_parse_name (name, e)
break;
case 'l':
- if (name[1] == 'o' && name[2] == 'c' && isdigit (name[3]))
+ if (name[1] == 'o' && name[2] == 'c' && ISDIGIT (name[3]))
{
dr = &md.loc;
name += 3;
@@ -6813,7 +7015,7 @@ ia64_parse_name (name, e)
break;
case 'o':
- if (name[1] == 'u' && name[2] == 't' && isdigit (name[3]))
+ if (name[1] == 'u' && name[2] == 't' && ISDIGIT (name[3]))
{
dr = &md.out;
name += 3;
@@ -6870,19 +7072,29 @@ ia64_canonicalize_symbol_name (name)
return name;
}
-/* Return true if idesc is a conditional branch instruction. */
+/* Return true if idesc is a conditional branch instruction. This excludes
+ the modulo scheduled branches, and br.ia. Mod-sched branches are excluded
+ because they always read/write resources regardless of the value of the
+ qualifying predicate. br.ia must always use p0, and hence is always
+ taken. Thus this function returns true for branches which can fall
+ through, and which use no resources if they do fall through. */
static int
is_conditional_branch (idesc)
struct ia64_opcode *idesc;
{
/* br is a conditional branch. Everything that starts with br. except
- br.ia is a conditional branch. Everything that starts with brl is a
- conditional branch. */
+ br.ia, br.c{loop,top,exit}, and br.w{top,exit} is a conditional branch.
+ Everything that starts with brl is a conditional branch. */
return (idesc->name[0] == 'b' && idesc->name[1] == 'r'
&& (idesc->name[2] == '\0'
- || (idesc->name[2] == '.' && idesc->name[3] != 'i')
- || idesc->name[2] == 'l'));
+ || (idesc->name[2] == '.' && idesc->name[3] != 'i'
+ && idesc->name[3] != 'c' && idesc->name[3] != 'w')
+ || idesc->name[2] == 'l'
+ /* br.cond, br.call, br.clr */
+ || (idesc->name[2] == '.' && idesc->name[3] == 'c'
+ && (idesc->name[4] == 'a' || idesc->name[4] == 'o'
+ || (idesc->name[4] == 'l' && idesc->name[5] == 'r')))));
}
/* Return whether the given opcode is a taken branch. If there's any doubt,
@@ -7616,8 +7828,8 @@ dep->name, idesc->name, (rsrc_write?"write":"read"), note)
{
int p1 = CURR_SLOT.opnd[0].X_add_number - REG_P;
int p2 = CURR_SLOT.opnd[1].X_add_number - REG_P;
- int or_andcm = strstr(idesc->name, "or.andcm") != NULL;
- int and_orcm = strstr(idesc->name, "and.orcm") != NULL;
+ int or_andcm = strstr (idesc->name, "or.andcm") != NULL;
+ int and_orcm = strstr (idesc->name, "and.orcm") != NULL;
if ((idesc->operands[0] == IA64_OPND_P1
|| idesc->operands[0] == IA64_OPND_P2)
@@ -7738,8 +7950,8 @@ dep->name, idesc->name, (rsrc_write?"write":"read"), note)
{
int p1 = CURR_SLOT.opnd[0].X_add_number - REG_P;
int p2 = CURR_SLOT.opnd[1].X_add_number - REG_P;
- int or_andcm = strstr(idesc->name, "or.andcm") != NULL;
- int and_orcm = strstr(idesc->name, "and.orcm") != NULL;
+ int or_andcm = strstr (idesc->name, "or.andcm") != NULL;
+ int and_orcm = strstr (idesc->name, "and.orcm") != NULL;
if ((idesc->operands[0] == IA64_OPND_P1
|| idesc->operands[0] == IA64_OPND_P2)
@@ -8201,8 +8413,8 @@ dep->name, idesc->name, (rsrc_write?"write":"read"), note)
{
int p1 = CURR_SLOT.opnd[0].X_add_number - REG_P;
int p2 = CURR_SLOT.opnd[1].X_add_number - REG_P;
- int or_andcm = strstr(idesc->name, "or.andcm") != NULL;
- int and_orcm = strstr(idesc->name, "and.orcm") != NULL;
+ int or_andcm = strstr (idesc->name, "or.andcm") != NULL;
+ int and_orcm = strstr (idesc->name, "and.orcm") != NULL;
if (p1 == 63
&& (idesc->operands[0] == IA64_OPND_P1
@@ -8453,6 +8665,19 @@ add_qp_mutex (mask)
qp_mutexes[qp_mutexeslen++].prmask = mask;
}
+static int
+has_suffix_p (name, suffix)
+ const char *name;
+ const char *suffix;
+{
+ size_t namelen = strlen (name);
+ size_t sufflen = strlen (suffix);
+
+ if (namelen <= sufflen)
+ return 0;
+ return strcmp (name + namelen - sufflen, suffix) == 0;
+}
+
static void
clear_register_values ()
{
@@ -8570,21 +8795,19 @@ note_register_values (idesc)
}
/* In general, clear mutexes and implies which include P1 or P2,
with the following exceptions. */
- else if (strstr (idesc->name, ".or.andcm") != NULL)
+ else if (has_suffix_p (idesc->name, ".or.andcm")
+ || has_suffix_p (idesc->name, ".and.orcm"))
{
add_qp_mutex (p1mask | p2mask);
clear_qp_implies (p2mask, p1mask);
}
- else if (strstr (idesc->name, ".and.orcm") != NULL)
- {
- add_qp_mutex (p1mask | p2mask);
- clear_qp_implies (p1mask, p2mask);
- }
- else if (strstr (idesc->name, ".and") != NULL)
+ else if (has_suffix_p (idesc->name, ".andcm")
+ || has_suffix_p (idesc->name, ".and"))
{
clear_qp_implies (0, p1mask | p2mask);
}
- else if (strstr (idesc->name, ".or") != NULL)
+ else if (has_suffix_p (idesc->name, ".orcm")
+ || has_suffix_p (idesc->name, ".or"))
{
clear_qp_mutex (p1mask | p2mask);
clear_qp_implies (p1mask | p2mask, 0);
@@ -8592,7 +8815,7 @@ note_register_values (idesc)
else
{
clear_qp_implies (p1mask | p2mask, p1mask | p2mask);
- if (strstr (idesc->name, ".unc") != NULL)
+ if (has_suffix_p (idesc->name, ".unc"))
{
add_qp_mutex (p1mask | p2mask);
if (CURR_SLOT.qp_regno != 0)
@@ -9680,6 +9903,21 @@ ia64_cons_fix_new (f, where, nbytes, exp)
code = BFD_RELOC_IA64_DIR64LSB;
break;
+ case 16:
+ if (exp->X_op == O_pseudo_fixup
+ && exp->X_op_symbol
+ && S_GET_VALUE (exp->X_op_symbol) == FUNC_IPLT_RELOC)
+ {
+ if (target_big_endian)
+ code = BFD_RELOC_IA64_IPLTMSB;
+ else
+ code = BFD_RELOC_IA64_IPLTLSB;
+
+ exp->X_op = O_symbol;
+ break;
+ }
+ /* FALLTHRU */
+
default:
as_bad ("Unsupported fixup size %d", nbytes);
ignore_rest_of_line ();
@@ -9691,10 +9929,11 @@ ia64_cons_fix_new (f, where, nbytes, exp)
exp->X_op = O_symbol;
code = ia64_gen_real_reloc_type (exp->X_op_symbol, code);
}
+
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_fix(). */
+ relocs available). See md_apply_fix3(). */
fix->tc_fix_data.bigendian = target_big_endian;
}
@@ -9818,6 +10057,10 @@ ia64_gen_real_reloc_type (sym, r_type)
break;
}
break;
+
+ case FUNC_IPLT_RELOC:
+ break;
+
default:
abort ();
}
@@ -9916,14 +10159,15 @@ fix_insn (fix, odesc, value)
If fixp->fx_addsy is non-NULL, we'll have to generate a reloc entry
(if possible). */
-int
-md_apply_fix3 (fix, valuep, seg)
+
+void
+md_apply_fix3 (fix, valP, seg)
fixS *fix;
- valueT *valuep;
+ valueT * valP;
segT seg ATTRIBUTE_UNUSED;
{
char *fixpos;
- valueT value = *valuep;
+ valueT value = * valP;
int adjust = 0;
fixpos = fix->fx_frag->fr_literal + fix->fx_where;
@@ -9958,16 +10202,15 @@ md_apply_fix3 (fix, valuep, seg)
}
if (fix->fx_addsy)
{
- switch (fix->fx_r_type)
+ if (fix->fx_r_type == (int) BFD_RELOC_UNUSED)
{
- case 0:
+ /* This must be a TAG13 or TAG13b operand. There are no external
+ relocs defined for them, so we must give an error. */
as_bad_where (fix->fx_file, fix->fx_line,
"%s must have a constant value",
elf64_ia64_operands[fix->tc_fix_data.opnd].desc);
- break;
-
- default:
- break;
+ fix->fx_done = 1;
+ return;
}
/* ??? This is a hack copied from tc-i386.c to make PCREL relocs
@@ -9982,15 +10225,12 @@ md_apply_fix3 (fix, valuep, seg)
else
number_to_chars_littleendian (fixpos, value, fix->fx_size);
fix->fx_done = 1;
- return 1;
}
else
{
fix_insn (fix, elf64_ia64_operands + fix->tc_fix_data.opnd, value);
fix->fx_done = 1;
- return 1;
}
- return 1;
}
/* Generate the BFD reloc to be stuck in the object file from the
OpenPOWER on IntegriCloud