X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-ia64.c;h=647724bed6ca6d05e7f32b3dd17a4230ae7f5cbe;hb=012a452b43b77eaf0f0f8a48192561702beea958;hp=875f4fd86fd33b60c785f9c4418270b9d13b2bf7;hpb=6174d9c85e9c00fcbf75f23e81064d2bcadb6d10;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-ia64.c b/gas/config/tc-ia64.c index 875f4fd86f..647724bed6 100644 --- a/gas/config/tc-ia64.c +++ b/gas/config/tc-ia64.c @@ -24,7 +24,6 @@ - optional operands - directives: - .alias .eb .estate .lb @@ -156,6 +155,20 @@ struct label_fix 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)); + +static struct hash_control *alias_hash; +static struct hash_control *alias_name_hash; +static struct hash_control *secalias_hash; +static struct hash_control *secalias_name_hash; + /* Characters which always start a comment. */ const char comment_chars[] = ""; @@ -525,9 +538,13 @@ pseudo_func[] = { "pause", PSEUDO_FUNC_CONST, { 0x0 } }, /* unwind-related constants: */ - { "svr4", PSEUDO_FUNC_CONST, { 0 } }, - { "hpux", PSEUDO_FUNC_CONST, { 1 } }, - { "nt", PSEUDO_FUNC_CONST, { 2 } }, + { "svr4", PSEUDO_FUNC_CONST, { ELFOSABI_NONE } }, + { "hpux", PSEUDO_FUNC_CONST, { ELFOSABI_HPUX } }, + { "nt", PSEUDO_FUNC_CONST, { 2 } }, /* conflicts w/ELFOSABI_NETBSD */ + { "linux", PSEUDO_FUNC_CONST, { ELFOSABI_LINUX } }, + { "freebsd", PSEUDO_FUNC_CONST, { ELFOSABI_FREEBSD } }, + { "openvms", PSEUDO_FUNC_CONST, { ELFOSABI_OPENVMS } }, + { "nsk", PSEUDO_FUNC_CONST, { ELFOSABI_NSK } }, /* unwind-related registers: */ { "priunat",PSEUDO_FUNC_REG, { REG_PRIUNAT } } @@ -959,9 +976,11 @@ ia64_elf_section_letter (letter, ptr_msg) { 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. */ @@ -995,6 +1014,9 @@ ia64_elf_section_type (str, len) 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; @@ -3261,14 +3283,14 @@ generate_unwind_image (text_name) 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); @@ -4308,7 +4330,32 @@ static void 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 @@ -4344,13 +4391,6 @@ dot_psr (dummy) demand_empty_rest_of_line (); } -static void -dot_alias (dummy) - int dummy ATTRIBUTE_UNUSED; -{ - as_bad (".alias not implemented yet"); -} - static void dot_ln (dummy) int dummy ATTRIBUTE_UNUSED; @@ -4410,19 +4450,25 @@ 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); } @@ -4832,8 +4878,6 @@ const pseudo_typeS md_pseudo_table[] = { "body", dot_body, 0 }, { "prologue", dot_prologue, 0 }, { "endp", dot_endp, 0 }, - { "file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0 }, - { "loc", dwarf2_directive_loc, 0 }, { "fframe", dot_fframe, 0 }, { "vframe", dot_vframe, 0 }, @@ -4890,6 +4934,7 @@ const pseudo_typeS md_pseudo_table[] = { "msb", dot_byteorder, 1 }, { "psr", dot_psr, 0 }, { "alias", dot_alias, 0 }, + { "secalias", dot_alias, 1 }, { "ln", dot_ln, 0 }, /* source line info (for debugging) */ { "xdata1", dot_xdata, 1 }, @@ -4899,6 +4944,7 @@ const pseudo_typeS md_pseudo_table[] = { "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 }, @@ -4909,6 +4955,7 @@ const pseudo_typeS md_pseudo_table[] = { "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 }, @@ -4952,6 +4999,7 @@ pseudo_opcode[] = { "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 }, @@ -4963,6 +5011,7 @@ pseudo_opcode[] = { "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 @@ -6525,7 +6574,15 @@ md_begin () 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); + + alias_hash = hash_new (); + alias_name_hash = hash_new (); + secalias_hash = hash_new (); + secalias_name_hash = hash_new (); + pseudo_func[FUNC_DTP_MODULE].u.sym = symbol_new (".", undefined_section, FUNC_DTP_MODULE, &zero_address_frag); @@ -8669,6 +8726,77 @@ clear_qp_branch_flag (mask) } } +/* MASK contains 2 and only 2 PRs which are mutually exclusive. Remove + any mutexes which contain one of the PRs and create new ones when + needed. */ + +static int +update_qp_mutex (valueT mask) +{ + int i; + int add = 0; + + i = 0; + while (i < qp_mutexeslen) + { + if ((qp_mutexes[i].prmask & mask) != 0) + { + /* If it destroys and creates the same mutex, do nothing. */ + if (qp_mutexes[i].prmask == mask + && qp_mutexes[i].path == md.path) + { + i++; + add = -1; + } + else + { + int keep = 0; + + if (md.debug_dv) + { + fprintf (stderr, " Clearing mutex relation"); + 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. + + FIXME: The 3+ mutex support is incomplete. + dot_pred_rel () may be a better place to fix it. */ + if (qp_mutexes[i].path == md.path) + { + /* If it is a proper subset of the mutex, create a + new mutex. */ + 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)) + { + /* Modify the mutex if there are more than one + PR left. */ + keep = 1; + i++; + } + } + + if (keep == 0) + /* Remove the mutex. */ + qp_mutexes[i] = qp_mutexes[--qp_mutexeslen]; + } + } + else + ++i; + } + + if (add == 1) + add_qp_mutex (mask); + + return add; +} + /* Remove any mutexes which contain any of the PRs indicated in the mask. Any changes to a PR clears the mutex relations which include that PR. */ @@ -8883,7 +9011,7 @@ note_register_values (idesc) else if (idesc->operands[i] == IA64_OPND_PR_ROT) { if (idesc->operands[1] & ((valueT) 1 << 43)) - qp_changemask = ~(valueT) 0xFFFFFFFFFFF | idesc->operands[1]; + qp_changemask = -((valueT) 1 << 44) | idesc->operands[1]; else qp_changemask = idesc->operands[1]; qp_changemask &= ~(valueT) 0xFFFF; @@ -8933,11 +9061,11 @@ note_register_values (idesc) { int p1 = CURR_SLOT.opnd[0].X_add_number - REG_P; int p2 = CURR_SLOT.opnd[1].X_add_number - REG_P; - valueT p1mask = (valueT) 1 << p1; - valueT p2mask = (valueT) 1 << p2; + valueT p1mask = (p1 != 0) ? (valueT) 1 << p1 : 0; + valueT p2mask = (p2 != 0) ? (valueT) 1 << p2 : 0; - /* If one of the PRs is PR0, we can't really do anything. */ - if (p1 == 0 || p2 == 0) + /* If both PRs are PR0, we can't really do anything. */ + if (p1 == 0 && p2 == 0) { if (md.debug_dv) fprintf (stderr, " Ignoring PRs due to inclusion of p0\n"); @@ -8947,7 +9075,6 @@ note_register_values (idesc) 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 (has_suffix_p (idesc->name, ".andcm") @@ -8963,26 +9090,29 @@ note_register_values (idesc) } else { + int added = 0; + clear_qp_implies (p1mask | p2mask, p1mask | p2mask); - if (has_suffix_p (idesc->name, ".unc")) + + /* If one of the PRs is PR0, we call clear_qp_mutex. */ + if (p1 == 0 || p2 == 0) + clear_qp_mutex (p1mask | p2mask); + else + added = update_qp_mutex (p1mask | p2mask); + + if (CURR_SLOT.qp_regno == 0 + || has_suffix_p (idesc->name, ".unc")) { - add_qp_mutex (p1mask | p2mask); + if (added == 0 && p1 && p2) + add_qp_mutex (p1mask | p2mask); if (CURR_SLOT.qp_regno != 0) { - add_qp_imply (CURR_SLOT.opnd[0].X_add_number - REG_P, - CURR_SLOT.qp_regno); - add_qp_imply (CURR_SLOT.opnd[1].X_add_number - REG_P, - CURR_SLOT.qp_regno); + if (p1) + add_qp_imply (p1, CURR_SLOT.qp_regno); + if (p2) + add_qp_imply (p2, CURR_SLOT.qp_regno); } } - else if (CURR_SLOT.qp_regno == 0) - { - add_qp_mutex (p1mask | p2mask); - } - else - { - clear_qp_mutex (p1mask | p2mask); - } } } /* Look for mov imm insns into GRs. */ @@ -10544,7 +10674,6 @@ md_atof (type, lit, size) int *size; { LITTLENUM_TYPE words[MAX_LITTLENUMS]; - LITTLENUM_TYPE *word; char *t; int prec; @@ -10579,26 +10708,19 @@ md_atof (type, lit, size) 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. */ @@ -10622,9 +10744,6 @@ ia64_handle_align (fragp) fragS *fragp; { /* Use mfi bundle of nops with no stop bits. */ - static const unsigned char be_nop[] - = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c}; static const unsigned char le_nop[] = { 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00}; @@ -10649,6 +10768,214 @@ ia64_handle_align (fragp) fragp->fr_fix += fix; } - memcpy (p, (target_big_endian ? be_nop : le_nop), 16); + /* Instruction bundles are always little-endian. */ + memcpy (p, 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++; + } +} + +/* Used to remember where .alias and .secalias directives are seen. We + will rename symbol and section names when we are about to output + the relocatable file. */ +struct alias +{ + char *file; /* The file where the directive is seen. */ + unsigned int line; /* The line number the directive is at. */ + const char *name; /* The orignale name of the symbol. */ +}; + +/* Called for .alias and .secalias directives. If SECTION is 1, it is + .secalias. Otherwise, it is .alias. */ +static void +dot_alias (int section) +{ + char *name, *alias; + char delim; + char *end_name; + int len; + const char *error_string; + struct alias *h; + const char *a; + struct hash_control *ahash, *nhash; + const char *kind; + + name = input_line_pointer; + delim = get_symbol_end (); + end_name = input_line_pointer; + *end_name = delim; + + if (name == end_name) + { + as_bad (_("expected symbol name")); + discard_rest_of_line (); + return; + } + + SKIP_WHITESPACE (); + + if (*input_line_pointer != ',') + { + *end_name = 0; + as_bad (_("expected comma after \"%s\""), name); + *end_name = delim; + ignore_rest_of_line (); + return; + } + + input_line_pointer++; + *end_name = 0; + + /* We call demand_copy_C_string to check if alias string is valid. + There should be a closing `"' and no `\0' in the string. */ + alias = demand_copy_C_string (&len); + if (alias == NULL) + { + ignore_rest_of_line (); + return; + } + + /* Make a copy of name string. */ + len = strlen (name) + 1; + obstack_grow (¬es, name, len); + name = obstack_finish (¬es); + + if (section) + { + kind = "section"; + ahash = secalias_hash; + nhash = secalias_name_hash; + } + else + { + kind = "symbol"; + ahash = alias_hash; + nhash = alias_name_hash; + } + + /* Check if alias has been used before. */ + h = (struct alias *) hash_find (ahash, alias); + if (h) + { + if (strcmp (h->name, name)) + as_bad (_("`%s' is already the alias of %s `%s'"), + alias, kind, h->name); + goto out; + } + + /* Check if name already has an alias. */ + a = (const char *) hash_find (nhash, name); + if (a) + { + if (strcmp (a, alias)) + as_bad (_("%s `%s' already has an alias `%s'"), kind, name, a); + goto out; + } + + h = (struct alias *) xmalloc (sizeof (struct alias)); + as_where (&h->file, &h->line); + h->name = name; + + error_string = hash_jam (ahash, alias, (PTR) h); + if (error_string) + { + as_fatal (_("inserting \"%s\" into %s alias hash table failed: %s"), + alias, kind, error_string); + goto out; + } + + error_string = hash_jam (nhash, name, (PTR) alias); + if (error_string) + { + as_fatal (_("inserting \"%s\" into %s name hash table failed: %s"), + alias, kind, error_string); +out: + obstack_free (¬es, name); + obstack_free (¬es, alias); + } + + demand_empty_rest_of_line (); +} + +/* It renames the original symbol name to its alias. */ +static void +do_alias (const char *alias, PTR value) +{ + struct alias *h = (struct alias *) value; + symbolS *sym = symbol_find (h->name); + + if (sym == NULL) + as_warn_where (h->file, h->line, + _("symbol `%s' aliased to `%s' is not used"), + h->name, alias); + else + S_SET_NAME (sym, (char *) alias); +} + +/* Called from write_object_file. */ +void +ia64_adjust_symtab (void) +{ + hash_traverse (alias_hash, do_alias); +} + +/* It renames the original section name to its alias. */ +static void +do_secalias (const char *alias, PTR value) +{ + struct alias *h = (struct alias *) value; + segT sec = bfd_get_section_by_name (stdoutput, h->name); + + if (sec == NULL) + as_warn_where (h->file, h->line, + _("section `%s' aliased to `%s' is not used"), + h->name, alias); + else + sec->name = alias; +} + +/* Called from write_object_file. */ +void +ia64_frob_file (void) +{ + hash_traverse (secalias_hash, do_secalias); +}