Fixes memory access violations triggered by running dlltool on fuzzed binaries.
[deliverable/binutils-gdb.git] / bfd / vms-alpha.c
index 7b543d20272835ce5427c595f93caef4c6487a3a..9576607a07e242b8060adcd90dfc1a7ea8563844 100644 (file)
@@ -1,6 +1,5 @@
 /* vms.c -- BFD back-end for EVAX (openVMS/Alpha) files.
-   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-   2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1996-2015 Free Software Foundation, Inc.
 
    Initial version written by Klaus Kaempf (kkaempf@rmi.de)
    Major rewrite by Adacore.
@@ -304,6 +303,7 @@ struct vms_private_data_struct
 
   struct module *modules;              /* list of all compilation units */
 
+  /* The DST section.  */
   asection *dst_section;
 
   unsigned int dst_ptr_offsets_count;  /* # of offsets in following array  */
@@ -329,11 +329,7 @@ struct vms_private_data_struct
   struct vms_internal_eisd_map *gbl_eisd_tail;
 
   /* linkage index counter used by conditional store commands */
-  int vms_linkage_index;
-
-  /* see tc-alpha.c of gas for a description.  */
-  int flag_hash_long_names;    /* -+, hash instead of truncate */
-  int flag_show_after_trunc;   /* -H, show hashing/truncation */
+  unsigned int vms_linkage_index;
 };
 
 #define PRIV2(abfd, name) \
@@ -368,18 +364,18 @@ struct vms_section_data_struct
   ((struct vms_section_data_struct *)sec->used_by_bfd)
 
 /* To be called from the debugger.  */
-struct vms_private_data_struct *bfd_vms_get_data (bfd *abfd);
+struct vms_private_data_struct *bfd_vms_get_data (bfd *);
 
-static int vms_get_remaining_object_record (bfd *abfd, int read_so_far);
+static int vms_get_remaining_object_record (bfd *, unsigned int);
 static bfd_boolean _bfd_vms_slurp_object_records (bfd * abfd);
 static void alpha_vms_add_fixup_lp (struct bfd_link_info *, bfd *, bfd *);
 static void alpha_vms_add_fixup_ca (struct bfd_link_info *, bfd *, bfd *);
 static void alpha_vms_add_fixup_qr (struct bfd_link_info *, bfd *, bfd *,
                                     bfd_vma);
-static void alpha_vms_add_lw_reloc (struct bfd_link_info *info);
-static void alpha_vms_add_qw_reloc (struct bfd_link_info *info);
-static void alpha_vms_add_lw_fixup (struct bfd_link_info *, unsigned int,
+static void alpha_vms_add_fixup_lr (struct bfd_link_info *, unsigned int,
                                     bfd_vma);
+static void alpha_vms_add_lw_reloc (struct bfd_link_info *);
+static void alpha_vms_add_qw_reloc (struct bfd_link_info *);
 
 struct vector_type
 {
@@ -439,7 +435,7 @@ struct alpha_vms_link_hash_table
 {
   struct bfd_link_hash_table root;
 
-  /* Vector of shared libaries.  */
+  /* Vector of shared libraries.  */
   struct vector_type shrlibs;
 
   /* Fixup section.  */
@@ -525,9 +521,11 @@ _bfd_vms_slurp_eisd (bfd *abfd, unsigned int offset)
       asection *section;
       flagword bfd_flags;
 
+      /* PR 17512: file: 3d9e9fe9.  */
+      if (offset >= PRIV (recrd.rec_size))
+       return FALSE;
       eisd = (struct vms_eisd *)(PRIV (recrd.rec) + offset);
       rec_size = bfd_getl32 (eisd->eisdsize);
-
       if (rec_size == 0)
         break;
 
@@ -792,7 +790,7 @@ _bfd_vms_get_object_record (bfd *abfd)
    Return the size of the record or 0 on failure.  */
 
 static int
-vms_get_remaining_object_record (bfd *abfd, int read_so_far)
+vms_get_remaining_object_record (bfd *abfd, unsigned int read_so_far)
 {
   unsigned int to_read;
 
@@ -801,7 +799,7 @@ vms_get_remaining_object_record (bfd *abfd, int read_so_far)
   /* Extract record size.  */
   PRIV (recrd.rec_size) = bfd_getl16 (PRIV (recrd.rec) + 2);
 
-  if (PRIV (recrd.rec_size) <= 0)
+  if (PRIV (recrd.rec_size) == 0)
     {
       bfd_set_error (bfd_error_file_truncated);
       return 0;
@@ -828,7 +826,10 @@ vms_get_remaining_object_record (bfd *abfd, int read_so_far)
         return 0;
       PRIV (recrd.buf_size) = to_read;
     }
-
+  /* PR 17512: file: 025-1974-0.004.  */
+  else if (to_read <= read_so_far)
+    return 0;
+  
   /* Read the remaining record.  */
   to_read -= read_so_far;
 
@@ -858,9 +859,12 @@ _bfd_vms_slurp_ehdr (bfd *abfd)
 {
   unsigned char *ptr;
   unsigned char *vms_rec;
+  unsigned char *end;
   int subtype;
 
   vms_rec = PRIV (recrd.rec);
+  /* PR 17512: file: 62736583.  */
+  end = PRIV (recrd.buf) + PRIV (recrd.buf_size);
 
   vms_debug2 ((2, "HDR/EMH\n"));
 
@@ -872,28 +876,42 @@ _bfd_vms_slurp_ehdr (bfd *abfd)
     {
     case EMH__C_MHD:
       /* Module header.  */
+      if (vms_rec + 21 >= end)
+       goto fail;
       PRIV (hdr_data).hdr_b_strlvl = vms_rec[6];
       PRIV (hdr_data).hdr_l_arch1  = bfd_getl32 (vms_rec + 8);
       PRIV (hdr_data).hdr_l_arch2  = bfd_getl32 (vms_rec + 12);
       PRIV (hdr_data).hdr_l_recsiz = bfd_getl32 (vms_rec + 16);
+      if ((vms_rec + 20 + vms_rec[20] + 1) >= end)
+       goto fail;
       PRIV (hdr_data).hdr_t_name   = _bfd_vms_save_counted_string (vms_rec + 20);
       ptr = vms_rec + 20 + vms_rec[20] + 1;
+      if ((ptr + *ptr + 1) >= end)
+       goto fail;
       PRIV (hdr_data).hdr_t_version =_bfd_vms_save_counted_string (ptr);
       ptr += *ptr + 1;
+      if (ptr + 17 >= end)
+       goto fail;
       PRIV (hdr_data).hdr_t_date = _bfd_vms_save_sized_string (ptr, 17);
       break;
 
     case EMH__C_LNM:
+      if (vms_rec + PRIV (recrd.rec_size - 6) > end)
+       goto fail;
       PRIV (hdr_data).hdr_c_lnm =
         _bfd_vms_save_sized_string (vms_rec, PRIV (recrd.rec_size - 6));
       break;
 
     case EMH__C_SRC:
+      if (vms_rec + PRIV (recrd.rec_size - 6) > end)
+       goto fail;
       PRIV (hdr_data).hdr_c_src =
         _bfd_vms_save_sized_string (vms_rec, PRIV (recrd.rec_size - 6));
       break;
 
     case EMH__C_TTL:
+      if (vms_rec + PRIV (recrd.rec_size - 6) > end)
+       goto fail;
       PRIV (hdr_data).hdr_c_ttl =
         _bfd_vms_save_sized_string (vms_rec, PRIV (recrd.rec_size - 6));
       break;
@@ -904,6 +922,7 @@ _bfd_vms_slurp_ehdr (bfd *abfd)
       break;
 
     default:
+    fail:
       bfd_set_error (bfd_error_wrong_format);
       return FALSE;
     }
@@ -939,60 +958,60 @@ struct sec_flags_struct
 static const struct sec_flags_struct evax_section_flags[] =
   {
     { EVAX_ABS_NAME,
-      (EGPS__V_SHR),
-      (SEC_DATA),
-      (EGPS__V_SHR),
-      (SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD) },
+      EGPS__V_SHR,
+      0,
+      EGPS__V_SHR,
+      0 },
     { EVAX_CODE_NAME,
-      (EGPS__V_PIC | EGPS__V_REL | EGPS__V_SHR | EGPS__V_EXE),
-      (SEC_CODE),
-      (EGPS__V_PIC | EGPS__V_REL | EGPS__V_SHR | EGPS__V_EXE),
-      (SEC_CODE | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD) },
+      EGPS__V_PIC | EGPS__V_REL | EGPS__V_SHR | EGPS__V_EXE,
+      SEC_CODE | SEC_READONLY,
+      EGPS__V_PIC | EGPS__V_REL | EGPS__V_SHR | EGPS__V_EXE,
+      SEC_CODE | SEC_READONLY | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD },
     { EVAX_LITERAL_NAME,
-      (EGPS__V_PIC | EGPS__V_REL | EGPS__V_SHR | EGPS__V_RD | EGPS__V_NOMOD),
-      (SEC_DATA | SEC_READONLY),
-      (EGPS__V_PIC | EGPS__V_REL | EGPS__V_SHR | EGPS__V_RD),
-      (SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_READONLY | SEC_LOAD) },
+      EGPS__V_PIC | EGPS__V_REL | EGPS__V_SHR | EGPS__V_RD | EGPS__V_NOMOD,
+      SEC_DATA | SEC_READONLY,
+      EGPS__V_PIC | EGPS__V_REL | EGPS__V_SHR | EGPS__V_RD,
+      SEC_DATA | SEC_READONLY | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD },
     { EVAX_LINK_NAME,
-      (EGPS__V_REL | EGPS__V_RD),
-      (SEC_DATA | SEC_READONLY),
-      (EGPS__V_REL | EGPS__V_RD),
-      (SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_READONLY | SEC_LOAD) },
+      EGPS__V_REL | EGPS__V_RD,
+      SEC_DATA | SEC_READONLY,
+      EGPS__V_REL | EGPS__V_RD,
+      SEC_DATA | SEC_READONLY | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD },
     { EVAX_DATA_NAME,
-      (EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT | EGPS__V_NOMOD),
-      (SEC_DATA),
-      (EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT),
-      (SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD) },
+      EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT | EGPS__V_NOMOD,
+      SEC_DATA,
+      EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT,
+      SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD },
     { EVAX_BSS_NAME,
-      (EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT | EGPS__V_NOMOD),
-      (SEC_NO_FLAGS),
-      (EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT | EGPS__V_NOMOD),
-      (SEC_ALLOC) },
+      EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT | EGPS__V_NOMOD,
+      SEC_NO_FLAGS,
+      EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT | EGPS__V_NOMOD,
+      SEC_ALLOC },
     { EVAX_READONLYADDR_NAME,
-      (EGPS__V_PIC | EGPS__V_REL | EGPS__V_RD),
-      (SEC_DATA | SEC_READONLY),
-      (EGPS__V_PIC | EGPS__V_REL | EGPS__V_RD),
-      (SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_READONLY | SEC_LOAD) },
+      EGPS__V_PIC | EGPS__V_REL | EGPS__V_RD,
+      SEC_DATA | SEC_READONLY,
+      EGPS__V_PIC | EGPS__V_REL | EGPS__V_RD,
+      SEC_DATA | SEC_READONLY | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD },
     { EVAX_READONLY_NAME,
-      (EGPS__V_PIC | EGPS__V_REL | EGPS__V_SHR | EGPS__V_RD | EGPS__V_NOMOD),
-      (SEC_DATA | SEC_READONLY),
-      (EGPS__V_PIC | EGPS__V_REL | EGPS__V_SHR | EGPS__V_RD),
-      (SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_READONLY | SEC_LOAD) },
+      EGPS__V_PIC | EGPS__V_REL | EGPS__V_SHR | EGPS__V_RD | EGPS__V_NOMOD,
+      SEC_DATA | SEC_READONLY,
+      EGPS__V_PIC | EGPS__V_REL | EGPS__V_SHR | EGPS__V_RD,
+      SEC_DATA | SEC_READONLY | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD },
     { EVAX_LOCAL_NAME,
-      (EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT),
-      (SEC_DATA),
-      (EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT),
-      (SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD) },
+      EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT,
+      SEC_DATA,
+      EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT,
+      SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD },
     { EVAX_LITERALS_NAME,
-      (EGPS__V_PIC | EGPS__V_OVR),
-      (SEC_DATA | SEC_READONLY),
-      (EGPS__V_PIC | EGPS__V_OVR),
-      (SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_READONLY | SEC_LOAD) },
+      EGPS__V_PIC | EGPS__V_OVR,
+      SEC_DATA | SEC_READONLY,
+      EGPS__V_PIC | EGPS__V_OVR,
+      SEC_DATA | SEC_READONLY | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD },
     { NULL,
-      (EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT),
-      (SEC_DATA),
-      (EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT),
-      (SEC_IN_MEMORY | SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD) }
+      EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT,
+      SEC_DATA,
+      EGPS__V_REL | EGPS__V_RD | EGPS__V_WRT,
+      SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD }
   };
 
 /* Retrieve BFD section flags by name and size.  */
@@ -1103,12 +1122,8 @@ static bfd_boolean
 _bfd_vms_slurp_egsd (bfd *abfd)
 {
   int gsd_type, gsd_size;
-  asection *section;
   unsigned char *vms_rec;
-  flagword new_flags, old_flags;
-  char *name;
   unsigned long base_addr;
-  unsigned long align_addr;
 
   vms_debug2 ((2, "EGSD\n"));
 
@@ -1130,32 +1145,59 @@ _bfd_vms_slurp_egsd (bfd *abfd)
       switch (gsd_type)
        {
        case EGSD__C_PSC:
+          /* Program section definition.  */
          {
-           /* Program section definition.  */
             struct vms_egps *egps = (struct vms_egps *)vms_rec;
+            flagword new_flags, vms_flags;
+            asection *section;
+
+           vms_flags = bfd_getl16 (egps->flags);
 
-           name = _bfd_vms_save_counted_string (&egps->namlng);
-           section = bfd_make_section (abfd, name);
-           if (!section)
-             return FALSE;
-
-           old_flags = bfd_getl16 (egps->flags);
-            vms_section_data (section)->flags = old_flags;
-            vms_section_data (section)->no_flags = 0;
-           section->size = bfd_getl32 (egps->alloc);
-           new_flags = vms_secflag_by_name (evax_section_flags, name,
-                                            section->size > 0);
-            if (!(old_flags & EGPS__V_NOMOD))
+            if ((vms_flags & EGPS__V_REL) == 0)
               {
-                new_flags |= SEC_HAS_CONTENTS;
-                if (old_flags & EGPS__V_REL)
-                  new_flags |= SEC_RELOC;
+                /* Use the global absolute section for all
+                   absolute sections.  */
+                section = bfd_abs_section_ptr;
               }
-           if (!bfd_set_section_flags (abfd, section, new_flags))
-             return FALSE;
-           section->alignment_power = egps->align;
-            if ((old_flags & EGPS__V_REL) != 0)
+            else
               {
+                char *name;
+                unsigned long align_addr;
+
+                name = _bfd_vms_save_counted_string (&egps->namlng);
+
+                section = bfd_make_section (abfd, name);
+                if (!section)
+                  return FALSE;
+
+                section->filepos = 0;
+                section->size = bfd_getl32 (egps->alloc);
+                section->alignment_power = egps->align;
+
+                vms_section_data (section)->flags = vms_flags;
+                vms_section_data (section)->no_flags = 0;
+
+                new_flags = vms_secflag_by_name (evax_section_flags, name,
+                                                 section->size > 0);
+                if (section->size > 0)
+                  new_flags |= SEC_LOAD;
+                if (!(vms_flags & EGPS__V_NOMOD) && section->size > 0)
+                  {
+                    /* Set RELOC and HAS_CONTENTS if the section is not
+                       demand-zero and not empty.  */
+                    new_flags |= SEC_HAS_CONTENTS;
+                    if (vms_flags & EGPS__V_REL)
+                      new_flags |= SEC_RELOC;
+                  }
+                if (vms_flags & EGPS__V_EXE)
+                  {
+                    /* Set CODE if section is executable.  */
+                    new_flags |= SEC_CODE;
+                    new_flags &= ~SEC_DATA;
+                  }
+                if (!bfd_set_section_flags (abfd, section, new_flags))
+                  return FALSE;
+
                 /* Give a non-overlapping vma to non absolute sections.  */
                 align_addr = (1 << section->alignment_power);
                 if ((base_addr % align_addr) != 0)
@@ -1163,9 +1205,6 @@ _bfd_vms_slurp_egsd (bfd *abfd)
                 section->vma = (bfd_vma)base_addr;
                 base_addr += section->size;
               }
-            else
-              section->vma = 0;
-           section->filepos = 0;
 
             /* Append it to the section array.  */
             if (PRIV (section_count) >= PRIV (section_max))
@@ -1182,14 +1221,6 @@ _bfd_vms_slurp_egsd (bfd *abfd)
 
             PRIV (sections)[PRIV (section_count)] = section;
             PRIV (section_count)++;
-
-#if VMS_DEBUG
-           vms_debug (4, "EGSD P-section %d (%s, flags %04x) ",
-                      section->index, name, old_flags);
-           vms_debug (4, "%lu bytes at 0x%08lx (mem %p)\n",
-                      (unsigned long)section->size,
-                       (unsigned long)section->vma, section->contents);
-#endif
          }
          break;
 
@@ -1198,6 +1229,7 @@ _bfd_vms_slurp_egsd (bfd *abfd)
             int nameoff;
             struct vms_symbol_entry *entry;
             struct vms_egsy *egsy = (struct vms_egsy *) vms_rec;
+            flagword old_flags;
 
            old_flags = bfd_getl16 (egsy->flags);
            if (old_flags & EGSY__V_DEF)
@@ -1241,15 +1273,11 @@ _bfd_vms_slurp_egsd (bfd *abfd)
 
        case EGSD__C_SYMG:
          {
-            int nameoff;
             struct vms_symbol_entry *entry;
             struct vms_egst *egst = (struct vms_egst *)vms_rec;
+            flagword old_flags;
 
            old_flags = bfd_getl16 (egst->header.flags);
-           if (old_flags & EGSY__V_DEF)
-              nameoff = ESDF__B_NAMLNG;
-            else
-              nameoff = ESRF__B_NAMLNG;
 
             entry = add_symbol (abfd, &egst->namlng);
 
@@ -1711,7 +1739,7 @@ _bfd_vms_slurp_etir (bfd *abfd, struct bfd_link_info *info)
 #if VMS_DEBUG
       _bfd_vms_debug (4, "etir: %s(%d)\n",
                       _bfd_vms_etir_name (cmd), cmd);
-      _bfd_hexdump (8, ptr, cmd_length - 4, (long) ptr);
+      _bfd_hexdump (8, ptr, cmd_length - 4, 0);
 #endif
 
       switch (cmd)
@@ -1801,7 +1829,7 @@ _bfd_vms_slurp_etir (bfd *abfd, struct bfd_link_info *info)
             }
           else if (rel1 & RELC_SHR_BASE)
             {
-              alpha_vms_add_lw_fixup (info, rel1 & RELC_MASK, op1);
+              alpha_vms_add_fixup_lr (info, rel1 & RELC_MASK, op1);
               rel1 = RELC_NONE;
             }
           if (rel1 != RELC_NONE)
@@ -2427,7 +2455,7 @@ vms_initialize (bfd * abfd)
 static const struct bfd_target *
 alpha_vms_object_p (bfd *abfd)
 {
-  PTR tdata_save = abfd->tdata.any;
+  void *tdata_save = abfd->tdata.any;
   unsigned int test_len;
   unsigned char *buf;
 
@@ -2469,10 +2497,7 @@ alpha_vms_object_p (bfd *abfd)
   PRIV (recrd.rec) = buf;
 
   if (bfd_bread (buf, test_len, abfd) != test_len)
-    {
-      bfd_set_error (bfd_error_file_truncated);
-      goto error_ret;
-    }
+    goto err_wrong_format;
 
   /* Is it an image?  */
   if ((bfd_getl32 (buf) == EIHD__K_MAJORID)
@@ -2497,7 +2522,6 @@ alpha_vms_object_p (bfd *abfd)
           if (buf == NULL)
             {
               PRIV (recrd.buf) = NULL;
-              bfd_set_error (bfd_error_no_memory);
               goto error_ret;
             }
           PRIV (recrd.buf) = buf;
@@ -2512,10 +2536,7 @@ alpha_vms_object_p (bfd *abfd)
       while (remaining > 0)
         {
           if (bfd_bread (buf + read_so_far, to_read, abfd) != to_read)
-            {
-              bfd_set_error (bfd_error_file_truncated);
-              goto err_wrong_format;
-            }
+           goto err_wrong_format;
 
           read_so_far += to_read;
           remaining -= to_read;
@@ -2526,6 +2547,9 @@ alpha_vms_object_p (bfd *abfd)
       /* Reset the record pointer.  */
       PRIV (recrd.rec) = buf;
 
+      /* PR 17512: file: 7d7c57c2.  */
+      if (PRIV (recrd.rec_size) < sizeof (struct vms_eihd))
+       goto error_ret;
       vms_debug2 ((2, "file type is image\n"));
 
       if (_bfd_vms_slurp_eihd (abfd, &eisd_offset, &eihs_offset) != TRUE)
@@ -2650,7 +2674,7 @@ _bfd_vms_write_eeom (bfd *abfd)
   _bfd_vms_output_alignment (recwr, 2);
 
   _bfd_vms_output_begin (recwr, EOBJ__C_EEOM);
-  _bfd_vms_output_long (recwr, (unsigned long) (PRIV (vms_linkage_index) >> 1));
+  _bfd_vms_output_long (recwr, PRIV (vms_linkage_index + 1) >> 1);
   _bfd_vms_output_byte (recwr, 0);     /* Completion code.  */
   _bfd_vms_output_byte (recwr, 0);     /* Fill byte.  */
 
@@ -2666,7 +2690,7 @@ _bfd_vms_write_eeom (bfd *abfd)
          return FALSE;
        }
       _bfd_vms_output_short (recwr, 0);
-      _bfd_vms_output_long (recwr, (unsigned long) (section->index));
+      _bfd_vms_output_long (recwr, (unsigned long) section->target_index);
       _bfd_vms_output_long (recwr,
                             (unsigned long) bfd_get_start_address (abfd));
       _bfd_vms_output_long (recwr, 0);
@@ -2676,88 +2700,6 @@ _bfd_vms_write_eeom (bfd *abfd)
   return TRUE;
 }
 
-/* This hash routine borrowed from GNU-EMACS, and strengthened
-   slightly.  ERY.  */
-
-static int
-hash_string (const char *ptr)
-{
-  const unsigned char *p = (unsigned char *) ptr;
-  const unsigned char *end = p + strlen (ptr);
-  unsigned char c;
-  int hash = 0;
-
-  while (p != end)
-    {
-      c = *p++;
-      hash = ((hash << 3) + (hash << 15) + (hash >> 28) + c);
-    }
-  return hash;
-}
-
-/* Generate a length-hashed VMS symbol name (limited to maxlen chars).  */
-
-static char *
-_bfd_vms_length_hash_symbol (bfd *abfd, const char *in, int maxlen)
-{
-  unsigned long result;
-  int in_len;
-  char *new_name;
-  const char *old_name;
-  int i;
-  static char outbuf[EOBJ__C_SYMSIZ + 1];
-  char *out = outbuf;
-
-#if VMS_DEBUG
-  vms_debug (4, "_bfd_vms_length_hash_symbol \"%s\"\n", in);
-#endif
-
-  if (maxlen > EOBJ__C_SYMSIZ)
-    maxlen = EOBJ__C_SYMSIZ;
-
-  /* Save this for later.  */
-  new_name = out;
-
-  /* We may need to truncate the symbol, save the hash for later.  */
-  in_len = strlen (in);
-
-  result = (in_len > maxlen) ? hash_string (in) : 0;
-
-  old_name = in;
-
-  /* Do the length checking.  */
-  if (in_len <= maxlen)
-    i = in_len;
-  else
-    {
-      if (PRIV (flag_hash_long_names))
-       i = maxlen - 9;
-      else
-       i = maxlen;
-    }
-
-  strncpy (out, in, (size_t) i);
-  in += i;
-  out += i;
-
-  if ((in_len > maxlen)
-      && PRIV (flag_hash_long_names))
-    sprintf (out, "_%08lx", result);
-  else
-    *out = 0;
-
-#if VMS_DEBUG
-  vms_debug (4, "--> [%d]\"%s\"\n", (int)strlen (outbuf), outbuf);
-#endif
-
-  if (in_len > maxlen
-       && PRIV (flag_hash_long_names)
-       && PRIV (flag_show_after_trunc))
-    printf (_("Symbol %s replaced by %s\n"), old_name, new_name);
-
-  return outbuf;
-}
-
 static void
 vector_grow1 (struct vector_type *vec, size_t elsz)
 {
@@ -2906,7 +2848,11 @@ alpha_vms_create_eisd_for_section (bfd *abfd, asection *sec)
   if (!(sec->flags & SEC_READONLY))
     eisd->u.eisd.flags |= EISD__M_WRT | EISD__M_CRF;
 
-  if (!(sec->flags & SEC_LOAD))
+  /* If relocations or fixup will be applied, make this isect writeable.  */
+  if (sec->flags & SEC_RELOC)
+    eisd->u.eisd.flags |= EISD__M_WRT | EISD__M_CRF;
+
+  if (!(sec->flags & SEC_HAS_CONTENTS))
     {
       eisd->u.eisd.flags |= EISD__M_DZRO;
       eisd->u.eisd.flags &= ~EISD__M_CRF;
@@ -3007,6 +2953,7 @@ alpha_vms_write_exec (bfd *abfd)
     char *module;
     unsigned int len;
 
+    /* Set module name.  */
     module = vms_get_module_name (bfd_get_filename (abfd), TRUE);
     len = strlen (module);
     if (len > sizeof (eihi->imgnam) - 1)
@@ -3015,8 +2962,15 @@ alpha_vms_write_exec (bfd *abfd)
     memcpy (eihi->imgnam + 1, module, len);
     free (module);
   }
-  bfd_putl32 (0, eihi->linktime + 0);
-  bfd_putl32 (0, eihi->linktime + 4);
+  {
+    unsigned int lo;
+    unsigned int hi;
+
+    /* Set time.  */
+    vms_get_time (&hi, &lo);
+    bfd_putl32 (lo, eihi->linktime + 0);
+    bfd_putl32 (hi, eihi->linktime + 4);
+  }
   eihi->imgid[0] = 0;
   eihi->linkid[0] = 0;
   eihi->imgbid[0] = 0;
@@ -3219,7 +3173,6 @@ alpha_vms_write_exec (bfd *abfd)
       for (i = 0; i < PRIV (gsd_sym_count); i++)
         {
           struct vms_symbol_entry *sym = PRIV (syms)[i];
-          char *hash;
           bfd_vma val;
           bfd_vma ep;
 
@@ -3246,8 +3199,7 @@ alpha_vms_write_exec (bfd *abfd)
          _bfd_vms_output_quad (recwr, ep);
          _bfd_vms_output_quad (recwr, val);
          _bfd_vms_output_long (recwr, 0);
-          hash = _bfd_vms_length_hash_symbol (abfd, sym->name, EOBJ__C_SYMSIZ);
-          _bfd_vms_output_counted (recwr, hash);
+          _bfd_vms_output_counted (recwr, sym->name);
           _bfd_vms_output_end_subrec (recwr);
           if ((i % 5) == 4)
             _bfd_vms_output_end (abfd, recwr);
@@ -3271,18 +3223,13 @@ _bfd_vms_write_egsd (bfd *abfd)
   asection *section;
   asymbol *symbol;
   unsigned int symnum;
-  int last_index = -1;
-  char dummy_name[10];
   const char *sname;
   flagword new_flags, old_flags;
-  int abs_section_index = 0;
+  int abs_section_index = -1;
+  unsigned int target_index = 0;
   struct vms_rec_wr *recwr = &PRIV (recwr);
 
-  vms_debug2 ((2, "vms_write_gsd\n"));
-
-  /* Output sections.  */
-  section = abfd->sections;
-  vms_debug2 ((3, "%d sections found\n", abfd->section_count));
+  vms_debug2 ((2, "vms_write_egsd\n"));
 
   /* Egsd is quadword aligned.  */
   _bfd_vms_output_alignment (recwr, 8);
@@ -3290,15 +3237,28 @@ _bfd_vms_write_egsd (bfd *abfd)
   _bfd_vms_output_begin (recwr, EOBJ__C_EGSD);
   _bfd_vms_output_long (recwr, 0);
 
-  while (section != 0)
+  /* Number sections.  */
+  for (section = abfd->sections; section != NULL; section = section->next)
+    {
+      if (section->flags & SEC_DEBUGGING)
+        continue;
+      if (!strcmp (section->name, ".vmsdebug"))
+        {
+          section->flags |= SEC_DEBUGGING;
+          continue;
+        }
+      section->target_index = target_index++;
+    }
+
+  for (section = abfd->sections; section != NULL; section = section->next)
     {
       vms_debug2 ((3, "Section #%d %s, %d bytes\n",
-                   section->index, section->name, (int)section->size));
+                   section->target_index, section->name, (int)section->size));
 
       /* 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;
+      if (section->flags & SEC_DEBUGGING)
+        continue;
 
       /* 13 bytes egsd, max 31 chars name -> should be 44 bytes.  */
       if (_bfd_vms_output_check (recwr, 64) < 0)
@@ -3308,20 +3268,6 @@ _bfd_vms_write_egsd (bfd *abfd)
          _bfd_vms_output_long (recwr, 0);
        }
 
-      /* Create dummy sections to keep consecutive indices.  */
-      while (section->index - last_index > 1)
-       {
-         vms_debug2 ((3, "index %d, last %d\n", section->index, last_index));
-         _bfd_vms_output_begin_subrec (recwr, EGSD__C_PSC);
-         _bfd_vms_output_short (recwr, 0);
-         _bfd_vms_output_short (recwr, 0);
-         _bfd_vms_output_long (recwr, 0);
-         sprintf (dummy_name, ".DUMMY%02d", last_index);
-         _bfd_vms_output_counted (recwr, dummy_name);
-         _bfd_vms_output_end_subrec (recwr);
-         last_index++;
-       }
-
       /* Don't know if this is necessary for the linker but for now it keeps
         vms_slurp_gsd happy.  */
       sname = section->name;
@@ -3342,20 +3288,12 @@ _bfd_vms_write_egsd (bfd *abfd)
          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;
-           }
+            sname = EVAX_LITERALS_NAME;
          else if ((*sname == 'c') && (strcmp (sname, "comm") == 0))
            sname = EVAX_COMMON_NAME;
          else if ((*sname == 'l') && (strcmp (sname, "lcomm") == 0))
            sname = EVAX_LOCAL_NAME;
        }
-      else
-       sname = _bfd_vms_length_hash_symbol (abfd, sname, EOBJ__C_SECSIZ);
-
-      _bfd_vms_output_begin_subrec (recwr, EGSD__C_PSC);
-      _bfd_vms_output_short (recwr, section->alignment_power & 0xff);
 
       if (bfd_is_com_section (section))
        new_flags = (EGPS__V_OVR | EGPS__V_REL | EGPS__V_GBL | EGPS__V_RD
@@ -3375,14 +3313,17 @@ _bfd_vms_write_egsd (bfd *abfd)
       vms_debug2 ((3, "new_flags %x, _raw_size %lu\n",
                    new_flags, (unsigned long)section->size));
 
+      _bfd_vms_output_begin_subrec (recwr, EGSD__C_PSC);
+      _bfd_vms_output_short (recwr, section->alignment_power & 0xff);
       _bfd_vms_output_short (recwr, new_flags);
       _bfd_vms_output_long (recwr, (unsigned long) section->size);
       _bfd_vms_output_counted (recwr, sname);
       _bfd_vms_output_end_subrec (recwr);
 
-      last_index = section->index;
-done:
-      section = section->next;
+      /* If the section is an obsolute one, remind its index as it will be
+         used later for absolute symbols.  */
+      if ((new_flags & EGPS__V_REL) == 0 && abs_section_index < 0)
+        abs_section_index = section->target_index;
     }
 
   /* Output symbols.  */
@@ -3392,17 +3333,13 @@ done:
 
   for (symnum = 0; symnum < abfd->symcount; symnum++)
     {
-      char *hash;
-
       symbol = abfd->outsymbols[symnum];
       old_flags = symbol->flags;
 
-      /* Work-around a missing feature:  consider __main as the main entry point.  */
-      if (*(symbol->name) == '_')
-       {
-         if (strcmp (symbol->name, "__main") == 0)
-           bfd_set_start_address (abfd, (bfd_vma)symbol->value);
-       }
+      /* Work-around a missing feature:  consider __main as the main entry
+         point.  */
+      if (symbol->name[0] == '_' && strcmp (symbol->name, "__main") == 0)
+       bfd_set_start_address (abfd, (bfd_vma)symbol->value);
 
       /* Only put in the GSD the global and the undefined symbols.  */
       if (old_flags & BSF_FILE)
@@ -3418,14 +3355,32 @@ done:
             continue;
         }
 
-      /* 13 bytes egsd, max 64 chars name -> should be 77 bytes.  */
-      if (_bfd_vms_output_check (recwr, 80) < 0)
+      /* 13 bytes egsd, max 64 chars name -> should be 77 bytes.  Add 16 more
+         bytes for a possible ABS section.  */
+      if (_bfd_vms_output_check (recwr, 80 + 16) < 0)
        {
          _bfd_vms_output_end (abfd, recwr);
          _bfd_vms_output_begin (recwr, EOBJ__C_EGSD);
          _bfd_vms_output_long (recwr, 0);
        }
 
+      if ((old_flags & BSF_GLOBAL) != 0
+          && bfd_is_abs_section (symbol->section)
+          && abs_section_index <= 0)
+        {
+          /* Create an absolute section if none was defined.  It is highly
+             unlikely that the name $ABS$ clashes with a user defined
+             non-absolute section name.  */
+          _bfd_vms_output_begin_subrec (recwr, EGSD__C_PSC);
+          _bfd_vms_output_short (recwr, 4);
+          _bfd_vms_output_short (recwr, EGPS__V_SHR);
+          _bfd_vms_output_long (recwr, 0);
+          _bfd_vms_output_counted (recwr, "$ABS$");
+          _bfd_vms_output_end_subrec (recwr);
+
+          abs_section_index = target_index++;
+        }
+
       _bfd_vms_output_begin_subrec (recwr, EGSD__C_SYM);
 
       /* Data type, alignment.  */
@@ -3462,22 +3417,22 @@ done:
            {
              asymbol *sym;
 
-              sym = ((struct evax_private_udata_struct *)symbol->udata.p)->enbsym;
+              sym =
+                ((struct evax_private_udata_struct *)symbol->udata.p)->enbsym;
              code_address = sym->value;
-             ca_psindx = sym->section->index;
+             ca_psindx = sym->section->target_index;
            }
          if (bfd_is_abs_section (symbol->section))
            psindx = abs_section_index;
          else
-           psindx = symbol->section->index;
+           psindx = symbol->section->target_index;
 
          _bfd_vms_output_quad (recwr, symbol->value);
          _bfd_vms_output_quad (recwr, code_address);
          _bfd_vms_output_long (recwr, ca_psindx);
          _bfd_vms_output_long (recwr, psindx);
        }
-      hash = _bfd_vms_length_hash_symbol (abfd, symbol->name, EOBJ__C_SYMSIZ);
-      _bfd_vms_output_counted (recwr, hash);
+      _bfd_vms_output_counted (recwr, symbol->name);
 
       _bfd_vms_output_end_subrec (recwr);
     }
@@ -3495,8 +3450,6 @@ _bfd_vms_write_ehdr (bfd *abfd)
 {
   asymbol *symbol;
   unsigned int symnum;
-  int had_case = 0;
-  int had_file = 0;
   struct vms_rec_wr *recwr = &PRIV (recwr);
 
   vms_debug2 ((2, "vms_write_ehdr (%p)\n", abfd));
@@ -3516,22 +3469,9 @@ _bfd_vms_write_ehdr (bfd *abfd)
 
       if (symbol->flags & BSF_FILE)
        {
-         if (CONST_STRNEQ ((char *)symbol->name, "<CASE:"))
-           {
-             PRIV (flag_hash_long_names) = symbol->name[6] - '0';
-             PRIV (flag_show_after_trunc) = symbol->name[7] - '0';
-
-             if (had_file)
-               break;
-             had_case = 1;
-             continue;
-           }
-
          _bfd_vms_output_dump (recwr, (unsigned char *) symbol->name,
                                (int) strlen (symbol->name));
-         if (had_case)
-           break;
-         had_file = 1;
+         break;
        }
     }
 
@@ -3579,8 +3519,7 @@ start_etir_or_etbt_record (bfd *abfd, asection *section, bfd_vma offset)
 {
   struct vms_rec_wr *recwr = &PRIV (recwr);
 
-  if (section->name[0] == '.' && section->name[1] == 'v'
-      && !strcmp (section->name, ".vmsdebug"))
+  if (section->flags & SEC_DEBUGGING)
     {
       _bfd_vms_output_begin (recwr, EOBJ__C_ETBT);
 
@@ -3604,7 +3543,7 @@ start_etir_or_etbt_record (bfd *abfd, asection *section, bfd_vma offset)
         {
           /* Push start offset.  */
           _bfd_vms_output_begin_subrec (recwr, ETIR__C_STA_PQ);
-          _bfd_vms_output_long (recwr, (unsigned long) section->index);
+          _bfd_vms_output_long (recwr, (unsigned long) section->target_index);
           _bfd_vms_output_quad (recwr, offset);
           _bfd_vms_output_end_subrec (recwr);
 
@@ -3704,12 +3643,12 @@ _bfd_vms_write_etir (bfd * abfd, int objtype ATTRIBUTE_UNUSED)
 
   _bfd_vms_output_alignment (recwr, 4);
 
-  PRIV (vms_linkage_index) = 1;
+  PRIV (vms_linkage_index) = 0;
 
   for (section = abfd->sections; section; section = section->next)
     {
       vms_debug2 ((4, "writing %d. section '%s' (%d bytes)\n",
-                   section->index, section->name, (int) (section->size)));
+                   section->target_index, section->name, (int) (section->size)));
 
       if (!(section->flags & SEC_HAS_CONTENTS)
          || bfd_is_com_section (section))
@@ -3732,7 +3671,7 @@ _bfd_vms_write_etir (bfd * abfd, int objtype ATTRIBUTE_UNUSED)
          int pass2_in_progress = 0;
          unsigned int irel;
 
-         if (section->reloc_count <= 0)
+         if (section->reloc_count == 0)
            (*_bfd_error_handler)
              (_("SEC_RELOC with no relocs in section %s"), section->name);
 
@@ -3768,7 +3707,6 @@ _bfd_vms_write_etir (bfd * abfd, int objtype ATTRIBUTE_UNUSED)
              asection *sec = sym->section;
              bfd_boolean defer = defer_reloc_p (rptr);
              unsigned int slen;
-             char *hash;
 
              if (pass2_in_progress)
                {
@@ -3807,13 +3745,11 @@ _bfd_vms_write_etir (bfd * abfd, int objtype ATTRIBUTE_UNUSED)
                    {
                      bfd_vma addend = rptr->addend;
                      slen = strlen ((char *) sym->name);
-                     hash = _bfd_vms_length_hash_symbol
-                        (abfd, sym->name, EOBJ__C_SYMSIZ);
                      etir_output_check (abfd, section, curr_addr, slen);
                      if (addend)
                        {
                          _bfd_vms_output_begin_subrec (recwr, ETIR__C_STA_GBL);
-                         _bfd_vms_output_counted (recwr, hash);
+                         _bfd_vms_output_counted (recwr, sym->name);
                          _bfd_vms_output_end_subrec (recwr);
                          _bfd_vms_output_begin_subrec (recwr, ETIR__C_STA_LW);
                          _bfd_vms_output_long (recwr, (unsigned long) addend);
@@ -3827,7 +3763,7 @@ _bfd_vms_write_etir (bfd * abfd, int objtype ATTRIBUTE_UNUSED)
                        {
                          _bfd_vms_output_begin_subrec
                             (recwr, ETIR__C_STO_GBL_LW);
-                         _bfd_vms_output_counted (recwr, hash);
+                         _bfd_vms_output_counted (recwr, sym->name);
                          _bfd_vms_output_end_subrec (recwr);
                        }
                    }
@@ -3844,7 +3780,8 @@ _bfd_vms_write_etir (bfd * abfd, int objtype ATTRIBUTE_UNUSED)
                    {
                      etir_output_check (abfd, section, curr_addr, 32);
                      _bfd_vms_output_begin_subrec (recwr, ETIR__C_STA_PQ);
-                     _bfd_vms_output_long (recwr, (unsigned long) sec->index);
+                     _bfd_vms_output_long (recwr,
+                                            (unsigned long) sec->target_index);
                      _bfd_vms_output_quad (recwr, rptr->addend + sym->value);
                      _bfd_vms_output_end_subrec (recwr);
                      /* ??? Table B-8 of the OpenVMS Linker Utilily Manual
@@ -3861,13 +3798,11 @@ _bfd_vms_write_etir (bfd * abfd, int objtype ATTRIBUTE_UNUSED)
                    {
                      bfd_vma addend = rptr->addend;
                      slen = strlen ((char *) sym->name);
-                     hash = _bfd_vms_length_hash_symbol
-                        (abfd, sym->name, EOBJ__C_SYMSIZ);
                      etir_output_check (abfd, section, curr_addr, slen);
                      if (addend)
                        {
                          _bfd_vms_output_begin_subrec (recwr, ETIR__C_STA_GBL);
-                         _bfd_vms_output_counted (recwr, hash);
+                         _bfd_vms_output_counted (recwr, sym->name);
                          _bfd_vms_output_end_subrec (recwr);
                          _bfd_vms_output_begin_subrec (recwr, ETIR__C_STA_QW);
                          _bfd_vms_output_quad (recwr, addend);
@@ -3880,7 +3815,7 @@ _bfd_vms_write_etir (bfd * abfd, int objtype ATTRIBUTE_UNUSED)
                      else
                        {
                          _bfd_vms_output_begin_subrec (recwr, ETIR__C_STO_GBL);
-                         _bfd_vms_output_counted (recwr, hash);
+                         _bfd_vms_output_counted (recwr, sym->name);
                          _bfd_vms_output_end_subrec (recwr);
                        }
                    }
@@ -3897,7 +3832,8 @@ _bfd_vms_write_etir (bfd * abfd, int objtype ATTRIBUTE_UNUSED)
                    {
                      etir_output_check (abfd, section, curr_addr, 32);
                      _bfd_vms_output_begin_subrec (recwr, ETIR__C_STA_PQ);
-                     _bfd_vms_output_long (recwr, (unsigned long) sec->index);
+                     _bfd_vms_output_long (recwr,
+                                            (unsigned long) sec->target_index);
                      _bfd_vms_output_quad (recwr, rptr->addend + sym->value);
                      _bfd_vms_output_end_subrec (recwr);
                      _bfd_vms_output_begin_subrec (recwr, ETIR__C_STO_OFF);
@@ -3913,22 +3849,19 @@ _bfd_vms_write_etir (bfd * abfd, int objtype ATTRIBUTE_UNUSED)
                  etir_output_check (abfd, section, curr_addr, 64);
                  _bfd_vms_output_begin_subrec (recwr, ETIR__C_STC_LP_PSB);
                  _bfd_vms_output_long
-                   (recwr, (unsigned long) PRIV (vms_linkage_index));
-                 PRIV (vms_linkage_index) += 2;
-                 hash = _bfd_vms_length_hash_symbol
-                    (abfd, sym->name, EOBJ__C_SYMSIZ);
-                 _bfd_vms_output_counted (recwr, hash);
+                   (recwr, (unsigned long) rptr->addend);
+                  if (rptr->addend > PRIV (vms_linkage_index))
+                    PRIV (vms_linkage_index) = rptr->addend;
+                 _bfd_vms_output_counted (recwr, sym->name);
                  _bfd_vms_output_byte (recwr, 0);
                  _bfd_vms_output_end_subrec (recwr);
                  break;
 
                case ALPHA_R_CODEADDR:
                  slen = strlen ((char *) sym->name);
-                 hash = _bfd_vms_length_hash_symbol
-                    (abfd, sym->name, EOBJ__C_SYMSIZ);
                  etir_output_check (abfd, section, curr_addr, slen);
                  _bfd_vms_output_begin_subrec (recwr, ETIR__C_STO_CA);
-                 _bfd_vms_output_counted (recwr, hash);
+                 _bfd_vms_output_counted (recwr, sym->name);
                  _bfd_vms_output_end_subrec (recwr);
                  break;
 
@@ -3940,15 +3873,13 @@ _bfd_vms_write_etir (bfd * abfd, int objtype ATTRIBUTE_UNUSED)
                  _bfd_vms_output_begin_subrec (recwr, ETIR__C_STC_NOP_GBL);
                  _bfd_vms_output_long (recwr, (unsigned long) udata->lkindex);
                  _bfd_vms_output_long
-                   (recwr, (unsigned long) udata->enbsym->section->index);
+                   (recwr, (unsigned long) section->target_index);
                  _bfd_vms_output_quad (recwr, rptr->address);
                  _bfd_vms_output_long (recwr, (unsigned long) 0x47ff041f);
                  _bfd_vms_output_long
-                   (recwr, (unsigned long) udata->enbsym->section->index);
+                   (recwr, (unsigned long) section->target_index);
                  _bfd_vms_output_quad (recwr, rptr->addend);
-                 _bfd_vms_output_counted
-                   (recwr, _bfd_vms_length_hash_symbol
-                     (abfd, udata->origname, EOBJ__C_SYMSIZ));
+                 _bfd_vms_output_counted (recwr, udata->origname);
                  _bfd_vms_output_end_subrec (recwr);
                  break;
 
@@ -3965,15 +3896,13 @@ _bfd_vms_write_etir (bfd * abfd, int objtype ATTRIBUTE_UNUSED)
                  _bfd_vms_output_long
                    (recwr, (unsigned long) udata->lkindex + 1);
                  _bfd_vms_output_long
-                   (recwr, (unsigned long) udata->enbsym->section->index);
+                   (recwr, (unsigned long) section->target_index);
                  _bfd_vms_output_quad (recwr, rptr->address);
                  _bfd_vms_output_long (recwr, (unsigned long) 0x237B0000);
                  _bfd_vms_output_long
-                   (recwr, (unsigned long) udata->bsym->section->index);
+                   (recwr, (unsigned long) udata->bsym->section->target_index);
                  _bfd_vms_output_quad (recwr, rptr->addend);
-                 _bfd_vms_output_counted
-                   (recwr, _bfd_vms_length_hash_symbol
-                     (abfd, udata->origname, EOBJ__C_SYMSIZ));
+                 _bfd_vms_output_counted (recwr, udata->origname);
                  _bfd_vms_output_end_subrec (recwr);
                  break;
 
@@ -3985,15 +3914,13 @@ _bfd_vms_write_etir (bfd * abfd, int objtype ATTRIBUTE_UNUSED)
                  _bfd_vms_output_begin_subrec (recwr, ETIR__C_STC_BOH_GBL);
                  _bfd_vms_output_long (recwr, (unsigned long) udata->lkindex);
                  _bfd_vms_output_long
-                   (recwr, (unsigned long) udata->enbsym->section->index);
+                   (recwr, (unsigned long) section->target_index);
                  _bfd_vms_output_quad (recwr, rptr->address);
                  _bfd_vms_output_long (recwr, (unsigned long) 0xD3400000);
                  _bfd_vms_output_long
-                   (recwr, (unsigned long) udata->enbsym->section->index);
+                   (recwr, (unsigned long) section->target_index);
                  _bfd_vms_output_quad (recwr, rptr->addend);
-                 _bfd_vms_output_counted
-                   (recwr, _bfd_vms_length_hash_symbol
-                     (abfd, udata->origname, EOBJ__C_SYMSIZ));
+                 _bfd_vms_output_counted (recwr, udata->origname);
                  _bfd_vms_output_end_subrec (recwr);
                  break;
 
@@ -4590,6 +4517,11 @@ build_module_list (bfd *abfd)
       /* We don't have a DMT section so this must be an object.  Parse
         the module right now in order to compute its start address and
         end address.  */
+      void *dst = PRIV (dst_section)->contents;
+
+      if (dst == NULL)
+        return NULL;
+
       module = new_module (abfd);
       parse_module (abfd, module, PRIV (dst_section)->contents, -1);
       list = module;
@@ -4669,10 +4601,14 @@ module_find_nearest_line (bfd *abfd, struct module *module, bfd_vma addr,
    location.  */
 
 static bfd_boolean
-_bfd_vms_find_nearest_dst_line (bfd *abfd, asection *section,
-                               asymbol **symbols ATTRIBUTE_UNUSED,
-                               bfd_vma offset, const char **file,
-                               const char **func, unsigned int *line)
+_bfd_vms_find_nearest_line (bfd *abfd,
+                           asymbol **symbols ATTRIBUTE_UNUSED,
+                           asection *section,
+                           bfd_vma offset,
+                           const char **file,
+                           const char **func,
+                           unsigned int *line,
+                           unsigned int *discriminator)
 {
   struct module *module;
 
@@ -4682,10 +4618,14 @@ _bfd_vms_find_nearest_dst_line (bfd *abfd, asection *section,
   *file = NULL;
   *func = NULL;
   *line = 0;
+  if (discriminator)
+    *discriminator = 0;
 
-  if (PRIV (dst_section) == NULL || !(abfd->flags & (EXEC_P | DYNAMIC)))
+  /* We can't do anything if there is no DST (debug symbol table).  */
+  if (PRIV (dst_section) == NULL)
     return FALSE;
 
+  /* Create the module list - if not already done.  */
   if (PRIV (modules) == NULL)
     {
       PRIV (modules) = build_module_list (abfd);
@@ -5060,7 +5000,14 @@ alpha_vms_slurp_relocs (bfd *abfd)
                 (*_bfd_error_handler) (_("Invalid section index in ETIR"));
                 return FALSE;
               }
+
             sec = PRIV (sections)[cur_psect];
+            if (sec == bfd_abs_section_ptr)
+              {
+                (*_bfd_error_handler) (_("Relocation for non-REL psect"));
+                return FALSE;
+              }
+
             vms_sec = vms_section_data (sec);
 
             /* Allocate a reloc entry.  */
@@ -5071,7 +5018,7 @@ alpha_vms_slurp_relocs (bfd *abfd)
                     vms_sec->reloc_max = 64;
                     sec->relocation = bfd_zmalloc
                       (vms_sec->reloc_max * sizeof (arelent));
-                }
+                  }
                 else
                   {
                     vms_sec->reloc_max *= 2;
@@ -5995,7 +5942,7 @@ evax_bfd_print_etir (FILE *file, const char *name,
                      unsigned char *rec, unsigned int rec_len)
 {
   unsigned int off = sizeof (struct vms_egsd);
-  unsigned int sec_len;
+  unsigned int sec_len = 0;
 
   fprintf (file, _("  %s (len=%u+%u):\n"), name,
            (unsigned)(rec_len - sizeof (struct vms_eobjrec)),
@@ -7800,7 +7747,7 @@ evax_bfd_print_image (bfd *abfd, FILE *file)
         }
       if (lpfixoff != 0)
         {
-          fprintf (file, _(" Linkage Pairs Referece Fixups:\n"));
+          fprintf (file, _(" Linkage Pairs Reference Fixups:\n"));
           evax_bfd_print_reference_fixups (file, buf + lpfixoff);
         }
       if (chgprtoff)
@@ -7994,8 +7941,11 @@ alpha_vms_add_fixup_lp (struct bfd_link_info *info, bfd *src, bfd *shlib)
   sl->has_fixups = TRUE;
   VEC_APPEND_EL (sl->lp, bfd_vma,
                  sect->output_section->vma + sect->output_offset + offset);
+  sect->output_section->flags |= SEC_RELOC;
 }
 
+/* Add a code address fixup at address SECT + OFFSET to SHLIB. */
+
 static void
 alpha_vms_add_fixup_ca (struct bfd_link_info *info, bfd *src, bfd *shlib)
 {
@@ -8008,8 +7958,11 @@ alpha_vms_add_fixup_ca (struct bfd_link_info *info, bfd *src, bfd *shlib)
   sl->has_fixups = TRUE;
   VEC_APPEND_EL (sl->ca, bfd_vma,
                  sect->output_section->vma + sect->output_offset + offset);
+  sect->output_section->flags |= SEC_RELOC;
 }
 
+/* Add a quad word relocation fixup at address SECT + OFFSET to SHLIB. */
+
 static void
 alpha_vms_add_fixup_qr (struct bfd_link_info *info, bfd *src,
                         bfd *shlib, bfd_vma vec)
@@ -8025,25 +7978,19 @@ alpha_vms_add_fixup_qr (struct bfd_link_info *info, bfd *src,
   r = VEC_APPEND (sl->qr, struct alpha_vms_vma_ref);
   r->vma = sect->output_section->vma + sect->output_offset + offset;
   r->ref = vec;
+  sect->output_section->flags |= SEC_RELOC;
 }
 
 static void
-alpha_vms_add_lw_fixup (struct bfd_link_info *info ATTRIBUTE_UNUSED,
+alpha_vms_add_fixup_lr (struct bfd_link_info *info ATTRIBUTE_UNUSED,
                         unsigned int shr ATTRIBUTE_UNUSED,
                         bfd_vma vec ATTRIBUTE_UNUSED)
 {
+  /* Not yet supported.  */
   abort ();
 }
 
-#if 0
-static void
-alpha_vms_add_qw_fixup (struct bfd_link_info *info ATTRIBUTE_UNUSED,
-                        unsigned int shr ATTRIBUTE_UNUSED,
-                        bfd_vma vec ATTRIBUTE_UNUSED)
-{
-  abort ();
-}
-#endif
+/* Add relocation.  FIXME: Not yet emitted.  */
 
 static void
 alpha_vms_add_lw_reloc (struct bfd_link_info *info ATTRIBUTE_UNUSED)
@@ -8228,7 +8175,10 @@ alpha_vms_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
        return FALSE;
 
       if (element->archive_pass == -1 || element->archive_pass == pass)
-        continue;
+        {
+          /* Next symbol if this archive is wrong or already handled.  */
+          continue;
+        }
 
       if (! bfd_check_format (element, bfd_object))
         {
@@ -8250,10 +8200,10 @@ alpha_vms_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
       /* Unlike the generic linker, we know that this element provides
         a definition for an undefined symbol and we know that we want
         to include it.  We don't need to check anything.  */
-      if (! (*info->callbacks->add_archive_element) (info, element,
-                                                     h->root.string))
+      if (!(*info->callbacks
+           ->add_archive_element) (info, element, h->root.string, &element))
        return FALSE;
-      if (! alpha_vms_link_add_object_symbols (element, info))
+      if (!alpha_vms_link_add_object_symbols (element, info))
        return FALSE;
 
       orig_element->archive_pass = pass;
@@ -8294,6 +8244,8 @@ alpha_vms_build_fixups (struct bfd_link_info *info)
   unsigned int ca_sz = 0;
   unsigned int qr_sz = 0;
   unsigned int shrimg_cnt = 0;
+  unsigned int chgprt_num = 0;
+  unsigned int chgprt_sz = 0;
   struct vms_eiaf *eiaf;
   unsigned int off;
   asection *sec;
@@ -8341,9 +8293,20 @@ alpha_vms_build_fixups (struct bfd_link_info *info)
   if (ca_sz + lp_sz + qr_sz == 0)
     return TRUE;
 
+  /* Add an eicp entry for the fixup itself.  */
+  chgprt_num = 1;
+  for (sec = info->output_bfd->sections; sec != NULL; sec = sec->next)
+    {
+      /* This isect could be made RO or EXE after relocations are applied.  */
+      if ((sec->flags & SEC_RELOC) != 0
+          && (sec->flags & (SEC_CODE | SEC_READONLY)) != 0)
+        chgprt_num++;
+    }
+  chgprt_sz = 4 + chgprt_num * sizeof (struct vms_eicp);
+
   /* Allocate section content (round-up size)  */
   sz = sizeof (struct vms_eiaf) + shrimg_cnt * sizeof (struct vms_shl)
-    + ca_sz + lp_sz + qr_sz;
+    + ca_sz + lp_sz + qr_sz + chgprt_sz;
   sz = (sz + VMS_BLOCK_SIZE - 1) & ~(VMS_BLOCK_SIZE - 1);
   content = bfd_zalloc (info->output_bfd, sz);
   if (content == NULL)
@@ -8506,27 +8469,63 @@ alpha_vms_build_fixups (struct bfd_link_info *info)
           bfd_putl32 (0, content + off + 4);
           off += 8;
         }
+    }
 
-      /* CA fixups.  */
+  /* Write the change protection table.  */
+  bfd_putl32 (off, eiaf->chgprtoff);
+  bfd_putl32 (chgprt_num, content + off);
+  off += 4;
+
+  for (sec = info->output_bfd->sections; sec != NULL; sec = sec->next)
+    {
+      struct vms_eicp *eicp;
+      unsigned int prot;
+
+      if ((sec->flags & SEC_LINKER_CREATED) != 0 &&
+          strcmp (sec->name, "$FIXUP$") == 0)
+        prot = PRT__C_UREW;
+      else if ((sec->flags & SEC_RELOC) != 0
+               && (sec->flags & (SEC_CODE | SEC_READONLY)) != 0)
+        prot = PRT__C_UR;
+      else
+        continue;
+
+      eicp = (struct vms_eicp *)(content + off);
+      bfd_putl64 (sec->vma - t->base_addr, eicp->baseva);
+      bfd_putl32 ((sec->size + VMS_BLOCK_SIZE - 1) & ~(VMS_BLOCK_SIZE - 1),
+                  eicp->size);
+      bfd_putl32 (prot, eicp->newprt);
+      off += sizeof (struct vms_eicp);
     }
 
   return TRUE;
 }
 
-/* Called by bfd_link_hash_traverse to fill the symbol table.
+/* Called by bfd_hash_traverse to fill the symbol table.
    Return FALSE in case of failure.  */
 
 static bfd_boolean
-alpha_vms_link_output_symbol (struct bfd_link_hash_entry *hc, void *infov)
+alpha_vms_link_output_symbol (struct bfd_hash_entry *bh, void *infov)
 {
+  struct bfd_link_hash_entry *hc = (struct bfd_link_hash_entry *) bh;
   struct bfd_link_info *info = (struct bfd_link_info *)infov;
-  struct alpha_vms_link_hash_entry *h = (struct alpha_vms_link_hash_entry *)hc;
+  struct alpha_vms_link_hash_entry *h;
   struct vms_symbol_entry *sym;
 
+  if (hc->type == bfd_link_hash_warning)
+    {
+      hc = hc->u.i.link;
+      if (hc->type == bfd_link_hash_new)
+       return TRUE;
+    }
+  h = (struct alpha_vms_link_hash_entry *) hc;
+
   switch (h->root.type)
     {
-    case bfd_link_hash_new:
     case bfd_link_hash_undefined:
+      return TRUE;
+    case bfd_link_hash_new:
+    case bfd_link_hash_warning:
       abort ();
     case bfd_link_hash_undefweak:
       return TRUE;
@@ -8546,7 +8545,6 @@ alpha_vms_link_output_symbol (struct bfd_link_hash_entry *hc, void *infov)
     case bfd_link_hash_common:
       break;
     case bfd_link_hash_indirect:
-    case bfd_link_hash_warning:
       return TRUE;
     }
 
@@ -8599,6 +8597,14 @@ alpha_vms_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
   asection *dst;
   asection *dmt;
 
+  if (info->relocatable)
+    {
+      /* FIXME: we do not yet support relocatable link.  It is not obvious
+         how to do it for debug infos.  */
+      (*info->callbacks->einfo)(_("%P: relocatable link is not supported\n"));
+      return FALSE;
+    }
+
   bfd_get_outsymbols (abfd) = NULL;
   bfd_get_symcount (abfd) = 0;
 
@@ -8644,14 +8650,14 @@ alpha_vms_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
   /* Generate the symbol table.  */
   BFD_ASSERT (PRIV (syms) == NULL);
   if (info->strip != strip_all)
-    bfd_link_hash_traverse (info->hash, alpha_vms_link_output_symbol, info);
+    bfd_hash_traverse (&info->hash->table, alpha_vms_link_output_symbol, info);
 
   /* Find the entry point.  */
   if (bfd_get_start_address (abfd) == 0)
     {
       bfd *startbfd = NULL;
 
-      for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+      for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
         {
           /* Consider only VMS object files.  */
           if (sub->xvec != abfd->xvec)
@@ -8701,7 +8707,8 @@ alpha_vms_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
       PRIV (transfer_address[i++]) = 0;
   }
 
-  /* Allocate contents.  */
+  /* Allocate contents.
+     Also compute the virtual base address.  */
   base_addr = (bfd_vma)-1;
   last_addr = 0;
   for (o = abfd->sections; o != NULL; o = o->next)
@@ -8719,6 +8726,9 @@ alpha_vms_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
           if (o->vma + o->size > last_addr)
             last_addr = o->vma + o->size;
         }
+      /* Clear the RELOC flags.  Currently we don't support incremental
+         linking.  We use the RELOC flag for computing the eicp entries.  */
+      o->flags &= ~SEC_RELOC;
     }
 
   /* Create the fixup section.  */
@@ -8751,7 +8761,7 @@ alpha_vms_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
     dmt = NULL;
 
   /* Read all sections from the inputs.  */
-  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+  for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
     {
       if (sub->flags & DYNAMIC)
         {
@@ -8802,7 +8812,7 @@ alpha_vms_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
           unsigned int off = 0;
 
           /* For each object file (ie for each module).  */
-          for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+          for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
             {
               asection *sub_dst;
               struct vms_dmt_header *dmth = NULL;
@@ -8892,9 +8902,17 @@ alpha_vms_get_section_contents (bfd *abfd, asection *section,
       return FALSE;
     }
 
-  /* Alloc in memory and read ETIRs.  */
-  BFD_ASSERT (section->contents == NULL);
+  /* If the section is already in memory, just copy it.  */
+  if (section->flags & SEC_IN_MEMORY)
+    {
+      BFD_ASSERT (section->contents != NULL);
+      memcpy (buf, section->contents + offset, count);
+      return TRUE;
+    }
+  if (section->size == 0)
+    return TRUE;
 
+  /* Alloc in memory and read ETIRs.  */
   for (sec = abfd->sections; sec; sec = sec->next)
     {
       BFD_ASSERT (sec->contents == NULL);
@@ -8909,8 +8927,8 @@ alpha_vms_get_section_contents (bfd *abfd, asection *section,
   if (!alpha_vms_read_sections_content (abfd, NULL))
     return FALSE;
   for (sec = abfd->sections; sec; sec = sec->next)
-    if (section->contents)
-      section->flags |= SEC_IN_MEMORY;
+    if (sec->contents)
+      sec->flags |= SEC_IN_MEMORY;
   memcpy (buf, section->contents + offset, count);
   return TRUE;
 }
@@ -8998,12 +9016,13 @@ vms_new_section_hook (bfd * abfd, asection *section)
   vms_debug2 ((1, "vms_new_section_hook (%p, [%d]%s)\n",
                abfd, section->index, section->name));
 
-  bfd_set_section_alignment (abfd, section, 0);
+  if (! bfd_set_section_alignment (abfd, section, 0))
+    return FALSE;
 
   vms_debug2 ((7, "%d: %s\n", section->index, section->name));
 
   amt = sizeof (struct vms_section_data_struct);
-  section->used_by_bfd = (PTR) bfd_zalloc (abfd, amt);
+  section->used_by_bfd = bfd_zalloc (abfd, amt);
   if (section->used_by_bfd == NULL)
     return FALSE;
 
@@ -9092,7 +9111,7 @@ vms_get_symbol_info (bfd * abfd ATTRIBUTE_UNUSED,
   else if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)
     ret->type = 'B';
   else
-    ret->type = '-';
+    ret->type = '?';
 
   if (ret->type != 'U')
     ret->value = symbol->value + symbol->section->vma;
@@ -9108,7 +9127,6 @@ static bfd_boolean
 vms_bfd_is_local_label_name (bfd * abfd ATTRIBUTE_UNUSED,
                             const char *name)
 {
-  vms_debug2 ((1, "vms_bfd_is_local_label_name (%p, %s)\n", abfd, name));
   return name[0] == '$';
 }
 \f
@@ -9196,12 +9214,16 @@ bfd_vms_get_data (bfd *abfd)
    ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false)
 #define alpha_vms_print_symbol             vms_print_symbol
 #define alpha_vms_get_symbol_info          vms_get_symbol_info
+#define alpha_vms_get_symbol_version_string \
+  _bfd_nosymbols_get_symbol_version_string
+
 #define alpha_vms_read_minisymbols         _bfd_generic_read_minisymbols
 #define alpha_vms_minisymbol_to_symbol     _bfd_generic_minisymbol_to_symbol
 #define alpha_vms_get_lineno               _bfd_nosymbols_get_lineno
 #define alpha_vms_find_inliner_info        _bfd_nosymbols_find_inliner_info
 #define alpha_vms_bfd_make_debug_symbol    _bfd_nosymbols_bfd_make_debug_symbol
-#define alpha_vms_find_nearest_line        _bfd_vms_find_nearest_dst_line
+#define alpha_vms_find_nearest_line        _bfd_vms_find_nearest_line
+#define alpha_vms_find_line                _bfd_nosymbols_find_line
 #define alpha_vms_bfd_is_local_label_name  vms_bfd_is_local_label_name
 
 /* Generic table.  */
@@ -9216,6 +9238,7 @@ bfd_vms_get_data (bfd *abfd)
 
 #define alpha_vms_bfd_relax_section bfd_generic_relax_section
 #define alpha_vms_bfd_gc_sections bfd_generic_gc_sections
+#define alpha_vms_bfd_lookup_section_flags bfd_generic_lookup_section_flags
 #define alpha_vms_bfd_merge_sections bfd_generic_merge_sections
 #define alpha_vms_bfd_is_group_section bfd_generic_is_group_section
 #define alpha_vms_bfd_discard_group bfd_generic_discard_group
@@ -9223,7 +9246,6 @@ bfd_vms_get_data (bfd *abfd)
   _bfd_generic_section_already_linked
 
 #define alpha_vms_bfd_define_common_symbol bfd_generic_define_common_symbol
-#define alpha_vms_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
 #define alpha_vms_bfd_link_just_syms _bfd_generic_link_just_syms
 #define alpha_vms_bfd_copy_link_hash_symbol_type \
   _bfd_generic_copy_link_hash_symbol_type
@@ -9239,7 +9261,7 @@ bfd_vms_get_data (bfd *abfd)
 #define alpha_vms_canonicalize_dynamic_reloc \
   _bfd_nodynamic_canonicalize_dynamic_reloc
 
-const bfd_target vms_alpha_vec =
+const bfd_target alpha_vms_vec =
 {
   "vms-alpha",                 /* Name.  */
   bfd_target_evax_flavour,
@@ -9254,6 +9276,7 @@ const bfd_target vms_alpha_vec =
   0,                           /* symbol_leading_char.  */
   ' ',                         /* ar_pad_char.  */
   15,                          /* ar_max_namelen.  */
+  0,                           /* match priority.  */
   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
   bfd_getl16, bfd_getl_signed_16, bfd_putl16,
@@ -9280,5 +9303,5 @@ const bfd_target vms_alpha_vec =
 
   NULL,
 
-  (PTR) 0
+  NULL
 };
This page took 0.045697 seconds and 4 git commands to generate.