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
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[] =
value += addr;
break;
}
- /* FALLTHROUGH. */
+ /* FALLTHROUGH. */
case R_MMIX_ADDR19:
case R_MMIX_ADDR27:
/* These must be in range, or else we emit an error. */
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;
}
}
else
- {
- return bfd_section_from_elf_index (abfd, sym->st_shndx);
- }
+ return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
return NULL;
}
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
= 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++;
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,
= 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;
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)
{
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
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;
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;
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;
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;
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);
}
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;
}
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