2002-10-23 Elena Zannoni <ezannoni@redhat.com>
[deliverable/binutils-gdb.git] / bfd / elf64-mmix.c
index 9da71450789a66039f01d074a8fec4d3d7f58ab5..8b76f34e03818296fc53080412b1debef8880fa5 100644 (file)
@@ -148,7 +148,7 @@ static boolean mmix_elf_relocate_section
           Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
 
 static asection * mmix_elf_gc_mark_hook
-  PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *,
+  PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
           struct elf_link_hash_entry *, Elf_Internal_Sym *));
 
 static boolean mmix_elf_gc_sweep_hook
@@ -182,6 +182,10 @@ extern boolean mmix_elf_final_link PARAMS ((bfd *, struct bfd_link_info *));
 
 extern void mmix_elf_symbol_processing PARAMS ((bfd *, asymbol *));
 
+/* Only intended to be called from a debugger.  */
+extern void mmix_dump_bpo_gregs
+  PARAMS ((struct bfd_link_info *, bfd_error_handler_type));
+
 /* Watch out: this currently needs to have elements with the same index as
    their R_MMIX_ number.  */
 static reloc_howto_type elf_mmix_howto_table[] =
@@ -939,7 +943,7 @@ mmix_elf_perform_relocation (isec, howto, datap, addr, value)
          value += addr;
          break;
        }
-      /* FALLTHROUGH. */
+      /* FALLTHROUGH.  */
     case R_MMIX_ADDR19:
     case R_MMIX_ADDR27:
       /* These must be in range, or else we emit an error.  */
@@ -1520,8 +1524,8 @@ mmix_final_link_relocate (howto, input_section, contents,
    relocation.  */
 
 static asection *
-mmix_elf_gc_mark_hook (abfd, info, rel, h, sym)
-     bfd *abfd;
+mmix_elf_gc_mark_hook (sec, info, rel, h, sym)
+     asection *sec;
      struct bfd_link_info *info ATTRIBUTE_UNUSED;
      Elf_Internal_Rela *rel;
      struct elf_link_hash_entry *h;
@@ -1551,9 +1555,7 @@ mmix_elf_gc_mark_hook (abfd, info, rel, h, sym)
        }
     }
   else
-    {
-      return bfd_section_from_elf_index (abfd, sym->st_shndx);
-    }
+    return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
 
   return NULL;
 }
@@ -1666,9 +1668,11 @@ mmix_elf_check_common_relocs  (abfd, info, sec, relocs)
              info->base_file = (PTR) bpo_greg_owner;
            }
 
-         allocated_gregs_section
-           = bfd_get_section_by_name (bpo_greg_owner,
-                                      MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME);
+         if (allocated_gregs_section == NULL)
+           allocated_gregs_section
+             = bfd_get_section_by_name (bpo_greg_owner,
+                                        MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME);
+
          if (allocated_gregs_section == NULL)
            {
              allocated_gregs_section
@@ -1716,6 +1720,7 @@ mmix_elf_check_common_relocs  (abfd, info, sec, relocs)
                = gregdata->n_max_bpo_relocs;
              bpodata->bpo_greg_section
                = allocated_gregs_section;
+             bpodata->n_bpo_relocs_this_section = 0;
            }
 
          bpodata->n_bpo_relocs_this_section++;
@@ -1946,16 +1951,16 @@ mmix_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
                       strlen (MMIX_LOC_SECTION_START_SYMBOL_PREFIX)) == 0)
     {
       /* See if we have another one.  */
-      struct elf_link_hash_entry *h
-       = (struct elf_link_hash_entry *) bfd_link_hash_lookup (info->hash,
-                                                              *namep,
-                                                              false,
-                                                              false, false);
+      struct bfd_link_hash_entry *h = bfd_link_hash_lookup (info->hash,
+                                                           *namep,
+                                                           false,
+                                                           false,
+                                                           false);
 
-      if (h != NULL && h->root.type != bfd_link_hash_undefined)
+      if (h != NULL && h->type != bfd_link_hash_undefined)
        {
          /* How do we get the asymbol (or really: the filename) from h?
-            h->root.u.def.section->owner is NULL.  */
+            h->u.def.section->owner is NULL.  */
          ((*_bfd_error_handler)
           (_("%s: Error: multiple definition of `%s'; start of %s is set in a earlier linked file\n"),
            bfd_get_filename (abfd), *namep,
@@ -2075,9 +2080,6 @@ _bfd_mmix_prepare_linker_allocated_gregs (abfd, info)
     = bfd_get_section_by_name (bpo_greg_owner,
                               MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME);
 
-  /* This can't happen without DSO handling.  When DSOs are handled
-     without any R_MMIX_BASE_PLUS_OFFSET seen, there will be no such
-     section.  */
   if (bpo_gregs_section == NULL)
     return true;
 
@@ -2173,6 +2175,21 @@ _bfd_mmix_finalize_linker_allocated_gregs (abfd, link_info)
   if (contents == NULL)
     return false;
 
+  /* Sanity check: If these numbers mismatch, some relocation has not been
+     accounted for and the rest of gregdata is probably inconsistent.
+     It's a bug, but it's more helpful to identify it than segfaulting
+     below.  */
+  if (gregdata->n_remaining_bpo_relocs_this_relaxation_round
+      != gregdata->n_bpo_relocs)
+    {
+      (*_bfd_error_handler)
+       (_("Internal inconsistency: remaining %u != max %u.\n\
+  Please report this bug."),
+        gregdata->n_remaining_bpo_relocs_this_relaxation_round,
+        gregdata->n_bpo_relocs);
+      return false;
+    }
+
   for (lastreg = 255, i = 0, j = 0; j < n_gregs; i++)
     if (gregdata->reloc_request[i].regindex != lastreg)
       {
@@ -2201,12 +2218,75 @@ bpo_reloc_request_sort_fn (p1, p2)
   if (r1->valid != r2->valid)
     return r2->valid - r1->valid;
 
-  /* Then sort on value.  */
+  /* Then sort on value.  Don't simplify and return just the difference of
+     the values: the upper bits of the 64-bit value would be truncated on
+     a host with 32-bit ints.  */
   if (r1->value != r2->value)
-    return r1->value - r2->value;
+    return r1->value > r2->value ? 1 : -1;
+
+  /* As a last re-sort, use the relocation number, so we get a stable
+     sort.  The *addresses* aren't stable since items are swapped during
+     sorting.  It depends on the qsort implementation if this actually
+     happens.  */
+  return r1->bpo_reloc_no > r2->bpo_reloc_no
+    ? 1 : (r1->bpo_reloc_no < r2->bpo_reloc_no ? -1 : 0);
+}
+
+/* For debug use only.  Dumps the global register allocations resulting
+   from base-plus-offset relocs.  */
 
-  /* As a last re-sort, use the address so we get a stable sort.  */
-  return r1 > r2 ? 1 : (r1 < r2 ? -1 : 0);
+void
+mmix_dump_bpo_gregs (link_info, pf)
+     struct bfd_link_info *link_info;
+     bfd_error_handler_type pf;
+{
+  bfd *bpo_greg_owner;
+  asection *bpo_gregs_section;
+  struct bpo_greg_section_info *gregdata;
+  unsigned int i;
+
+  if (link_info == NULL || link_info->base_file == NULL)
+    return;
+
+  bpo_greg_owner = (bfd *) link_info->base_file;
+
+  bpo_gregs_section
+    = bfd_get_section_by_name (bpo_greg_owner,
+                              MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME);
+
+  if (bpo_gregs_section == NULL)
+    return;
+
+  gregdata = (struct bpo_greg_section_info *)
+    elf_section_data (bpo_gregs_section)->tdata;
+  if (gregdata == NULL)
+    return;
+
+  if (pf == NULL)
+    pf = _bfd_error_handler;
+
+  /* These format strings are not translated.  They are for debug purposes
+     only and never displayed to an end user.  Should they escape, we
+     surely want them in original.  */
+  (*pf) (" n_bpo_relocs: %u\n n_max_bpo_relocs: %u\n n_remain...round: %u\n\
+ n_allocated_bpo_gregs: %u\n", gregdata->n_bpo_relocs,
+     gregdata->n_max_bpo_relocs,
+     gregdata->n_remaining_bpo_relocs_this_relaxation_round,
+     gregdata->n_allocated_bpo_gregs);
+
+  if (gregdata->reloc_request)
+    for (i = 0; i < gregdata->n_max_bpo_relocs; i++)
+      (*pf) ("%4u (%4u)/%4u#%u: 0x%08lx%08lx  r: %3u o: %3u\n",
+            i,
+            gregdata->bpo_reloc_indexes != NULL
+            ? gregdata->bpo_reloc_indexes[i] : -1,
+            gregdata->reloc_request[i].bpo_reloc_no,
+            gregdata->reloc_request[i].valid,
+
+            (unsigned long) (gregdata->reloc_request[i].value >> 32),
+            (unsigned long) gregdata->reloc_request[i].value,
+            gregdata->reloc_request[i].regindex,
+            gregdata->reloc_request[i].offset);
 }
 
 /* This links all R_MMIX_BASE_PLUS_OFFSET relocs into a special array, and
@@ -2224,11 +2304,8 @@ mmix_elf_relax_section (abfd, sec, link_info, again)
      struct bfd_link_info *link_info;
      boolean *again;
 {
-
   Elf_Internal_Shdr *symtab_hdr;
-  Elf_Internal_Shdr *shndx_hdr;
   Elf_Internal_Rela *internal_relocs;
-  Elf_Internal_Rela *free_relocs = NULL;
   Elf_Internal_Rela *irel, *irelend;
   asection *bpo_gregs_section = NULL;
   struct bpo_greg_section_info *gregdata;
@@ -2237,9 +2314,7 @@ mmix_elf_relax_section (abfd, sec, link_info, again)
     elf_section_data (sec)->tdata;
   size_t bpono;
   bfd *bpo_greg_owner;
-  Elf64_External_Sym *extsyms = NULL;
-  Elf64_External_Sym *free_extsyms = NULL;
-  Elf_External_Sym_Shndx *shndx_buf = NULL;
+  Elf_Internal_Sym *isymbuf = NULL;
 
   /* Assume nothing changes.  */
   *again = false;
@@ -2262,7 +2337,6 @@ mmix_elf_relax_section (abfd, sec, link_info, again)
     return true;
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-  shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
 
   bpo_greg_owner = (bfd *) link_info->base_file;
   bpo_gregs_section = bpodata->bpo_greg_section;
@@ -2278,8 +2352,6 @@ mmix_elf_relax_section (abfd, sec, link_info, again)
                                   link_info->keep_memory);
   if (internal_relocs == NULL)
     goto error_return;
-  if (! link_info->keep_memory)
-    free_relocs = internal_relocs;
 
   /* Walk through them looking for relaxing opportunities.  */
   irelend = internal_relocs + sec->reloc_count;
@@ -2290,69 +2362,35 @@ mmix_elf_relax_section (abfd, sec, link_info, again)
       if (ELF64_R_TYPE (irel->r_info) != (int) R_MMIX_BASE_PLUS_OFFSET)
        continue;
 
-      /* Read this BFD's symbols if we haven't done so already.  */
-      if (extsyms == NULL)
-       {
-         /* Get cached copy if it exists.  */
-         if (symtab_hdr->contents != NULL)
-           extsyms = (Elf64_External_Sym *) symtab_hdr->contents;
-         else
-           {
-             /* Go get them off disk.  */
-             bfd_size_type amt;
-
-             amt = symtab_hdr->sh_info;
-             amt *= sizeof (Elf64_External_Sym);
-             extsyms = (Elf64_External_Sym *) bfd_malloc (amt);
-             if (extsyms == NULL)
-               goto error_return;
-             free_extsyms = extsyms;
-             if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0
-                 || bfd_bread ((PTR) extsyms, amt, abfd) != amt)
-               goto error_return;
-             symtab_hdr->contents = (bfd_byte *) extsyms;
-           }
-
-         /* If >64k sections, this presumable happens.  No test-case.  */
-         if (shndx_hdr->sh_size != 0)
-           {
-             bfd_size_type amt;
-
-             amt = symtab_hdr->sh_info;
-             amt *= sizeof (Elf_External_Sym_Shndx);
-             shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
-             if (shndx_buf == NULL)
-               goto error_return;
-             if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0
-                 || bfd_bread ((PTR) shndx_buf, amt, abfd) != amt)
-               goto error_return;
-             shndx_hdr->contents = (bfd_byte *) shndx_buf;
-           }
-       }
-
       /* Get the value of the symbol referred to by the reloc.  */
       if (ELF64_R_SYM (irel->r_info) < symtab_hdr->sh_info)
        {
          /* A local symbol.  */
-         Elf64_External_Sym *esym;
-         Elf_External_Sym_Shndx *shndx;
-         Elf_Internal_Sym isym;
+         Elf_Internal_Sym *isym;
          asection *sym_sec;
 
-         esym = extsyms + ELF64_R_SYM (irel->r_info);
-         shndx = shndx_buf + (shndx_buf
-                              ? ELF64_R_SYM (irel->r_info) : 0);
-         bfd_elf64_swap_symbol_in (abfd, esym, shndx, &isym);
+         /* Read this BFD's local symbols if we haven't already.  */
+         if (isymbuf == NULL)
+           {
+             isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+             if (isymbuf == NULL)
+               isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+                                               symtab_hdr->sh_info, 0,
+                                               NULL, NULL, NULL);
+             if (isymbuf == 0)
+               goto error_return;
+           }
 
-         if (isym.st_shndx == SHN_UNDEF)
+         isym = isymbuf + ELF64_R_SYM (irel->r_info);
+         if (isym->st_shndx == SHN_UNDEF)
            sym_sec = bfd_und_section_ptr;
-         else if (isym.st_shndx == SHN_ABS)
+         else if (isym->st_shndx == SHN_ABS)
            sym_sec = bfd_abs_section_ptr;
-         else if (isym.st_shndx == SHN_COMMON)
+         else if (isym->st_shndx == SHN_COMMON)
            sym_sec = bfd_com_section_ptr;
          else
-           sym_sec = bfd_section_from_elf_index (abfd, isym.st_shndx);
-         symval = (isym.st_value
+           sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
+         symval = (isym->st_value
                    + sym_sec->output_section->vma
                    + sym_sec->output_offset);
        }
@@ -2368,9 +2406,12 @@ mmix_elf_relax_section (abfd, sec, link_info, again)
          if (h->root.type != bfd_link_hash_defined
              && h->root.type != bfd_link_hash_defweak)
            {
-             /* This appears to be a reference to an undefined
-                 symbol.  Just ignore it--it will be caught by the
-                 regular reloc processing.  */
+             /* This appears to be a reference to an undefined symbol.
+                Just ignore it--it will be caught by the regular reloc
+                processing.  We need to keep BPO reloc accounting
+                consistent, though.  */
+             gregdata->n_remaining_bpo_relocs_this_relaxation_round--;
+             bpono++;
              continue;
            }
 
@@ -2446,40 +2487,29 @@ mmix_elf_relax_section (abfd, sec, link_info, again)
       bpo_gregs_section->_cooked_size = (regindex + 1) * 8;
     }
 
-  if (free_relocs != NULL)
-    free (free_relocs);
-
-  if (shndx_buf != NULL)
-    {
-      shndx_hdr->contents = NULL;
-      free (shndx_buf);
-    }
-
-  if (free_extsyms != NULL)
+  if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents)
     {
       if (! link_info->keep_memory)
+       free (isymbuf);
+      else
        {
-         symtab_hdr->contents = NULL;
-         free (free_extsyms);
+         /* Cache the symbols for elf_link_input_bfd.  */
+         symtab_hdr->contents = (unsigned char *) isymbuf;
        }
     }
 
+  if (internal_relocs != NULL
+      && elf_section_data (sec)->relocs != internal_relocs)
+    free (internal_relocs);
+
   return true;
 
  error_return:
-  if (free_relocs != NULL)
-    free (free_relocs);
-  if (shndx_buf != NULL)
-    {
-      shndx_hdr->contents = NULL;
-      free (shndx_buf);
-    }
-  if (free_extsyms != NULL)
-    {
-      symtab_hdr->contents = NULL;
-      free (free_extsyms);
-    }
-
+  if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents)
+    free (isymbuf);
+  if (internal_relocs != NULL
+      && elf_section_data (sec)->relocs != internal_relocs)
+    free (internal_relocs);
   return false;
 }
 \f
This page took 0.028375 seconds and 4 git commands to generate.