Add TLS support for hppa-linux

This commit is contained in:
Nick Clifton 2006-05-24 11:05:42 +00:00
parent 9dd728f1af
commit 9b52905e69
8 changed files with 3537 additions and 3004 deletions

View file

@ -1,3 +1,34 @@
2006-05-24 Carlos O'Donell <carlos@systemhalted.org>
Randolph Chung <tausq@debian.org>
* elf-hppa.h (reloc_hppa_howto_table): Check bitfield for
TPREL21L/TPREL14R relocations. Handle LTOFF_TP14R relocations.
Add handling for TLS relocations.
(elf_hpp_reloc_final_type): Handle TLS relocs.
* elf32-hppa.c: Add authors for cleanup and TLS support.
(hppa_elf_local_got_tls_type, hh_name, eh_name): Define.
(elf32_hppa_link_hash_entry): Add tls_type.
(elf32_hppa_link_hash_table): Add tld_ldm_got.
(hppa_link_has_newfunc): Set tls_type.
(elf32_hppa_link_hash_table_create): Set tls_ldm_got refcount.
(hppa_stub_name): Use hh_name macro.
(elf32_hppa_copy_indirect_symbol): Copy TLS information.
(elf32_hppa_check_relocs): Call elf32_hppa_optimized_tls_reloc.
Handle TLS relocs.
(elf32_hppa_gc_sweep_hook): Likewise.
(allocate_dynrelocs): Handle TLS relocs.
(elf32_hppa_size_dynamic_sections): Count space required by TLS
relocs. Use hh_name macro.
(dtpoff_base): New function.
(tpoff): Likewise.
(elf32_hppa_optimized_tls_reloc): Likewise.
(final_link_relocate): Handle TLS relocs.
(elf32_hppa_relocate_section): Handle TLS relocs. Use eh_name
and hh_name macros.
(elf32_hppa_finish_dynamic_symbol): Setup TLS got entries. Use
hh_name and eh_name macros.
(elf32_hppa_reloc_type_clas): Handle TLS relocs.
2006-05-24 Bjoern Haase <bjoern.m.haase@web.de> 2006-05-24 Bjoern Haase <bjoern.m.haase@web.de>
* archures.c: Add bfd_mach_avr6. * archures.c: Add bfd_mach_avr6.

View file

@ -1,22 +1,22 @@
/* Common code for PA ELF implementations. /* Common code for PA ELF implementations.
Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005 Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc. Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library. This file is part of BFD, the Binary File Descriptor library.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
#define ELF_HOWTO_TABLE_SIZE R_PARISC_UNIMPLEMENTED + 1 #define ELF_HOWTO_TABLE_SIZE R_PARISC_UNIMPLEMENTED + 1
@ -27,30 +27,20 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
external constraints require 32 or 64 bit specific code. We remap external constraints require 32 or 64 bit specific code. We remap
the definitions/functions as necessary here. */ the definitions/functions as necessary here. */
#if ARCH_SIZE == 64 #if ARCH_SIZE == 64
#define ELF_R_TYPE(X) ELF64_R_TYPE(X) #define ELF_R_TYPE(X) ELF64_R_TYPE(X)
#define ELF_R_SYM(X) ELF64_R_SYM(X) #define ELF_R_SYM(X) ELF64_R_SYM(X)
#define elf_hppa_reloc_final_type elf64_hppa_reloc_final_type #define elf_hppa_reloc_final_type elf64_hppa_reloc_final_type
#define _bfd_elf_hppa_gen_reloc_type _bfd_elf64_hppa_gen_reloc_type #define _bfd_elf_hppa_gen_reloc_type _bfd_elf64_hppa_gen_reloc_type
#define elf_hppa_relocate_section elf64_hppa_relocate_section #define elf_hppa_relocate_section elf64_hppa_relocate_section
#define elf_hppa_final_link elf64_hppa_final_link #define elf_hppa_final_link elf64_hppa_final_link
#endif #endif
#if ARCH_SIZE == 32 #if ARCH_SIZE == 32
#define ELF_R_TYPE(X) ELF32_R_TYPE(X) #define ELF_R_TYPE(X) ELF32_R_TYPE(X)
#define ELF_R_SYM(X) ELF32_R_SYM(X) #define ELF_R_SYM(X) ELF32_R_SYM(X)
#define elf_hppa_reloc_final_type elf32_hppa_reloc_final_type #define elf_hppa_reloc_final_type elf32_hppa_reloc_final_type
#define _bfd_elf_hppa_gen_reloc_type _bfd_elf32_hppa_gen_reloc_type #define _bfd_elf_hppa_gen_reloc_type _bfd_elf32_hppa_gen_reloc_type
#define elf_hppa_relocate_section elf32_hppa_relocate_section #define elf_hppa_relocate_section elf32_hppa_relocate_section
#define elf_hppa_final_link elf32_hppa_final_link #define elf_hppa_final_link elf32_hppa_final_link
#endif
#if ARCH_SIZE == 64
static bfd_reloc_status_type elf_hppa_final_link_relocate
(Elf_Internal_Rela *, bfd *, bfd *, asection *, bfd_byte *, bfd_vma,
struct bfd_link_info *, asection *, struct elf_link_hash_entry *,
struct elf64_hppa_dyn_hash_entry *);
static int elf_hppa_relocate_insn
(int, int, unsigned int);
#endif #endif
/* ELF/PA relocation howto entries. */ /* ELF/PA relocation howto entries. */
@ -387,7 +377,7 @@ static reloc_howto_type elf_hppa_howto_table[ELF_HOWTO_TABLE_SIZE] =
bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE },
{ R_PARISC_TPREL32, 0, 0, 32, FALSE, 0, complain_overflow_dont, { R_PARISC_TPREL32, 0, 0, 32, FALSE, 0, complain_overflow_dont,
bfd_elf_generic_reloc, "R_PARISC_TPREL32", FALSE, 0, 0, FALSE }, bfd_elf_generic_reloc, "R_PARISC_TPREL32", FALSE, 0, 0, FALSE },
{ R_PARISC_TPREL21L, 0, 0, 21, FALSE, 0, complain_overflow_dont, { R_PARISC_TPREL21L, 0, 0, 21, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_PARISC_TPREL21L", FALSE, 0, 0, FALSE }, bfd_elf_generic_reloc, "R_PARISC_TPREL21L", FALSE, 0, 0, FALSE },
{ R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont,
bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE },
@ -395,7 +385,7 @@ static reloc_howto_type elf_hppa_howto_table[ELF_HOWTO_TABLE_SIZE] =
bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE },
{ R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont,
bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE },
{ R_PARISC_TPREL14R, 0, 0, 14, FALSE, 0, complain_overflow_dont, { R_PARISC_TPREL14R, 0, 0, 14, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_PARISC_TPREL14R", FALSE, 0, 0, FALSE }, bfd_elf_generic_reloc, "R_PARISC_TPREL14R", FALSE, 0, 0, FALSE },
{ R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont,
bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE },
@ -413,7 +403,7 @@ static reloc_howto_type elf_hppa_howto_table[ELF_HOWTO_TABLE_SIZE] =
{ R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE },
{ R_PARISC_LTOFF_TP14R, 0, 0, 14, FALSE, 0, complain_overflow_bitfield, { R_PARISC_LTOFF_TP14R, 0, 0, 14, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, bfd_elf_generic_reloc, "R_PARISC_LTOFF_TP14R", FALSE, 0, 0, FALSE },
{ R_PARISC_LTOFF_TP14F, 0, 0, 14, FALSE, 0, complain_overflow_bitfield, { R_PARISC_LTOFF_TP14F, 0, 0, 14, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_PARISC_LTOFF_TP14F", FALSE, 0, 0, FALSE }, bfd_elf_generic_reloc, "R_PARISC_LTOFF_TP14F", FALSE, 0, 0, FALSE },
/* 168 */ /* 168 */
@ -557,6 +547,31 @@ static reloc_howto_type elf_hppa_howto_table[ELF_HOWTO_TABLE_SIZE] =
bfd_elf_generic_reloc, "R_PARISC_GNU_VTENTRY", FALSE, 0, 0, FALSE }, bfd_elf_generic_reloc, "R_PARISC_GNU_VTENTRY", FALSE, 0, 0, FALSE },
{ R_PARISC_GNU_VTINHERIT, 0, 0, 0, FALSE, 0, complain_overflow_dont, { R_PARISC_GNU_VTINHERIT, 0, 0, 0, FALSE, 0, complain_overflow_dont,
bfd_elf_generic_reloc, "R_PARISC_GNU_VTINHERIT", FALSE, 0, 0, FALSE }, bfd_elf_generic_reloc, "R_PARISC_GNU_VTINHERIT", FALSE, 0, 0, FALSE },
{ R_PARISC_TLS_GD21L, 0, 0, 21, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_PARISC_TLS_GD21L", FALSE, 0, 0, FALSE },
{ R_PARISC_TLS_GD14R, 0, 0, 14, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_PARISC_TLS_GD14R", FALSE, 0, 0, FALSE },
{ R_PARISC_TLS_GDCALL, 0, 0, 0, FALSE, 0, complain_overflow_dont,
bfd_elf_generic_reloc, "R_PARISC_TLS_GDCALL", FALSE, 0, 0, FALSE },
{ R_PARISC_TLS_LDM21L, 0, 0, 21, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_PARISC_TLS_LDM21L", FALSE, 0, 0, FALSE },
{ R_PARISC_TLS_LDM14R, 0, 0, 14, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_PARISC_TLS_LDM14R", FALSE, 0, 0, FALSE },
{ R_PARISC_TLS_LDMCALL, 0, 0, 0, FALSE, 0, complain_overflow_dont,
bfd_elf_generic_reloc, "R_PARISC_TLS_LDMCALL", FALSE, 0, 0, FALSE },
/* 240 */
{ R_PARISC_TLS_LDO21L, 0, 0, 21, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_PARISC_TLS_LDO21L", FALSE, 0, 0, FALSE },
{ R_PARISC_TLS_LDO14R, 0, 0, 14, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_PARISC_TLS_LDO14R", FALSE, 0, 0, FALSE },
{ R_PARISC_TLS_DTPMOD32, 0, 0, 32, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_PARISC_TLS_DTPMOD32", FALSE, 0, 0, FALSE },
{ R_PARISC_TLS_DTPMOD64, 0, 0, 64, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_PARISC_TLS_DTPMOD64", FALSE, 0, 0, FALSE },
{ R_PARISC_TLS_DTPOFF32, 0, 0, 32, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_PARISC_TLS_DTPOFF32", FALSE, 0, 0, FALSE },
{ R_PARISC_TLS_DTPOFF64, 0, 0, 64, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_PARISC_TLS_DTPOFF64", FALSE, 0, 0, FALSE },
}; };
#define OFFSET_14R_FROM_21L 4 #define OFFSET_14R_FROM_21L 4
@ -578,9 +593,9 @@ elf_hppa_reloc_final_type (bfd *abfd,
for PA ELF. */ for PA ELF. */
switch (base_type) switch (base_type)
{ {
/* We have been using generic relocation types. However, that may not /* We have been using generic relocation types. However, that may not
really make sense. Anyway, we need to support both R_PARISC_DIR64 really make sense. Anyway, we need to support both R_PARISC_DIR64
and R_PARISC_DIR32 here. */ and R_PARISC_DIR32 here. */
case R_PARISC_DIR32: case R_PARISC_DIR32:
case R_PARISC_DIR64: case R_PARISC_DIR64:
case R_HPPA_ABS_CALL: case R_HPPA_ABS_CALL:
@ -701,11 +716,11 @@ elf_hppa_reloc_final_type (bfd *abfd,
case e_rsel: case e_rsel:
case e_rrsel: case e_rrsel:
case e_rdsel: case e_rdsel:
/* R_PARISC_DLTREL14R for elf64, R_PARISC_DPREL14R for elf32 */ /* R_PARISC_DLTREL14R for elf64, R_PARISC_DPREL14R for elf32. */
final_type = base_type + OFFSET_14R_FROM_21L; final_type = base_type + OFFSET_14R_FROM_21L;
break; break;
case e_fsel: case e_fsel:
/* R_PARISC_DLTREL14F for elf64, R_PARISC_DPREL14F for elf32 */ /* R_PARISC_DLTREL14F for elf64, R_PARISC_DPREL14F for elf32. */
final_type = base_type + OFFSET_14F_FROM_21L; final_type = base_type + OFFSET_14F_FROM_21L;
break; break;
default: default:
@ -721,7 +736,7 @@ elf_hppa_reloc_final_type (bfd *abfd,
case e_ldsel: case e_ldsel:
case e_nlsel: case e_nlsel:
case e_nlrsel: case e_nlrsel:
/* R_PARISC_DLTREL21L for elf64, R_PARISC_DPREL21L for elf32 */ /* R_PARISC_DLTREL21L for elf64, R_PARISC_DPREL21L for elf32. */
final_type = base_type; final_type = base_type;
break; break;
default: default:
@ -838,6 +853,82 @@ elf_hppa_reloc_final_type (bfd *abfd,
} }
break; break;
case R_PARISC_TLS_GD21L:
switch (field)
{
case e_ltsel:
case e_lrsel:
final_type = R_PARISC_TLS_GD21L;
break;
case e_rtsel:
case e_rrsel:
final_type = R_PARISC_TLS_GD14R;
break;
default:
return R_PARISC_NONE;
}
break;
case R_PARISC_TLS_LDM21L:
switch (field)
{
case e_ltsel:
case e_lrsel:
final_type = R_PARISC_TLS_LDM21L;
break;
case e_rtsel:
case e_rrsel:
final_type = R_PARISC_TLS_LDM14R;
break;
default:
return R_PARISC_NONE;
}
break;
case R_PARISC_TLS_LDO21L:
switch (field)
{
case e_lrsel:
final_type = R_PARISC_TLS_LDO21L;
break;
case e_rrsel:
final_type = R_PARISC_TLS_LDO14R;
break;
default:
return R_PARISC_NONE;
}
break;
case R_PARISC_TLS_IE21L:
switch (field)
{
case e_ltsel:
case e_lrsel:
final_type = R_PARISC_TLS_IE21L;
break;
case e_rtsel:
case e_rrsel:
final_type = R_PARISC_TLS_IE14R;
break;
default:
return R_PARISC_NONE;
}
break;
case R_PARISC_TLS_LE21L:
switch (field)
{
case e_lrsel:
final_type = R_PARISC_TLS_LE21L;
break;
case e_rrsel:
final_type = R_PARISC_TLS_LE14R;
break;
default:
return R_PARISC_NONE;
}
break;
case R_PARISC_GNU_VTENTRY: case R_PARISC_GNU_VTENTRY:
case R_PARISC_GNU_VTINHERIT: case R_PARISC_GNU_VTINHERIT:
case R_PARISC_SEGREL32: case R_PARISC_SEGREL32:
@ -906,7 +997,7 @@ elf_hppa_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
arelent *bfd_reloc, arelent *bfd_reloc,
Elf_Internal_Rela *elf_reloc) Elf_Internal_Rela *elf_reloc)
{ {
BFD_ASSERT (ELF_R_TYPE(elf_reloc->r_info) BFD_ASSERT (ELF_R_TYPE (elf_reloc->r_info)
< (unsigned int) R_PARISC_UNIMPLEMENTED); < (unsigned int) R_PARISC_UNIMPLEMENTED);
bfd_reloc->howto = &elf_hppa_howto_table[ELF_R_TYPE (elf_reloc->r_info)]; bfd_reloc->howto = &elf_hppa_howto_table[ELF_R_TYPE (elf_reloc->r_info)];
} }
@ -932,7 +1023,7 @@ static bfd_boolean
elf_hppa_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, const char *name) elf_hppa_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, const char *name)
{ {
if (name[0] == 'L' && name[1] == '$') if (name[0] == 'L' && name[1] == '$')
return 1; return TRUE;
return _bfd_elf_is_local_label_name (abfd, name); return _bfd_elf_is_local_label_name (abfd, name);
} }
@ -950,6 +1041,7 @@ elf_hppa_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
{ {
int indx; int indx;
asection *asec; asection *asec;
#if ARCH_SIZE == 64 #if ARCH_SIZE == 64
hdr->sh_type = SHT_LOPROC + 1; hdr->sh_type = SHT_LOPROC + 1;
#else #else
@ -1030,7 +1122,8 @@ hppa_unwind_entry_compare (const void *a, const void *b)
return av < bv ? -1 : av > bv ? 1 : 0; return av < bv ? -1 : av > bv ? 1 : 0;
} }
static bfd_boolean elf_hppa_sort_unwind (bfd *abfd) static bfd_boolean
elf_hppa_sort_unwind (bfd *abfd)
{ {
asection *s; asection *s;
@ -1315,208 +1408,116 @@ elf_hppa_final_link (bfd *abfd, struct bfd_link_info *info)
return retval; return retval;
} }
/* Relocate an HPPA ELF section. */ /* Relocate the given INSN. VALUE should be the actual value we want
to insert into the instruction, ie by this point we should not be
concerned with computing an offset relative to the DLT, PC, etc.
Instead this routine is meant to handle the bit manipulations needed
to insert the relocation into the given instruction. */
static bfd_boolean static int
elf_hppa_relocate_section (bfd *output_bfd, elf_hppa_relocate_insn (int insn, int sym_value, unsigned int r_type)
struct bfd_link_info *info,
bfd *input_bfd,
asection *input_section,
bfd_byte *contents,
Elf_Internal_Rela *relocs,
Elf_Internal_Sym *local_syms,
asection **local_sections)
{ {
Elf_Internal_Shdr *symtab_hdr; switch (r_type)
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
struct elf64_hppa_link_hash_table *hppa_info;
if (info->relocatable)
return TRUE;
hppa_info = elf64_hppa_hash_table (info);
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
rel = relocs;
relend = relocs + input_section->reloc_count;
for (; rel < relend; rel++)
{ {
int r_type; /* This is any 22 bit branch. In PA2.0 syntax it corresponds to
reloc_howto_type *howto = elf_hppa_howto_table + ELF_R_TYPE (rel->r_info); the "B" instruction. */
unsigned long r_symndx; case R_PARISC_PCREL22F:
struct elf_link_hash_entry *h; case R_PARISC_PCREL22C:
Elf_Internal_Sym *sym; return (insn & ~0x3ff1ffd) | re_assemble_22 (sym_value);
asection *sym_sec;
bfd_vma relocation;
bfd_reloc_status_type r;
const char *dyn_name;
char *dynh_buf = NULL;
size_t dynh_buflen = 0;
struct elf64_hppa_dyn_hash_entry *dyn_h = NULL;
r_type = ELF_R_TYPE (rel->r_info); /* This is any 12 bit branch. */
if (r_type < 0 || r_type >= (int) R_PARISC_UNIMPLEMENTED) case R_PARISC_PCREL12F:
{ return (insn & ~0x1ffd) | re_assemble_12 (sym_value);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
/* This is a final link. */ /* This is any 17 bit branch. In PA2.0 syntax it also corresponds
r_symndx = ELF_R_SYM (rel->r_info); to the "B" instruction as well as BE. */
h = NULL; case R_PARISC_PCREL17F:
sym = NULL; case R_PARISC_DIR17F:
sym_sec = NULL; case R_PARISC_DIR17R:
if (r_symndx < symtab_hdr->sh_info) case R_PARISC_PCREL17C:
{ case R_PARISC_PCREL17R:
/* This is a local symbol. */ return (insn & ~0x1f1ffd) | re_assemble_17 (sym_value);
sym = local_syms + r_symndx;
sym_sec = local_sections[r_symndx];
relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sym_sec, rel);
/* If this symbol has an entry in the PA64 dynamic hash /* ADDIL or LDIL instructions. */
table, then get it. */ case R_PARISC_DLTREL21L:
dyn_name = get_dyn_name (input_bfd, h, rel, case R_PARISC_DLTIND21L:
&dynh_buf, &dynh_buflen); case R_PARISC_LTOFF_FPTR21L:
dyn_h = elf64_hppa_dyn_hash_lookup (&hppa_info->dyn_hash_table, case R_PARISC_PCREL21L:
dyn_name, FALSE, FALSE); case R_PARISC_LTOFF_TP21L:
case R_PARISC_DPREL21L:
case R_PARISC_PLTOFF21L:
case R_PARISC_DIR21L:
return (insn & ~0x1fffff) | re_assemble_21 (sym_value);
} /* LDO and integer loads/stores with 14 bit displacements. */
else case R_PARISC_DLTREL14R:
{ case R_PARISC_DLTREL14F:
/* This is not a local symbol. */ case R_PARISC_DLTIND14R:
long indx; case R_PARISC_DLTIND14F:
case R_PARISC_LTOFF_FPTR14R:
case R_PARISC_PCREL14R:
case R_PARISC_PCREL14F:
case R_PARISC_LTOFF_TP14R:
case R_PARISC_LTOFF_TP14F:
case R_PARISC_DPREL14R:
case R_PARISC_DPREL14F:
case R_PARISC_PLTOFF14R:
case R_PARISC_PLTOFF14F:
case R_PARISC_DIR14R:
case R_PARISC_DIR14F:
return (insn & ~0x3fff) | low_sign_unext (sym_value, 14);
indx = r_symndx - symtab_hdr->sh_info; /* PA2.0W LDO and integer loads/stores with 16 bit displacements. */
h = elf_sym_hashes (input_bfd)[indx]; case R_PARISC_LTOFF_FPTR16F:
while (h->root.type == bfd_link_hash_indirect case R_PARISC_PCREL16F:
|| h->root.type == bfd_link_hash_warning) case R_PARISC_LTOFF_TP16F:
h = (struct elf_link_hash_entry *) h->root.u.i.link; case R_PARISC_GPREL16F:
if (h->root.type == bfd_link_hash_defined case R_PARISC_PLTOFF16F:
|| h->root.type == bfd_link_hash_defweak) case R_PARISC_DIR16F:
{ case R_PARISC_LTOFF16F:
sym_sec = h->root.u.def.section; return (insn & ~0xffff) | re_assemble_16 (sym_value);
/* If this symbol has an entry in the PA64 dynamic hash /* Doubleword loads and stores with a 14 bit displacement. */
table, then get it. */ case R_PARISC_DLTREL14DR:
dyn_name = get_dyn_name (input_bfd, h, rel, case R_PARISC_DLTIND14DR:
&dynh_buf, &dynh_buflen); case R_PARISC_LTOFF_FPTR14DR:
dyn_h = elf64_hppa_dyn_hash_lookup (&hppa_info->dyn_hash_table, case R_PARISC_LTOFF_FPTR16DF:
dyn_name, FALSE, FALSE); case R_PARISC_PCREL14DR:
case R_PARISC_PCREL16DF:
case R_PARISC_LTOFF_TP14DR:
case R_PARISC_LTOFF_TP16DF:
case R_PARISC_DPREL14DR:
case R_PARISC_GPREL16DF:
case R_PARISC_PLTOFF14DR:
case R_PARISC_PLTOFF16DF:
case R_PARISC_DIR14DR:
case R_PARISC_DIR16DF:
case R_PARISC_LTOFF16DF:
return (insn & ~0x3ff1) | (((sym_value & 0x2000) >> 13)
| ((sym_value & 0x1ff8) << 1));
/* If we have a relocation against a symbol defined in a /* Floating point single word load/store instructions. */
shared library and we have not created an entry in the case R_PARISC_DLTREL14WR:
PA64 dynamic symbol hash table for it, then we lose. */ case R_PARISC_DLTIND14WR:
if (sym_sec->output_section == NULL && dyn_h == NULL) case R_PARISC_LTOFF_FPTR14WR:
{ case R_PARISC_LTOFF_FPTR16WF:
(*_bfd_error_handler) case R_PARISC_PCREL14WR:
(_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"), case R_PARISC_PCREL16WF:
input_bfd, case R_PARISC_LTOFF_TP14WR:
input_section, case R_PARISC_LTOFF_TP16WF:
(long) rel->r_offset, case R_PARISC_DPREL14WR:
howto->name, case R_PARISC_GPREL16WF:
h->root.root.string); case R_PARISC_PLTOFF14WR:
relocation = 0; case R_PARISC_PLTOFF16WF:
} case R_PARISC_DIR16WF:
else if (sym_sec->output_section) case R_PARISC_DIR14WR:
relocation = (h->root.u.def.value case R_PARISC_LTOFF16WF:
+ sym_sec->output_offset return (insn & ~0x3ff9) | (((sym_value & 0x2000) >> 13)
+ sym_sec->output_section->vma); | ((sym_value & 0x1ffc) << 1));
/* Value will be provided via one of the offsets in the
dyn_h hash table entry. */
else
relocation = 0;
}
else if (info->unresolved_syms_in_objects == RM_IGNORE
&& ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
{
/* If this symbol has an entry in the PA64 dynamic hash
table, then get it. */
dyn_name = get_dyn_name (input_bfd, h, rel,
&dynh_buf, &dynh_buflen);
dyn_h = elf64_hppa_dyn_hash_lookup (&hppa_info->dyn_hash_table,
dyn_name, FALSE, FALSE);
if (dyn_h == NULL) default:
{ return insn;
(*_bfd_error_handler)
(_("%B(%A): warning: unresolvable relocation against symbol `%s'"),
input_bfd, input_section, h->root.root.string);
}
relocation = 0;
}
else if (h->root.type == bfd_link_hash_undefweak)
{
dyn_name = get_dyn_name (input_bfd, h, rel,
&dynh_buf, &dynh_buflen);
dyn_h = elf64_hppa_dyn_hash_lookup (&hppa_info->dyn_hash_table,
dyn_name, FALSE, FALSE);
if (dyn_h == NULL)
{
(*_bfd_error_handler)
(_("%B(%A): warning: unresolvable relocation against symbol `%s'"),
input_bfd, input_section, h->root.root.string);
}
relocation = 0;
}
else
{
/* Ignore dynamic loader defined symbols. */
if (elf_hppa_is_dynamic_loader_symbol (h->root.root.string))
relocation = 0;
else
{
if (!((*info->callbacks->undefined_symbol)
(info, h->root.root.string, input_bfd,
input_section, rel->r_offset,
(info->unresolved_syms_in_objects == RM_GENERATE_ERROR
|| ELF_ST_VISIBILITY (h->other)))))
return FALSE;
break;
}
}
}
r = elf_hppa_final_link_relocate (rel, input_bfd, output_bfd,
input_section, contents,
relocation, info, sym_sec,
h, dyn_h);
if (r != bfd_reloc_ok)
{
switch (r)
{
default:
abort ();
case bfd_reloc_overflow:
{
const char *sym_name;
if (h != NULL)
sym_name = NULL;
else
{
sym_name = bfd_elf_string_from_elf_section (input_bfd,
symtab_hdr->sh_link,
sym->st_name);
if (sym_name == NULL)
return FALSE;
if (*sym_name == '\0')
sym_name = bfd_section_name (input_bfd, sym_sec);
}
if (!((*info->callbacks->reloc_overflow)
(info, (h ? &h->root : NULL), sym_name,
howto->name, (bfd_vma) 0, input_bfd,
input_section, rel->r_offset)))
return FALSE;
}
break;
}
}
} }
return TRUE;
} }
/* Compute the value for a relocation (REL) during a final link stage, /* Compute the value for a relocation (REL) during a final link stage,
@ -1806,10 +1807,8 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
value = hppa_field_adjust (value, addend, e_rrsel); value = hppa_field_adjust (value, addend, e_rrsel);
if (r_type == R_PARISC_DIR17R || r_type == R_PARISC_DIR17F) if (r_type == R_PARISC_DIR17R || r_type == R_PARISC_DIR17F)
{ /* All branches are implicitly shifted by 2 places. */
/* All branches are implicitly shifted by 2 places. */ value >>= 2;
value >>= 2;
}
insn = elf_hppa_relocate_insn (insn, (int) value, r_type); insn = elf_hppa_relocate_insn (insn, (int) value, r_type);
break; break;
@ -2081,115 +2080,208 @@ elf_hppa_final_link_relocate (Elf_Internal_Rela *rel,
return bfd_reloc_ok; return bfd_reloc_ok;
} }
/* Relocate the given INSN. VALUE should be the actual value we want /* Relocate an HPPA ELF section. */
to insert into the instruction, ie by this point we should not be
concerned with computing an offset relative to the DLT, PC, etc.
Instead this routine is meant to handle the bit manipulations needed
to insert the relocation into the given instruction. */
static int static bfd_boolean
elf_hppa_relocate_insn (int insn, int sym_value, unsigned int r_type) elf_hppa_relocate_section (bfd *output_bfd,
struct bfd_link_info *info,
bfd *input_bfd,
asection *input_section,
bfd_byte *contents,
Elf_Internal_Rela *relocs,
Elf_Internal_Sym *local_syms,
asection **local_sections)
{ {
switch (r_type) Elf_Internal_Shdr *symtab_hdr;
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
struct elf64_hppa_link_hash_table *hppa_info;
if (info->relocatable)
return TRUE;
hppa_info = elf64_hppa_hash_table (info);
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
rel = relocs;
relend = relocs + input_section->reloc_count;
for (; rel < relend; rel++)
{ {
/* This is any 22 bit branch. In PA2.0 syntax it corresponds to int r_type;
the "B" instruction. */ reloc_howto_type *howto = elf_hppa_howto_table + ELF_R_TYPE (rel->r_info);
case R_PARISC_PCREL22F: unsigned long r_symndx;
case R_PARISC_PCREL22C: struct elf_link_hash_entry *h;
return (insn & ~0x3ff1ffd) | re_assemble_22 (sym_value); Elf_Internal_Sym *sym;
asection *sym_sec;
bfd_vma relocation;
bfd_reloc_status_type r;
const char *dyn_name;
char *dynh_buf = NULL;
size_t dynh_buflen = 0;
struct elf64_hppa_dyn_hash_entry *dyn_h = NULL;
/* This is any 12 bit branch. */ r_type = ELF_R_TYPE (rel->r_info);
case R_PARISC_PCREL12F: if (r_type < 0 || r_type >= (int) R_PARISC_UNIMPLEMENTED)
return (insn & ~0x1ffd) | re_assemble_12 (sym_value); {
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
/* This is any 17 bit branch. In PA2.0 syntax it also corresponds /* This is a final link. */
to the "B" instruction as well as BE. */ r_symndx = ELF_R_SYM (rel->r_info);
case R_PARISC_PCREL17F: h = NULL;
case R_PARISC_DIR17F: sym = NULL;
case R_PARISC_DIR17R: sym_sec = NULL;
case R_PARISC_PCREL17C: if (r_symndx < symtab_hdr->sh_info)
case R_PARISC_PCREL17R: {
return (insn & ~0x1f1ffd) | re_assemble_17 (sym_value); /* This is a local symbol. */
sym = local_syms + r_symndx;
sym_sec = local_sections[r_symndx];
relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sym_sec, rel);
/* ADDIL or LDIL instructions. */ /* If this symbol has an entry in the PA64 dynamic hash
case R_PARISC_DLTREL21L: table, then get it. */
case R_PARISC_DLTIND21L: dyn_name = get_dyn_name (input_bfd, h, rel,
case R_PARISC_LTOFF_FPTR21L: &dynh_buf, &dynh_buflen);
case R_PARISC_PCREL21L: dyn_h = elf64_hppa_dyn_hash_lookup (&hppa_info->dyn_hash_table,
case R_PARISC_LTOFF_TP21L: dyn_name, FALSE, FALSE);
case R_PARISC_DPREL21L:
case R_PARISC_PLTOFF21L:
case R_PARISC_DIR21L:
return (insn & ~0x1fffff) | re_assemble_21 (sym_value);
/* LDO and integer loads/stores with 14 bit displacements. */ }
case R_PARISC_DLTREL14R: else
case R_PARISC_DLTREL14F: {
case R_PARISC_DLTIND14R: /* This is not a local symbol. */
case R_PARISC_DLTIND14F: long indx;
case R_PARISC_LTOFF_FPTR14R:
case R_PARISC_PCREL14R:
case R_PARISC_PCREL14F:
case R_PARISC_LTOFF_TP14R:
case R_PARISC_LTOFF_TP14F:
case R_PARISC_DPREL14R:
case R_PARISC_DPREL14F:
case R_PARISC_PLTOFF14R:
case R_PARISC_PLTOFF14F:
case R_PARISC_DIR14R:
case R_PARISC_DIR14F:
return (insn & ~0x3fff) | low_sign_unext (sym_value, 14);
/* PA2.0W LDO and integer loads/stores with 16 bit displacements. */ indx = r_symndx - symtab_hdr->sh_info;
case R_PARISC_LTOFF_FPTR16F: h = elf_sym_hashes (input_bfd)[indx];
case R_PARISC_PCREL16F: while (h->root.type == bfd_link_hash_indirect
case R_PARISC_LTOFF_TP16F: || h->root.type == bfd_link_hash_warning)
case R_PARISC_GPREL16F: h = (struct elf_link_hash_entry *) h->root.u.i.link;
case R_PARISC_PLTOFF16F: if (h->root.type == bfd_link_hash_defined
case R_PARISC_DIR16F: || h->root.type == bfd_link_hash_defweak)
case R_PARISC_LTOFF16F: {
return (insn & ~0xffff) | re_assemble_16 (sym_value); sym_sec = h->root.u.def.section;
/* Doubleword loads and stores with a 14 bit displacement. */ /* If this symbol has an entry in the PA64 dynamic hash
case R_PARISC_DLTREL14DR: table, then get it. */
case R_PARISC_DLTIND14DR: dyn_name = get_dyn_name (input_bfd, h, rel,
case R_PARISC_LTOFF_FPTR14DR: &dynh_buf, &dynh_buflen);
case R_PARISC_LTOFF_FPTR16DF: dyn_h = elf64_hppa_dyn_hash_lookup (&hppa_info->dyn_hash_table,
case R_PARISC_PCREL14DR: dyn_name, FALSE, FALSE);
case R_PARISC_PCREL16DF:
case R_PARISC_LTOFF_TP14DR:
case R_PARISC_LTOFF_TP16DF:
case R_PARISC_DPREL14DR:
case R_PARISC_GPREL16DF:
case R_PARISC_PLTOFF14DR:
case R_PARISC_PLTOFF16DF:
case R_PARISC_DIR14DR:
case R_PARISC_DIR16DF:
case R_PARISC_LTOFF16DF:
return (insn & ~0x3ff1) | (((sym_value & 0x2000) >> 13)
| ((sym_value & 0x1ff8) << 1));
/* Floating point single word load/store instructions. */ /* If we have a relocation against a symbol defined in a
case R_PARISC_DLTREL14WR: shared library and we have not created an entry in the
case R_PARISC_DLTIND14WR: PA64 dynamic symbol hash table for it, then we lose. */
case R_PARISC_LTOFF_FPTR14WR: if (sym_sec->output_section == NULL && dyn_h == NULL)
case R_PARISC_LTOFF_FPTR16WF: {
case R_PARISC_PCREL14WR: (*_bfd_error_handler)
case R_PARISC_PCREL16WF: (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
case R_PARISC_LTOFF_TP14WR: input_bfd,
case R_PARISC_LTOFF_TP16WF: input_section,
case R_PARISC_DPREL14WR: (long) rel->r_offset,
case R_PARISC_GPREL16WF: howto->name,
case R_PARISC_PLTOFF14WR: h->root.root.string);
case R_PARISC_PLTOFF16WF: relocation = 0;
case R_PARISC_DIR16WF: }
case R_PARISC_DIR14WR: else if (sym_sec->output_section)
case R_PARISC_LTOFF16WF: relocation = (h->root.u.def.value
return (insn & ~0x3ff9) | (((sym_value & 0x2000) >> 13) + sym_sec->output_offset
| ((sym_value & 0x1ffc) << 1)); + sym_sec->output_section->vma);
/* Value will be provided via one of the offsets in the
dyn_h hash table entry. */
else
relocation = 0;
}
else if (info->unresolved_syms_in_objects == RM_IGNORE
&& ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
{
/* If this symbol has an entry in the PA64 dynamic hash
table, then get it. */
dyn_name = get_dyn_name (input_bfd, h, rel,
&dynh_buf, &dynh_buflen);
dyn_h = elf64_hppa_dyn_hash_lookup (&hppa_info->dyn_hash_table,
dyn_name, FALSE, FALSE);
default: if (dyn_h == NULL)
return insn; {
(*_bfd_error_handler)
(_("%B(%A): warning: unresolvable relocation against symbol `%s'"),
input_bfd, input_section, h->root.root.string);
}
relocation = 0;
}
else if (h->root.type == bfd_link_hash_undefweak)
{
dyn_name = get_dyn_name (input_bfd, h, rel,
&dynh_buf, &dynh_buflen);
dyn_h = elf64_hppa_dyn_hash_lookup (&hppa_info->dyn_hash_table,
dyn_name, FALSE, FALSE);
if (dyn_h == NULL)
{
(*_bfd_error_handler)
(_("%B(%A): warning: unresolvable relocation against symbol `%s'"),
input_bfd, input_section, h->root.root.string);
}
relocation = 0;
}
else
{
/* Ignore dynamic loader defined symbols. */
if (elf_hppa_is_dynamic_loader_symbol (h->root.root.string))
relocation = 0;
else
{
if (!((*info->callbacks->undefined_symbol)
(info, h->root.root.string, input_bfd,
input_section, rel->r_offset,
(info->unresolved_syms_in_objects == RM_GENERATE_ERROR
|| ELF_ST_VISIBILITY (h->other)))))
return FALSE;
break;
}
}
}
r = elf_hppa_final_link_relocate (rel, input_bfd, output_bfd,
input_section, contents,
relocation, info, sym_sec,
h, dyn_h);
if (r != bfd_reloc_ok)
{
switch (r)
{
default:
abort ();
case bfd_reloc_overflow:
{
const char *sym_name;
if (h != NULL)
sym_name = NULL;
else
{
sym_name = bfd_elf_string_from_elf_section (input_bfd,
symtab_hdr->sh_link,
sym->st_name);
if (sym_name == NULL)
return FALSE;
if (*sym_name == '\0')
sym_name = bfd_section_name (input_bfd, sym_sec);
}
if (!((*info->callbacks->reloc_overflow)
(info, (h ? &h->root : NULL), sym_name,
howto->name, (bfd_vma) 0, input_bfd,
input_section, rel->r_offset)))
return FALSE;
}
break;
}
}
} }
return TRUE;
} }
#endif
#endif /* ARCH_SIZE == 64 */

View file

@ -7,7 +7,9 @@
Department of Computer Science Department of Computer Science
University of Utah University of Utah
Largely rewritten by Alan Modra <alan@linuxcare.com.au> Largely rewritten by Alan Modra <alan@linuxcare.com.au>
Naming cleanup by Carlos O'Donell <carlos@systemhalted.org>
TLS support written by Randolph Chung <tausq@debian.org>
This file is part of BFD, the Binary File Descriptor library. This file is part of BFD, the Binary File Descriptor library.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@ -168,7 +170,8 @@ static const bfd_byte plt_stub[] =
shared lib. */ shared lib. */
#define ELIMINATE_COPY_RELOCS 1 #define ELIMINATE_COPY_RELOCS 1
enum elf32_hppa_stub_type { enum elf32_hppa_stub_type
{
hppa_stub_long_branch, hppa_stub_long_branch,
hppa_stub_long_branch_shared, hppa_stub_long_branch_shared,
hppa_stub_import, hppa_stub_import,
@ -177,8 +180,8 @@ enum elf32_hppa_stub_type {
hppa_stub_none hppa_stub_none
}; };
struct elf32_hppa_stub_hash_entry { struct elf32_hppa_stub_hash_entry
{
/* Base hash table entry structure. */ /* Base hash table entry structure. */
struct bfd_hash_entry bh_root; struct bfd_hash_entry bh_root;
@ -203,8 +206,8 @@ struct elf32_hppa_stub_hash_entry {
asection *id_sec; asection *id_sec;
}; };
struct elf32_hppa_link_hash_entry { struct elf32_hppa_link_hash_entry
{
struct elf_link_hash_entry eh; struct elf_link_hash_entry eh;
/* A pointer to the most recently used stub hash entry against this /* A pointer to the most recently used stub hash entry against this
@ -213,8 +216,8 @@ struct elf32_hppa_link_hash_entry {
/* Used to count relocations for delayed sizing of relocation /* Used to count relocations for delayed sizing of relocation
sections. */ sections. */
struct elf32_hppa_dyn_reloc_entry { struct elf32_hppa_dyn_reloc_entry
{
/* Next relocation in the chain. */ /* Next relocation in the chain. */
struct elf32_hppa_dyn_reloc_entry *hdh_next; struct elf32_hppa_dyn_reloc_entry *hdh_next;
@ -230,12 +233,17 @@ struct elf32_hppa_link_hash_entry {
#endif #endif
} *dyn_relocs; } *dyn_relocs;
enum
{
GOT_UNKNOWN = 0, GOT_NORMAL = 1, GOT_TLS_GD = 2, GOT_TLS_LDM = 4, GOT_TLS_IE = 8
} tls_type;
/* Set if this symbol is used by a plabel reloc. */ /* Set if this symbol is used by a plabel reloc. */
unsigned int plabel:1; unsigned int plabel:1;
}; };
struct elf32_hppa_link_hash_table { struct elf32_hppa_link_hash_table
{
/* The main hash table. */ /* The main hash table. */
struct elf_link_hash_table etab; struct elf_link_hash_table etab;
@ -251,7 +259,8 @@ struct elf32_hppa_link_hash_table {
/* Array to keep track of which stub sections have been created, and /* Array to keep track of which stub sections have been created, and
information on stub grouping. */ information on stub grouping. */
struct map_stub { struct map_stub
{
/* This is the section to which stubs in the group will be /* This is the section to which stubs in the group will be
attached. */ attached. */
asection *link_sec; asection *link_sec;
@ -292,6 +301,13 @@ struct elf32_hppa_link_hash_table {
/* Small local sym to section mapping cache. */ /* Small local sym to section mapping cache. */
struct sym_sec_cache sym_sec; struct sym_sec_cache sym_sec;
/* Data for LDM relocations. */
union
{
bfd_signed_vma refcount;
bfd_vma offset;
} tls_ldm_got;
}; };
/* Various hash macros and functions. */ /* Various hash macros and functions. */
@ -308,6 +324,15 @@ struct elf32_hppa_link_hash_table {
((struct elf32_hppa_stub_hash_entry *) \ ((struct elf32_hppa_stub_hash_entry *) \
bfd_hash_lookup ((table), (string), (create), (copy))) bfd_hash_lookup ((table), (string), (create), (copy)))
#define hppa_elf_local_got_tls_type(abfd) \
((char *)(elf_local_got_offsets (abfd) + (elf_tdata (abfd)->symtab_hdr.sh_info * 2)))
#define hh_name(hh) \
(hh ? hh->eh.root.root.string : "<undef>")
#define eh_name(eh) \
(eh ? eh->root.root.string : "<undef>")
/* Assorted hash table functions. */ /* Assorted hash table functions. */
/* Initialize an entry in the stub hash table. */ /* Initialize an entry in the stub hash table. */
@ -375,6 +400,7 @@ hppa_link_hash_newfunc (struct bfd_hash_entry *entry,
hh->hsh_cache = NULL; hh->hsh_cache = NULL;
hh->dyn_relocs = NULL; hh->dyn_relocs = NULL;
hh->plabel = 0; hh->plabel = 0;
hh->tls_type = GOT_UNKNOWN;
} }
return entry; return entry;
@ -390,7 +416,7 @@ elf32_hppa_link_hash_table_create (bfd *abfd)
struct elf32_hppa_link_hash_table *htab; struct elf32_hppa_link_hash_table *htab;
bfd_size_type amt = sizeof (*htab); bfd_size_type amt = sizeof (*htab);
htab = (struct elf32_hppa_link_hash_table *) bfd_malloc (amt); htab = bfd_malloc (amt);
if (htab == NULL) if (htab == NULL)
return NULL; return NULL;
@ -424,6 +450,7 @@ elf32_hppa_link_hash_table_create (bfd *abfd)
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_sec.abfd = NULL;
htab->tls_ldm_got.refcount = 0;
return &htab->etab.root; return &htab->etab.root;
} }
@ -453,28 +480,24 @@ hppa_stub_name (const asection *input_section,
if (hh) if (hh)
{ {
len = 8 + 1 + strlen (hh->eh.root.root.string) + 1 + 8 + 1; len = 8 + 1 + strlen (hh_name (hh)) + 1 + 8 + 1;
stub_name = bfd_malloc (len); stub_name = bfd_malloc (len);
if (stub_name != NULL) if (stub_name != NULL)
{ sprintf (stub_name, "%08x_%s+%x",
sprintf (stub_name, "%08x_%s+%x", input_section->id & 0xffffffff,
input_section->id & 0xffffffff, hh_name (hh),
hh->eh.root.root.string, (int) rela->r_addend & 0xffffffff);
(int) rela->r_addend & 0xffffffff);
}
} }
else else
{ {
len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1; len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1;
stub_name = bfd_malloc (len); stub_name = bfd_malloc (len);
if (stub_name != NULL) if (stub_name != NULL)
{ sprintf (stub_name, "%08x_%x:%x+%x",
sprintf (stub_name, "%08x_%x:%x+%x", input_section->id & 0xffffffff,
input_section->id & 0xffffffff, sym_sec->id & 0xffffffff,
sym_sec->id & 0xffffffff, (int) ELF32_R_SYM (rela->r_info) & 0xffffffff,
(int) ELF32_R_SYM (rela->r_info) & 0xffffffff, (int) rela->r_addend & 0xffffffff);
(int) rela->r_addend & 0xffffffff);
}
} }
return stub_name; return stub_name;
} }
@ -620,17 +643,13 @@ hppa_type_of_stub (asection *input_sec,
bytes on from the branch instruction location. The offset is bytes on from the branch instruction location. The offset is
signed and counts in units of 4 bytes. */ signed and counts in units of 4 bytes. */
if (r_type == (unsigned int) R_PARISC_PCREL17F) if (r_type == (unsigned int) R_PARISC_PCREL17F)
{ max_branch_offset = (1 << (17 - 1)) << 2;
max_branch_offset = (1 << (17-1)) << 2;
}
else if (r_type == (unsigned int) R_PARISC_PCREL12F) else if (r_type == (unsigned int) R_PARISC_PCREL12F)
{ max_branch_offset = (1 << (12 - 1)) << 2;
max_branch_offset = (1 << (12-1)) << 2;
}
else /* R_PARISC_PCREL22F. */ else /* R_PARISC_PCREL22F. */
{ max_branch_offset = (1 << (22 - 1)) << 2;
max_branch_offset = (1 << (22-1)) << 2;
}
if (branch_offset + max_branch_offset >= 2*max_branch_offset) if (branch_offset + max_branch_offset >= 2*max_branch_offset)
return hppa_stub_long_branch; return hppa_stub_long_branch;
@ -1063,7 +1082,24 @@ elf32_hppa_copy_indirect_symbol (struct bfd_link_info *info,
eh_dir->needs_plt |= eh_ind->needs_plt; eh_dir->needs_plt |= eh_ind->needs_plt;
} }
else else
_bfd_elf_link_hash_copy_indirect (info, eh_dir, eh_ind); {
if (eh_ind->root.type == bfd_link_hash_indirect
&& eh_dir->got.refcount <= 0)
{
hh_dir->tls_type = hh_ind->tls_type;
hh_ind->tls_type = GOT_UNKNOWN;
}
_bfd_elf_link_hash_copy_indirect (info, eh_dir, eh_ind);
}
}
static int
elf32_hppa_optimized_tls_reloc (struct bfd_link_info *info ATTRIBUTE_UNUSED,
int r_type, int is_local ATTRIBUTE_UNUSED)
{
/* For now we don't support linker optimizations. */
return r_type;
} }
/* Look through the relocs for a section during the first phase, and /* Look through the relocs for a section during the first phase, and
@ -1084,6 +1120,7 @@ elf32_hppa_check_relocs (bfd *abfd,
struct elf32_hppa_link_hash_table *htab; struct elf32_hppa_link_hash_table *htab;
asection *sreloc; asection *sreloc;
asection *stubreloc; asection *stubreloc;
int tls_type = GOT_UNKNOWN, old_tls_type = GOT_UNKNOWN;
if (info->relocatable) if (info->relocatable)
return TRUE; return TRUE;
@ -1121,6 +1158,7 @@ elf32_hppa_check_relocs (bfd *abfd,
} }
r_type = ELF32_R_TYPE (rela->r_info); r_type = ELF32_R_TYPE (rela->r_info);
r_type = elf32_hppa_optimized_tls_reloc (info, r_type, hh == NULL);
switch (r_type) switch (r_type)
{ {
@ -1243,6 +1281,20 @@ elf32_hppa_check_relocs (bfd *abfd,
return FALSE; return FALSE;
continue; continue;
case R_PARISC_TLS_GD21L:
case R_PARISC_TLS_GD14R:
case R_PARISC_TLS_LDM21L:
case R_PARISC_TLS_LDM14R:
need_entry = NEED_GOT;
break;
case R_PARISC_TLS_IE21L:
case R_PARISC_TLS_IE14R:
if (info->shared)
info->flags |= DF_STATIC_TLS;
need_entry = NEED_GOT;
break;
default: default:
continue; continue;
} }
@ -1250,6 +1302,25 @@ elf32_hppa_check_relocs (bfd *abfd,
/* Now carry out our orders. */ /* Now carry out our orders. */
if (need_entry & NEED_GOT) if (need_entry & NEED_GOT)
{ {
switch (r_type)
{
default:
tls_type = GOT_NORMAL;
break;
case R_PARISC_TLS_GD21L:
case R_PARISC_TLS_GD14R:
tls_type |= GOT_TLS_GD;
break;
case R_PARISC_TLS_LDM21L:
case R_PARISC_TLS_LDM14R:
tls_type |= GOT_TLS_LDM;
break;
case R_PARISC_TLS_IE21L:
case R_PARISC_TLS_IE14R:
tls_type |= GOT_TLS_IE;
break;
}
/* Allocate space for a GOT entry, as well as a dynamic /* Allocate space for a GOT entry, as well as a dynamic
relocation for this entry. */ relocation for this entry. */
if (htab->sgot == NULL) if (htab->sgot == NULL)
@ -1260,31 +1331,56 @@ elf32_hppa_check_relocs (bfd *abfd,
return FALSE; return FALSE;
} }
if (hh != NULL) if (r_type == R_PARISC_TLS_LDM21L
{ || r_type == R_PARISC_TLS_LDM14R)
hh->eh.got.refcount += 1; hppa_link_hash_table (info)->tls_ldm_got.refcount += 1;
}
else else
{ {
bfd_signed_vma *local_got_refcounts; if (hh != NULL)
/* This is a global offset table entry for a local symbol. */ {
local_got_refcounts = elf_local_got_refcounts (abfd); hh->eh.got.refcount += 1;
if (local_got_refcounts == NULL) old_tls_type = hh->tls_type;
{ }
bfd_size_type size; else
{
bfd_signed_vma *local_got_refcounts;
/* This is a global offset table entry for a local symbol. */
local_got_refcounts = elf_local_got_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)
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;
old_tls_type = hppa_elf_local_got_tls_type (abfd) [r_symndx];
}
tls_type |= old_tls_type;
if (old_tls_type != tls_type)
{
if (hh != NULL)
hh->tls_type = tls_type;
else
hppa_elf_local_got_tls_type (abfd) [r_symndx] = tls_type;
}
/* 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);
local_got_refcounts = bfd_zalloc (abfd, size);
if (local_got_refcounts == NULL)
return FALSE;
elf_local_got_refcounts (abfd) = local_got_refcounts;
}
local_got_refcounts[r_symndx] += 1;
} }
} }
@ -1325,6 +1421,8 @@ elf32_hppa_check_relocs (bfd *abfd,
plt offsets. */ plt offsets. */
size = symtab_hdr->sh_info; size = symtab_hdr->sh_info;
size *= 2 * sizeof (bfd_signed_vma); 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); local_got_refcounts = bfd_zalloc (abfd, size);
if (local_got_refcounts == NULL) if (local_got_refcounts == NULL)
return FALSE; return FALSE;
@ -1578,11 +1676,17 @@ elf32_hppa_gc_sweep_hook (bfd *abfd,
} }
r_type = ELF32_R_TYPE (rela->r_info); r_type = ELF32_R_TYPE (rela->r_info);
r_type = elf32_hppa_optimized_tls_reloc (info, r_type, eh != NULL);
switch (r_type) switch (r_type)
{ {
case R_PARISC_DLTIND14F: case R_PARISC_DLTIND14F:
case R_PARISC_DLTIND14R: case R_PARISC_DLTIND14R:
case R_PARISC_DLTIND21L: case R_PARISC_DLTIND21L:
case R_PARISC_TLS_GD21L:
case R_PARISC_TLS_GD14R:
case R_PARISC_TLS_IE21L:
case R_PARISC_TLS_IE14R:
if (eh != NULL) if (eh != NULL)
{ {
if (eh->got.refcount > 0) if (eh->got.refcount > 0)
@ -1595,6 +1699,11 @@ elf32_hppa_gc_sweep_hook (bfd *abfd,
} }
break; break;
case R_PARISC_TLS_LDM21L:
case R_PARISC_TLS_LDM14R:
hppa_link_hash_table (info)->tls_ldm_got.refcount -= 1;
break;
case R_PARISC_PCREL12F: case R_PARISC_PCREL12F:
case R_PARISC_PCREL17C: case R_PARISC_PCREL17C:
case R_PARISC_PCREL17F: case R_PARISC_PCREL17F:
@ -1709,7 +1818,7 @@ elf32_hppa_hide_symbol (struct bfd_link_info *info,
} }
} }
if (! hppa_elf_hash_entry(eh)->plabel) if (! hppa_elf_hash_entry (eh)->plabel)
{ {
eh->needs_plt = 0; eh->needs_plt = 0;
eh->plt = elf_hash_table (info)->init_plt_refcount; eh->plt = elf_hash_table (info)->init_plt_refcount;
@ -1882,7 +1991,7 @@ allocate_plt_static (struct elf_link_hash_entry *eh, void *inf)
eh = (struct elf_link_hash_entry *) eh->root.u.i.link; eh = (struct elf_link_hash_entry *) eh->root.u.i.link;
info = (struct bfd_link_info *) inf; info = (struct bfd_link_info *) inf;
hh = hppa_elf_hash_entry(eh); hh = hppa_elf_hash_entry (eh);
htab = hppa_link_hash_table (info); htab = hppa_link_hash_table (info);
if (htab->etab.dynamic_sections_created if (htab->etab.dynamic_sections_created
&& eh->plt.refcount > 0) && eh->plt.refcount > 0)
@ -1982,12 +2091,21 @@ allocate_dynrelocs (struct elf_link_hash_entry *eh, void *inf)
sec = htab->sgot; sec = htab->sgot;
eh->got.offset = sec->size; eh->got.offset = sec->size;
sec->size += GOT_ENTRY_SIZE; sec->size += GOT_ENTRY_SIZE;
/* R_PARISC_TLS_GD* needs two GOT entries */
if ((hh->tls_type & (GOT_TLS_GD | GOT_TLS_IE)) == (GOT_TLS_GD | GOT_TLS_IE))
sec->size += GOT_ENTRY_SIZE * 2;
else if ((hh->tls_type & GOT_TLS_GD) == GOT_TLS_GD)
sec->size += GOT_ENTRY_SIZE;
if (htab->etab.dynamic_sections_created if (htab->etab.dynamic_sections_created
&& (info->shared && (info->shared
|| (eh->dynindx != -1 || (eh->dynindx != -1
&& !eh->forced_local))) && !eh->forced_local)))
{ {
htab->srelgot->size += sizeof (Elf32_External_Rela); htab->srelgot->size += sizeof (Elf32_External_Rela);
if ((hh->tls_type & (GOT_TLS_GD | GOT_TLS_IE)) == (GOT_TLS_GD | GOT_TLS_IE))
htab->srelgot->size += 2 * sizeof (Elf32_External_Rela);
else if ((hh->tls_type & GOT_TLS_GD) == GOT_TLS_GD)
htab->srelgot->size += sizeof (Elf32_External_Rela);
} }
} }
else else
@ -2181,6 +2299,7 @@ elf32_hppa_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
bfd_size_type locsymcount; bfd_size_type locsymcount;
Elf_Internal_Shdr *symtab_hdr; Elf_Internal_Shdr *symtab_hdr;
asection *srel; asection *srel;
char *local_tls_type;
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
continue; continue;
@ -2219,6 +2338,7 @@ elf32_hppa_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
locsymcount = symtab_hdr->sh_info; locsymcount = symtab_hdr->sh_info;
end_local_got = local_got + locsymcount; end_local_got = local_got + locsymcount;
local_tls_type = hppa_elf_local_got_tls_type (ibfd);
sec = htab->sgot; sec = htab->sgot;
srel = htab->srelgot; srel = htab->srelgot;
for (; local_got < end_local_got; ++local_got) for (; local_got < end_local_got; ++local_got)
@ -2227,11 +2347,23 @@ elf32_hppa_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
{ {
*local_got = sec->size; *local_got = sec->size;
sec->size += GOT_ENTRY_SIZE; sec->size += GOT_ENTRY_SIZE;
if ((*local_tls_type & (GOT_TLS_GD | GOT_TLS_IE)) == (GOT_TLS_GD | GOT_TLS_IE))
sec->size += 2 * GOT_ENTRY_SIZE;
else if ((*local_tls_type & GOT_TLS_GD) == GOT_TLS_GD)
sec->size += GOT_ENTRY_SIZE;
if (info->shared) if (info->shared)
srel->size += sizeof (Elf32_External_Rela); {
srel->size += sizeof (Elf32_External_Rela);
if ((*local_tls_type & (GOT_TLS_GD | GOT_TLS_IE)) == (GOT_TLS_GD | GOT_TLS_IE))
srel->size += 2 * sizeof (Elf32_External_Rela);
else if ((*local_tls_type & GOT_TLS_GD) == GOT_TLS_GD)
srel->size += sizeof (Elf32_External_Rela);
}
} }
else else
*local_got = (bfd_vma) -1; *local_got = (bfd_vma) -1;
++local_tls_type;
} }
local_plt = end_local_got; local_plt = end_local_got;
@ -2260,6 +2392,17 @@ elf32_hppa_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
} }
} }
} }
if (htab->tls_ldm_got.refcount > 0)
{
/* Allocate 2 got entries and 1 dynamic reloc for
R_PARISC_TLS_DTPMOD32 relocs. */
htab->tls_ldm_got.offset = htab->sgot->size;
htab->sgot->size += (GOT_ENTRY_SIZE * 2);
htab->srelgot->size += sizeof (Elf32_External_Rela);
}
else
htab->tls_ldm_got.offset = -1;
/* Do all the .plt entries without relocs first. The dynamic linker /* Do all the .plt entries without relocs first. The dynamic linker
uses the last .plt reloc to find the end of the .plt (and hence uses the last .plt reloc to find the end of the .plt (and hence
@ -2670,7 +2813,7 @@ get_local_syms (bfd *output_bfd, bfd *input_bfd, struct bfd_link_info *info)
struct elf32_hppa_stub_hash_entry *hsh; struct elf32_hppa_stub_hash_entry *hsh;
sec = hh->eh.root.u.def.section; sec = hh->eh.root.u.def.section;
stub_name = hh->eh.root.root.string; stub_name = hh_name (hh);
hsh = hppa_stub_hash_lookup (&htab->bstab, hsh = hppa_stub_hash_lookup (&htab->bstab,
stub_name, stub_name,
FALSE, FALSE); FALSE, FALSE);
@ -3104,6 +3247,35 @@ elf32_hppa_build_stubs (struct bfd_link_info *info)
return TRUE; return TRUE;
} }
/* Return the base vma address which should be subtracted from the real
address when resolving a dtpoff relocation.
This is PT_TLS segment p_vaddr. */
static bfd_vma
dtpoff_base (struct bfd_link_info *info)
{
/* If tls_sec is NULL, we should have signalled an error already. */
if (elf_hash_table (info)->tls_sec == NULL)
return 0;
return elf_hash_table (info)->tls_sec->vma;
}
/* Return the relocation value for R_PARISC_TLS_TPOFF*.. */
static bfd_vma
tpoff (struct bfd_link_info *info, bfd_vma address)
{
struct elf_link_hash_table *htab = elf_hash_table (info);
/* If tls_sec is NULL, we should have signalled an error already. */
if (htab->tls_sec == NULL)
return 0;
/* hppa TLS ABI is variant I and static TLS block start just after
tcbhead structure which has 2 pointer fields. */
return (address - htab->tls_sec->vma
+ align_power ((bfd_vma) 8, htab->tls_sec->alignment_power));
}
/* Perform a final link. */ /* Perform a final link. */
static bfd_boolean static bfd_boolean
@ -3315,6 +3487,12 @@ final_link_relocate (asection *input_section,
case R_PARISC_DLTIND21L: case R_PARISC_DLTIND21L:
case R_PARISC_DLTIND14R: case R_PARISC_DLTIND14R:
case R_PARISC_DLTIND14F: case R_PARISC_DLTIND14F:
case R_PARISC_TLS_GD21L:
case R_PARISC_TLS_GD14R:
case R_PARISC_TLS_LDM21L:
case R_PARISC_TLS_LDM14R:
case R_PARISC_TLS_IE21L:
case R_PARISC_TLS_IE14R:
value -= elf_gp (input_section->output_section->owner); value -= elf_gp (input_section->output_section->owner);
break; break;
@ -3342,6 +3520,9 @@ final_link_relocate (asection *input_section,
case R_PARISC_DLTIND14F: case R_PARISC_DLTIND14F:
case R_PARISC_SEGBASE: case R_PARISC_SEGBASE:
case R_PARISC_SEGREL32: case R_PARISC_SEGREL32:
case R_PARISC_TLS_DTPMOD32:
case R_PARISC_TLS_DTPOFF32:
case R_PARISC_TLS_TPREL32:
r_field = e_fsel; r_field = e_fsel;
break; break;
@ -3353,6 +3534,11 @@ final_link_relocate (asection *input_section,
case R_PARISC_DIR21L: case R_PARISC_DIR21L:
case R_PARISC_DPREL21L: case R_PARISC_DPREL21L:
case R_PARISC_TLS_GD21L:
case R_PARISC_TLS_LDM21L:
case R_PARISC_TLS_LDO21L:
case R_PARISC_TLS_IE21L:
case R_PARISC_TLS_LE21L:
r_field = e_lrsel; r_field = e_lrsel;
break; break;
@ -3366,6 +3552,11 @@ final_link_relocate (asection *input_section,
case R_PARISC_DIR17R: case R_PARISC_DIR17R:
case R_PARISC_DIR14R: case R_PARISC_DIR14R:
case R_PARISC_DPREL14R: case R_PARISC_DPREL14R:
case R_PARISC_TLS_GD14R:
case R_PARISC_TLS_LDM14R:
case R_PARISC_TLS_LDO14R:
case R_PARISC_TLS_IE14R:
case R_PARISC_TLS_LE14R:
r_field = e_rrsel; r_field = e_rrsel;
break; break;
@ -3546,7 +3737,7 @@ elf32_hppa_relocate_section (bfd *output_bfd,
&& eh->type == STT_PARISC_MILLI) && eh->type == STT_PARISC_MILLI)
{ {
if (! info->callbacks->undefined_symbol if (! info->callbacks->undefined_symbol
(info, eh->root.root.string, input_bfd, (info, eh_name (eh), input_bfd,
input_section, rela->r_offset, FALSE)) input_section, rela->r_offset, FALSE))
return FALSE; return FALSE;
warned_undef = TRUE; warned_undef = TRUE;
@ -3875,6 +4066,198 @@ elf32_hppa_relocate_section (bfd *output_bfd,
bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
} }
break; break;
case R_PARISC_TLS_LDM21L:
case R_PARISC_TLS_LDM14R:
{
bfd_vma off;
off = htab->tls_ldm_got.offset;
if (off & 1)
off &= ~1;
else
{
Elf_Internal_Rela outrel;
bfd_byte *loc;
outrel.r_offset = (off
+ htab->sgot->output_section->vma
+ htab->sgot->output_offset);
outrel.r_addend = 0;
outrel.r_info = ELF32_R_INFO (0, R_PARISC_TLS_DTPMOD32);
loc = htab->srelgot->contents;
loc += htab->srelgot->reloc_count++ * sizeof (Elf32_External_Rela);
bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
htab->tls_ldm_got.offset |= 1;
}
/* Add the base of the GOT to the relocation value. */
relocation = (off
+ htab->sgot->output_offset
+ htab->sgot->output_section->vma);
break;
}
case R_PARISC_TLS_LDO21L:
case R_PARISC_TLS_LDO14R:
relocation -= dtpoff_base (info);
break;
case R_PARISC_TLS_GD21L:
case R_PARISC_TLS_GD14R:
case R_PARISC_TLS_IE21L:
case R_PARISC_TLS_IE14R:
{
bfd_vma off;
int indx;
char tls_type;
indx = 0;
if (hh != NULL)
{
bfd_boolean dyn;
dyn = htab->etab.dynamic_sections_created;
if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, &hh->eh)
&& (!info->shared
|| !SYMBOL_REFERENCES_LOCAL (info, &hh->eh)))
{
indx = hh->eh.dynindx;
}
off = hh->eh.got.offset;
tls_type = hh->tls_type;
}
else
{
off = local_got_offsets[r_symndx];
tls_type = hppa_elf_local_got_tls_type (input_bfd)[r_symndx];
}
if (tls_type == GOT_UNKNOWN)
abort ();
if ((off & 1) != 0)
off &= ~1;
else
{
bfd_boolean need_relocs = FALSE;
Elf_Internal_Rela outrel;
bfd_byte *loc = NULL;
int cur_off = off;
/* The GOT entries have not been initialized yet. Do it
now, and emit any relocations. If both an IE GOT and a
GD GOT are necessary, we emit the GD first. */
if ((info->shared || indx != 0)
&& (hh == NULL
|| ELF_ST_VISIBILITY (hh->eh.other) == STV_DEFAULT
|| hh->eh.root.type != bfd_link_hash_undefweak))
{
need_relocs = TRUE;
loc = htab->srelgot->contents;
/* FIXME (CAO): Should this be reloc_count++ ? */
loc += htab->srelgot->reloc_count * sizeof (Elf32_External_Rela);
}
if (tls_type & GOT_TLS_GD)
{
if (need_relocs)
{
outrel.r_offset = (cur_off
+ htab->sgot->output_section->vma
+ htab->sgot->output_offset);
outrel.r_info = ELF32_R_INFO (indx,R_PARISC_TLS_DTPMOD32);
outrel.r_addend = 0;
bfd_put_32 (output_bfd, 0, htab->sgot->contents + cur_off);
bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
htab->srelgot->reloc_count++;
loc += sizeof (Elf32_External_Rela);
if (indx == 0)
bfd_put_32 (output_bfd, relocation - dtpoff_base (info),
htab->sgot->contents + cur_off + 4);
else
{
bfd_put_32 (output_bfd, 0,
htab->sgot->contents + cur_off + 4);
outrel.r_info = ELF32_R_INFO (indx, R_PARISC_TLS_DTPOFF32);
outrel.r_offset += 4;
bfd_elf32_swap_reloca_out (output_bfd, &outrel,loc);
htab->srelgot->reloc_count++;
loc += sizeof (Elf32_External_Rela);
}
}
else
{
/* If we are not emitting relocations for a
general dynamic reference, then we must be in a
static link or an executable link with the
symbol binding locally. Mark it as belonging
to module 1, the executable. */
bfd_put_32 (output_bfd, 1,
htab->sgot->contents + cur_off);
bfd_put_32 (output_bfd, relocation - dtpoff_base (info),
htab->sgot->contents + cur_off + 4);
}
cur_off += 8;
}
if (tls_type & GOT_TLS_IE)
{
if (need_relocs)
{
outrel.r_offset = (cur_off
+ htab->sgot->output_section->vma
+ htab->sgot->output_offset);
outrel.r_info = ELF32_R_INFO (indx, R_PARISC_TLS_TPREL32);
if (indx == 0)
outrel.r_addend = relocation - dtpoff_base (info);
else
outrel.r_addend = 0;
bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
htab->srelgot->reloc_count++;
loc += sizeof (Elf32_External_Rela);
}
else
bfd_put_32 (output_bfd, tpoff (info, relocation),
htab->sgot->contents + cur_off);
cur_off += 4;
}
if (hh != NULL)
hh->eh.got.offset |= 1;
else
local_got_offsets[r_symndx] |= 1;
}
if ((tls_type & GOT_TLS_GD)
&& r_type != R_PARISC_TLS_GD21L
&& r_type != R_PARISC_TLS_GD14R)
off += 2 * GOT_ENTRY_SIZE;
/* Add the base of the GOT to the relocation value. */
relocation = (off
+ htab->sgot->output_offset
+ htab->sgot->output_section->vma);
break;
}
case R_PARISC_TLS_LE21L:
case R_PARISC_TLS_LE14R:
{
relocation = tpoff (info, relocation);
break;
}
break;
default: default:
break; break;
@ -3887,7 +4270,7 @@ elf32_hppa_relocate_section (bfd *output_bfd,
continue; continue;
if (hh != NULL) if (hh != NULL)
sym_name = hh->eh.root.root.string; sym_name = hh_name (hh);
else else
{ {
sym_name = bfd_elf_string_from_elf_section (input_bfd, sym_name = bfd_elf_string_from_elf_section (input_bfd,
@ -3996,7 +4379,9 @@ elf32_hppa_finish_dynamic_symbol (bfd *output_bfd,
} }
} }
if (eh->got.offset != (bfd_vma) -1) if (eh->got.offset != (bfd_vma) -1
&& (hppa_elf_hash_entry (eh)->tls_type & GOT_TLS_GD) == 0
&& (hppa_elf_hash_entry (eh)->tls_type & GOT_TLS_IE) == 0)
{ {
/* This symbol has an entry in the global offset table. Set it /* This symbol has an entry in the global offset table. Set it
up. */ up. */
@ -4057,8 +4442,8 @@ elf32_hppa_finish_dynamic_symbol (bfd *output_bfd,
} }
/* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */
if (eh->root.root.string[0] == '_' if (eh_name (eh)[0] == '_'
&& (strcmp (eh->root.root.string, "_DYNAMIC") == 0 && (strcmp (eh_name (eh), "_DYNAMIC") == 0
|| eh == htab->etab.hgot)) || eh == htab->etab.hgot))
{ {
sym->st_shndx = SHN_ABS; sym->st_shndx = SHN_ABS;
@ -4073,6 +4458,17 @@ elf32_hppa_finish_dynamic_symbol (bfd *output_bfd,
static enum elf_reloc_type_class static enum elf_reloc_type_class
elf32_hppa_reloc_type_class (const Elf_Internal_Rela *rela) elf32_hppa_reloc_type_class (const Elf_Internal_Rela *rela)
{ {
/* Handle TLS relocs first; we don't want them to be marked
relative by the "if (ELF32_R_SYM (rela->r_info) == 0)"
check below. */
switch ((int) ELF32_R_TYPE (rela->r_info))
{
case R_PARISC_TLS_DTPMOD32:
case R_PARISC_TLS_DTPOFF32:
case R_PARISC_TLS_TPREL32:
return reloc_class_normal;
}
if (ELF32_R_SYM (rela->r_info) == 0) if (ELF32_R_SYM (rela->r_info) == 0)
return reloc_class_relative; return reloc_class_relative;

View file

@ -1,3 +1,19 @@
2006-05-24 Nick Clifton <nickc@redhat.com>
* config/tc-hppa.c: Convert to ISO C90 format.
* config/tc-hppa.h: Likewise.
2006-05-24 Carlos O'Donell <carlos@systemhalted.org>
Randolph Chung <randolph@tausq.org>
* config/tc-hppa.c (is_tls_gdidx, is_tls_ldidx, is_tls_dtpoff,
is_tls_ieoff, is_tls_leoff): Define.
(fix_new_hppa): Handle TLS.
(cons_fix_new_hppa): Likewise.
(pa_ip): Likewise.
(md_apply_fix): Handle TLS relocs.
* config/tc-hppa.h (hppa_fix_adjustable): Handle TLS.
2006-05-24 Bjoern Haase <bjoern.m.haase@web.de> 2006-05-24 Bjoern Haase <bjoern.m.haase@web.de>
* config/tc-avr.c: Add new cpu targets avr6, avr2560 and avr2561. * config/tc-avr.c: Add new cpu targets avr6, avr2560 and avr2561.

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/* tc-hppa.h -- Header file for the PA /* tc-hppa.h -- Header file for the PA
Copyright 1989, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, Copyright 1989, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002,
2003, 2004, 2005 Free Software Foundation, Inc. 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler. This file is part of GAS, the GNU Assembler.
@ -90,15 +90,14 @@
#define ASEC_NULL (asection *)0 #define ASEC_NULL (asection *)0
/* pa_define_label gets used outside of tc-hppa.c via tc_frob_label. */ /* pa_define_label gets used outside of tc-hppa.c via tc_frob_label. */
extern void pa_define_label PARAMS ((symbolS *)); extern void pa_define_label (symbolS *);
extern void parse_cons_expression_hppa (expressionS *);
extern void parse_cons_expression_hppa PARAMS ((expressionS *)); extern void cons_fix_new_hppa (fragS *, int, int, expressionS *);
extern void cons_fix_new_hppa PARAMS ((fragS *, int, int, expressionS *)); extern int hppa_force_relocation (struct fix *);
extern int hppa_force_relocation PARAMS ((struct fix *));
/* This gets called before writing the object file to make sure /* This gets called before writing the object file to make sure
things like entry/exit and proc/procend pairs match. */ things like entry/exit and proc/procend pairs match. */
extern void pa_check_eof PARAMS ((void)); extern void pa_check_eof (void);
#define tc_frob_file pa_check_eof #define tc_frob_file pa_check_eof
#define tc_frob_label(sym) pa_define_label (sym) #define tc_frob_label(sym) pa_define_label (sym)
@ -120,7 +119,7 @@ extern const char hppa_symbol_chars[];
When used in an instruction it will always follow a comma. */ When used in an instruction it will always follow a comma. */
#define TC_EOL_IN_INSN(PTR) (*(PTR) == '!' && (PTR)[-1] == ',') #define TC_EOL_IN_INSN(PTR) (*(PTR) == '!' && (PTR)[-1] == ',')
int hppa_fix_adjustable PARAMS((struct fix *)); int hppa_fix_adjustable (struct fix *);
#define tc_fix_adjustable hppa_fix_adjustable #define tc_fix_adjustable hppa_fix_adjustable
#define EXTERN_FORCE_RELOC 1 #define EXTERN_FORCE_RELOC 1
@ -170,17 +169,23 @@ int hppa_fix_adjustable PARAMS((struct fix *));
#define tc_frob_symbol(sym,punt) \ #define tc_frob_symbol(sym,punt) \
{ \ { \
if ((S_GET_SEGMENT (sym) == &bfd_und_section && ! symbol_used_p (sym) && \ if ((S_GET_SEGMENT (sym) == &bfd_und_section \
ELF_ST_VISIBILITY (S_GET_OTHER (sym)) == STV_DEFAULT) \ && ! symbol_used_p (sym) \
&& ELF_ST_VISIBILITY (S_GET_OTHER (sym)) == STV_DEFAULT) \
|| (S_GET_SEGMENT (sym) == &bfd_abs_section \ || (S_GET_SEGMENT (sym) == &bfd_abs_section \
&& ! S_IS_EXTERNAL (sym)) \ && ! S_IS_EXTERNAL (sym)) \
|| strcmp (S_GET_NAME (sym), "$global$") == 0 \ || strcmp (S_GET_NAME (sym), "$global$") == 0 \
|| strcmp (S_GET_NAME (sym), "$PIC_pcrel$0") == 0) \ || strcmp (S_GET_NAME (sym), "$PIC_pcrel$0") == 0 \
|| strcmp (S_GET_NAME (sym), "$tls_gdidx$") == 0 \
|| strcmp (S_GET_NAME (sym), "$tls_ldidx$") == 0 \
|| strcmp (S_GET_NAME (sym), "$tls_dtpoff$") == 0 \
|| strcmp (S_GET_NAME (sym), "$tls_ieoff$") == 0 \
|| strcmp (S_GET_NAME (sym), "$tls_leoff$") == 0) \
punt = 1; \ punt = 1; \
} }
#define elf_tc_final_processing elf_hppa_final_processing #define elf_tc_final_processing elf_hppa_final_processing
void elf_hppa_final_processing PARAMS ((void)); void elf_hppa_final_processing (void);
#define DWARF2_LINE_MIN_INSN_LENGTH 4 #define DWARF2_LINE_MIN_INSN_LENGTH 4
#endif /* OBJ_ELF */ #endif /* OBJ_ELF */
@ -191,8 +196,7 @@ void elf_hppa_final_processing PARAMS ((void));
A silly fudge required for backwards compatibility. */ A silly fudge required for backwards compatibility. */
#define md_optimize_expr hppa_force_reg_syms_absolute #define md_optimize_expr hppa_force_reg_syms_absolute
int hppa_force_reg_syms_absolute int hppa_force_reg_syms_absolute (expressionS *, operatorT, expressionS *);
PARAMS ((expressionS *, operatorT, expressionS *));
#define TC_FIX_TYPE PTR #define TC_FIX_TYPE PTR
#define TC_INIT_FIX_DATA(FIX) ((FIX)->tc_fix_data = NULL) #define TC_INIT_FIX_DATA(FIX) ((FIX)->tc_fix_data = NULL)

View file

@ -1,3 +1,14 @@
2006-05-24 Carlos O'Donell <carlos@systemhalted.org>
Randolph Chung <randolph@tausq.org>
* hppa.h (R_PARISC_TLS_GD21L, R_PARISC_TLS_GD14R, R_PARISC_TLS_GDCALL,
R_PARISC_TLS_LDM21L, R_PARISC_TLS_LDM14R, R_PARISC_TLS_LDMCALL,
R_PARISC_TLS_LDO21L, R_PARISC_TLS_LDO14R, R_PARISC_TLS_DTPMOD32,
R_PARISC_TLS_DTPMOD64, R_PARISC_TLS_DTPOFF32, R_PARISC_TLS_DTPOFF64):
New TLS relocs.
(R_PARISC_TLS_LE21L, R_PARISC_TLS_LE14R, R_PARISC_TLS_IE21L,
R_PARISC_TLS_IE14R, R_PARISC_TLS_TPREL32, R_PARISC_TLS_TPREL64):
Define TLS relocs using existing equivalents.
2006-05-24 Bjoern Haase <bjoern.m.haase@web.de> 2006-05-24 Bjoern Haase <bjoern.m.haase@web.de>
* avr.h: Add E_AVR_MACH_AVR6, R_AVR_LO8_LDI_GS and R_AVR_HI8_LDI_GS. * avr.h: Add E_AVR_MACH_AVR6, R_AVR_LO8_LDI_GS and R_AVR_HI8_LDI_GS.

View file

@ -1,22 +1,22 @@
/* HPPA ELF support for BFD. /* HPPA ELF support for BFD.
Copyright 1993, 1994, 1995, 1998, 1999, 2000, 2005 Copyright 1993, 1994, 1995, 1998, 1999, 2000, 2005, 2006
Free Software Foundation, Inc. Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library. This file is part of BFD, the Binary File Descriptor library.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
/* This file holds definitions specific to the HPPA ELF ABI. Note /* This file holds definitions specific to the HPPA ELF ABI. Note
that most of this is not actually implemented by BFD. */ that most of this is not actually implemented by BFD. */
@ -80,10 +80,10 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
/* These are strictly for compatibility with the older elf32-hppa /* These are strictly for compatibility with the older elf32-hppa
implementation. Hopefully we can eliminate them in the future. */ implementation. Hopefully we can eliminate them in the future. */
/* Optional section holding argument location/relocation info. */ /* Optional section holding argument location/relocation info. */
#define SHT_PARISC_SYMEXTN SHT_LOPROC+8 #define SHT_PARISC_SYMEXTN SHT_LOPROC + 8
/* Option section for linker stubs. */ /* Option section for linker stubs. */
#define SHT_PARISC_STUBS SHT_LOPROC+9 #define SHT_PARISC_STUBS SHT_LOPROC + 9
/* Processor specific section flags. */ /* Processor specific section flags. */
@ -480,8 +480,28 @@ RELOC_NUMBER (R_PARISC_LTOFF_TP16DF, 231)
RELOC_NUMBER (R_PARISC_GNU_VTENTRY, 232) RELOC_NUMBER (R_PARISC_GNU_VTENTRY, 232)
RELOC_NUMBER (R_PARISC_GNU_VTINHERIT, 233) RELOC_NUMBER (R_PARISC_GNU_VTINHERIT, 233)
RELOC_NUMBER (R_PARISC_TLS_GD21L, 234)
RELOC_NUMBER (R_PARISC_TLS_GD14R, 235)
RELOC_NUMBER (R_PARISC_TLS_GDCALL, 236)
RELOC_NUMBER (R_PARISC_TLS_LDM21L, 237)
RELOC_NUMBER (R_PARISC_TLS_LDM14R, 238)
RELOC_NUMBER (R_PARISC_TLS_LDMCALL, 239)
RELOC_NUMBER (R_PARISC_TLS_LDO21L, 240)
RELOC_NUMBER (R_PARISC_TLS_LDO14R, 241)
RELOC_NUMBER (R_PARISC_TLS_DTPMOD32, 242)
RELOC_NUMBER (R_PARISC_TLS_DTPMOD64, 243)
RELOC_NUMBER (R_PARISC_TLS_DTPOFF32, 244)
RELOC_NUMBER (R_PARISC_TLS_DTPOFF64, 245)
END_RELOC_NUMBERS (R_PARISC_UNIMPLEMENTED) END_RELOC_NUMBERS (R_PARISC_UNIMPLEMENTED)
#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L
#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R
#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L
#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R
#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32
#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64
#ifndef RELOC_MACROS_GEN_FUNC #ifndef RELOC_MACROS_GEN_FUNC
typedef enum elf_hppa_reloc_type elf_hppa_reloc_type; typedef enum elf_hppa_reloc_type elf_hppa_reloc_type;
#endif #endif