aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTristan Gingold <gingold@adacore.com>2009-03-03 10:04:58 +0000
committerTristan Gingold <gingold@adacore.com>2009-03-03 10:04:58 +0000
commit198f1251457bf99a3f3aec2d2db1977b99e6f519 (patch)
treebb675f11b07ece8dcefe50aed8284f06ab32ab16
parent54b70fa3143fa8c444e8d4bec971f868becf7e49 (diff)
downloadgdb-198f1251457bf99a3f3aec2d2db1977b99e6f519.zip
gdb-198f1251457bf99a3f3aec2d2db1977b99e6f519.tar.gz
gdb-198f1251457bf99a3f3aec2d2db1977b99e6f519.tar.bz2
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.
-rw-r--r--gas/ChangeLog106
-rw-r--r--gas/as.c4
-rw-r--r--gas/config/obj-evax.c450
-rw-r--r--gas/config/obj-evax.h34
-rw-r--r--gas/config/tc-alpha.c1083
-rw-r--r--gas/config/tc-alpha.h10
-rw-r--r--gas/doc/as.texinfo1
-rw-r--r--gas/doc/c-alpha.texi9
-rw-r--r--gas/dwarf2dbg.c6
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
diff --git a/gas/as.c b/gas/as.c
index 246ee68..87e88da 100644
--- a/gas/as.c
+++ b/gas/as.c
@@ -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);