Line 1... |
Line 1... |
/* BFD back-end for HP PA-RISC ELF files.
|
/* BFD back-end for HP PA-RISC ELF files.
|
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1999, 2000, 2001,
|
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1999, 2000, 2001,
|
2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
|
2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
|
|
Free Software Foundation, Inc.
|
|
|
Original code by
|
Original code by
|
Center for Software Science
|
Center for Software Science
|
Department of Computer Science
|
Department of Computer Science
|
University of Utah
|
University of Utah
|
Line 298... |
Line 299... |
unsigned int has_22bit_branch:1;
|
unsigned int has_22bit_branch:1;
|
|
|
/* Set if we need a .plt stub to support lazy dynamic linking. */
|
/* Set if we need a .plt stub to support lazy dynamic linking. */
|
unsigned int need_plt_stub:1;
|
unsigned int need_plt_stub:1;
|
|
|
/* Small local sym to section mapping cache. */
|
/* Small local sym cache. */
|
struct sym_sec_cache sym_sec;
|
struct sym_cache sym_cache;
|
|
|
/* Data for LDM relocations. */
|
/* Data for LDM relocations. */
|
union
|
union
|
{
|
{
|
bfd_signed_vma refcount;
|
bfd_signed_vma refcount;
|
Line 457... |
Line 458... |
htab->multi_subspace = 0;
|
htab->multi_subspace = 0;
|
htab->has_12bit_branch = 0;
|
htab->has_12bit_branch = 0;
|
htab->has_17bit_branch = 0;
|
htab->has_17bit_branch = 0;
|
htab->has_22bit_branch = 0;
|
htab->has_22bit_branch = 0;
|
htab->need_plt_stub = 0;
|
htab->need_plt_stub = 0;
|
htab->sym_sec.abfd = NULL;
|
htab->sym_cache.abfd = NULL;
|
htab->tls_ldm_got.refcount = 0;
|
htab->tls_ldm_got.refcount = 0;
|
|
|
return &htab->etab.root;
|
return &htab->etab.root;
|
}
|
}
|
|
|
Line 1008... |
Line 1009... |
|
|
htab->splt = bfd_get_section_by_name (abfd, ".plt");
|
htab->splt = bfd_get_section_by_name (abfd, ".plt");
|
htab->srelplt = bfd_get_section_by_name (abfd, ".rela.plt");
|
htab->srelplt = bfd_get_section_by_name (abfd, ".rela.plt");
|
|
|
htab->sgot = bfd_get_section_by_name (abfd, ".got");
|
htab->sgot = bfd_get_section_by_name (abfd, ".got");
|
htab->srelgot = bfd_make_section_with_flags (abfd, ".rela.got",
|
htab->srelgot = bfd_get_section_by_name (abfd, ".rela.got");
|
(SEC_ALLOC
|
|
| SEC_LOAD
|
|
| SEC_HAS_CONTENTS
|
|
| SEC_IN_MEMORY
|
|
| SEC_LINKER_CREATED
|
|
| SEC_READONLY));
|
|
if (htab->srelgot == NULL
|
|
|| ! bfd_set_section_alignment (abfd, htab->srelgot, 2))
|
|
return FALSE;
|
|
|
|
htab->sdynbss = bfd_get_section_by_name (abfd, ".dynbss");
|
htab->sdynbss = bfd_get_section_by_name (abfd, ".dynbss");
|
htab->srelbss = bfd_get_section_by_name (abfd, ".rela.bss");
|
htab->srelbss = bfd_get_section_by_name (abfd, ".rela.bss");
|
|
|
/* hppa-linux needs _GLOBAL_OFFSET_TABLE_ to be visible from the main
|
/* hppa-linux needs _GLOBAL_OFFSET_TABLE_ to be visible from the main
|
Line 1110... |
Line 1102... |
{
|
{
|
/* For now we don't support linker optimizations. */
|
/* For now we don't support linker optimizations. */
|
return r_type;
|
return r_type;
|
}
|
}
|
|
|
|
/* Return a pointer to the local GOT, PLT and TLS reference counts
|
|
for ABFD. Returns NULL if the storage allocation fails. */
|
|
|
|
static bfd_signed_vma *
|
|
hppa32_elf_local_refcounts (bfd *abfd)
|
|
{
|
|
Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
|
|
bfd_signed_vma *local_refcounts;
|
|
|
|
local_refcounts = elf_local_got_refcounts (abfd);
|
|
if (local_refcounts == NULL)
|
|
{
|
|
bfd_size_type size;
|
|
|
|
/* Allocate space for local GOT and PLT reference
|
|
counts. Done this way to save polluting elf_obj_tdata
|
|
with another target specific pointer. */
|
|
size = symtab_hdr->sh_info;
|
|
size *= 2 * sizeof (bfd_signed_vma);
|
|
/* Add in space to store the local GOT TLS types. */
|
|
size += symtab_hdr->sh_info;
|
|
local_refcounts = bfd_zalloc (abfd, size);
|
|
if (local_refcounts == NULL)
|
|
return NULL;
|
|
elf_local_got_refcounts (abfd) = local_refcounts;
|
|
memset (hppa_elf_local_got_tls_type (abfd), GOT_UNKNOWN,
|
|
symtab_hdr->sh_info);
|
|
}
|
|
return local_refcounts;
|
|
}
|
|
|
|
|
/* Look through the relocs for a section during the first phase, and
|
/* Look through the relocs for a section during the first phase, and
|
calculate needed space in the global offset table, procedure linkage
|
calculate needed space in the global offset table, procedure linkage
|
table, and dynamic reloc sections. At this point we haven't
|
table, and dynamic reloc sections. At this point we haven't
|
necessarily read all the input files. */
|
necessarily read all the input files. */
|
|
|
Line 1356... |
Line 1380... |
else
|
else
|
{
|
{
|
bfd_signed_vma *local_got_refcounts;
|
bfd_signed_vma *local_got_refcounts;
|
|
|
/* This is a global offset table entry for a local symbol. */
|
/* This is a global offset table entry for a local symbol. */
|
local_got_refcounts = elf_local_got_refcounts (abfd);
|
local_got_refcounts = hppa32_elf_local_refcounts (abfd);
|
if (local_got_refcounts == NULL)
|
|
{
|
|
bfd_size_type size;
|
|
|
|
/* Allocate space for local got offsets and local
|
|
plt offsets. Done this way to save polluting
|
|
elf_obj_tdata with another target specific
|
|
pointer. */
|
|
size = symtab_hdr->sh_info;
|
|
size *= 2 * sizeof (bfd_signed_vma);
|
|
/* Add in space to store the local GOT TLS types. */
|
|
size += symtab_hdr->sh_info;
|
|
local_got_refcounts = bfd_zalloc (abfd, size);
|
|
if (local_got_refcounts == NULL)
|
if (local_got_refcounts == NULL)
|
return FALSE;
|
return FALSE;
|
elf_local_got_refcounts (abfd) = local_got_refcounts;
|
|
memset (hppa_elf_local_got_tls_type (abfd),
|
|
GOT_UNKNOWN, symtab_hdr->sh_info);
|
|
}
|
|
local_got_refcounts[r_symndx] += 1;
|
local_got_refcounts[r_symndx] += 1;
|
|
|
old_tls_type = hppa_elf_local_got_tls_type (abfd) [r_symndx];
|
old_tls_type = hppa_elf_local_got_tls_type (abfd) [r_symndx];
|
}
|
}
|
|
|
Line 1422... |
Line 1429... |
else if (need_entry & PLT_PLABEL)
|
else if (need_entry & PLT_PLABEL)
|
{
|
{
|
bfd_signed_vma *local_got_refcounts;
|
bfd_signed_vma *local_got_refcounts;
|
bfd_signed_vma *local_plt_refcounts;
|
bfd_signed_vma *local_plt_refcounts;
|
|
|
local_got_refcounts = elf_local_got_refcounts (abfd);
|
local_got_refcounts = hppa32_elf_local_refcounts (abfd);
|
if (local_got_refcounts == NULL)
|
|
{
|
|
bfd_size_type size;
|
|
|
|
/* Allocate space for local got offsets and local
|
|
plt offsets. */
|
|
size = symtab_hdr->sh_info;
|
|
size *= 2 * sizeof (bfd_signed_vma);
|
|
/* Add in space to store the local GOT TLS types. */
|
|
size += symtab_hdr->sh_info;
|
|
local_got_refcounts = bfd_zalloc (abfd, size);
|
|
if (local_got_refcounts == NULL)
|
if (local_got_refcounts == NULL)
|
return FALSE;
|
return FALSE;
|
elf_local_got_refcounts (abfd) = local_got_refcounts;
|
|
}
|
|
local_plt_refcounts = (local_got_refcounts
|
local_plt_refcounts = (local_got_refcounts
|
+ symtab_hdr->sh_info);
|
+ symtab_hdr->sh_info);
|
local_plt_refcounts[r_symndx] += 1;
|
local_plt_refcounts[r_symndx] += 1;
|
}
|
}
|
}
|
}
|
Line 1502... |
Line 1496... |
|
|
/* Create a reloc section in dynobj and make room for
|
/* Create a reloc section in dynobj and make room for
|
this reloc. */
|
this reloc. */
|
if (sreloc == NULL)
|
if (sreloc == NULL)
|
{
|
{
|
char *name;
|
|
bfd *dynobj;
|
|
|
|
name = (bfd_elf_string_from_elf_section
|
|
(abfd,
|
|
elf_elfheader (abfd)->e_shstrndx,
|
|
elf_section_data (sec)->rel_hdr.sh_name));
|
|
if (name == NULL)
|
|
{
|
|
(*_bfd_error_handler)
|
|
(_("Could not find relocation section for %s"),
|
|
sec->name);
|
|
bfd_set_error (bfd_error_bad_value);
|
|
return FALSE;
|
|
}
|
|
|
|
if (htab->etab.dynobj == NULL)
|
if (htab->etab.dynobj == NULL)
|
htab->etab.dynobj = abfd;
|
htab->etab.dynobj = abfd;
|
|
|
dynobj = htab->etab.dynobj;
|
sreloc = _bfd_elf_make_dynamic_reloc_section
|
sreloc = bfd_get_section_by_name (dynobj, name);
|
(sec, htab->etab.dynobj, 2, abfd, /*rela?*/ TRUE);
|
|
|
if (sreloc == NULL)
|
if (sreloc == NULL)
|
{
|
{
|
flagword flags;
|
bfd_set_error (bfd_error_bad_value);
|
|
|
flags = (SEC_HAS_CONTENTS | SEC_READONLY
|
|
| SEC_IN_MEMORY | SEC_LINKER_CREATED);
|
|
if ((sec->flags & SEC_ALLOC) != 0)
|
|
flags |= SEC_ALLOC | SEC_LOAD;
|
|
sreloc = bfd_make_section_with_flags (dynobj,
|
|
name,
|
|
flags);
|
|
if (sreloc == NULL
|
|
|| !bfd_set_section_alignment (dynobj, sreloc, 2))
|
|
return FALSE;
|
return FALSE;
|
}
|
}
|
|
|
elf_section_data (sec)->sreloc = sreloc;
|
|
}
|
}
|
|
|
/* If this is a global symbol, we count the number of
|
/* If this is a global symbol, we count the number of
|
relocations we need for this symbol. */
|
relocations we need for this symbol. */
|
if (hh != NULL)
|
if (hh != NULL)
|
Line 1553... |
Line 1520... |
else
|
else
|
{
|
{
|
/* Track dynamic relocs needed for local syms too.
|
/* Track dynamic relocs needed for local syms too.
|
We really need local syms available to do this
|
We really need local syms available to do this
|
easily. Oh well. */
|
easily. Oh well. */
|
|
|
asection *sr;
|
asection *sr;
|
void *vpp;
|
void *vpp;
|
|
Elf_Internal_Sym *isym;
|
|
|
sr = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
|
isym = bfd_sym_from_r_symndx (&htab->sym_cache,
|
sec, r_symndx);
|
abfd, r_symndx);
|
if (sr == NULL)
|
if (isym == NULL)
|
return FALSE;
|
return FALSE;
|
|
|
|
sr = bfd_section_from_elf_index (abfd, isym->st_shndx);
|
|
if (sr == NULL)
|
|
sr = sec;
|
|
|
vpp = &elf_section_data (sr)->local_dynrel;
|
vpp = &elf_section_data (sr)->local_dynrel;
|
hdh_head = (struct elf32_hppa_dyn_reloc_entry **) vpp;
|
hdh_head = (struct elf32_hppa_dyn_reloc_entry **) vpp;
|
}
|
}
|
|
|
hdh_p = *hdh_head;
|
hdh_p = *hdh_head;
|
Line 2974... |
Line 2945... |
if (r_indx < symtab_hdr->sh_info)
|
if (r_indx < symtab_hdr->sh_info)
|
{
|
{
|
/* It's a local symbol. */
|
/* It's a local symbol. */
|
Elf_Internal_Sym *sym;
|
Elf_Internal_Sym *sym;
|
Elf_Internal_Shdr *hdr;
|
Elf_Internal_Shdr *hdr;
|
|
unsigned int shndx;
|
|
|
sym = local_syms + r_indx;
|
sym = local_syms + r_indx;
|
hdr = elf_elfsections (input_bfd)[sym->st_shndx];
|
|
sym_sec = hdr->bfd_section;
|
|
if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
|
if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
|
sym_value = sym->st_value;
|
sym_value = sym->st_value;
|
|
shndx = sym->st_shndx;
|
|
if (shndx < elf_numsections (input_bfd))
|
|
{
|
|
hdr = elf_elfsections (input_bfd)[shndx];
|
|
sym_sec = hdr->bfd_section;
|
destination = (sym_value + irela->r_addend
|
destination = (sym_value + irela->r_addend
|
+ sym_sec->output_offset
|
+ sym_sec->output_offset
|
+ sym_sec->output_section->vma);
|
+ sym_sec->output_section->vma);
|
}
|
}
|
|
}
|
else
|
else
|
{
|
{
|
/* It's an external symbol. */
|
/* It's an external symbol. */
|
int e_indx;
|
int e_indx;
|
|
|
Line 3428... |
Line 3404... |
error. */
|
error. */
|
(*_bfd_error_handler)
|
(*_bfd_error_handler)
|
(_("%B(%A+0x%lx): %s fixup for insn 0x%x is not supported in a non-shared link"),
|
(_("%B(%A+0x%lx): %s fixup for insn 0x%x is not supported in a non-shared link"),
|
input_bfd,
|
input_bfd,
|
input_section,
|
input_section,
|
offset,
|
(long) offset,
|
howto->name,
|
howto->name,
|
insn);
|
insn);
|
}
|
}
|
else if (orig_r_type == R_PARISC_DLTIND14F)
|
else if (orig_r_type == R_PARISC_DLTIND14F)
|
{
|
{
|
Line 3592... |
Line 3568... |
{
|
{
|
(*_bfd_error_handler)
|
(*_bfd_error_handler)
|
(_("%B(%A+0x%lx): cannot reach %s, recompile with -ffunction-sections"),
|
(_("%B(%A+0x%lx): cannot reach %s, recompile with -ffunction-sections"),
|
input_bfd,
|
input_bfd,
|
input_section,
|
input_section,
|
offset,
|
(long) offset,
|
hsh->bh_root.string);
|
hsh->bh_root.string);
|
bfd_set_error (bfd_error_bad_value);
|
bfd_set_error (bfd_error_bad_value);
|
return bfd_reloc_notsupported;
|
return bfd_reloc_notsupported;
|
}
|
}
|
|
|