X-Git-Url: https://oss.titaniummirror.com/gitweb?p=msp430-binutils.git;a=blobdiff_plain;f=gas%2Fconfig%2Fobj-evax.c;fp=gas%2Fconfig%2Fobj-evax.c;h=033ccae66002c3e423ab8e5c9660083947da12f3;hp=6f484d06ba346f5e5e9d37c955a6984eef5ca032;hb=d5da4f291af551c0b8b79e1d4a9b173d60e5c10e;hpb=7b5ea4fcdf2819e070665ab5610f8b48e3867c10 diff --git a/gas/config/obj-evax.c b/gas/config/obj-evax.c index 6f484d0..033ccae 100644 --- a/gas/config/obj-evax.c +++ b/gas/config/obj-evax.c @@ -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 @@ -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 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 $.. 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 $.. 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 */