]> oss.titaniummirror.com Git - msp430-binutils.git/blobdiff - gas/config/obj-evax.c
Imported binutils-2.20
[msp430-binutils.git] / gas / config / obj-evax.c
index 6f484d06ba346f5e5e9d37c955a6984eef5ca032..033ccae66002c3e423ab8e5c9660083947da12f3 100644 (file)
@@ -1,7 +1,8 @@
 /* obj-evax.c - EVAX (openVMS/Alpha) object file format.
-   Copyright 1996, 1997, 2007 Free Software Foundation, Inc.
+   Copyright 1996, 1997, 2005, 2007, 2008, 2009 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
 
 
 #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 PARAMS ((int));
+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 */