X-Git-Url: https://oss.titaniummirror.com/gitweb?p=msp430-binutils.git;a=blobdiff_plain;f=bfd%2Fvms-gsd.c;fp=bfd%2Fvms-gsd.c;h=e641d0de422ff78cab80509c346b5c413f8f31b2;hp=4bdc27c98d1d54dbf57ddb77ed954617af3f3bb5;hb=d5da4f291af551c0b8b79e1d4a9b173d60e5c10e;hpb=7b5ea4fcdf2819e070665ab5610f8b48e3867c10 diff --git a/bfd/vms-gsd.c b/bfd/vms-gsd.c index 4bdc27c..e641d0d 100644 --- a/bfd/vms-gsd.c +++ b/bfd/vms-gsd.c @@ -1,9 +1,12 @@ /* vms-gsd.c -- BFD back-end for VAX (openVMS/VAX) and EVAX (openVMS/Alpha) files. Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, - 2007 Free Software Foundation, Inc. + 2007, 2009 Free Software Foundation, Inc. - go and read the openVMS linker manual (esp. appendix B) + GSD record handling functions + EGSD record handling functions + + Go and read the openVMS linker manual (esp. appendix B) if you don't know what's going on here :-) Written by Klaus K"ampf (kkaempf@rmi.de) @@ -46,6 +49,7 @@ #define EVAX_READONLYADDR_NAME "$READONLY_ADDR$" #define EVAX_READONLY_NAME "$READONLY$" #define EVAX_LITERAL_NAME "$LITERAL$" +#define EVAX_LITERALS_NAME "$LITERALS" #define EVAX_COMMON_NAME "$COMMON$" #define EVAX_LOCAL_NAME "$LOCAL$" @@ -133,6 +137,11 @@ static struct sec_flags_struct evax_section_flags[] = (SEC_DATA), (EGPS_S_V_REL | EGPS_S_V_RD | EGPS_S_V_WRT), (SEC_IN_MEMORY | SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD) }, + { EVAX_LITERALS_NAME, + (EGPS_S_V_PIC | EGPS_S_V_OVR), + (SEC_DATA | SEC_READONLY), + (EGPS_S_V_PIC | EGPS_S_V_OVR), + (SEC_IN_MEMORY | SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_READONLY | SEC_LOAD) }, { NULL, (EGPS_S_V_REL | EGPS_S_V_RD | EGPS_S_V_WRT), (SEC_DATA), @@ -197,6 +206,37 @@ vms_esecflag_by_name (struct sec_flags_struct *section_flags, struct flagdescstruct { char *name; flagword value; }; +static const struct flagdescstruct gpsflagdesc[] = +{ + { "PIC", GPS_S_M_PIC }, + { "LIB", GPS_S_M_LIB }, + { "OVR", GPS_S_M_OVR }, + { "REL", GPS_S_M_REL }, + { "GBL", GPS_S_M_GBL }, + { "SHR", GPS_S_M_SHR }, + { "EXE", GPS_S_M_EXE }, + { "RD", GPS_S_M_RD }, + { "WRT", GPS_S_M_WRT }, + { "VEC", GPS_S_M_VEC }, + { "NOMOD", EGPS_S_V_NOMOD }, + { "COM", EGPS_S_V_COM }, + { NULL, 0 } +}; + +static const struct flagdescstruct gsyflagdesc[] = +{ + { "WEAK", GSY_S_M_WEAK }, + { "DEF", GSY_S_M_DEF }, + { "UNI", GSY_S_M_UNI }, + { "REL", GSY_S_M_REL }, + { "COMM", EGSY_S_V_COMM }, + { "VECEP", EGSY_S_V_VECEP }, + { "NORM", EGCY_S_V_NORM }, + { NULL, 0 } +}; + +static char *flag2str (struct flagdescstruct *, flagword); + /* Convert flag to printable string. */ static char * @@ -224,43 +264,15 @@ flag2str (struct flagdescstruct * flagdesc, flagword flags) /* Input routines. */ +static int register_universal_symbol (bfd *abfd, asymbol *symbol, + int vms_flags); + /* Process GSD/EGSD record return 0 on success, -1 on error. */ int _bfd_vms_slurp_gsd (bfd * abfd, int objtype) { -#if VMS_DEBUG - static struct flagdescstruct gpsflagdesc[] = - { - { "PIC", 0x0001 }, - { "LIB", 0x0002 }, - { "OVR", 0x0004 }, - { "REL", 0x0008 }, - { "GBL", 0x0010 }, - { "SHR", 0x0020 }, - { "EXE", 0x0040 }, - { "RD", 0x0080 }, - { "WRT", 0x0100 }, - { "VEC", 0x0200 }, - { "NOMOD", 0x0400 }, - { "COM", 0x0800 }, - { NULL, 0 } - }; - - static struct flagdescstruct gsyflagdesc[] = - { - { "WEAK", 0x0001 }, - { "DEF", 0x0002 }, - { "UNI", 0x0004 }, - { "REL", 0x0008 }, - { "COMM", 0x0010 }, - { "VECEP", 0x0020 }, - { "NORM", 0x0040 }, - { NULL, 0 } - }; -#endif - int gsd_type, gsd_size; asection *section; unsigned char *vms_rec; @@ -300,7 +312,7 @@ _bfd_vms_slurp_gsd (bfd * abfd, int objtype) vms_rec = PRIV (vms_rec); if (objtype == OBJ_S_C_GSD) - gsd_type = *vms_rec; + gsd_type = vms_rec[0]; else { _bfd_vms_get_header_values (abfd, vms_rec, &gsd_type, &gsd_size); @@ -322,7 +334,7 @@ _bfd_vms_slurp_gsd (bfd * abfd, int objtype) vms_debug (4, "GSD_S_C_PSC\n"); #endif /* If this section isn't a bfd section. */ - if (PRIV (is_vax) && (psect_idx < (abfd->section_count-1))) + if (PRIV (is_vax) && (psect_idx < (abfd->section_count - 1))) { /* Check for temporary section from TIR record. */ if (psect_idx < PRIV (section_count)) @@ -362,7 +374,6 @@ _bfd_vms_slurp_gsd (bfd * abfd, int objtype) base_addr += section->size; /* Global section is common symbol. */ - if (old_flags & GPS_S_M_GBL) { entry = _bfd_vms_enter_symbol (abfd, name); @@ -496,21 +507,20 @@ _bfd_vms_slurp_gsd (bfd * abfd, int objtype) else psect = vms_rec[value_offset-1]; - symbol->section = (asection *) (size_t) psect; + symbol->section = (asection *)(unsigned long)psect; #if VMS_DEBUG - vms_debug (4, "gsd sym def #%d (%s, %d [%p], %04x=%s)\n", abfd->symcount, - symbol->name, (int)symbol->section, symbol->section, old_flags, flag2str (gsyflagdesc, old_flags)); + vms_debug (4, "gsd sym def #%d (%s, %ld, %04x=%s)\n", abfd->symcount, + symbol->name, (long)symbol->section, old_flags, flag2str(gsyflagdesc, old_flags)); #endif } else { /* Symbol reference. */ - symbol->section = bfd_make_section (abfd, BFD_UND_SECTION_NAME); #if VMS_DEBUG - vms_debug (4, "gsd sym ref #%d (%s, %s [%p], %04x=%s)\n", - abfd->symcount, symbol->name, symbol->section->name, - symbol->section, old_flags, flag2str (gsyflagdesc, old_flags)); + vms_debug (4, "gsd sym ref #%d (%s, %04x=%s)\n", abfd->symcount, + symbol->name, old_flags, flag2str (gsyflagdesc, old_flags)); #endif + symbol->section = (asection *)(unsigned long)-1; } gsd_size = vms_rec[name_offset] + name_offset + 1; @@ -574,19 +584,19 @@ _bfd_vms_slurp_gsd (bfd * abfd, int objtype) case EGSD_S_C_PSC + EVAX_OFFSET: { /* Program section definition. */ - name = _bfd_vms_save_counted_string (vms_rec + 12); + name = _bfd_vms_save_counted_string (vms_rec + EGPS_S_B_NAMLNG); section = bfd_make_section (abfd, name); if (!section) return -1; - old_flags = bfd_getl16 (vms_rec + 6); - section->size = bfd_getl32 (vms_rec + 8); /* Allocation. */ + old_flags = bfd_getl16 (vms_rec + EGPS_S_W_FLAGS); + section->size = bfd_getl32 (vms_rec + EGPS_S_L_ALLOC); new_flags = vms_secflag_by_name (abfd, evax_section_flags, name, section->size > 0); if (old_flags & EGPS_S_V_REL) new_flags |= SEC_RELOC; if (!bfd_set_section_flags (abfd, section, new_flags)) return -1; - section->alignment_power = vms_rec[4]; + section->alignment_power = vms_rec[EGPS_S_B_ALIGN]; align_addr = (1 << section->alignment_power); if ((base_addr % align_addr) != 0) base_addr += (align_addr - (base_addr % align_addr)); @@ -595,9 +605,10 @@ _bfd_vms_slurp_gsd (bfd * abfd, int objtype) section->contents = bfd_zmalloc (section->size); if (section->contents == NULL) return -1; + section->filepos = (unsigned int)-1; #if VMS_DEBUG - vms_debug (4, "egsd psc %d (%s, flags %04x=%s) ", - section->index, name, old_flags, flag2str (gpsflagdesc, old_flags)); + vms_debug (4, "EGSD P-section %d (%s, flags %04x=%s) ", + section->index, name, old_flags, flag2str(gpsflagdesc, old_flags)); vms_debug (4, "%d bytes at 0x%08lx (mem %p)\n", section->size, section->vma, section->contents); #endif @@ -606,50 +617,52 @@ _bfd_vms_slurp_gsd (bfd * abfd, int objtype) case EGSD_S_C_SYM + EVAX_OFFSET: { - /* Symbol specification (definition or reference). */ + /* Global symbol specification (definition or reference). */ symbol = bfd_make_empty_symbol (abfd); if (symbol == 0) return -1; - old_flags = bfd_getl16 (vms_rec + 6); + old_flags = bfd_getl16 (vms_rec + EGSY_S_W_FLAGS); new_flags = BSF_NO_FLAGS; if (old_flags & EGSY_S_V_WEAK) new_flags |= BSF_WEAK; - if (vms_rec[6] & EGSY_S_V_DEF) + if (old_flags & EGSY_S_V_DEF) { /* Symbol definition. */ - symbol->name = _bfd_vms_save_counted_string (vms_rec + 32); if (old_flags & EGSY_S_V_NORM) - /* Proc def. */ new_flags |= BSF_FUNCTION; - - symbol->value = bfd_getl64 (vms_rec + 8); - symbol->section = (asection *) ((unsigned long) bfd_getl32 (vms_rec + 28)); + symbol->name = + _bfd_vms_save_counted_string (vms_rec + ESDF_S_B_NAMLNG); + symbol->value = bfd_getl64 (vms_rec + ESDF_S_L_VALUE); + symbol->section = + (asection *)(unsigned long) bfd_getl32 (vms_rec + ESDF_S_L_PSINDX); #if VMS_DEBUG - vms_debug (4, "egsd sym def #%d (%s, %d, %04x=%s)\n", abfd->symcount, - symbol->name, (int) symbol->section, old_flags, - flag2str (gsyflagdesc, old_flags)); + vms_debug (4, "EGSD sym def #%d (%s, %ld, %04x=%s)\n", + abfd->symcount, symbol->name, (long)symbol->section, + old_flags, flag2str (gsyflagdesc, old_flags)); #endif } else { /* Symbol reference. */ - symbol->name = _bfd_vms_save_counted_string (vms_rec + 8); + symbol->name = + _bfd_vms_save_counted_string (vms_rec + ESRF_S_B_NAMLNG); #if VMS_DEBUG - vms_debug (4, "egsd sym ref #%d (%s, %04x=%s)\n", abfd->symcount, - symbol->name, old_flags, flag2str (gsyflagdesc, old_flags)); + vms_debug (4, "EGSD sym ref #%d (%s, %04x=%s)\n", + abfd->symcount, symbol->name, old_flags, + flag2str (gsyflagdesc, old_flags)); #endif - symbol->section = bfd_make_section (abfd, BFD_UND_SECTION_NAME); + symbol->section = (asection *)(unsigned long)-1; } symbol->flags = new_flags; - /* Save symbol in vms_symbol_table. */ - entry = (vms_symbol_entry *) bfd_hash_lookup (PRIV (vms_symbol_table), - symbol->name, - TRUE, FALSE); + /* Register symbol in VMS symbol table. */ + entry = (vms_symbol_entry *) bfd_hash_lookup + (PRIV (vms_symbol_table), symbol->name, TRUE, FALSE); + if (entry == NULL) { bfd_set_error (bfd_error_no_memory); @@ -672,11 +685,73 @@ _bfd_vms_slurp_gsd (bfd * abfd, int objtype) } break; - case EGSD_S_C_IDC + EVAX_OFFSET: + case EGSD_S_C_SYMG + EVAX_OFFSET: + { + /* Universal symbol specification (definition). */ + symbol = bfd_make_empty_symbol (abfd); + if (symbol == 0) + return -1; + + old_flags = bfd_getl16 (vms_rec + EGST_S_W_FLAGS); + new_flags = BSF_NO_FLAGS; + + if (old_flags & EGSY_S_V_WEAK) + new_flags |= BSF_WEAK; + + if (old_flags & EGSY_S_V_DEF) /* symbol definition */ + { + if (old_flags & EGSY_S_V_NORM) + new_flags |= BSF_FUNCTION; + + symbol->name = + _bfd_vms_save_counted_string (vms_rec + EGST_S_B_NAMLNG); + + /* For BSF_FUNCTION symbols, the entry point is in LP_1 + and the descriptor in LP_2. For other symbols, the + unique value is in LP_2. */ + symbol->value = bfd_getl64 (vms_rec + EGST_S_Q_LP_2); + + /* Adding this offset is necessary in order for GDB to + read the DWARF-2 debug info from shared libraries. */ + if (abfd->flags & DYNAMIC + && strstr (symbol->name, "$DWARF2.DEBUG") != 0) + symbol->value += PRIV (symvva); + } + else /* symbol reference */ + (*_bfd_error_handler) ("Invalid EGST reference"); + + symbol->flags = new_flags; + + if (register_universal_symbol (abfd, symbol, old_flags) < 0) + return -1; + + /* Make a second symbol for the entry point. */ + if (symbol->flags & BSF_FUNCTION) + { + asymbol *en_sym; + char *name = bfd_alloc (abfd, strlen (symbol->name) + 5); + + en_sym = bfd_make_empty_symbol (abfd); + if (en_sym == 0) + return -1; + + strcpy (name, symbol->name); + strcat (name, "..en"); + + en_sym->name = name; + en_sym->value = bfd_getl64 (vms_rec + EGST_S_Q_LP_1); + + if (register_universal_symbol (abfd, en_sym, old_flags) < 0) + return -1; + } + } break; + case EGSD_S_C_IDC + EVAX_OFFSET: + break; + default: - (*_bfd_error_handler) (_("unknown gsd/egsd subtype %d"), gsd_type); + (*_bfd_error_handler) (_("Unknown GSD/EGSD subtype %d"), gsd_type); bfd_set_error (bfd_error_bad_value); return -1; } @@ -691,7 +766,79 @@ _bfd_vms_slurp_gsd (bfd * abfd, int objtype) return 0; } -/* Output routines. */ +/* Register a universal symbol in the VMS symbol table. */ + +static int +register_universal_symbol (bfd *abfd, asymbol *symbol, int vms_flags) +{ + bfd_vma sbase = 0; + asection *s, *sec = NULL; + vms_symbol_entry *entry; + + /* A universal symbol is by definition global... */ + symbol->flags |= BSF_GLOBAL; + + /* ...and dynamic in shared libraries. */ + if (abfd->flags & DYNAMIC) + symbol->flags |= BSF_DYNAMIC; + + /* Find containing section. */ + for (s = abfd->sections; s; s = s->next) + { + if (symbol->value >= s->vma + && s->vma > sbase + && !(s->flags & SEC_COFF_SHARED_LIBRARY) + && (s->size > 0 || !(vms_flags & EGSY_S_V_REL))) + { + sbase = s->vma; + sec = s; + } + } + + symbol->value -= sbase; + symbol->section = sec; + +#if VMS_DEBUG + vms_debug (4, "EGST sym def #%d (%s, 0x%llx => 0x%llx, %04x=%s)\n", + abfd->symcount, symbol->name, symbol->value + sbase, + symbol->value, vms_flags, + flag2str(gsyflagdesc, vms_flags)); +#endif + + entry = (vms_symbol_entry *) bfd_hash_lookup (PRIV (vms_symbol_table), + symbol->name, + TRUE, FALSE); + + if (entry == NULL) + { + bfd_set_error (bfd_error_no_memory); + return -1; + } + + if (entry->symbol) /* FIXME: DEC C generates this */ + { +#if VMS_DEBUG + vms_debug (4, "EGSD_S_C_SYMG: duplicate \"%s\"\n", symbol->name); +#endif + } + else + { + entry->symbol = symbol; + PRIV (gsd_sym_count)++; + abfd->symcount++; + } + + return 0; +} + +/* Set section VMS flags. */ + +void +bfd_vms_set_section_flags (bfd *abfd ATTRIBUTE_UNUSED, + asection *sec, flagword flags) +{ + vms_section_data (sec)->vflags = flags; +} /* Write section and symbol directory of bfd abfd. */ @@ -705,6 +852,7 @@ _bfd_vms_write_gsd (bfd *abfd, int objtype ATTRIBUTE_UNUSED) char dummy_name[10]; char *sname; flagword new_flags, old_flags; + int abs_section_index = 0; #if VMS_DEBUG vms_debug (2, "vms_write_gsd (%p, %d)\n", abfd, objtype); @@ -730,6 +878,11 @@ _bfd_vms_write_gsd (bfd *abfd, int objtype ATTRIBUTE_UNUSED) vms_debug (3, "Section #%d %s, %d bytes\n", section->index, section->name, (int)section->size); #endif + /* Don't write out the VMS debug info section since it is in the + ETBT and EDBG sections in etir. */ + if (!strcmp (section->name, ".vmsdebug")) + goto done; + /* 13 bytes egsd, max 31 chars name -> should be 44 bytes. */ if (_bfd_vms_output_check (abfd, 64) < 0) { @@ -775,6 +928,11 @@ _bfd_vms_write_gsd (bfd *abfd, int objtype ATTRIBUTE_UNUSED) sname = EVAX_READONLY_NAME; else if ((*sname == 'l') && (strcmp (sname, "literal") == 0)) sname = EVAX_LITERAL_NAME; + else if ((*sname == 'l') && (strcmp (sname, "literals") == 0)) + { + sname = EVAX_LITERALS_NAME; + abs_section_index = section->index; + } else if ((*sname == 'c') && (strcmp (sname, "comm") == 0)) sname = EVAX_COMMON_NAME; else if ((*sname == 'l') && (strcmp (sname, "lcomm") == 0)) @@ -785,18 +943,34 @@ _bfd_vms_write_gsd (bfd *abfd, int objtype ATTRIBUTE_UNUSED) _bfd_vms_output_begin (abfd, EGSD_S_C_PSC, -1); _bfd_vms_output_short (abfd, section->alignment_power & 0xff); + if (bfd_is_com_section (section)) - new_flags = (EGPS_S_V_OVR | EGPS_S_V_REL | EGPS_S_V_GBL | EGPS_S_V_RD | EGPS_S_V_WRT | EGPS_S_V_NOMOD | EGPS_S_V_COM); + new_flags = (EGPS_S_V_OVR | EGPS_S_V_REL | EGPS_S_V_GBL | EGPS_S_V_RD + | EGPS_S_V_WRT | EGPS_S_V_NOMOD | EGPS_S_V_COM); else new_flags = vms_esecflag_by_name (evax_section_flags, sname, section->size > 0); + /* Modify them as directed. */ + if (section->flags & SEC_READONLY) + new_flags &= ~EGPS_S_V_WRT; + + new_flags |= vms_section_data (section)->vflags & 0xffff; + new_flags &= + ~((vms_section_data (section)->vflags >> EGPS_S_V_NO_SHIFT) & 0xffff); + +#if VMS_DEBUG + vms_debug (3, "sec flags %x\n", section->flags); + vms_debug (3, "new_flags %x, _raw_size %d\n", new_flags, section->size); +#endif + _bfd_vms_output_short (abfd, new_flags); _bfd_vms_output_long (abfd, (unsigned long) section->size); _bfd_vms_output_counted (abfd, sname); _bfd_vms_output_flush (abfd); last_index = section->index; +done: section = section->next; } @@ -822,9 +996,11 @@ _bfd_vms_write_gsd (bfd *abfd, int objtype ATTRIBUTE_UNUSED) if (old_flags & BSF_FILE) continue; - if (((old_flags & (BSF_GLOBAL | BSF_WEAK)) == 0) /* Not xdef... */ - && (!bfd_is_und_section (symbol->section))) /* ...and not xref. */ - continue; /* Dont output. */ + if ((old_flags & BSF_GLOBAL) == 0 /* Not xdef... */ + && !bfd_is_und_section (symbol->section) /* and not xref... */ + && !((old_flags & BSF_SECTION_SYM) != 0 /* and not LIB$INITIALIZE. */ + && strcmp (symbol->section->name, "LIB$INITIALIZE") == 0)) + continue; /* 13 bytes egsd, max 64 chars name -> should be 77 bytes. */ if (_bfd_vms_output_check (abfd, 80) < 0) @@ -846,7 +1022,7 @@ _bfd_vms_write_gsd (bfd *abfd, int objtype ATTRIBUTE_UNUSED) if (old_flags & BSF_WEAK) new_flags |= EGSY_S_V_WEAK; - if (bfd_is_com_section (symbol->section)) + if (bfd_is_com_section (symbol->section)) /* .comm */ new_flags |= (EGSY_S_V_WEAK | EGSY_S_V_COMM); if (old_flags & BSF_FUNCTION) @@ -854,7 +1030,7 @@ _bfd_vms_write_gsd (bfd *abfd, int objtype ATTRIBUTE_UNUSED) new_flags |= EGSY_S_V_NORM; new_flags |= EGSY_S_V_REL; } - if (old_flags & (BSF_GLOBAL | BSF_WEAK)) + if (old_flags & BSF_GLOBAL) { new_flags |= EGSY_S_V_DEF; if (!bfd_is_abs_section (symbol->section)) @@ -862,7 +1038,7 @@ _bfd_vms_write_gsd (bfd *abfd, int objtype ATTRIBUTE_UNUSED) } _bfd_vms_output_short (abfd, new_flags); - if (old_flags & (BSF_GLOBAL | BSF_WEAK)) + if (old_flags & BSF_GLOBAL) { /* Symbol definition. */ uquad code_address = 0; @@ -871,10 +1047,19 @@ _bfd_vms_write_gsd (bfd *abfd, int objtype ATTRIBUTE_UNUSED) if ((old_flags & BSF_FUNCTION) && symbol->udata.p != NULL) { - code_address = ((asymbol *) (symbol->udata.p))->value; - ca_psindx = ((asymbol *) (symbol->udata.p))->section->index; + asymbol *sym; + + if (bfd_get_flavour (abfd) == bfd_target_evax_flavour) + sym = ((struct evax_private_udata_struct *)symbol->udata.p)->enbsym; + else + sym = (asymbol *)symbol->udata.p; + code_address = sym->value; + ca_psindx = sym->section->index; } - psindx = symbol->section->index; + if (bfd_is_abs_section (symbol->section)) + psindx = abs_section_index; + else + psindx = symbol->section->index; _bfd_vms_output_quad (abfd, symbol->value); _bfd_vms_output_quad (abfd, code_address);