diff options
-rw-r--r-- | gas/ChangeLog | 106 | ||||
-rw-r--r-- | gas/as.c | 4 | ||||
-rw-r--r-- | gas/config/obj-evax.c | 450 | ||||
-rw-r--r-- | gas/config/obj-evax.h | 34 | ||||
-rw-r--r-- | gas/config/tc-alpha.c | 1083 | ||||
-rw-r--r-- | gas/config/tc-alpha.h | 10 | ||||
-rw-r--r-- | gas/doc/as.texinfo | 1 | ||||
-rw-r--r-- | gas/doc/c-alpha.texi | 9 | ||||
-rw-r--r-- | gas/dwarf2dbg.c | 6 |
9 files changed, 1487 insertions, 216 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index 7bd0ec2..d90b214 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,109 @@ +2009-03-03 Tristan Gingold <gingold@adacore.com> + Eric Botcazou <ebotcazou@adacore.com> + Douglas B Rupp <rupp@gnat.com> + + * doc/as.texinfo (Overview): Mention -replace/-noreplace options + for Alpha. + * doc/c-alpha.texi (Alpha Options): Document -replace/-noreplace. + * config/tc-alpha.h (TC_VALIDATE_FIX_SUB): Define to 1 (evax). + (OBJ_SYMFIELD_TYPE): Remove. + (tc_canonicalize_symbol_name): Define to evax_shorten_name. + (TC_IMPLICIT_LCOMM_ALIGNMENT): For alignment to 3 on evax. + (tc_frob_file_before_fix): Do not defined on evax. + * config/tc-alpha.c: Always includes dwarf2dbg.h. + Include vms.h if OBJ_EVAX. + (struct alpha_fixup): Add xtrasym and procsym (evax only). + (enum alpha_macro_arg): Remove trailing comma. + (md_longopts): Add replace and noreplace arguments (evax only). + (alpha_evax_proc_hash): New variable. + (alpha_link_section): Make it global. + (alpha_ctors_section, alpha_dtors_section): Removed. + (alpha_ctors_symbol, alpha_dtors_symbol): Ditto. + (alpha_lit8_section): Ifndef'ed on evax. + (alpha_lit8_symbol): Ditto. + (alpha_prologue_label): New variable. + (alpha_linkage_symbol): New variable (evax only). + (alpha_flag_replace): Ditto. + (struct alpha_evax_procs): Add handler and handler_data field. + (alpha_evax_proc): Now of type pointer. + (alpha_linkage_fixup_root, alpha_linkage_fixup_tail): New variables. + (struct alpha_reloc_tag): Add sym and psym fields (evax only). + (get_alpha_reloc_tag): Initialize sym and psym fields (evax only). + (alpha_adjust_relocs): Ifndef'ed on evax. + (load_expression): Add opname argument. + Implement LDA/BSR optimization for evax. + (emit_lda): Adjust for new prototype of load_expression. + (emit_ir_load): Ditto. Do not nothing for GP if ..lk symbols. + (emit_loadstore): Likewise. + (emit_ldXu): Likewise. + (emit_stX): Likewise. + (emit_jsrjmp): Likewise. Implement LDA/BSR optimization for evax. + (emit_ldgp): Avoid warning in evax case. + (add_to_link_pool): Make it static. Return symbolic expression rather + than number expression for the offset. + (s_alpha_text): Create .text symbol for evax if not already created. + (s_alpha_comm): Do not create specific section for common symbol. + Fill common area with zeros for evax. + (s_alpha_prologue): Create alpha_prologue_label. + (s_alpha_section_name): New function (evax). + (s_alpha_section_word): Likewise. + (section_name): New static variabke moved out from ... + (s_alpha_section): ... here. Create new sections on demand. + (s_alpha_literals): New function (evax). + (s_alpha_ent): Create alpha_evax_proc instance and insert it in the + alpha_evax_proc_hash table. + (s_alpha_handler): New function (evax). + (s_alpha_frame): Adjust for new type of alpha_evax_proc. + (s_alpha_prologue): New function (evax). + (s_alpha_pdesc): Adjust for new type of alpha_evax_proc and new + handling of procedures with hash table. + Add support for condition handlers. + (s_alpha_linkage): Create linkage_fixup instance and chain it. + (s_alpha_fp_save): Adjust for new type of alpha_evax_proc. + (s_alpha_mask): Likewise. + (s_alpha_fmask): Likewise. + (s_alpha_end): Clear alpha_evax_proc. + (s_alpha_align): Increase max_alignment to 16. + (alpha_print_token): Call print_expr_1 instead of print_expr. + (md_pseudo_table): Add "section", "literals", "handler" and + "handler_data" (evax). Do not ignore "prologue" on evax. + Fix indentation. + (md_begin): Create hash table for alpha_evax_proc_hash. + (md_parse_option): Handle OPTION_REPLACE and OPTION_NOREPLACE. + (md_show_usage): Mention -replace/-noreplace for evax. + (md_apply_fix): Handle evax relocs (_NOP, _LDA, _BSR and _BOH). + (alpha_force_relocation): Likewise. + (alpha_fix_adjustable): Likewise. Add BFD_RELOC_16 case. + (tc_gen_reloc): Likewise. Add BFD_RELOC_ALPHA_LINKAGE for evax. + (emit_insn): New cases for evax specific relocs. + (assemble_insn): Fix indentation. + Take care of -MDISP in operand table. + * config/obj-evax.h (struct alpha_linkage_fixups): New struct. + (OBJ_SYMFIELD_TYPE): New macro. + (obj_symbol_new_hook): Define. + (obj_frob_symbol, obj_frob_file_before_adjust): Ditto. + (obj_frob_file_before_fix): Ditto. + (PDSC_S_M_HANDLER_VALID): New macro. + (PDSC_S_M_HANDLER_DATA_VALID): Ditto. + (TC_IMPLICIT_LCOMM_ALIGNMENT): Remove. + Add prototypes for functions declared in obj-evax.c + * config/obj-evax.c: Include subsegs.h, struc-symbol.h, safe-ctype.h. + (s_evax_weak): Convert to ansi-C. + (evax_symbol_new_hook): New function. + (evax_frob_symbol): Ditto. + (evax_frob_file_before_adjust): Ditto. + (evax_frob_file_before_fix): Ditto. + (evax_shorten_name): Ditto. + (crc32): Ditto. + (encode_32): Ditto. + (encode_16): Ditto. + (decode_16): Ditto. + (shorten_identifier): Ditto. + (is_truncated_identifier): Ditto. + * dwarf2dbg.c (out_debug_info): Do not append trailing slash on VMS. + * as.c (close_output_file): Remove #ifndef OBJ_VMS. + (main): Ditto. + 2009-03-02 Nick Clifton <nickc@redhat.com> PR 9874 @@ -948,13 +948,11 @@ dump_statistics (void) #endif } -#ifndef OBJ_VMS static void close_output_file (void) { output_file_close (out_file_name); } -#endif /* The interface between the macro code and gas expression handling. */ @@ -1136,10 +1134,8 @@ main (int argc, char ** argv) input_scrub_begin (); expr_begin (); -#ifndef OBJ_VMS /* Does its own file handling. */ /* It has to be called after dump_statistics (). */ xatexit (close_output_file); -#endif if (flag_print_statistics) xatexit (dump_statistics); diff --git a/gas/config/obj-evax.c b/gas/config/obj-evax.c index a0cbae2..eb50283 100644 --- a/gas/config/obj-evax.c +++ b/gas/config/obj-evax.c @@ -2,6 +2,7 @@ Copyright 1996, 1997, 2007, 2008 Free Software Foundation, Inc. Contributed by Klaus Kämpf (kkaempf@progis.de) of proGIS Software, Aachen, Germany. + Extensively enhanced by Douglas Rupp of AdaCore. This file is part of GAS, the GNU Assembler @@ -22,9 +23,18 @@ #define OBJ_HEADER "obj-evax.h" +#include "bfd.h" +#include "vms.h" #include "as.h" +#include "subsegs.h" +#include "struc-symbol.h" +#include "safe-ctype.h" static void s_evax_weak (int); +static unsigned int crc32 (unsigned char *, int); +static char *encode_32 (unsigned int); +static char *encode_16 (unsigned int); +static int decode_16 (const char *); const pseudo_typeS obj_pseudo_table[] = { @@ -37,8 +47,7 @@ void obj_read_begin_hook () {} /* Handle the weak specific pseudo-op. */ static void -s_evax_weak (ignore) - int ignore; +s_evax_weak (int ignore ATTRIBUTE_UNUSED) { char *name; int c; @@ -73,11 +82,436 @@ s_evax_weak (ignore) demand_empty_rest_of_line (); } -/* - * Local Variables: - * comment-column: 0 - * fill-column: 131 - * End: - */ +void +evax_symbol_new_hook (symbolS *sym) +{ + struct evax_private_udata_struct *udata; + + udata = (struct evax_private_udata_struct *) + xmalloc (sizeof (struct evax_private_udata_struct)); + + udata->bsym = symbol_get_bfdsym (sym); + udata->enbsym = NULL; + udata->origname = xstrdup (S_GET_NAME (sym)); + udata->lkindex = 0; + symbol_get_bfdsym(sym)->udata.p = (PTR) udata; +} + +void +evax_frob_symbol (symbolS *sym, int *punt) +{ + const char *symname = S_GET_NAME (sym); + int symlen = strlen (symname); + asymbol *symbol = symbol_get_bfdsym (sym); + + if (symlen > 4 + && strcmp (symname + symlen - 4, "..en") == 0 + && S_GET_SEGMENT (sym) == undefined_section) + { + symbol_clear_used_in_reloc (sym); + *punt = 1; + } + + else if ((symbol->flags & BSF_GLOBAL) && (symbol->flags & BSF_FUNCTION)) + { + struct evax_private_udata_struct *udata + = (struct evax_private_udata_struct *)symbol->udata.p; + + /* Fix up equates of function definitions. */ + while (udata->enbsym == NULL) + { + /* ??? Equates have been resolved at this point so their + expression is O_constant; but they previously were + O_symbol and we hope the equated symbol is still there. */ + sym = symbol_get_value_expression (sym)->X_add_symbol; + if (sym == NULL) + abort (); + symbol = symbol_get_bfdsym (sym); + udata->enbsym + = ((struct evax_private_udata_struct *)symbol->udata.p)->enbsym; + } + } +} + +void +evax_frob_file_before_adjust (void) +{ + struct alpha_linkage_fixups *l; + segT current_section = now_seg; + int current_subsec = now_subseg; + segment_info_type *seginfo; + int linkage_index = 1; + + subseg_set (alpha_link_section, 0); + seginfo = seg_info (alpha_link_section); + + for (l = alpha_linkage_fixup_root; l != NULL; l = l->next) + { + if (S_GET_SEGMENT (l->fixp->fx_addsy) == alpha_link_section) + { + symbolS * entry_sym; + fixS *fixpentry, *fixppdesc, *fixtail; + + fixtail = seginfo->fix_tail; + + /* Replace the linkage with the local symbols */ + entry_sym = symbol_find + (((struct evax_private_udata_struct *)symbol_get_bfdsym (l->fixp->fx_addsy)->udata.p)->enbsym->name); + if (!entry_sym) + abort (); + fixpentry = fix_new (l->fixp->fx_frag, l->fixp->fx_where, 8, + entry_sym, l->fixp->fx_offset, 0, + BFD_RELOC_64); + fixppdesc = fix_new (l->fixp->fx_frag, l->fixp->fx_where+8, 8, + l->fixp->fx_addsy, l->fixp->fx_offset, 0, + BFD_RELOC_64); + l->fixp->fx_size = 0; + l->fixp->fx_done = 1; + + /* If not already at the tail, splice the new fixups into + the chain right after the one we are nulling out */ + if (fixtail != l->fixp) + { + fixppdesc->fx_next = l->fixp->fx_next; + l->fixp->fx_next = fixpentry; + fixtail->fx_next = 0; + seginfo->fix_tail = fixtail; + } + } + else + { + ((struct evax_private_udata_struct *) + symbol_get_bfdsym (l->label)->udata.p)->lkindex = linkage_index; + + l->fixp->fx_addnumber = linkage_index; + + linkage_index += 2; + } + } + + subseg_set (current_section, current_subsec); +} + +void +evax_frob_file_before_fix (void) +{ + /* Now that the fixups are done earlier, we need to transfer the values + into the BFD symbols before calling fix_segment (ideally should not + be done also later). */ + if (symbol_rootP) + { + symbolS *symp; + + /* Set the value into the BFD symbol. Up til now the value + has only been kept in the gas symbolS struct. */ + for (symp = symbol_rootP; symp; symp = symbol_next (symp)) + symbol_get_bfdsym (symp)->value = S_GET_VALUE (symp); + } +} + +/* The length is computed from the maximum allowable length of 64 less the + 4 character ..xx extension that must be preserved (removed before + krunching and appended back on afterwards). The $<nnn>.. prefix is + also removed and prepened back on, but doesn't enter into the length + computation because symbols with that prefix are always resolved + by the assembler and will never appear in the symbol table. At least + I hope that's true, TBD. */ +#define MAX_LABEL_LENGTH 60 + +static char *shorten_identifier (char *); +static int is_truncated_identifier (char *); + +char * +evax_shorten_name (char *id) +{ + int prefix_dotdot = 0; + char prefix [64]; + int len = strlen (id); + int suffix_dotdot = len; + char suffix [64]; + char *base_id; + + /* This test may be too conservative. */ + if (len <= MAX_LABEL_LENGTH) + return id; + + suffix [0] = 0; + prefix [0] = 0; + + /* Check for ..xx suffix and save it. */ + if (strncmp (&id[len-4], "..", 2) == 0) + { + suffix_dotdot = len - 4; + strncpy (suffix, &id[len-4], 4); + suffix [4] = 0; + } + + /* Check for $<nnn>.. prefix and save it. */ + if ((id[0] == '$') && ISDIGIT (id[1])) + { + int i; + + for (i=2; i < len; i++) + { + if (!ISDIGIT (id[i])) + { + if (id[i] == '.' && id [i+1] == '.') + { + prefix_dotdot = i+2; + strncpy (prefix, id, prefix_dotdot); + prefix [prefix_dotdot] = 0; + } + break; + } + } + } + + /* We only need worry about krunching the base symbol. */ + base_id = xmalloc (suffix_dotdot - prefix_dotdot + 1); + strncpy (base_id, &id[prefix_dotdot], suffix_dotdot - prefix_dotdot); + base_id [suffix_dotdot - prefix_dotdot] = 0; + + if (strlen (base_id) > MAX_LABEL_LENGTH) + { + char new_id [4096]; + char *return_id; + + strcpy (new_id, base_id); + + /* Shorten it. */ + strcpy (new_id, shorten_identifier (new_id)); + + /* Prepend back the prefix if there was one. */ + if (prefix_dotdot) + { + memmove (&new_id [prefix_dotdot], new_id, strlen (new_id) + 1); + strncpy (new_id, prefix, prefix_dotdot); + } + + /* Append back the suffix if there was one. */ + if (strlen (suffix)) + strcat (new_id, suffix); + + /* Save it on the heap and return. */ + return_id = xmalloc (strlen (new_id) + 1); + strcpy (return_id, new_id); + + return return_id; + } + else + return id; +} + +/* The code below implements a mechanism for truncating long + identifiers to an arbitrary length (set by MAX_LABEL_LENGTH). + + It attempts to make each truncated identifier unique by replacing + part of the identifier with an encoded 32-bit CRC and an associated + checksum (the checksum is used as a way to determine that the name + was truncated). + + Note that both a portion of the start and of the end of the + identifier may be kept. The macro ID_SUFFIX_LENGTH will return the + number of characters in the suffix of the identifier that should be + kept. + + The portion of the identifier that is going to be removed is + checksummed. The checksum is then encoded as a 5-character string, + the characters of which are then summed. This sum is then encoded + as a 3-character string. Finally, the original length of the + identifier is encoded as a 3-character string. + + These three strings are then concatenated together (along with an _h + which further designates that the name was truncated): + + "original_identifier"_haaaaabbbccc + + aaaaa = 32-bit CRC + bbb = length of original identifier + ccc = sum of 32-bit CRC characters + + The resulting identifier will be MAX_LABEL_LENGTH characters long. + + */ + + +/* Table used to convert an integer into a string. */ + +static const char codings[] = { + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '_'}; + +/* The number of codings in the above table. */ +static const int number_of_codings = sizeof (codings) / sizeof (char); + +/* Table used by decode_16 () to convert an encoded string back into + an integer. */ +static char decodings[256]; + +/* Table used by the crc32 function to calcuate the checksum. */ +static unsigned int crc32_table[256] = {0, 0}; + +/* Given a string in BUF, calculate a 32-bit CRC for it. + + This is used as a reasonably unique hash for the given string. */ + +static unsigned int +crc32 (unsigned char *buf, int len) +{ + unsigned int crc = 0xffffffff; + + if (! crc32_table[1]) + { + /* Initialize the CRC table and the decoding table. */ + int i, j; + unsigned int c; + + for (i = 0; i < 256; i++) + { + for (c = i << 24, j = 8; j > 0; --j) + c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1); + crc32_table[i] = c; + decodings[i] = 0; + } + for (i = 0; i < number_of_codings; i++) + decodings[codings[i] & 255] = i; + } + + while (len--) + { + crc = (crc << 8) ^ crc32_table[(crc >> 24) ^ *buf]; + buf++; + } + return crc; +} + +/* Encode the lower 32 bits of VALUE as a 5-character string. */ + +static char * +encode_32 (unsigned int value) +{ + static char res[6]; + int x; + + res[5] = 0; + for(x = 0; x < 5; x++) + { + res[x] = codings[value % number_of_codings]; + value = value / number_of_codings; + } + return res; +} + +/* Encode the lower 16 bits of VALUE as a 3-character string. */ + +static char * +encode_16 (unsigned int value) +{ + static char res[4]; + int x; + + res[3] = 0; + for(x = 0; x < 3; x++) + { + res[x] = codings[value % number_of_codings]; + value = value / number_of_codings; + } + return res; +} + +/* Convert the encoded string obtained from encode_16 () back into a + 16-bit integer. */ + +static int +decode_16 (const char *string) +{ + return decodings[(int) string[2]] * number_of_codings * number_of_codings + + decodings[(int) string[1]] * number_of_codings + + decodings[(int) string[0]]; +} + +/* ID_SUFFIX_LENGTH is used to determine how many characters in the + suffix of the identifier are to be preserved, if any. */ + +#ifndef ID_SUFFIX_LENGTH +#define ID_SUFFIX_LENGTH(ID) (0) +#endif + +/* Return a reasonably-unique version of NAME that is less than or + equal to MAX_LABEL_LENGTH characters long. The string returned from + this function may be a copy of NAME; the function will never + actually modify the contents of NAME. */ + +static char newname[MAX_LABEL_LENGTH + 1]; + +static char * +shorten_identifier (char *name) +{ + int crc, len, sum, x, final_len; + char *crc_chars; + int suffix_length = ID_SUFFIX_LENGTH (name); + + if ((len = strlen (name)) <= MAX_LABEL_LENGTH) + return name; + + final_len = MAX_LABEL_LENGTH - 2 - 5 - 3 - 3 - suffix_length; + crc = crc32 ((unsigned char *)name + final_len, + len - final_len - suffix_length); + crc_chars = encode_32 (crc); + sum = 0; + for (x = 0; x < 5; x++) + sum += crc_chars [x]; + strncpy (newname, name, final_len); + newname [MAX_LABEL_LENGTH] = 0; + /* Now append the suffix of the original identifier, if any. */ + if (suffix_length) + strncpy (newname + MAX_LABEL_LENGTH - suffix_length, + name + len - suffix_length, + suffix_length); + strncpy (newname + final_len, "_h", 2); + strncpy (newname + final_len + 2 , crc_chars, 5); + strncpy (newname + final_len + 2 + 5, encode_16 (len), 3); + strncpy (newname + final_len + 2 + 5 + 3, encode_16 (sum), 3); + if (!is_truncated_identifier (newname)) + abort (); + return newname; +} + +/* Determine whether or not ID is a truncated identifier, and return a + non-zero value if it is. */ + +static int +is_truncated_identifier (char *id) +{ + char *ptr; + int len = strlen (id); + /* If it's not exactly MAX_LABEL_LENGTH characters long, it can't be + a truncated identifier. */ + if (len != MAX_LABEL_LENGTH) + return 0; + + /* Start scanning backwards for a _h. */ + len = len - 3 - 3 - 5 - 2; + ptr = id + len; + while (ptr >= id) + { + if (ptr[0] == '_' && ptr[1] == 'h') + { + /* Now see if the sum encoded in the identifer matches. */ + int x, sum; + sum = 0; + for (x = 0; x < 5; x++) + sum += ptr[x + 2]; + /* If it matches, this is probably a truncated identifier. */ + if (sum == decode_16 (ptr + 5 + 2 + 3)) + return 1; + } + ptr--; + } + return 0; +} /* end of obj-evax.c */ diff --git a/gas/config/obj-evax.h b/gas/config/obj-evax.h index 824eeac..162d566 100644 --- a/gas/config/obj-evax.h +++ b/gas/config/obj-evax.h @@ -25,6 +25,8 @@ * object format specific header files. */ +#include "as.h" + /* define an obj specific macro off which target cpu back ends may key. */ #define OBJ_EVAX 1 @@ -33,6 +35,16 @@ #define OUTPUT_FLAVOR bfd_target_evax_flavour +struct fix; + +struct alpha_linkage_fixups +{ + struct alpha_linkage_fixups *next; + struct fix *fixp; + segT seg; + symbolS *label; +}; + /* * SYMBOLS */ @@ -58,7 +70,13 @@ typedef void *object_headers; #define OBJ_EMIT_LINENO(a,b,c) /* must be *something*. This no-op's it out. */ -#define obj_symbol_new_hook(s) {;} +/* This field keeps the symbols position in the link section. */ +#define OBJ_SYMFIELD_TYPE valueT + +#define obj_symbol_new_hook(s) evax_symbol_new_hook (s) +#define obj_frob_symbol(s,p) evax_frob_symbol (s, &p) +#define obj_frob_file_before_adjust evax_frob_file_before_adjust +#define obj_frob_file_before_fix evax_frob_file_before_fix #define S_SET_OTHER(S,V) #define S_SET_TYPE(S,T) @@ -75,13 +93,23 @@ typedef void *object_headers; #define PDSC_S_K_MIN_REGISTER_SIZE 24 #define PDSC_S_K_NULL_SIZE 16 -#define PDSC_S_M_BASE_REG_IS_FP 0x80 /* low byte */ +#define PDSC_S_M_HANDLER_VALID 0x10 /* low byte */ +#define PDSC_S_M_HANDLER_DATA_VALID 0x40 /* low byte */ +#define PDSC_S_M_BASE_REG_IS_FP 0x80 /* low byte */ #define PDSC_S_M_NATIVE 0x10 /* high byte */ #define PDSC_S_M_NO_JACKET 0x20 /* high byte */ #define LKP_S_K_SIZE 16 -#define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR) (P2VAR) = 3 +extern segT alpha_link_section; +extern struct alpha_linkage_fixups *alpha_linkage_fixup_root; + +extern void evax_section (int); +extern void evax_symbol_new_hook (symbolS *); +extern void evax_frob_symbol (symbolS *, int *); +extern void evax_frob_file_before_adjust (void); +extern void evax_frob_file_before_fix (void); +extern char *evax_shorten_name (char *); /* * Local Variables: diff --git a/gas/config/tc-alpha.c b/gas/config/tc-alpha.c index cc3f74e..bc355b8 100644 --- a/gas/config/tc-alpha.c +++ b/gas/config/tc-alpha.c @@ -57,9 +57,13 @@ #ifdef OBJ_ELF #include "elf/alpha.h" -#include "dwarf2dbg.h" #endif +#ifdef OBJ_EVAX +#include "vms.h" +#endif + +#include "dwarf2dbg.h" #include "dw2gencfi.h" #include "safe-ctype.h" @@ -74,6 +78,9 @@ struct alpha_fixup { expressionS exp; bfd_reloc_code_real_type reloc; +#ifdef OBJ_EVAX + symbolS *xtrasym, *procsym; +#endif }; struct alpha_insn @@ -92,7 +99,7 @@ enum alpha_macro_arg MACRO_OPIR, MACRO_CPIR, MACRO_FPR, - MACRO_EXP, + MACRO_EXP }; struct alpha_macro @@ -245,6 +252,12 @@ struct option md_longopts[] = { "mdebug", no_argument, NULL, OPTION_MDEBUG }, { "no-mdebug", no_argument, NULL, OPTION_NO_MDEBUG }, #endif +#ifdef OBJ_EVAX +#define OPTION_REPLACE (OPTION_RELAX + 1) +#define OPTION_NOREPLACE (OPTION_REPLACE+1) + { "replace", no_argument, NULL, OPTION_REPLACE }, + { "noreplace", no_argument, NULL, OPTION_NOREPLACE }, +#endif { NULL, no_argument, NULL, 0 } }; @@ -268,6 +281,9 @@ size_t md_longopts_size = sizeof (md_longopts); #undef AXP_REG_GP #define AXP_REG_GP AXP_REG_PV + +static struct hash_control *alpha_evax_proc_hash; + #endif /* OBJ_EVAX */ /* The cpu for which we are generating code. */ @@ -299,11 +315,11 @@ static symbolS *alpha_register_table[64]; static segT alpha_lita_section; #endif #ifdef OBJ_EVAX -static segT alpha_link_section; -static segT alpha_ctors_section; -static segT alpha_dtors_section; +segT alpha_link_section; #endif +#ifndef OBJ_EVAX static segT alpha_lit8_section; +#endif /* Symbols referring to said sections. */ #ifdef OBJ_ECOFF @@ -311,10 +327,10 @@ static symbolS *alpha_lita_symbol; #endif #ifdef OBJ_EVAX static symbolS *alpha_link_symbol; -static symbolS *alpha_ctors_symbol; -static symbolS *alpha_dtors_symbol; #endif +#ifndef OBJ_EVAX static symbolS *alpha_lit8_symbol; +#endif /* Literal for .litX+0x8000 within .lita. */ #ifdef OBJ_ECOFF @@ -339,6 +355,12 @@ static int alpha_addr32_on = 0; and the section happens to not be on an eight byte boundary, it will align both the symbol and the .quad to an eight byte boundary. */ static symbolS *alpha_insn_label; +static symbolS *alpha_prologue_label; + +#ifdef OBJ_EVAX +/* Symbol associate with the current jsr instruction. */ +static symbolS *alpha_linkage_symbol; +#endif /* Whether we should automatically align data generation pseudo-ops. .align 0 will turn this off. */ @@ -358,6 +380,11 @@ static int alpha_debug; int alpha_flag_mdebug = -1; #endif +#ifdef OBJ_EVAX +/* Whether to perform the VMS procedure call optimization. */ +int alpha_flag_replace = 1; +#endif + /* Don't fully resolve relocations, allowing code movement in the linker. */ static int alpha_flag_relax; @@ -366,7 +393,7 @@ static int g_switch_value = 8; #ifdef OBJ_EVAX /* Collect information about current procedure here. */ -static struct +struct alpha_evax_procs { symbolS *symbol; /* Proc pdesc symbol. */ int pdsckind; @@ -379,7 +406,14 @@ static struct long fmask; int type; int prologue; -} alpha_evax_proc; + symbolS *handler; + int handler_data; +}; + +struct alpha_linkage_fixups *alpha_linkage_fixup_root; +static struct alpha_linkage_fixups *alpha_linkage_fixup_tail; + +static struct alpha_evax_procs *alpha_evax_proc; static int alpha_flag_hash_long_names = 0; /* -+ */ static int alpha_flag_show_after_trunc = 0; /* -H */ @@ -451,6 +485,10 @@ static const int alpha_num_reloc_op struct alpha_reloc_tag { fixS *master; /* The literal reloc. */ +#ifdef OBJ_EVAX + struct symbol *sym; + struct symbol *psym; +#endif fixS *slaves; /* Head of linked list of lituses. */ segT segment; /* Segment relocs are in or undefined_section. */ long sequence; /* Sequence #. */ @@ -527,6 +565,10 @@ static const char * const ldXu_op[] = { "ldbu", "ldwu", NULL, NULL }; static void assemble_insn (const struct alpha_opcode *, const expressionS *, int, struct alpha_insn *, bfd_reloc_code_real_type); static void emit_insn (struct alpha_insn *); static void assemble_tokens (const char *, const expressionS *, int, int); +#ifdef OBJ_EVAX +static char *s_alpha_section_name (void); +static symbolS *add_to_link_pool (symbolS *, symbolS *, offsetT); +#endif static struct alpha_reloc_tag * get_alpha_reloc_tag (long sequence) @@ -550,11 +592,17 @@ get_alpha_reloc_tag (long sequence) errmsg = hash_insert (alpha_literal_hash, info->string, (void *) info); if (errmsg) as_fatal (errmsg); +#ifdef OBJ_EVAX + info->sym = 0; + info->psym = 0; +#endif } return info; } +#ifndef OBJ_EVAX + static void alpha_adjust_relocs (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, @@ -718,6 +766,8 @@ alpha_before_fix (void) if (alpha_literal_hash) bfd_map_over_sections (stdoutput, alpha_adjust_relocs, NULL); } + +#endif #ifdef DEBUG_ALPHA static void @@ -1176,7 +1226,8 @@ static long load_expression (int targreg, const expressionS *exp, int *pbasereg, - expressionS *poffset) + expressionS *poffset, + const char *opname) { long emit_lituse = 0; offsetT addend = exp->X_add_number; @@ -1268,11 +1319,9 @@ load_expression (int targreg, insn.sequence = emit_lituse = next_sequence_num--; #endif /* OBJ_ELF */ #ifdef OBJ_EVAX - offsetT link; - /* Find symbol or symbol pointer in link section. */ - if (exp->X_add_symbol == alpha_evax_proc.symbol) + if (exp->X_add_symbol == alpha_evax_proc->symbol) { if (range_signed_16 (addend)) { @@ -1292,20 +1341,97 @@ load_expression (int targreg, } else { - if (!range_signed_32 (addend)) + const char *symname = S_GET_NAME (exp->X_add_symbol); + const char *ptr1, *ptr2; + int symlen = strlen (symname); + + if ((symlen > 4 && + strcmp (ptr2 = &symname [symlen - 4], "..lk") == 0)) { - link = add_to_link_pool (alpha_evax_proc.symbol, - exp->X_add_symbol, addend); - addend = 0; + set_tok_reg (newtok[0], targreg); + + newtok[1] = *exp; + newtok[1].X_op = O_subtract; + newtok[1].X_op_symbol = alpha_evax_proc->symbol; + + set_tok_preg (newtok[2], basereg); + assemble_tokens_to_insn ("ldq", newtok, 3, &insn); + alpha_linkage_symbol = exp->X_add_symbol; + + if (poffset) + set_tok_const (*poffset, 0); + + if (alpha_flag_replace && targreg == 26) + { + char *ensymname; + symbolS *ensym; + volatile asymbol *dummy; + + ptr1 = strstr (symname, "..") + 2; + if (ptr1 > ptr2) + ptr1 = symname; + ensymname = (char *) xmalloc (ptr2 - ptr1 + 5); + memcpy (ensymname, ptr1, ptr2 - ptr1); + memcpy (ensymname + (ptr2 - ptr1), "..en", 5); + + assert (insn.nfixups + 1 <= MAX_INSN_FIXUPS); + insn.fixups[insn.nfixups].reloc = BFD_RELOC_ALPHA_NOP; + ensym = symbol_find_or_make (ensymname); + ensym->sy_used = 1; + /* The fixup must be the same as the BFD_RELOC_ALPHA_BOH + case in emit_jsrjmp. See B.4.5.2 of the OpenVMS Linker + Utility Manual. */ + insn.fixups[insn.nfixups].exp.X_op = O_symbol; + insn.fixups[insn.nfixups].exp.X_add_symbol = ensym; + insn.fixups[insn.nfixups].exp.X_add_number = 0; + insn.fixups[insn.nfixups].xtrasym = alpha_linkage_symbol; + insn.fixups[insn.nfixups].procsym = alpha_evax_proc->symbol; + insn.nfixups++; + + /* ??? Force bsym to be instantiated now, as it will be + too late to do so in tc_gen_reloc. */ + dummy = symbol_get_bfdsym (exp->X_add_symbol); + } + else if (alpha_flag_replace && targreg == 27) + { + char *psymname; + symbolS *psym; + + ptr1 = strstr (symname, "..") + 2; + if (ptr1 > ptr2) + ptr1 = symname; + psymname = (char *) xmalloc (ptr2 - ptr1 + 1); + memcpy (psymname, ptr1, ptr2 - ptr1); + psymname [ptr2 - ptr1] = 0; + assert (insn.nfixups + 1 <= MAX_INSN_FIXUPS); + insn.fixups[insn.nfixups].reloc = BFD_RELOC_ALPHA_LDA; + psym = symbol_find_or_make (psymname); + psym->sy_used = 1; + insn.fixups[insn.nfixups].exp.X_op = O_subtract; + insn.fixups[insn.nfixups].exp.X_add_symbol = psym; + insn.fixups[insn.nfixups].exp.X_op_symbol = alpha_evax_proc->symbol; + insn.fixups[insn.nfixups].exp.X_add_number = 0; + insn.fixups[insn.nfixups].xtrasym = alpha_linkage_symbol; + insn.fixups[insn.nfixups].procsym = alpha_evax_proc->symbol; + insn.nfixups++; + } + + emit_insn(&insn); + return 0; } else - link = add_to_link_pool (alpha_evax_proc.symbol, - exp->X_add_symbol, 0); + { + symbolS *linkexp; - set_tok_reg (newtok[0], targreg); - set_tok_const (newtok[1], link); - set_tok_preg (newtok[2], basereg); - assemble_tokens_to_insn ("ldq", newtok, 3, &insn); + if (!range_signed_32 (addend)) + addend = sign_extend_32 (addend); + linkexp = add_to_link_pool (alpha_evax_proc->symbol, + exp->X_add_symbol, 0); + set_tok_reg (newtok[0], targreg); + set_tok_sym (newtok[1], linkexp, 0); + set_tok_preg (newtok[2], basereg); + assemble_tokens_to_insn ("ldq", newtok, 3, &insn); + } } #endif /* OBJ_EVAX */ @@ -1335,7 +1461,7 @@ load_expression (int targreg, set_tok_reg (newtok[0], targreg); newtok[1] = *exp; set_tok_preg (newtok[2], basereg); - assemble_tokens ("lda", newtok, 3, 0); + assemble_tokens (opname, newtok, 3, 0); if (poffset) set_tok_const (*poffset, 0); @@ -1357,16 +1483,20 @@ load_expression (int targreg, if (!range_signed_32 (addend)) { +#ifdef OBJ_EVAX + symbolS *litexp; +#else offsetT lit; long seq_num = next_sequence_num--; +#endif /* For 64-bit addends, just put it in the literal pool. */ #ifdef OBJ_EVAX /* Emit "ldq targreg, lit(basereg)". */ - lit = add_to_link_pool (alpha_evax_proc.symbol, - section_symbol (absolute_section), addend); + litexp = add_to_link_pool (alpha_evax_proc->symbol, + section_symbol (absolute_section), addend); set_tok_reg (newtok[0], targreg); - set_tok_const (newtok[1], lit); + set_tok_sym (newtok[1], litexp, 0); set_tok_preg (newtok[2], alpha_gp_register); assemble_tokens ("ldq", newtok, 3, 0); #else @@ -1525,7 +1655,7 @@ emit_lda (const expressionS *tok, else basereg = tok[2].X_add_number; - (void) load_expression (tok[0].X_add_number, &tok[1], &basereg, NULL); + (void) load_expression (tok[0].X_add_number, &tok[1], &basereg, NULL, "lda"); } /* The ldah macro differs from the ldah instruction in that it has $31 @@ -1636,8 +1766,20 @@ emit_insn (struct alpha_insn *insn) assert (reloc_howto); size = bfd_get_reloc_size (reloc_howto); - assert (size >= 1 && size <= 4); + switch (fixup->reloc) + { +#ifdef OBJ_EVAX + case BFD_RELOC_ALPHA_NOP: + case BFD_RELOC_ALPHA_BSR: + case BFD_RELOC_ALPHA_LDA: + case BFD_RELOC_ALPHA_BOH: + break; +#endif + default: + assert (size >= 1 && size <= 4); + } + pcrel = reloc_howto->pc_relative; } @@ -1784,6 +1926,18 @@ emit_insn (struct alpha_insn *insn) fixP->tc_fix_data.info = info; break; #endif +#ifdef OBJ_EVAX + case BFD_RELOC_ALPHA_NOP: + case BFD_RELOC_ALPHA_LDA: + case BFD_RELOC_ALPHA_BSR: + case BFD_RELOC_ALPHA_BOH: + info = get_alpha_reloc_tag (next_sequence_num--); + fixP->tc_fix_data.info = info; + fixP->tc_fix_data.info->sym = fixup->xtrasym; + fixP->tc_fix_data.info->psym = fixup->procsym; + break; +#endif + default: if ((int) fixup->reloc < 0) { @@ -1963,8 +2117,9 @@ assemble_insn (const struct alpha_opcode *opcode, } /* If this is a real relocation (as opposed to a lituse hint), then - the relocation width should match the operand width. */ - else if (reloc < BFD_RELOC_UNUSED) + the relocation width should match the operand width. + Take care of -MDISP in operand table. */ + else if (reloc < BFD_RELOC_UNUSED && reloc > 0) { reloc_howto_type *reloc_howto = bfd_reloc_type_lookup (stdoutput, reloc); @@ -2000,15 +2155,22 @@ emit_ir_load (const expressionS *tok, long lituse; expressionS newtok[3]; struct alpha_insn insn; + const char *symname + = tok[1].X_add_symbol ? S_GET_NAME (tok[1].X_add_symbol): ""; + int symlen = strlen (symname); if (ntok == 2) basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register); else basereg = tok[2].X_add_number; - lituse = load_expression (tok[0].X_add_number, &tok[1], &basereg, - &newtok[1]); + lituse = load_expression (tok[0].X_add_number, &tok[1], + &basereg, &newtok[1], opname); + if (basereg == alpha_gp_register && + (symlen > 4 && strcmp (&symname [symlen - 4], "..lk") == 0)) + return; + newtok[0] = tok[0]; set_tok_preg (newtok[2], basereg); @@ -2049,7 +2211,8 @@ emit_loadstore (const expressionS *tok, if (alpha_noat_on) as_bad (_("macro requires $at register while noat in effect")); - lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, &newtok[1]); + lituse = load_expression (AXP_REG_AT, &tok[1], + &basereg, &newtok[1], opname); } else { @@ -2100,7 +2263,7 @@ emit_ldXu (const expressionS *tok, basereg = tok[2].X_add_number; /* Emit "lda $at, exp". */ - lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL); + lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL, "lda"); /* Emit "ldq_u targ, 0($at)". */ newtok[0] = tok[0]; @@ -2252,7 +2415,7 @@ emit_stX (const expressionS *tok, basereg = tok[2].X_add_number; /* Emit "lda $at, exp". */ - lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL); + lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL, "lda"); /* Emit "ldq_u $t9, 0($at)". */ set_tok_reg (newtok[0], AXP_REG_T9); @@ -2662,15 +2825,14 @@ emit_jsrjmp (const expressionS *tok, else { int basereg = alpha_gp_register; - lituse = load_expression (r = AXP_REG_PV, &tok[tokidx], &basereg, NULL); + lituse = load_expression (r = AXP_REG_PV, &tok[tokidx], + &basereg, NULL, opname); } #endif set_tok_cpreg (newtok[1], r); -#ifdef OBJ_EVAX - /* FIXME: Add hint relocs to BFD for evax. */ -#else +#ifndef OBJ_EVAX if (tokidx < ntok) newtok[2] = tok[tokidx]; else @@ -2688,6 +2850,41 @@ emit_jsrjmp (const expressionS *tok, insn.sequence = lituse; } +#ifdef OBJ_EVAX + if (alpha_flag_replace + && r == AXP_REG_RA + && tok[tokidx].X_add_symbol + && alpha_linkage_symbol) + { + const char *symname = S_GET_NAME (tok[tokidx].X_add_symbol); + int symlen = strlen (symname); + char *ensymname; + + ensymname = (char *) xmalloc (symlen + 5); + memcpy (ensymname, symname, symlen); + memcpy (ensymname + symlen, "..en", 5); + + assert (insn.nfixups < MAX_INSN_FIXUPS); + if (insn.nfixups > 0) + { + memmove (&insn.fixups[1], &insn.fixups[0], + sizeof(struct alpha_fixup) * insn.nfixups); + } + + /* The fixup must be the same as the BFD_RELOC_ALPHA_NOP + case in load_expression. See B.4.5.2 of the OpenVMS + Linker Utility Manual. */ + insn.fixups[0].reloc = BFD_RELOC_ALPHA_BOH; + insn.fixups[0].exp.X_op = O_symbol; + insn.fixups[0].exp.X_add_symbol = symbol_find_or_make (ensymname); + insn.fixups[0].exp.X_add_number = 0; + insn.fixups[0].xtrasym = alpha_linkage_symbol; + insn.fixups[0].procsym = alpha_evax_proc->symbol; + insn.nfixups++; + alpha_linkage_symbol = 0; + } +#endif + emit_insn (&insn); } @@ -2784,7 +2981,10 @@ FIXME insn.sequence = next_sequence_num--; emit_insn (&insn); -#endif /* OBJ_ECOFF || OBJ_ELF */ +#else /* OBJ_ECOFF || OBJ_ELF */ + /* Avoid warning. */ + tok = NULL; +#endif } /* The macro table. */ @@ -3153,7 +3353,7 @@ assemble_tokens (const char *opname, Add new fixup only if offset isn't 16bit. */ -valueT +static symbolS * add_to_link_pool (symbolS *basesym, symbolS *sym, offsetT addend) @@ -3161,12 +3361,13 @@ add_to_link_pool (symbolS *basesym, segT current_section = now_seg; int current_subsec = now_subseg; valueT offset; - bfd_reloc_code_real_type reloc_type; char *p; segment_info_type *seginfo = seg_info (alpha_link_section); fixS *fixp; - - offset = - *symbol_get_obj (basesym); + symbolS *linksym, *expsym; + expressionS e; + + offset = 0; /* ??? DBR */ /* @@ This assumes all entries in a given section will be of the same size... Probably correct, but unwise to rely on. */ @@ -3175,31 +3376,44 @@ add_to_link_pool (symbolS *basesym, if (seginfo->frchainP) for (fixp = seginfo->frchainP->fix_root; fixp != (fixS *) NULL; - fixp = fixp->fx_next, offset += 8) + fixp = fixp->fx_next) { - if (fixp->fx_addsy == sym && fixp->fx_offset == addend) - { - if (range_signed_16 (offset)) - { - return offset; - } - } + if (fixp->tc_fix_data.info + && fixp->tc_fix_data.info->sym + && fixp->tc_fix_data.info->sym->sy_value.X_op_symbol == basesym) + offset += 8; + + if (fixp->fx_addsy == sym + && fixp->fx_offset == (valueT)addend + && fixp->tc_fix_data.info + && fixp->tc_fix_data.info->sym + && fixp->tc_fix_data.info->sym->sy_value.X_op_symbol == basesym) + return fixp->tc_fix_data.info->sym; } /* Not found in 16bit signed range. */ subseg_set (alpha_link_section, 0); + linksym = symbol_new + (FAKE_LABEL_NAME, now_seg, (valueT) frag_now_fix (), frag_now); p = frag_more (8); memset (p, 0, 8); - fix_new (frag_now, p - frag_now->fr_literal, 8, sym, addend, 0, - BFD_RELOC_64); + e.X_op = O_subtract; + e.X_add_symbol = linksym; + e.X_op_symbol = basesym; + e.X_add_number = 0; + expsym = make_expr_symbol (&e); + + fixp = fix_new + (frag_now, p-frag_now->fr_literal, 8, sym, addend, 0, BFD_RELOC_64); + fixp->tc_fix_data.info = get_alpha_reloc_tag (next_sequence_num--); + fixp->tc_fix_data.info->sym = expsym; subseg_set (current_section, current_subsec); seginfo->literal_pool_size += 8; - return offset; + return expsym; } - #endif /* OBJ_EVAX */ /* Assembler directives. */ @@ -3209,13 +3423,25 @@ add_to_link_pool (symbolS *basesym, static void s_alpha_text (int i) - { #ifdef OBJ_ELF obj_elf_text (i); #else s_text (i); #endif +#ifdef OBJ_EVAX + { + symbolS * symbolP; + + symbolP = symbol_find (".text"); + if (symbolP == NULL) + { + symbolP = symbol_make (".text"); + S_SET_SEGMENT (symbolP, text_section); + symbol_table_insert (symbolP); + } + } +#endif alpha_insn_label = NULL; alpha_auto_align_on = 1; alpha_current_align = 0; @@ -3239,8 +3465,7 @@ s_alpha_data (int i) #if defined (OBJ_ECOFF) || defined (OBJ_EVAX) -/* Handle the OSF/1 and openVMS .comm pseudo quirks. - openVMS constructs a section for every common symbol. */ +/* Handle the OSF/1 and openVMS .comm pseudo quirks. */ static void s_alpha_comm (int ignore ATTRIBUTE_UNUSED) @@ -3248,13 +3473,9 @@ s_alpha_comm (int ignore ATTRIBUTE_UNUSED) char *name; char c; char *p; - offsetT temp; + offsetT temp, size; symbolS *symbolP; -#ifdef OBJ_EVAX - segT current_section = now_seg; - int current_subsec = now_subseg; - segT new_seg; -#endif + int log_align = 0; name = input_line_pointer; c = get_symbol_end (); @@ -3271,35 +3492,17 @@ s_alpha_comm (int ignore ATTRIBUTE_UNUSED) input_line_pointer++; SKIP_WHITESPACE (); } - if ((temp = get_absolute_expression ()) < 0) + if ((size = get_absolute_expression ()) < 0) { - as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) temp); + as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) size); ignore_rest_of_line (); return; } *p = 0; symbolP = symbol_find_or_make (name); - -#ifdef OBJ_EVAX - /* Make a section for the common symbol. */ - new_seg = subseg_new (xstrdup (name), 0); -#endif - *p = c; -#ifdef OBJ_EVAX - /* Alignment might follow. */ - if (*input_line_pointer == ',') - { - offsetT align; - - input_line_pointer++; - align = get_absolute_expression (); - bfd_set_section_alignment (stdoutput, new_seg, align); - } -#endif - if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) { as_bad (_("Ignoring attempt to re-define symbol")); @@ -3308,44 +3511,108 @@ s_alpha_comm (int ignore ATTRIBUTE_UNUSED) } #ifdef OBJ_EVAX - if (bfd_section_size (stdoutput, new_seg) > 0) + if (*input_line_pointer != ',') + temp = 8; /* Default alignment. */ + else { - if (bfd_section_size (stdoutput, new_seg) != temp) - as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."), - S_GET_NAME (symbolP), - (long) bfd_section_size (stdoutput, new_seg), - (long) temp); + input_line_pointer++; + SKIP_WHITESPACE (); + temp = get_absolute_expression (); } -#else - if (S_GET_VALUE (symbolP)) + + /* ??? Unlike on OSF/1, the alignment factor is not in log units. */ + while ((temp >>= 1) != 0) + ++log_align; + + if (*input_line_pointer == ',') { - if (S_GET_VALUE (symbolP) != (valueT) temp) - as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."), - S_GET_NAME (symbolP), - (long) S_GET_VALUE (symbolP), - (long) temp); + /* Extended form of the directive + + .comm symbol, size, alignment, section + + where the "common" semantics is transferred to the section. + The symbol is effectively an alias for the section name. */ + + segT sec; + char *sec_name; + symbolS *sec_symbol; + segT current_seg = now_seg; + subsegT current_subseg = now_subseg; + int cur_size; + + input_line_pointer++; + SKIP_WHITESPACE (); + sec_name = s_alpha_section_name (); + sec_symbol = symbol_find_or_make (sec_name); + sec = subseg_new (sec_name, 0); + S_SET_SEGMENT (sec_symbol, sec); + symbol_get_bfdsym (sec_symbol)->flags |= BSF_SECTION_SYM; + bfd_vms_set_section_flags (stdoutput, sec, + EGPS_S_V_OVR | EGPS_S_V_GBL | EGPS_S_V_NOMOD); + record_alignment (sec, log_align); + + /* Reuse stab_string_size to store the size of the section. */ + cur_size = seg_info (sec)->stabu.stab_string_size; + 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; + seg_info (sec)->stabu.stab_string_size = (int)size; + } + + S_SET_SEGMENT (symbolP, sec); + + subseg_set (current_seg, current_subseg); + } + else + { + /* Regular form of the directive + + .comm symbol, size, alignment + + where the "common" semantics in on the symbol. + These symbols are assembled in the .bss section. */ + + char *pfrag; + segT current_seg = now_seg; + subsegT current_subseg = now_subseg; + + subseg_set (bss_section, 1); + frag_align (log_align, 0, 0); + record_alignment (bss_section, log_align); + + symbolP->sy_frag = frag_now; + pfrag = frag_var (rs_org, 1, 1, (relax_substateT)0, symbolP, + size, NULL); + *pfrag = 0; + + S_SET_SEGMENT (symbolP, bss_section); + + subseg_set (current_seg, current_subseg); } #endif + + if (S_GET_VALUE (symbolP)) + { + if (S_GET_VALUE (symbolP) != (valueT) size) + as_bad ("Length of .comm \"%s\" is already %ld. Not changed to %ld.", + S_GET_NAME (symbolP), + (long) S_GET_VALUE (symbolP), + (long) size); + } else { -#ifdef OBJ_EVAX - subseg_set (new_seg, 0); - p = frag_more (temp); - new_seg->flags |= SEC_IS_COMMON; - S_SET_SEGMENT (symbolP, new_seg); -#else - S_SET_VALUE (symbolP, (valueT) temp); - S_SET_SEGMENT (symbolP, bfd_com_section_ptr); +#ifndef OBJ_EVAX + S_SET_VALUE (symbolP, (valueT) size); #endif S_SET_EXTERNAL (symbolP); } - -#ifdef OBJ_EVAX - subseg_set (current_section, current_subsec); + +#ifndef OBJ_EVAX + know (symbolP->sy_frag == &zero_address_frag); #endif - - know (symbol_get_frag (symbolP) == &zero_address_frag); - demand_empty_rest_of_line (); } @@ -3623,6 +3890,8 @@ s_alpha_prologue (int ignore ATTRIBUTE_UNUSED) arg = get_absolute_expression (); demand_empty_rest_of_line (); + alpha_prologue_label = symbol_new + (FAKE_LABEL_NAME, now_seg, (valueT) frag_now_fix (), frag_now); if (ECOFF_DEBUGGING) sym = ecoff_get_cur_proc_sym (); @@ -3886,24 +4155,169 @@ alpha_cfi_frame_initial_instructions (void) #ifdef OBJ_EVAX +/* Get name of section. */ +static char * +s_alpha_section_name (void) +{ + char *name; + + SKIP_WHITESPACE (); + if (*input_line_pointer == '"') + { + int dummy; + + name = demand_copy_C_string (&dummy); + if (name == NULL) + { + ignore_rest_of_line (); + return NULL; + } + } + else + { + char *end = input_line_pointer; + + while (0 == strchr ("\n\t,; ", *end)) + end++; + if (end == input_line_pointer) + { + as_warn (_("missing name")); + ignore_rest_of_line (); + return NULL; + } + + name = xmalloc (end - input_line_pointer + 1); + memcpy (name, input_line_pointer, end - input_line_pointer); + name[end - input_line_pointer] = '\0'; + input_line_pointer = end; + } + SKIP_WHITESPACE (); + return name; +} + +static flagword +s_alpha_section_word (char *str, size_t len) +{ + int no = 0; + flagword flag = 0; + + if (len == 5 && strncmp (str, "NO", 2) == 0) + { + no = 1; + str += 2; + len -= 2; + } + + if (len == 3) + { + if (strncmp (str, "PIC", 3) == 0) + flag = EGPS_S_V_PIC; + else if (strncmp (str, "LIB", 3) == 0) + flag = EGPS_S_V_LIB; + else if (strncmp (str, "OVR", 3) == 0) + flag = EGPS_S_V_OVR; + else if (strncmp (str, "REL", 3) == 0) + flag = EGPS_S_V_REL; + else if (strncmp (str, "GBL", 3) == 0) + flag = EGPS_S_V_GBL; + else if (strncmp (str, "SHR", 3) == 0) + flag = EGPS_S_V_SHR; + else if (strncmp (str, "EXE", 3) == 0) + flag = EGPS_S_V_EXE; + else if (strncmp (str, "WRT", 3) == 0) + flag = EGPS_S_V_WRT; + else if (strncmp (str, "VEC", 3) == 0) + flag = EGPS_S_V_VEC; + else if (strncmp (str, "MOD", 3) == 0) + { + flag = no ? EGPS_S_V_NOMOD : EGPS_S_V_NOMOD << EGPS_S_V_NO_SHIFT; + no = 0; + } + else if (strncmp (str, "COM", 3) == 0) + flag = EGPS_S_V_COM; + } + + if (flag == 0) + { + char c = str[len]; + str[len] = 0; + as_warn (_("unknown section attribute %s"), str); + str[len] = c; + return 0; + } + + if (no) + return flag << EGPS_S_V_NO_SHIFT; + else + return flag; +} + /* Handle the section specific pseudo-op. */ +#define EVAX_SECTION_COUNT 5 + +static char *section_name[EVAX_SECTION_COUNT + 1] = + { "NULL", ".rdata", ".comm", ".link", ".ctors", ".dtors" }; + static void s_alpha_section (int secid) { int temp; -#define EVAX_SECTION_COUNT 5 - static char *section_name[EVAX_SECTION_COUNT + 1] = - { "NULL", ".rdata", ".comm", ".link", ".ctors", ".dtors" }; + char *name, *beg; + segT sec; + flagword vms_flags = 0; + symbolS *symbol; - if ((secid <= 0) || (secid > EVAX_SECTION_COUNT)) + if (secid == 0) { - as_fatal (_("Unknown section directive")); - demand_empty_rest_of_line (); - return; + name = s_alpha_section_name (); + if (name == NULL) + return; + sec = subseg_new (name, 0); + if (*input_line_pointer == ',') + { + /* Skip the comma. */ + ++input_line_pointer; + SKIP_WHITESPACE (); + + do + { + char c; + + SKIP_WHITESPACE (); + beg = input_line_pointer; + c = get_symbol_end (); + *input_line_pointer = c; + + vms_flags |= s_alpha_section_word (beg, input_line_pointer - beg); + + SKIP_WHITESPACE (); + } + while (*input_line_pointer++ == ','); + --input_line_pointer; + } + + symbol = symbol_find_or_make (name); + S_SET_SEGMENT (symbol, sec); + symbol_get_bfdsym (symbol)->flags |= BSF_SECTION_SYM; + bfd_vms_set_section_flags (stdoutput, sec, vms_flags); } - temp = get_absolute_expression (); - subseg_new (section_name[secid], 0); + else + { + temp = get_absolute_expression (); + subseg_new (section_name[secid], 0); + } + + demand_empty_rest_of_line (); + alpha_insn_label = NULL; + alpha_auto_align_on = 1; + alpha_current_align = 0; +} + +static void +s_alpha_literals (int ignore ATTRIBUTE_UNUSED) +{ + subseg_new (".literals", 0); demand_empty_rest_of_line (); alpha_insn_label = NULL; alpha_auto_align_on = 1; @@ -3918,16 +4332,21 @@ s_alpha_ent (int ignore ATTRIBUTE_UNUSED) symbolS *symbol; expressionS symexpr; - alpha_evax_proc.pdsckind = 0; - alpha_evax_proc.framereg = -1; - alpha_evax_proc.framesize = 0; - alpha_evax_proc.rsa_offset = 0; - alpha_evax_proc.ra_save = AXP_REG_RA; - alpha_evax_proc.fp_save = -1; - alpha_evax_proc.imask = 0; - alpha_evax_proc.fmask = 0; - alpha_evax_proc.prologue = 0; - alpha_evax_proc.type = 0; + alpha_evax_proc + = (struct alpha_evax_procs *) xmalloc (sizeof (struct alpha_evax_procs)); + + alpha_evax_proc->pdsckind = 0; + alpha_evax_proc->framereg = -1; + alpha_evax_proc->framesize = 0; + alpha_evax_proc->rsa_offset = 0; + alpha_evax_proc->ra_save = AXP_REG_RA; + alpha_evax_proc->fp_save = -1; + alpha_evax_proc->imask = 0; + alpha_evax_proc->fmask = 0; + alpha_evax_proc->prologue = 0; + alpha_evax_proc->type = 0; + alpha_evax_proc->handler = 0; + alpha_evax_proc->handler_data = 0; expression (&symexpr); @@ -3940,11 +4359,44 @@ s_alpha_ent (int ignore ATTRIBUTE_UNUSED) symbol = make_expr_symbol (&symexpr); symbol_get_bfdsym (symbol)->flags |= BSF_FUNCTION; - alpha_evax_proc.symbol = symbol; + alpha_evax_proc->symbol = symbol; + + (void) hash_insert + (alpha_evax_proc_hash, + symbol_get_bfdsym (alpha_evax_proc->symbol)->name, (PTR)alpha_evax_proc); demand_empty_rest_of_line (); } +static void +s_alpha_handler (int is_data) +{ + if (is_data) + alpha_evax_proc->handler_data = get_absolute_expression (); + else + { + char *name, name_end; + name = input_line_pointer; + name_end = get_symbol_end (); + + if (! is_name_beginner (*name)) + { + as_warn (_(".handler directive has no name")); + *input_line_pointer = name_end; + } + else + { + symbolS *sym; + + sym = symbol_find_or_make (name); + symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION; + alpha_evax_proc->handler = sym; + *input_line_pointer = name_end; + } + } + demand_empty_rest_of_line (); +} + /* Parse .frame <framreg>,<framesize>,RA,<rsa_offset> directives. */ static void @@ -3952,7 +4404,7 @@ s_alpha_frame (int ignore ATTRIBUTE_UNUSED) { long val; - alpha_evax_proc.framereg = tc_get_register (1); + alpha_evax_proc->framereg = tc_get_register (1); SKIP_WHITESPACE (); if (*input_line_pointer++ != ',' @@ -3964,7 +4416,7 @@ s_alpha_frame (int ignore ATTRIBUTE_UNUSED) return; } - alpha_evax_proc.framesize = val; + alpha_evax_proc->framesize = val; (void) tc_get_register (1); SKIP_WHITESPACE (); @@ -3975,7 +4427,18 @@ s_alpha_frame (int ignore ATTRIBUTE_UNUSED) demand_empty_rest_of_line (); return; } - alpha_evax_proc.rsa_offset = get_absolute_expression (); + alpha_evax_proc->rsa_offset = get_absolute_expression (); +} + +static void +s_alpha_prologue (int ignore ATTRIBUTE_UNUSED) +{ + int arg; + + arg = get_absolute_expression (); + demand_empty_rest_of_line (); + alpha_prologue_label = symbol_new + (FAKE_LABEL_NAME, now_seg, (valueT) frag_now_fix (), frag_now); } static void @@ -3983,12 +4446,14 @@ s_alpha_pdesc (int ignore ATTRIBUTE_UNUSED) { char *name; char name_end; - long val; register char *p; expressionS exp; symbolS *entry_sym; fixS *fixp; segment_info_type *seginfo = seg_info (alpha_link_section); + const char *entry_sym_name; + char *sym_name; + int len; if (now_seg != alpha_link_section) { @@ -3997,30 +4462,42 @@ s_alpha_pdesc (int ignore ATTRIBUTE_UNUSED) return; } - if ((alpha_evax_proc.symbol == 0) - || (!S_IS_DEFINED (alpha_evax_proc.symbol))) + expression (&exp); + if (exp.X_op != O_symbol) { - as_fatal (_(".pdesc has no matching .ent")); + as_warn (_(".pdesc directive has no entry symbol")); demand_empty_rest_of_line (); return; } - - *symbol_get_obj (alpha_evax_proc.symbol) = - (valueT) seginfo->literal_pool_size; - - expression (&exp); - if (exp.X_op != O_symbol) + + entry_sym = make_expr_symbol (&exp); + entry_sym_name = symbol_get_bfdsym (entry_sym)->name; + + len = strlen (entry_sym_name); + sym_name = (char *) xmalloc (len - 4 + 1); + strncpy (sym_name, entry_sym_name, len - 4); + sym_name [len - 4] = 0; + + alpha_evax_proc = (struct alpha_evax_procs *) + hash_find (alpha_evax_proc_hash, sym_name); + + if (!alpha_evax_proc || !S_IS_DEFINED (alpha_evax_proc->symbol)) { - as_warn (_(".pdesc directive has no entry symbol")); + as_fatal (_(".pdesc has no matching .ent")); demand_empty_rest_of_line (); return; } - entry_sym = make_expr_symbol (&exp); - /* Save bfd symbol of proc desc in function symbol. */ - symbol_get_bfdsym (alpha_evax_proc.symbol)->udata.p - = symbol_get_bfdsym (entry_sym); + *symbol_get_obj (alpha_evax_proc->symbol) = + (valueT) seginfo->literal_pool_size; + alpha_evax_proc->symbol->sy_obj = (valueT)seginfo->literal_pool_size; + + /* Save bfd symbol of proc entry in function symbol. */ + ((struct evax_private_udata_struct *) + symbol_get_bfdsym (alpha_evax_proc->symbol)->udata.p)->enbsym + = symbol_get_bfdsym (entry_sym); + SKIP_WHITESPACE (); if (*input_line_pointer++ != ',') { @@ -4034,13 +4511,13 @@ s_alpha_pdesc (int ignore ATTRIBUTE_UNUSED) name_end = get_symbol_end (); if (strncmp (name, "stack", 5) == 0) - alpha_evax_proc.pdsckind = PDSC_S_K_KIND_FP_STACK; + alpha_evax_proc->pdsckind = PDSC_S_K_KIND_FP_STACK; else if (strncmp (name, "reg", 3) == 0) - alpha_evax_proc.pdsckind = PDSC_S_K_KIND_FP_REGISTER; + alpha_evax_proc->pdsckind = PDSC_S_K_KIND_FP_REGISTER; else if (strncmp (name, "null", 4) == 0) - alpha_evax_proc.pdsckind = PDSC_S_K_KIND_NULL; + alpha_evax_proc->pdsckind = PDSC_S_K_KIND_NULL; else { @@ -4062,53 +4539,58 @@ s_alpha_pdesc (int ignore ATTRIBUTE_UNUSED) fixp->fx_done = 1; seginfo->literal_pool_size += 16; - *p = alpha_evax_proc.pdsckind - | ((alpha_evax_proc.framereg == 29) ? PDSC_S_M_BASE_REG_IS_FP : 0); + *p = alpha_evax_proc->pdsckind + | ((alpha_evax_proc->framereg == 29) ? PDSC_S_M_BASE_REG_IS_FP : 0) + | ((alpha_evax_proc->handler) ? PDSC_S_M_HANDLER_VALID : 0) + | ((alpha_evax_proc->handler_data) ? PDSC_S_M_HANDLER_DATA_VALID : 0); *(p + 1) = PDSC_S_M_NATIVE | PDSC_S_M_NO_JACKET; - switch (alpha_evax_proc.pdsckind) + switch (alpha_evax_proc->pdsckind) { case PDSC_S_K_KIND_NULL: *(p + 2) = 0; *(p + 3) = 0; break; case PDSC_S_K_KIND_FP_REGISTER: - *(p + 2) = alpha_evax_proc.fp_save; - *(p + 3) = alpha_evax_proc.ra_save; + *(p + 2) = alpha_evax_proc->fp_save; + *(p + 3) = alpha_evax_proc->ra_save; break; case PDSC_S_K_KIND_FP_STACK: - md_number_to_chars (p + 2, (valueT) alpha_evax_proc.rsa_offset, 2); + md_number_to_chars (p + 2, (valueT) alpha_evax_proc->rsa_offset, 2); break; default: /* impossible */ break; } *(p + 4) = 0; - *(p + 5) = alpha_evax_proc.type & 0x0f; + *(p + 5) = alpha_evax_proc->type & 0x0f; /* Signature offset. */ md_number_to_chars (p + 6, (valueT) 0, 2); fix_new_exp (frag_now, p - frag_now->fr_literal+8, 8, &exp, 0, BFD_RELOC_64); - if (alpha_evax_proc.pdsckind == PDSC_S_K_KIND_NULL) + if (alpha_evax_proc->pdsckind == PDSC_S_K_KIND_NULL) return; /* Add dummy fix to make add_to_link_pool work. */ - p = frag_more (8); - fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0); + p = frag_more (6); + fixp = fix_new (frag_now, p - frag_now->fr_literal, 6, 0, 0, 0, 0); fixp->fx_done = 1; - seginfo->literal_pool_size += 8; - + seginfo->literal_pool_size += 6; + /* pdesc+16: Size. */ - md_number_to_chars (p, (valueT) alpha_evax_proc.framesize, 4); + md_number_to_chars (p, (valueT) alpha_evax_proc->framesize, 4); md_number_to_chars (p + 4, (valueT) 0, 2); /* Entry length. */ - md_number_to_chars (p + 6, alpha_evax_proc.prologue, 2); + exp.X_op = O_subtract; + exp.X_add_symbol = alpha_prologue_label; + exp.X_op_symbol = entry_sym; + emit_expr (&exp, 2); - if (alpha_evax_proc.pdsckind == PDSC_S_K_KIND_FP_REGISTER) + if (alpha_evax_proc->pdsckind == PDSC_S_K_KIND_FP_REGISTER) return; /* Add dummy fix to make add_to_link_pool work. */ @@ -4119,8 +4601,25 @@ s_alpha_pdesc (int ignore ATTRIBUTE_UNUSED) /* pdesc+24: register masks. */ - md_number_to_chars (p, alpha_evax_proc.imask, 4); - md_number_to_chars (p + 4, alpha_evax_proc.fmask, 4); + md_number_to_chars (p, alpha_evax_proc->imask, 4); + md_number_to_chars (p + 4, alpha_evax_proc->fmask, 4); + + if (alpha_evax_proc->handler) + { + p = frag_more (8); + fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, + alpha_evax_proc->handler, 0, 0, BFD_RELOC_64); + } + + if (alpha_evax_proc->handler_data) + { + /* Add dummy fix to make add_to_link_pool work. */ + p = frag_more (8); + fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0); + fixp->fx_done = 1; + seginfo->literal_pool_size += 8; + md_number_to_chars (p, alpha_evax_proc->handler_data, 8); + } } /* Support for crash debug on vms. */ @@ -4165,6 +4664,7 @@ s_alpha_linkage (int ignore ATTRIBUTE_UNUSED) { expressionS exp; char *p; + fixS *fixp; #ifdef md_flush_pending_output md_flush_pending_output (); @@ -4177,10 +4677,36 @@ s_alpha_linkage (int ignore ATTRIBUTE_UNUSED) } else { + struct alpha_linkage_fixups *linkage_fixup; + p = frag_more (LKP_S_K_SIZE); memset (p, 0, LKP_S_K_SIZE); - fix_new_exp (frag_now, p - frag_now->fr_literal, LKP_S_K_SIZE, &exp, 0,\ - BFD_RELOC_ALPHA_LINKAGE); + fixp = fix_new_exp + (frag_now, p - frag_now->fr_literal, LKP_S_K_SIZE, &exp, 0,\ + BFD_RELOC_ALPHA_LINKAGE); + + linkage_fixup = (struct alpha_linkage_fixups *) + xmalloc (sizeof (struct alpha_linkage_fixups)); + + linkage_fixup->fixp = fixp; + linkage_fixup->next = 0; + + if (alpha_insn_label == 0) + alpha_insn_label = symbol_new + (FAKE_LABEL_NAME, now_seg, (valueT) frag_now_fix (), frag_now); + linkage_fixup->label = alpha_insn_label; + + if (alpha_linkage_fixup_root == 0) + { + alpha_linkage_fixup_root = alpha_linkage_fixup_tail = linkage_fixup; + alpha_linkage_fixup_tail->next = 0; + } + else + { + alpha_linkage_fixup_tail->next = linkage_fixup; + alpha_linkage_fixup_tail = linkage_fixup; + alpha_linkage_fixup_tail->next = 0; + } } demand_empty_rest_of_line (); } @@ -4212,7 +4738,7 @@ static void s_alpha_fp_save (int ignore ATTRIBUTE_UNUSED) { - alpha_evax_proc.fp_save = tc_get_register (1); + alpha_evax_proc->fp_save = tc_get_register (1); demand_empty_rest_of_line (); } @@ -4229,7 +4755,7 @@ s_alpha_mask (int ignore ATTRIBUTE_UNUSED) } else { - alpha_evax_proc.imask = val; + alpha_evax_proc->imask = val; (void) get_absolute_expression (); } demand_empty_rest_of_line (); @@ -4247,7 +4773,7 @@ s_alpha_fmask (int ignore ATTRIBUTE_UNUSED) } else { - alpha_evax_proc.fmask = val; + alpha_evax_proc->fmask = val; (void) get_absolute_expression (); } demand_empty_rest_of_line (); @@ -4261,7 +4787,7 @@ s_alpha_end (int ignore ATTRIBUTE_UNUSED) c = get_symbol_end (); *input_line_pointer = c; demand_empty_rest_of_line (); - alpha_evax_proc.symbol = 0; + alpha_evax_proc = 0; } static void @@ -4485,7 +5011,7 @@ s_alpha_align (int ignore ATTRIBUTE_UNUSED) { int align; char fill, *pfill; - long max_alignment = 15; + long max_alignment = 16; align = get_absolute_expression (); if (align > max_alignment) @@ -4612,12 +5138,12 @@ alpha_print_token (FILE *f, const expressionS *exp) { expressionS nexp = *exp; nexp.X_op = O_register; - print_expr (f, &nexp); + print_expr_1 (f, &nexp); } putc (')', f); break; default: - print_expr (f, exp); + print_expr_1 (f, exp); break; } } @@ -4643,22 +5169,26 @@ const pseudo_typeS md_pseudo_table[] = {"sect.s", s_alpha_section, 0}, #endif #ifdef OBJ_EVAX - { "pdesc", s_alpha_pdesc, 0}, - { "name", s_alpha_name, 0}, - { "linkage", s_alpha_linkage, 0}, - { "code_address", s_alpha_code_address, 0}, - { "ent", s_alpha_ent, 0}, - { "frame", s_alpha_frame, 0}, - { "fp_save", s_alpha_fp_save, 0}, - { "mask", s_alpha_mask, 0}, - { "fmask", s_alpha_fmask, 0}, - { "end", s_alpha_end, 0}, - { "file", s_alpha_file, 0}, - { "rdata", s_alpha_section, 1}, - { "comm", s_alpha_comm, 0}, - { "link", s_alpha_section, 3}, - { "ctors", s_alpha_section, 4}, - { "dtors", s_alpha_section, 5}, + {"section", s_alpha_section, 0}, + {"literals", s_alpha_literals, 0}, + {"pdesc", s_alpha_pdesc, 0}, + {"name", s_alpha_name, 0}, + {"linkage", s_alpha_linkage, 0}, + {"code_address", s_alpha_code_address, 0}, + {"ent", s_alpha_ent, 0}, + {"frame", s_alpha_frame, 0}, + {"fp_save", s_alpha_fp_save, 0}, + {"mask", s_alpha_mask, 0}, + {"fmask", s_alpha_fmask, 0}, + {"end", s_alpha_end, 0}, + {"file", s_alpha_file, 0}, + {"rdata", s_alpha_section, 1}, + {"comm", s_alpha_comm, 0}, + {"link", s_alpha_section, 3}, + {"ctors", s_alpha_section, 4}, + {"dtors", s_alpha_section, 5}, + {"handler", s_alpha_handler, 0}, + {"handler_data", s_alpha_handler, 1}, #endif #ifdef OBJ_ELF /* Frame related pseudos. */ @@ -4683,8 +5213,12 @@ const pseudo_typeS md_pseudo_table[] = {"tag", s_alpha_coff_wrapper, 6}, {"val", s_alpha_coff_wrapper, 7}, #else +#ifdef OBJ_EVAX + {"prologue", s_alpha_prologue, 0}, +#else {"prologue", s_ignore, 0}, #endif +#endif {"gprel32", s_alpha_gprel32, 0}, {"t_floating", s_alpha_float_cons, 'd'}, {"s_floating", s_alpha_float_cons, 'f'}, @@ -4955,6 +5489,7 @@ md_begin (void) #ifdef OBJ_EVAX create_literal_section (".link", &alpha_link_section, &alpha_link_symbol); + alpha_evax_proc_hash = hash_new (); #endif #ifdef OBJ_ELF @@ -5089,6 +5624,14 @@ md_parse_option (int c, char *arg) case 'h': /* For gnu-c/vax compatibility. */ break; + + case OPTION_REPLACE: + alpha_flag_replace = 1; + break; + + case OPTION_NOREPLACE: + alpha_flag_replace = 0; + break; #endif case OPTION_RELAX: @@ -5128,8 +5671,9 @@ Alpha options:\n\ #ifdef OBJ_EVAX fputs (_("\ VMS options:\n\ --+ hash encode (don't truncate) names longer than 64 characters\n\ --H show new symbol after hash truncation\n"), +-+ encode (don't truncate) names longer than 64 characters\n\ +-H show new symbol after hash truncation\n\ +-replace/-noreplace enable or disable the optimization of procedure calls\n"), stream); #endif } @@ -5294,6 +5838,79 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg) case BFD_RELOC_ALPHA_CODEADDR: return; +#ifdef OBJ_EVAX + case BFD_RELOC_ALPHA_NOP: + value -= (8 + 4); /* PC-relative, base is jsr+4. */ + + /* From B.4.5.2 of the OpenVMS Linker Utility Manual: + "Finally, the ETIR$C_STC_BSR command passes the same address + as ETIR$C_STC_NOP (so that they will fail or succeed together), + and the same test is done again." */ + if (S_GET_SEGMENT (fixP->fx_addsy) == undefined_section) + { + fixP->fx_addnumber = -value; + return; + } + + if ((abs (value) >> 2) & ~0xfffff) + goto done; + else + { + /* Change to a nop. */ + image = 0x47FF041F; + goto write_done; + } + + case BFD_RELOC_ALPHA_LDA: + /* fixup_segment sets fixP->fx_addsy to NULL when it can pre-compute + the value for an O_subtract. */ + if (fixP->fx_addsy + && S_GET_SEGMENT (fixP->fx_addsy) == undefined_section) + { + fixP->fx_addnumber = symbol_get_bfdsym (fixP->fx_subsy)->value; + return; + } + + if ((abs (value)) & ~0x7fff) + goto done; + else + { + /* Change to an lda. */ + image = 0x237B0000 | (value & 0xFFFF); + goto write_done; + } + + case BFD_RELOC_ALPHA_BSR: + case BFD_RELOC_ALPHA_BOH: + value -= 4; /* PC-relative, base is jsr+4. */ + + /* See comment in the BFD_RELOC_ALPHA_NOP case above. */ + if (S_GET_SEGMENT (fixP->fx_addsy) == undefined_section) + { + fixP->fx_addnumber = -value; + return; + } + + if ((abs (value) >> 2) & ~0xfffff) + { + /* Out of range. */ + if (fixP->fx_r_type == BFD_RELOC_ALPHA_BOH) + { + /* Add a hint. */ + image = bfd_getl32(fixpos); + image = (image & ~0x3FFF) | ((value >> 2) & 0x3FFF); + goto write_done; + } + goto done; + } + else + { + /* Change to a branch. */ + image = 0xD3400000 | ((value >> 2) & 0x1FFFFF); + goto write_done; + } +#endif + case BFD_RELOC_VTABLE_INHERIT: case BFD_RELOC_VTABLE_ENTRY: return; @@ -5463,6 +6080,12 @@ alpha_force_relocation (fixS *f) case BFD_RELOC_ALPHA_TPREL_HI16: case BFD_RELOC_ALPHA_TPREL_LO16: case BFD_RELOC_ALPHA_TPREL16: +#ifdef OBJ_EVAX + case BFD_RELOC_ALPHA_NOP: + case BFD_RELOC_ALPHA_BSR: + case BFD_RELOC_ALPHA_LDA: + case BFD_RELOC_ALPHA_BOH: +#endif return 1; default: @@ -5502,6 +6125,7 @@ alpha_fix_adjustable (fixS *f) case BFD_RELOC_ALPHA_GPREL_HI16: case BFD_RELOC_ALPHA_GPREL_LO16: case BFD_RELOC_23_PCREL_S2: + case BFD_RELOC_16: case BFD_RELOC_32: case BFD_RELOC_64: case BFD_RELOC_ALPHA_HINT: @@ -5555,6 +6179,13 @@ alpha_fix_adjustable (fixS *f) return 1; } #endif +#ifdef OBJ_EVAX + case BFD_RELOC_ALPHA_NOP: + case BFD_RELOC_ALPHA_BSR: + case BFD_RELOC_ALPHA_LDA: + case BFD_RELOC_ALPHA_BOH: + return 1; +#endif default: return 1; @@ -5615,6 +6246,62 @@ tc_gen_reloc (asection *sec ATTRIBUTE_UNUSED, #endif } +#ifdef OBJ_EVAX + switch (fixp->fx_r_type) + { + struct evax_private_udata_struct *udata; + const char *pname; + int pname_len; + + case BFD_RELOC_ALPHA_LINKAGE: + reloc->addend = fixp->fx_addnumber; + break; + + case BFD_RELOC_ALPHA_NOP: + case BFD_RELOC_ALPHA_BSR: + case BFD_RELOC_ALPHA_LDA: + case BFD_RELOC_ALPHA_BOH: + pname = symbol_get_bfdsym (fixp->fx_addsy)->name; + + /* We need the non-suffixed name of the procedure. Beware that + the main symbol might be equated so look it up and take its name. */ + pname_len = strlen (pname); + if (pname_len > 4 && strcmp (pname + pname_len - 4, "..en") == 0) + { + symbolS *sym; + char *my_pname = xstrdup (pname); + my_pname [pname_len - 4] = 0; + sym = symbol_find (my_pname); + if (sym == NULL) + abort (); + while (symbol_equated_reloc_p (sym)) + { + symbolS *n = symbol_get_value_expression (sym)->X_add_symbol; + + /* We must avoid looping, as that can occur with a badly + written program. */ + if (n == sym) + break; + sym = n; + } + pname = symbol_get_bfdsym (sym)->name; + } + + udata = (struct evax_private_udata_struct *) + xmalloc (sizeof (struct evax_private_udata_struct)); + udata->enbsym = symbol_get_bfdsym (fixp->fx_addsy); + udata->bsym = symbol_get_bfdsym (fixp->tc_fix_data.info->psym); + udata->origname = (char *)pname; + udata->lkindex = ((struct evax_private_udata_struct *) + symbol_get_bfdsym (fixp->tc_fix_data.info->sym)->udata.p)->lkindex; + reloc->sym_ptr_ptr = (void *)udata; + reloc->addend = fixp->fx_addnumber; + + default: + break; + } +#endif + return reloc; } diff --git a/gas/config/tc-alpha.h b/gas/config/tc-alpha.h index eb104cc..b3c930b 100644 --- a/gas/config/tc-alpha.h +++ b/gas/config/tc-alpha.h @@ -69,9 +69,9 @@ extern valueT alpha_gp_value; #define md_operand(x) #ifdef OBJ_EVAX +#define TC_VALIDATE_FIX_SUB(FIX, SEG) 1 -/* This field keeps the symbols position in the link section. */ -#define OBJ_SYMFIELD_TYPE valueT +#define tc_canonicalize_symbol_name evax_shorten_name #define TC_CONS_FIX_NEW(FRAG,OFF,LEN,EXP) \ fix_new_exp (FRAG, OFF, (int)LEN, EXP, 0, \ @@ -81,7 +81,9 @@ extern valueT alpha_gp_value; : BFD_RELOC_ALPHA_LINKAGE); #endif -#ifndef VMS +#ifdef OBJ_EVAX +#define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR) (P2VAR) = 3 +#else #define TC_IMPLICIT_LCOMM_ALIGNMENT(size, align) \ do \ { \ @@ -133,12 +135,14 @@ extern flagword alpha_elf_section_flags (flagword, bfd_vma, int); #define RELOC_OP_P #endif +#ifndef OBJ_EVAX /* Before the relocations are written, reorder them, so that user supplied !lituse relocations follow the appropriate !literal relocations. Also convert the gas-internal relocations to the appropriate linker relocations. */ #define tc_frob_file_before_fix() alpha_before_fix () extern void alpha_before_fix (void); +#endif #ifdef OBJ_ELF #define md_end alpha_elf_md_end diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo index fd6c0a3..a64b3d0 100644 --- a/gas/doc/as.texinfo +++ b/gas/doc/as.texinfo @@ -248,6 +248,7 @@ gcc(1), ld(1), and the Info entries for @file{binutils} and @file{ld}. @emph{Target Alpha options:} [@b{-m@var{cpu}}] [@b{-mdebug} | @b{-no-mdebug}] + [@b{-replace} | @b{-noreplace}] [@b{-relax}] [@b{-g}] [@b{-G@var{size}}] [@b{-F}] [@b{-32addr}] @end ifset diff --git a/gas/doc/c-alpha.texi b/gas/doc/c-alpha.texi index f426b82..0d789d2 100644 --- a/gas/doc/c-alpha.texi +++ b/gas/doc/c-alpha.texi @@ -90,6 +90,15 @@ this option does not propagate all symbol arithmetic into the object file, because not all symbol arithmetic can be represented. However, the option can still be useful in specific applications. +@cindex @code{-replace} command line option, Alpha +@cindex @code{-noreplace} command line option, Alpha +@item -replace +@item -noreplace +Enables or disables the optimization of procedure calls, both at assemblage +and at link time. These options are only available for VMS targets and +@code{-replace} is the default. See section 1.4.1 of the OpenVMS Linker +Utility Manual. + @cindex @code{-g} command line option, Alpha @item -g This option is used when the compiler generates debug information. When diff --git a/gas/dwarf2dbg.c b/gas/dwarf2dbg.c index 2bcba9b..f332865 100644 --- a/gas/dwarf2dbg.c +++ b/gas/dwarf2dbg.c @@ -1636,9 +1636,15 @@ out_debug_info (segT info_seg, segT abbrev_seg, segT line_seg, segT ranges_seg) { dirname = remap_debug_filename (dirs[files[1].dir]); len = strlen (dirname); +#ifdef TE_VMS + /* Already has trailing slash. */ + p = frag_more (len); + memcpy (p, dirname, len); +#else p = frag_more (len + 1); memcpy (p, dirname, len); INSERT_DIR_SEPARATOR (p, len); +#endif } len = strlen (files[1].filename) + 1; p = frag_more (len); |