This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
alpha tls relocation relaxation
- From: Richard Henderson <rth at redhat dot com>
- To: binutils at sources dot redhat dot com
- Date: Sat, 1 Jun 2002 19:29:32 -0700
- Subject: alpha tls relocation relaxation
include/elf/
* alpha.h (LITUSE_ALPHA_ADDR, LITUSE_ALPHA_BASE, LITUSE_ALPHA_BYTOFF,
LITUSE_ALPHA_JSR, LITUSE_ALPHA_TLSGD, LITUSE_ALPHA_TLSLDM): New.
gas/
* config/tc-alpha.c: Move LITUSE constants to "elf/alpha.h".
Rename them LITUSE_ALPHA_*.
bfd/
* elf64-alpha.c (alpha_get_dtprel_base, alpha_get_tprel_base): New.
(elf64_alpha_relocate_section): Use them. Reject LE TLS relocs
in shared libraries. Fix DTPRELHI and TPRELHI value.
(INSN_ADDQ, INSN_RDUNIQ): New.
(struct alpha_relax_info): Add symtab_hdr, tls_segment, first_gotent.
(elf64_alpha_relax_with_lituse): Return boolean. Remove irelend
argument. Reject dynamic symbols. Use LITUSE symbolic constants.
(elf64_alpha_relax_got_load): Rename from relax_without_lituse.
Handle GOTDTPREL and GOTTPREL relocations.
(elf64_alpha_relax_gprelhilo): New.
(elf64_alpha_relax_tls_get_addr): New.
(elf64_alpha_relax_find_tls_segment): New.
(elf64_alpha_relax_section): Handle TLS relocations.
(ALPHA_ELF_LINK_HASH_TLS_IE): New.
(elf64_alpha_check_relocs): Set it.
Index: include/elf/alpha.h
===================================================================
RCS file: /cvs/src/src/include/elf/alpha.h,v
retrieving revision 1.7
diff -c -p -d -r1.7 alpha.h
*** include/elf/alpha.h 30 May 2002 22:01:38 -0000 1.7
--- include/elf/alpha.h 2 Jun 2002 02:16:02 -0000
*************** START_RELOC_NUMBERS (elf_alpha_reloc_typ
*** 116,119 ****
--- 116,126 ----
END_RELOC_NUMBERS (R_ALPHA_max)
+ #define LITUSE_ALPHA_ADDR 0
+ #define LITUSE_ALPHA_BASE 1
+ #define LITUSE_ALPHA_BYTOFF 2
+ #define LITUSE_ALPHA_JSR 3
+ #define LITUSE_ALPHA_TLSGD 4
+ #define LITUSE_ALPHA_TLSLDM 5
+
#endif /* _ELF_ALPHA_H */
Index: gas/config/tc-alpha.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-alpha.c,v
retrieving revision 1.42
diff -c -p -d -r1.42 tc-alpha.c
*** gas/config/tc-alpha.c 30 May 2002 22:01:32 -0000 1.42
--- gas/config/tc-alpha.c 2 Jun 2002 02:16:02 -0000
*************** struct alpha_macro {
*** 137,149 ****
#define DUMMY_RELOC_LITUSE_TLSGD (BFD_RELOC_UNUSED + 5)
#define DUMMY_RELOC_LITUSE_TLSLDM (BFD_RELOC_UNUSED + 6)
- #define LITUSE_ADDR 0
- #define LITUSE_BASE 1
- #define LITUSE_BYTOFF 2
- #define LITUSE_JSR 3
- #define LITUSE_TLSGD 4
- #define LITUSE_TLSLDM 5
-
#define USER_RELOC_P(R) ((R) >= O_literal && (R) <= O_tprel)
/* Macros for extracting the type and number of encoded register tokens */
--- 137,142 ----
*************** alpha_adjust_symtab_relocs (abfd, sec, p
*** 1758,1771 ****
as_bad_where (fixp->fx_file, fixp->fx_line,
_("No !literal!%ld was found"),
fixp->tc_fix_data.info->sequence);
! if (fixp->fx_offset == LITUSE_TLSGD)
{
if (! fixp->tc_fix_data.info->saw_tlsgd)
as_bad_where (fixp->fx_file, fixp->fx_line,
_("No !tlsgd!%ld was found"),
fixp->tc_fix_data.info->sequence);
}
! else if (fixp->fx_offset == LITUSE_TLSLDM)
{
if (! fixp->tc_fix_data.info->saw_tlsldm)
as_bad_where (fixp->fx_file, fixp->fx_line,
--- 1751,1764 ----
as_bad_where (fixp->fx_file, fixp->fx_line,
_("No !literal!%ld was found"),
fixp->tc_fix_data.info->sequence);
! if (fixp->fx_offset == LITUSE_ALPHA_TLSGD)
{
if (! fixp->tc_fix_data.info->saw_tlsgd)
as_bad_where (fixp->fx_file, fixp->fx_line,
_("No !tlsgd!%ld was found"),
fixp->tc_fix_data.info->sequence);
}
! else if (fixp->fx_offset == LITUSE_ALPHA_TLSLDM)
{
if (! fixp->tc_fix_data.info->saw_tlsldm)
as_bad_where (fixp->fx_file, fixp->fx_line,
*************** emit_insn (insn)
*** 2686,2707 ****
break;
case DUMMY_RELOC_LITUSE_ADDR:
! fixP->fx_offset = LITUSE_ADDR;
goto do_lituse;
case DUMMY_RELOC_LITUSE_BASE:
! fixP->fx_offset = LITUSE_BASE;
goto do_lituse;
case DUMMY_RELOC_LITUSE_BYTOFF:
! fixP->fx_offset = LITUSE_BYTOFF;
goto do_lituse;
case DUMMY_RELOC_LITUSE_JSR:
! fixP->fx_offset = LITUSE_JSR;
goto do_lituse;
case DUMMY_RELOC_LITUSE_TLSGD:
! fixP->fx_offset = LITUSE_TLSGD;
goto do_lituse;
case DUMMY_RELOC_LITUSE_TLSLDM:
! fixP->fx_offset = LITUSE_TLSLDM;
goto do_lituse;
do_lituse:
fixP->fx_addsy = section_symbol (now_seg);
--- 2679,2700 ----
break;
case DUMMY_RELOC_LITUSE_ADDR:
! fixP->fx_offset = LITUSE_ALPHA_ADDR;
goto do_lituse;
case DUMMY_RELOC_LITUSE_BASE:
! fixP->fx_offset = LITUSE_ALPHA_BASE;
goto do_lituse;
case DUMMY_RELOC_LITUSE_BYTOFF:
! fixP->fx_offset = LITUSE_ALPHA_BYTOFF;
goto do_lituse;
case DUMMY_RELOC_LITUSE_JSR:
! fixP->fx_offset = LITUSE_ALPHA_JSR;
goto do_lituse;
case DUMMY_RELOC_LITUSE_TLSGD:
! fixP->fx_offset = LITUSE_ALPHA_TLSGD;
goto do_lituse;
case DUMMY_RELOC_LITUSE_TLSLDM:
! fixP->fx_offset = LITUSE_ALPHA_TLSLDM;
goto do_lituse;
do_lituse:
fixP->fx_addsy = section_symbol (now_seg);
Index: bfd/elf64-alpha.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-alpha.c,v
retrieving revision 1.66
diff -c -p -d -r1.66 elf64-alpha.c
*** bfd/elf64-alpha.c 1 Jun 2002 21:56:41 -0000 1.66
--- bfd/elf64-alpha.c 2 Jun 2002 02:16:02 -0000
*************** struct alpha_elf_link_hash_entry
*** 153,159 ****
/* Cumulative flags for all the .got entries. */
int flags;
! /* Contexts (LITUSE) in which a literal was referenced. */
#define ALPHA_ELF_LINK_HASH_LU_ADDR 0x01
#define ALPHA_ELF_LINK_HASH_LU_MEM 0x02
#define ALPHA_ELF_LINK_HASH_LU_BYTE 0x04
--- 153,159 ----
/* Cumulative flags for all the .got entries. */
int flags;
! /* Contexts in which a literal was referenced. */
#define ALPHA_ELF_LINK_HASH_LU_ADDR 0x01
#define ALPHA_ELF_LINK_HASH_LU_MEM 0x02
#define ALPHA_ELF_LINK_HASH_LU_BYTE 0x04
*************** struct alpha_elf_link_hash_entry
*** 161,166 ****
--- 161,167 ----
#define ALPHA_ELF_LINK_HASH_LU_TLSGD 0x10
#define ALPHA_ELF_LINK_HASH_LU_TLSLDM 0x20
#define ALPHA_ELF_LINK_HASH_LU_FUNC 0x38
+ #define ALPHA_ELF_LINK_HASH_TLS_IE 0x40
/* Used to implement multiple .got subsections. */
struct alpha_elf_got_entry
*************** elf64_alpha_info_to_howto (abfd, cache_p
*** 1165,1170 ****
--- 1166,1180 ----
/* These two relocations create a two-word entry in the got. */
#define alpha_got_entry_size(r_type) \
(r_type == R_ALPHA_TLSGD || r_type == R_ALPHA_TLSLDM ? 16 : 8)
+
+ /* This is PT_TLS segment p_vaddr. */
+ #define alpha_get_dtprel_base(tlss) \
+ ((tlss)->start)
+
+ /* Main program TLS (whose template starts at PT_TLS p_vaddr)
+ is assigned offset round(16, PT_TLS p_align). */
+ #define alpha_get_tprel_base(tlss) \
+ ((tlss)->start - align_power ((bfd_vma) 16, (tlss)->align))
/* These functions do relaxation for Alpha ELF.
*************** elf64_alpha_info_to_howto (abfd, cache_p
*** 1187,1221 ****
#define OP_BR 0x30
#define OP_BSR 0x34
#define INSN_UNOP 0x2ffe0000
struct alpha_relax_info
{
bfd *abfd;
asection *sec;
bfd_byte *contents;
Elf_Internal_Rela *relocs, *relend;
struct bfd_link_info *link_info;
! boolean changed_contents;
! boolean changed_relocs;
bfd_vma gp;
bfd *gotobj;
asection *tsec;
struct alpha_elf_link_hash_entry *h;
struct alpha_elf_got_entry *gotent;
unsigned char other;
};
! static Elf_Internal_Rela * elf64_alpha_relax_with_lituse
! PARAMS((struct alpha_relax_info *info, bfd_vma symval,
! Elf_Internal_Rela *irel, Elf_Internal_Rela *irelend));
!
! static boolean elf64_alpha_relax_without_lituse
PARAMS((struct alpha_relax_info *info, bfd_vma symval,
Elf_Internal_Rela *irel));
-
static bfd_vma elf64_alpha_relax_opt_call
PARAMS((struct alpha_relax_info *info, bfd_vma symval));
!
static boolean elf64_alpha_relax_section
PARAMS((bfd *abfd, asection *sec, struct bfd_link_info *link_info,
boolean *again));
--- 1197,1241 ----
#define OP_BR 0x30
#define OP_BSR 0x34
#define INSN_UNOP 0x2ffe0000
+ #define INSN_ADDQ 0x40000400
+ #define INSN_RDUNIQ 0x0000009e
struct alpha_relax_info
{
bfd *abfd;
asection *sec;
bfd_byte *contents;
+ Elf_Internal_Shdr *symtab_hdr;
Elf_Internal_Rela *relocs, *relend;
struct bfd_link_info *link_info;
! struct elf_link_tls_segment *tls_segment;
bfd_vma gp;
bfd *gotobj;
asection *tsec;
struct alpha_elf_link_hash_entry *h;
+ struct alpha_elf_got_entry **first_gotent;
struct alpha_elf_got_entry *gotent;
+ boolean changed_contents;
+ boolean changed_relocs;
unsigned char other;
};
! static boolean elf64_alpha_relax_with_lituse
PARAMS((struct alpha_relax_info *info, bfd_vma symval,
Elf_Internal_Rela *irel));
static bfd_vma elf64_alpha_relax_opt_call
PARAMS((struct alpha_relax_info *info, bfd_vma symval));
! static boolean elf64_alpha_relax_got_load
! PARAMS((struct alpha_relax_info *info, bfd_vma symval,
! Elf_Internal_Rela *irel, unsigned long));
! static boolean elf64_alpha_relax_gprelhilo
! PARAMS((struct alpha_relax_info *info, bfd_vma symval,
! Elf_Internal_Rela *irel, boolean));
! static boolean elf64_alpha_relax_tls_get_addr
! PARAMS((struct alpha_relax_info *info, bfd_vma symval,
! Elf_Internal_Rela *irel, boolean));
! static struct elf_link_tls_segment *elf64_alpha_relax_find_tls_segment
! PARAMS((struct alpha_relax_info *, struct elf_link_tls_segment *));
static boolean elf64_alpha_relax_section
PARAMS((bfd *abfd, asection *sec, struct bfd_link_info *link_info,
boolean *again));
*************** elf64_alpha_find_reloc_at_ofs (rel, rele
*** 1236,1248 ****
return NULL;
}
! static Elf_Internal_Rela *
! elf64_alpha_relax_with_lituse (info, symval, irel, irelend)
struct alpha_relax_info *info;
bfd_vma symval;
! Elf_Internal_Rela *irel, *irelend;
{
! Elf_Internal_Rela *urel;
int flags, count, i;
bfd_signed_vma disp;
boolean fits16;
--- 1256,1268 ----
return NULL;
}
! static boolean
! elf64_alpha_relax_with_lituse (info, symval, irel)
struct alpha_relax_info *info;
bfd_vma symval;
! Elf_Internal_Rela *irel;
{
! Elf_Internal_Rela *urel, *irelend = info->relend;
int flags, count, i;
bfd_signed_vma disp;
boolean fits16;
*************** elf64_alpha_relax_with_lituse (info, sym
*** 1258,1266 ****
("%s: %s+0x%lx: warning: LITERAL relocation against unexpected insn",
bfd_archive_filename (info->abfd), info->sec->name,
(unsigned long) irel->r_offset));
! return irel;
}
/* Summarize how this particular LITERAL is used. */
for (urel = irel+1, flags = count = 0; urel < irelend; ++urel, ++count)
{
--- 1278,1290 ----
("%s: %s+0x%lx: warning: LITERAL relocation against unexpected insn",
bfd_archive_filename (info->abfd), info->sec->name,
(unsigned long) irel->r_offset));
! return true;
}
+ /* Can't relax dynamic symbols. */
+ if (alpha_elf_dynamic_symbol_p (&info->h->root, info->link_info))
+ return true;
+
/* Summarize how this particular LITERAL is used. */
for (urel = irel+1, flags = count = 0; urel < irelend; ++urel, ++count)
{
*************** elf64_alpha_relax_with_lituse (info, sym
*** 1283,1307 ****
switch (urel->r_addend)
{
! default: /* 0 = ADDRESS FORMAT */
/* This type is really just a placeholder to note that all
uses cannot be optimized, but to still allow some. */
all_optimized = false;
break;
! case 1: /* MEM FORMAT */
/* We can always optimize 16-bit displacements. */
/* Extract the displacement from the instruction, sign-extending
it if necessary, then test whether it is within 16 or 32 bits
displacement from GP. */
insn_disp = insn & 0x0000ffff;
! if (insn_disp & 0x00008000)
! insn_disp |= 0xffff0000; /* Negative: sign-extend. */
xdisp = disp + insn_disp;
! fits16 = (xdisp >= - (bfd_signed_vma) 0x00008000 && xdisp < 0x00008000);
! fits32 = (xdisp >= - (bfd_signed_vma) 0x80000000 && xdisp < 0x7fff8000);
if (fits16)
{
--- 1307,1333 ----
switch (urel->r_addend)
{
! case LITUSE_ALPHA_ADDR:
! default:
/* This type is really just a placeholder to note that all
uses cannot be optimized, but to still allow some. */
all_optimized = false;
break;
! case LITUSE_ALPHA_BASE:
/* We can always optimize 16-bit displacements. */
/* Extract the displacement from the instruction, sign-extending
it if necessary, then test whether it is within 16 or 32 bits
displacement from GP. */
insn_disp = insn & 0x0000ffff;
! if (insn_disp & 0x8000)
! insn_disp |= ~0xffff; /* Negative: sign-extend. */
xdisp = disp + insn_disp;
! fits16 = (xdisp >= - (bfd_signed_vma) 0x8000 && xdisp < 0x8000);
! fits32 = (xdisp >= - (bfd_signed_vma) 0x80000000
! && xdisp < 0x7fff8000);
if (fits16)
{
*************** elf64_alpha_relax_with_lituse (info, sym
*** 1340,1346 ****
all_optimized = false;
break;
! case 2: /* BYTE OFFSET FORMAT */
/* We can always optimize byte instructions. */
/* FIXME: sanity check the insn for byte op. Check that the
--- 1366,1372 ----
all_optimized = false;
break;
! case LITUSE_ALPHA_BYTOFF:
/* We can always optimize byte instructions. */
/* FIXME: sanity check the insn for byte op. Check that the
*************** elf64_alpha_relax_with_lituse (info, sym
*** 1358,1364 ****
info->changed_contents = true;
break;
! case 3: /* CALL FORMAT */
{
/* If not zero, place to jump without needing pv. */
bfd_vma optdest = elf64_alpha_relax_opt_call (info, symval);
--- 1384,1392 ----
info->changed_contents = true;
break;
! case LITUSE_ALPHA_JSR:
! case LITUSE_ALPHA_TLSGD:
! case LITUSE_ALPHA_TLSLDM:
{
/* If not zero, place to jump without needing pv. */
bfd_vma optdest = elf64_alpha_relax_opt_call (info, symval);
*************** elf64_alpha_relax_with_lituse (info, sym
*** 1409,1415 ****
{
Elf_Internal_Rela *gpdisp
= (elf64_alpha_find_reloc_at_ofs
! (irel, irelend, urel->r_offset + 4, R_ALPHA_GPDISP));
if (gpdisp)
{
bfd_byte *p_ldah = info->contents + gpdisp->r_offset;
--- 1437,1444 ----
{
Elf_Internal_Rela *gpdisp
= (elf64_alpha_find_reloc_at_ofs
! (info->relocs, irelend, urel->r_offset + 4,
! R_ALPHA_GPDISP));
if (gpdisp)
{
bfd_byte *p_ldah = info->contents + gpdisp->r_offset;
*************** elf64_alpha_relax_with_lituse (info, sym
*** 1444,1453 ****
{
if (--info->gotent->use_count == 0)
{
! int sz = alpha_got_entry_size (info->gotent->reloc_type);
! alpha_elf_tdata (info->gotent->gotobj)->total_got_size -= sz;
if (!info->h)
! alpha_elf_tdata (info->gotent->gotobj)->local_got_size -= sz;
}
/* If the literal instruction is no longer needed (it may have been
--- 1473,1482 ----
{
if (--info->gotent->use_count == 0)
{
! int sz = alpha_got_entry_size (R_ALPHA_LITERAL);
! alpha_elf_tdata (info->gotobj)->total_got_size -= sz;
if (!info->h)
! alpha_elf_tdata (info->gotobj)->local_got_size -= sz;
}
/* If the literal instruction is no longer needed (it may have been
*************** elf64_alpha_relax_with_lituse (info, sym
*** 1465,1471 ****
}
}
! return irel + count;
}
static bfd_vma
--- 1494,1500 ----
}
}
! return true;
}
static bfd_vma
*************** elf64_alpha_relax_opt_call (info, symval
*** 1541,1550 ****
}
static boolean
! elf64_alpha_relax_without_lituse (info, symval, irel)
struct alpha_relax_info *info;
bfd_vma symval;
Elf_Internal_Rela *irel;
{
unsigned int insn;
bfd_signed_vma disp;
--- 1570,1580 ----
}
static boolean
! elf64_alpha_relax_got_load (info, symval, irel, r_type)
struct alpha_relax_info *info;
bfd_vma symval;
Elf_Internal_Rela *irel;
+ unsigned long r_type;
{
unsigned int insn;
bfd_signed_vma disp;
*************** elf64_alpha_relax_without_lituse (info,
*** 1554,1592 ****
if (insn >> 26 != OP_LDQ)
{
((*_bfd_error_handler)
! ("%s: %s+0x%lx: warning: LITERAL relocation against unexpected insn",
bfd_archive_filename (info->abfd), info->sec->name,
! (unsigned long) irel->r_offset));
return true;
}
! /* So we aren't told much. Do what we can with the address load and
! fake the rest. All of the optimizations here require that the
! offset from the GP fit in 16 bits. */
! disp = symval - info->gp;
! if (disp < -0x8000 || disp >= 0x8000)
return true;
! /* On the LITERAL instruction itself, consider exchanging
! `ldq R,X(gp)' for `lda R,Y(gp)'. */
! insn = (OP_LDA << 26) | (insn & 0x03ff0000);
bfd_put_32 (info->abfd, (bfd_vma) insn, info->contents + irel->r_offset);
info->changed_contents = true;
! irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), R_ALPHA_GPREL16);
info->changed_relocs = true;
/* Reduce the use count on this got entry by one, possibly
eliminating it. */
if (--info->gotent->use_count == 0)
{
! int sz = alpha_got_entry_size (info->gotent->reloc_type);
! alpha_elf_tdata (info->gotent->gotobj)->total_got_size -= sz;
if (!info->h)
! alpha_elf_tdata (info->gotent->gotobj)->local_got_size -= sz;
}
/* ??? Search forward through this basic block looking for insns
--- 1584,1656 ----
if (insn >> 26 != OP_LDQ)
{
+ reloc_howto_type *howto = elf64_alpha_howto_table + r_type;
((*_bfd_error_handler)
! ("%s: %s+0x%lx: warning: %s relocation against unexpected insn",
bfd_archive_filename (info->abfd), info->sec->name,
! (unsigned long) irel->r_offset, howto->name));
return true;
}
! /* Can't relax dynamic symbols. */
! if (alpha_elf_dynamic_symbol_p (&info->h->root, info->link_info))
! return true;
! /* Can't use local-exec relocations in shared libraries. */
! if (r_type == R_ALPHA_GOTTPREL && info->link_info->shared)
return true;
! if (r_type == R_ALPHA_LITERAL)
! disp = symval - info->gp;
! else
! {
! bfd_vma dtp_base, tp_base;
! BFD_ASSERT (info->tls_segment != NULL);
! dtp_base = alpha_get_dtprel_base (info->tls_segment);
! tp_base = alpha_get_tprel_base (info->tls_segment);
! disp = symval - (r_type == R_ALPHA_GOTDTPREL ? dtp_base : tp_base);
! }
!
! if (disp < -0x8000 || disp >= 0x8000)
! return true;
!
! /* Exchange LDQ for LDA. In the case of the TLS relocs, we're loading
! a constant, so force the base register to be $31. */
! if (r_type == R_ALPHA_LITERAL)
! insn = (OP_LDA << 26) | (insn & 0x03ff0000);
! else
! insn = (OP_LDA << 26) | (insn & (31 << 21)) | (31 << 16);
bfd_put_32 (info->abfd, (bfd_vma) insn, info->contents + irel->r_offset);
info->changed_contents = true;
+
+ switch (r_type)
+ {
+ case R_ALPHA_LITERAL:
+ r_type = R_ALPHA_GPREL16;
+ break;
+ case R_ALPHA_GOTDTPREL:
+ r_type = R_ALPHA_DTPREL16;
+ break;
+ case R_ALPHA_GOTTPREL:
+ r_type = R_ALPHA_TPREL16;
+ break;
+ default:
+ BFD_ASSERT (0);
+ return false;
+ }
! irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), r_type);
info->changed_relocs = true;
/* Reduce the use count on this got entry by one, possibly
eliminating it. */
if (--info->gotent->use_count == 0)
{
! int sz = alpha_got_entry_size (r_type);
! alpha_elf_tdata (info->gotobj)->total_got_size -= sz;
if (!info->h)
! alpha_elf_tdata (info->gotobj)->local_got_size -= sz;
}
/* ??? Search forward through this basic block looking for insns
*************** elf64_alpha_relax_without_lituse (info,
*** 1606,1611 ****
--- 1670,2023 ----
}
static boolean
+ elf64_alpha_relax_gprelhilo (info, symval, irel, hi)
+ struct alpha_relax_info *info;
+ bfd_vma symval;
+ Elf_Internal_Rela *irel;
+ boolean hi;
+ {
+ unsigned int insn;
+ bfd_signed_vma disp;
+ bfd_byte *pos = info->contents + irel->r_offset;
+
+ /* ??? This assumes that the compiler doesn't render
+
+ array[i]
+ as
+ ldah t, array(gp) !gprelhigh
+ s8addl i, t, t
+ ldq r, array(t) !gprellow
+
+ which would indeed be the most efficient way to implement this. */
+
+ return true;
+
+ disp = symval - info->gp;
+ if (disp < -0x8000 || disp >= 0x8000)
+ return true;
+
+ if (hi)
+ {
+ /* Nop out the high instruction. */
+
+ bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos);
+ info->changed_contents = true;
+
+ irel->r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
+ irel->r_addend = 0;
+ info->changed_relocs = true;
+ }
+ else
+ {
+ /* Adjust the low instruction to reference GP directly. */
+
+ insn = bfd_get_32 (info->abfd, pos);
+ insn = (insn & 0xffe00000) | (29 << 16);
+ bfd_put_32 (info->abfd, (bfd_vma) insn, pos);
+ info->changed_contents = true;
+
+ irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
+ R_ALPHA_GPREL16);
+ info->changed_relocs = true;
+ }
+
+ return true;
+ }
+
+ static boolean
+ elf64_alpha_relax_tls_get_addr (info, symval, irel, is_gd)
+ struct alpha_relax_info *info;
+ bfd_vma symval;
+ Elf_Internal_Rela *irel;
+ boolean is_gd;
+ {
+ bfd_byte *pos[5];
+ unsigned int insn;
+ Elf_Internal_Rela *gpdisp, *hint;
+ boolean dynamic, use_gottprel;
+
+ dynamic = alpha_elf_dynamic_symbol_p (&info->h->root, info->link_info);
+
+ /* ??? For LD relaxation, we need a symbol referencing the beginning
+ of the TLS segment. */
+ if (!is_gd)
+ return true;
+
+ /* If a TLS symbol is accessed using IE at least once, there is no point
+ to use dynamic model for it. */
+ if (is_gd && info->h && (info->h->flags & ALPHA_ELF_LINK_HASH_TLS_IE))
+ ;
+
+ /* If the symbol is local, and we've already committed to DF_STATIC_TLS,
+ then we might as well relax to IE. */
+ else if (info->link_info->shared && !dynamic
+ && (info->link_info->flags & DF_STATIC_TLS))
+ ;
+
+ /* Otherwise we must be building an executable to do anything. */
+ else if (info->link_info->shared)
+ return true;
+
+ /* The TLSGD/TLSLDM relocation must be followed by a LITERAL and
+ the matching LITUSE_TLS relocations. */
+ if (irel + 2 >= info->relend)
+ return true;
+ if (ELF64_R_TYPE (irel[1].r_info) != R_ALPHA_LITERAL
+ || ELF64_R_TYPE (irel[2].r_info) != R_ALPHA_LITUSE
+ || irel[2].r_addend != (is_gd ? LITUSE_ALPHA_TLSGD : LITUSE_ALPHA_TLSLDM))
+ return true;
+
+ /* There must be a GPDISP relocation positioned immediately after the
+ LITUSE relocation. */
+ gpdisp = elf64_alpha_find_reloc_at_ofs (info->relocs, info->relend,
+ irel[2].r_offset + 4, R_ALPHA_GPDISP);
+ if (!gpdisp)
+ return true;
+
+ pos[0] = info->contents + irel[0].r_offset;
+ pos[1] = info->contents + irel[1].r_offset;
+ pos[2] = info->contents + irel[2].r_offset;
+ pos[3] = info->contents + gpdisp->r_offset;
+ pos[4] = pos[3] + gpdisp->r_addend;
+
+ /* Only positions 0 and 1 are allowed to be out of order. */
+ if (pos[1] < pos[0])
+ {
+ bfd_byte *tmp = pos[0];
+ pos[0] = pos[1];
+ pos[1] = tmp;
+ }
+ if (pos[1] >= pos[2] || pos[2] >= pos[3] || pos[3] >= pos[4])
+ return true;
+
+ /* Reduce the use count on the LITERAL relocation. Do this before we
+ smash the symndx when we adjust the relocations below. */
+ {
+ struct alpha_elf_got_entry *lit_gotent;
+ struct alpha_elf_link_hash_entry *lit_h;
+ unsigned long indx;
+
+ BFD_ASSERT (ELF64_R_SYM (irel[1].r_info) >= info->symtab_hdr->sh_info);
+ indx = ELF64_R_SYM (irel[1].r_info) - info->symtab_hdr->sh_info;
+ lit_h = alpha_elf_sym_hashes (info->abfd)[indx];
+
+ while (lit_h->root.root.type == bfd_link_hash_indirect
+ || lit_h->root.root.type == bfd_link_hash_warning)
+ lit_h = (struct alpha_elf_link_hash_entry *) lit_h->root.root.u.i.link;
+
+ for (lit_gotent = lit_h->got_entries; lit_gotent ;
+ lit_gotent = lit_gotent->next)
+ if (lit_gotent->gotobj == info->gotobj
+ && lit_gotent->reloc_type == R_ALPHA_LITERAL
+ && lit_gotent->addend == irel[1].r_addend)
+ break;
+ BFD_ASSERT (lit_gotent);
+
+ if (--lit_gotent->use_count == 0)
+ {
+ int sz = alpha_got_entry_size (R_ALPHA_LITERAL);
+ alpha_elf_tdata (info->gotobj)->total_got_size -= sz;
+ }
+ }
+
+ /* Change
+
+ lda $16,x($gp) !tlsgd!1
+ ldq $27,__tls_get_addr($gp) !literal!1
+ jsr $26,($27)__tls_get_addr !lituse_tlsgd!1
+ ldah $29,0($26) !gpdisp!2
+ lda $29,0($29) !gpdisp!2
+ to
+ ldq $16,x($gp) !gottprel
+ unop
+ call_pal rduniq
+ addq $16,$0,$0
+ unop
+ or the first pair to
+ lda $16,x($gp) !tprel
+ unop
+ or
+ ldah $16,x($gp) !tprelhi
+ lda $16,x($16) !tprello
+
+ as appropriate. */
+
+ use_gottprel = false;
+ switch (!dynamic && !info->link_info->shared)
+ {
+ case 1:
+ {
+ bfd_vma tp_base;
+ bfd_signed_vma disp;
+
+ BFD_ASSERT (info->tls_segment != NULL);
+ tp_base = alpha_get_tprel_base (info->tls_segment);
+ disp = symval - tp_base;
+
+ if (disp >= -0x8000 && disp < 0x8000)
+ {
+ insn = (OP_LDA << 26) | (16 << 21) | (31 << 16);
+ bfd_put_32 (info->abfd, (bfd_vma) insn, pos[0]);
+ bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos[1]);
+
+ irel[0].r_offset = pos[0] - info->contents;
+ irel[0].r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
+ R_ALPHA_TPREL16);
+ irel[1].r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
+ break;
+ }
+ else if (disp >= -(bfd_signed_vma) 0x80000000
+ && disp < (bfd_signed_vma) 0x7fff8000)
+ {
+ insn = (OP_LDAH << 26) | (16 << 21) | (31 << 16);
+ bfd_put_32 (info->abfd, (bfd_vma) insn, pos[0]);
+ insn = (OP_LDA << 26) | (16 << 21) | (16 << 16);
+ bfd_put_32 (info->abfd, (bfd_vma) insn, pos[1]);
+
+ irel[0].r_offset = pos[0] - info->contents;
+ irel[0].r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
+ R_ALPHA_TPRELHI);
+ irel[1].r_offset = pos[1] - info->contents;
+ irel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
+ R_ALPHA_TPRELLO);
+ break;
+ }
+ }
+ /* FALLTHRU */
+
+ default:
+ use_gottprel = true;
+
+ insn = (OP_LDQ << 26) | (16 << 21) | (29 << 16);
+ bfd_put_32 (info->abfd, (bfd_vma) insn, pos[0]);
+ bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos[1]);
+
+ irel[0].r_offset = pos[0] - info->contents;
+ irel[0].r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
+ R_ALPHA_GOTTPREL);
+ irel[1].r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
+ break;
+ }
+
+ bfd_put_32 (info->abfd, (bfd_vma) INSN_RDUNIQ, pos[2]);
+
+ insn = INSN_ADDQ | (16 << 21) | (0 << 16) | (0 << 0);
+ bfd_put_32 (info->abfd, (bfd_vma) insn, pos[3]);
+
+ bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos[4]);
+
+ irel[2].r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
+ gpdisp->r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
+
+ hint = elf64_alpha_find_reloc_at_ofs (info->relocs, info->relend,
+ irel[2].r_offset, R_ALPHA_HINT);
+ if (hint)
+ hint->r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
+
+ info->changed_contents = true;
+ info->changed_relocs = true;
+
+ /* Reduce the use count on the TLSGD/TLSLDM relocation. */
+ if (--info->gotent->use_count == 0)
+ {
+ int sz = alpha_got_entry_size (info->gotent->reloc_type);
+ alpha_elf_tdata (info->gotobj)->total_got_size -= sz;
+ if (!info->h)
+ alpha_elf_tdata (info->gotobj)->local_got_size -= sz;
+ }
+
+ /* If we've switched to a GOTTPREL relocation, increment the reference
+ count on that got entry. */
+ if (use_gottprel)
+ {
+ struct alpha_elf_got_entry *tprel_gotent;
+
+ for (tprel_gotent = *info->first_gotent; tprel_gotent ;
+ tprel_gotent = tprel_gotent->next)
+ if (tprel_gotent->gotobj == info->gotobj
+ && tprel_gotent->reloc_type == R_ALPHA_GOTTPREL
+ && tprel_gotent->addend == irel->r_addend)
+ break;
+ if (tprel_gotent)
+ tprel_gotent->use_count++;
+ else
+ {
+ if (info->gotent->use_count == 0)
+ tprel_gotent = info->gotent;
+ else
+ {
+ tprel_gotent = (struct alpha_elf_got_entry *)
+ bfd_alloc (info->abfd, sizeof (struct alpha_elf_got_entry));
+ if (!tprel_gotent)
+ return false;
+
+ tprel_gotent->next = *info->first_gotent;
+ *info->first_gotent = tprel_gotent;
+
+ tprel_gotent->gotobj = info->gotobj;
+ tprel_gotent->addend = irel->r_addend;
+ tprel_gotent->got_offset = -1;
+ tprel_gotent->reloc_done = 0;
+ tprel_gotent->reloc_xlated = 0;
+ }
+
+ tprel_gotent->use_count = 1;
+ tprel_gotent->reloc_type = R_ALPHA_GOTTPREL;
+ }
+ }
+
+ return true;
+ }
+
+ static struct elf_link_tls_segment *
+ elf64_alpha_relax_find_tls_segment (info, seg)
+ struct alpha_relax_info *info;
+ struct elf_link_tls_segment *seg;
+ {
+ bfd *output_bfd = info->sec->output_section->owner;
+ asection *first_tls_sec = NULL, *o;
+ unsigned int align;
+ bfd_vma base, end;
+
+ for (o = output_bfd->sections; o ; o = o->next)
+ if ((o->flags & SEC_THREAD_LOCAL) != 0
+ && (o->flags & SEC_LOAD) != 0)
+ {
+ first_tls_sec = o;
+ break;
+ }
+ if (!first_tls_sec)
+ return NULL;
+
+ base = first_tls_sec->vma;
+ align = 0;
+
+ for (o = first_tls_sec; o && (o->flags & SEC_THREAD_LOCAL); o = o->next)
+ {
+ bfd_vma size;
+
+ if (bfd_get_section_alignment (output_bfd, o) > align)
+ align = bfd_get_section_alignment (output_bfd, o);
+
+ size = o->_raw_size;
+ if (size == 0 && (o->flags & SEC_HAS_CONTENTS) == 0)
+ {
+ struct bfd_link_order *lo;
+ for (lo = o->link_order_head; lo ; lo = lo->next)
+ if (size < lo->offset + lo->size)
+ size = lo->offset + lo->size;
+ }
+ end = o->vma + size;
+ }
+
+ seg->start = base;
+ seg->size = end - base;
+ seg->align = align;
+
+ return seg;
+ }
+
+ static boolean
elf64_alpha_relax_section (abfd, sec, link_info, again)
bfd *abfd;
asection *sec;
*************** elf64_alpha_relax_section (abfd, sec, li
*** 1618,1628 ****
Elf_Internal_Rela *free_relocs = NULL;
Elf_Internal_Rela *irel, *irelend;
bfd_byte *free_contents = NULL;
! Elf64_External_Sym *extsyms = NULL;
Elf64_External_Sym *free_extsyms = NULL;
Elf_External_Sym_Shndx *shndx_buf = NULL;
struct alpha_elf_got_entry **local_got_entries;
struct alpha_relax_info info;
/* We are not currently changing any sizes, so only one pass. */
*again = false;
--- 2030,2041 ----
Elf_Internal_Rela *free_relocs = NULL;
Elf_Internal_Rela *irel, *irelend;
bfd_byte *free_contents = NULL;
! Elf64_External_Sym *extsyms;
Elf64_External_Sym *free_extsyms = NULL;
Elf_External_Sym_Shndx *shndx_buf = NULL;
struct alpha_elf_got_entry **local_got_entries;
struct alpha_relax_info info;
+ struct elf_link_tls_segment tls_segment;
/* We are not currently changing any sizes, so only one pass. */
*again = false;
*************** elf64_alpha_relax_section (abfd, sec, li
*** 1653,1658 ****
--- 2066,2072 ----
info.abfd = abfd;
info.sec = sec;
info.link_info = link_info;
+ info.symtab_hdr = symtab_hdr;
info.relocs = internal_relocs;
info.relend = irelend = internal_relocs + sec->reloc_count;
*************** elf64_alpha_relax_section (abfd, sec, li
*** 1667,1731 ****
+ 0x8000);
}
! for (irel = internal_relocs; irel < irelend; irel++)
{
! bfd_vma symval;
! Elf_Internal_Sym isym;
! struct alpha_elf_got_entry *gotent;
!
! if (ELF64_R_TYPE (irel->r_info) != (int) R_ALPHA_LITERAL)
! continue;
!
! /* Get the section contents. */
if (info.contents == NULL)
! {
! if (elf_section_data (sec)->this_hdr.contents != NULL)
! info.contents = elf_section_data (sec)->this_hdr.contents;
! else
! {
! info.contents = (bfd_byte *) bfd_malloc (sec->_raw_size);
! if (info.contents == NULL)
! goto error_return;
! free_contents = info.contents;
! if (! bfd_get_section_contents (abfd, sec, info.contents,
! (file_ptr) 0, sec->_raw_size))
! goto error_return;
! }
! }
! /* Read this BFD's symbols if we haven't done so already. */
if (extsyms == NULL)
! {
! bfd_size_type amt;
! if (symtab_hdr->contents != NULL)
! extsyms = (Elf64_External_Sym *) symtab_hdr->contents;
! else
! {
! 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;
! }
! shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
! if (shndx_hdr->sh_size != 0)
! {
! 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;
! }
}
/* Get the value of the symbol referred to by the reloc. */
--- 2081,2154 ----
+ 0x8000);
}
! /* Get the section contents. */
! if (elf_section_data (sec)->this_hdr.contents != NULL)
! info.contents = elf_section_data (sec)->this_hdr.contents;
! else
{
! info.contents = (bfd_byte *) bfd_malloc (sec->_raw_size);
if (info.contents == NULL)
! goto error_return;
! free_contents = info.contents;
! if (! bfd_get_section_contents (abfd, sec, info.contents,
! (file_ptr) 0, sec->_raw_size))
! goto error_return;
! }
! /* Read this BFD's symbols. */
! if (symtab_hdr->contents != NULL)
! extsyms = (Elf64_External_Sym *) symtab_hdr->contents;
! else
! {
! bfd_size_type amt = symtab_hdr->sh_info * 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;
! }
! shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
! if (shndx_hdr->sh_size != 0)
! {
! bfd_size_type amt;
! amt = symtab_hdr->sh_info * 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;
! }
! /* Compute the TLS segment information. The version normally found in
! elf_hash_table (link_info)->tls_segment isn't built until final_link.
! ??? Probably should look into extracting this into a common function. */
! info.tls_segment = elf64_alpha_relax_find_tls_segment (&info, &tls_segment);
!
! for (irel = internal_relocs; irel < irelend; irel++)
! {
! bfd_vma symval;
! Elf_Internal_Sym isym;
! struct alpha_elf_got_entry *gotent;
! unsigned long r_type = ELF64_R_TYPE (irel->r_info);
!
! /* Early exit for unhandled or unrelaxable relocations. */
! switch (r_type)
! {
! case R_ALPHA_LITERAL:
! case R_ALPHA_GPRELHIGH:
! case R_ALPHA_GPRELLOW:
! case R_ALPHA_GOTDTPREL:
! case R_ALPHA_GOTTPREL:
! case R_ALPHA_TLSGD:
! case R_ALPHA_TLSLDM:
! break;
! default:
! continue;
}
/* Get the value of the symbol referred to by the reloc. */
*************** elf64_alpha_relax_section (abfd, sec, li
*** 1749,1755 ****
info.h = NULL;
info.other = isym.st_other;
! gotent = local_got_entries[ELF64_R_SYM(irel->r_info)];
symval = isym.st_value;
}
else
--- 2172,2178 ----
info.h = NULL;
info.other = isym.st_other;
! info.first_gotent = &local_got_entries[ELF64_R_SYM(irel->r_info)];
symval = isym.st_value;
}
else
*************** elf64_alpha_relax_section (abfd, sec, li
*** 1765,1807 ****
|| h->root.root.type == bfd_link_hash_warning)
h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link;
- /* We can't do anthing with undefined or dynamic symbols. */
- if (h->root.root.type == bfd_link_hash_undefined
- || h->root.root.type == bfd_link_hash_undefweak
- || alpha_elf_dynamic_symbol_p (&h->root, link_info))
- continue;
-
info.h = h;
info.tsec = h->root.root.u.def.section;
info.other = h->root.other;
! gotent = h->got_entries;
symval = h->root.root.u.def.value;
}
/* Search for the got entry to be used by this relocation. */
! while (gotent->gotobj != info.gotobj || gotent->addend != irel->r_addend)
! gotent = gotent->next;
info.gotent = gotent;
symval += info.tsec->output_section->vma + info.tsec->output_offset;
symval += irel->r_addend;
! BFD_ASSERT(info.gotent != NULL);
! /* If there exist LITUSE relocations immediately following, this
! opens up all sorts of interesting optimizations, because we
! now know every location that this address load is used. */
! if (irel+1 < irelend && ELF64_R_TYPE (irel[1].r_info) == R_ALPHA_LITUSE)
! {
! irel = elf64_alpha_relax_with_lituse (&info, symval, irel, irelend);
! if (irel == NULL)
goto error_return;
! }
! else
! {
! if (!elf64_alpha_relax_without_lituse (&info, symval, irel))
goto error_return;
}
}
--- 2188,2253 ----
|| h->root.root.type == bfd_link_hash_warning)
h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link;
info.h = h;
info.tsec = h->root.root.u.def.section;
info.other = h->root.other;
! info.first_gotent = &h->got_entries;
symval = h->root.root.u.def.value;
}
/* Search for the got entry to be used by this relocation. */
! for (gotent = *info.first_gotent; gotent ; gotent = gotent->next)
! if (gotent->gotobj == info.gotobj
! && gotent->reloc_type == r_type
! && gotent->addend == irel->r_addend)
! break;
info.gotent = gotent;
symval += info.tsec->output_section->vma + info.tsec->output_offset;
symval += irel->r_addend;
! switch (r_type)
! {
! case R_ALPHA_LITERAL:
! BFD_ASSERT(info.gotent != NULL);
! /* If there exist LITUSE relocations immediately following, this
! opens up all sorts of interesting optimizations, because we
! now know every location that this address load is used. */
! if (irel+1 < irelend
! && ELF64_R_TYPE (irel[1].r_info) == R_ALPHA_LITUSE)
! {
! if (!elf64_alpha_relax_with_lituse (&info, symval, irel))
! goto error_return;
! }
! else
! {
! if (!elf64_alpha_relax_got_load (&info, symval, irel, r_type))
! goto error_return;
! }
! break;
! case R_ALPHA_GPRELHIGH:
! case R_ALPHA_GPRELLOW:
! if (!elf64_alpha_relax_gprelhilo (&info, symval, irel,
! r_type == R_ALPHA_GPRELHIGH))
goto error_return;
! break;
!
! case R_ALPHA_GOTDTPREL:
! case R_ALPHA_GOTTPREL:
! BFD_ASSERT(info.gotent != NULL);
! if (!elf64_alpha_relax_got_load (&info, symval, irel, r_type))
goto error_return;
+ break;
+
+ case R_ALPHA_TLSGD:
+ case R_ALPHA_TLSLDM:
+ BFD_ASSERT(info.gotent != NULL);
+ if (!elf64_alpha_relax_tls_get_addr (&info, symval, irel,
+ r_type == R_ALPHA_TLSGD))
+ goto error_return;
+ break;
}
}
*************** elf64_alpha_relax_section (abfd, sec, li
*** 1809,1826 ****
return false;
if (info.changed_relocs)
! {
! elf_section_data (sec)->relocs = internal_relocs;
! }
else if (free_relocs != NULL)
! {
! free (free_relocs);
! }
if (info.changed_contents)
! {
! elf_section_data (sec)->this_hdr.contents = info.contents;
! }
else if (free_contents != NULL)
{
if (! link_info->keep_memory)
--- 2255,2266 ----
return false;
if (info.changed_relocs)
! elf_section_data (sec)->relocs = internal_relocs;
else if (free_relocs != NULL)
! free (free_relocs);
if (info.changed_contents)
! elf_section_data (sec)->this_hdr.contents = info.contents;
else if (free_contents != NULL)
{
if (! link_info->keep_memory)
*************** elf64_alpha_check_relocs (abfd, info, se
*** 2674,2679 ****
--- 3114,3120 ----
case R_ALPHA_GOTTPREL:
need = NEED_GOT | NEED_GOT_ENTRY;
+ gotent_flags = ALPHA_ELF_LINK_HASH_TLS_IE;
if (info->shared)
info->flags |= DF_STATIC_TLS;
break;
*************** elf64_alpha_relocate_section (output_bfd
*** 3653,3664 ****
tls_segment = elf_hash_table (info)->tls_segment;
if (tls_segment)
{
! /* This is PT_TLS segment p_vaddr. */
! dtp_base = tls_segment->start;
!
! /* Main program TLS (whose template starts at PT_TLS p_vaddr)
! is assigned offset round(16, PT_TLS p_align). */
! tp_base = dtp_base - align_power (16, tls_segment->align);
}
}
--- 4094,4101 ----
tls_segment = elf_hash_table (info)->tls_segment;
if (tls_segment)
{
! dtp_base = alpha_get_dtprel_base (tls_segment);
! tp_base = alpha_get_tprel_base (tls_segment);
}
}
*************** elf64_alpha_relocate_section (output_bfd
*** 4156,4167 ****
}
BFD_ASSERT(tls_segment != NULL);
value -= dtp_base;
goto default_reloc;
case R_ALPHA_TPRELHI:
case R_ALPHA_TPRELLO:
case R_ALPHA_TPREL16:
! if (dynamic_symbol_p)
{
(*_bfd_error_handler)
(_("%s: tp-relative relocation against dynamic symbol %s"),
--- 4593,4613 ----
}
BFD_ASSERT(tls_segment != NULL);
value -= dtp_base;
+ if (r_type == R_ALPHA_DTPRELHI)
+ value = ((bfd_signed_vma) value >> 16) + ((value >> 15) & 1);
goto default_reloc;
case R_ALPHA_TPRELHI:
case R_ALPHA_TPRELLO:
case R_ALPHA_TPREL16:
! if (info->shared)
! {
! (*_bfd_error_handler)
! (_("%s: TLS local exec code cannot be linked into shared objects"),
! bfd_archive_filename (input_bfd));
! ret_val = false;
! }
! else if (dynamic_symbol_p)
{
(*_bfd_error_handler)
(_("%s: tp-relative relocation against dynamic symbol %s"),
*************** elf64_alpha_relocate_section (output_bfd
*** 4170,4175 ****
--- 4616,4623 ----
}
BFD_ASSERT(tls_segment != NULL);
value -= tp_base;
+ if (r_type == R_ALPHA_TPRELHI)
+ value = ((bfd_signed_vma) value >> 16) + ((value >> 15) & 1);
goto default_reloc;
case R_ALPHA_GOTDTPREL: