Index: bfd/elf-m10300.c |
diff --git a/bfd/elf-m10300.c b/bfd/elf-m10300.c |
index fa33b4a2fbe19f6be4b9549b0b68feba80242175..709ea161eb1a026d8f14910277ac4326537128f7 100644 |
--- a/bfd/elf-m10300.c |
+++ b/bfd/elf-m10300.c |
@@ -1,6 +1,6 @@ |
/* Matsushita 10300 specific support for 32-bit ELF |
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, |
- 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. |
+ 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. |
This file is part of BFD, the Binary File Descriptor library. |
@@ -69,6 +69,14 @@ struct elf32_mn10300_link_hash_entry |
/* Calculated value. */ |
bfd_vma value; |
+ |
+#define GOT_UNKNOWN 0 |
+#define GOT_NORMAL 1 |
+#define GOT_TLS_GD 2 |
+#define GOT_TLS_LD 3 |
+#define GOT_TLS_IE 4 |
+ /* Used to distinguish GOT entries for TLS types from normal GOT entries. */ |
+ unsigned char tls_type; |
}; |
/* We derive a hash table from the main elf linker hash table so |
@@ -87,8 +95,31 @@ struct elf32_mn10300_link_hash_table |
/* Random linker state flags. */ |
#define MN10300_HASH_ENTRIES_INITIALIZED 0x1 |
char flags; |
+ struct |
+ { |
+ bfd_signed_vma refcount; |
+ bfd_vma offset; |
+ char got_allocated; |
+ char rel_emitted; |
+ } tls_ldm_got; |
+}; |
+ |
+#define elf_mn10300_hash_entry(ent) ((struct elf32_mn10300_link_hash_entry *)(ent)) |
+ |
+struct elf_mn10300_obj_tdata |
+{ |
+ struct elf_obj_tdata root; |
+ |
+ /* tls_type for each local got entry. */ |
+ char * local_got_tls_type; |
}; |
+#define elf_mn10300_tdata(abfd) \ |
+ ((struct elf_mn10300_obj_tdata *) (abfd)->tdata.any) |
+ |
+#define elf_mn10300_local_got_tls_type(abfd) \ |
+ (elf_mn10300_tdata (abfd)->local_got_tls_type) |
+ |
#ifndef streq |
#define streq(a, b) (strcmp ((a),(b)) == 0) |
#endif |
@@ -448,15 +479,131 @@ static reloc_howto_type elf_mn10300_howto_table[] = |
0xffffffff, /* dst_mask */ |
FALSE), /* pcrel_offset */ |
- EMPTY_HOWTO (24), |
- EMPTY_HOWTO (25), |
- EMPTY_HOWTO (26), |
- EMPTY_HOWTO (27), |
- EMPTY_HOWTO (28), |
- EMPTY_HOWTO (29), |
- EMPTY_HOWTO (30), |
- EMPTY_HOWTO (31), |
- EMPTY_HOWTO (32), |
+ HOWTO (R_MN10300_TLS_GD, /* type */ |
+ 0, /* rightshift */ |
+ 2, /* size (0 = byte, 1 = short, 2 = long) */ |
+ 32, /* bitsize */ |
+ FALSE, /* pc_relative */ |
+ 0, /* bitpos */ |
+ complain_overflow_bitfield, /* complain_on_overflow */ |
+ bfd_elf_generic_reloc, /* */ |
+ "R_MN10300_TLS_GD", /* name */ |
+ FALSE, /* partial_inplace */ |
+ 0xffffffff, /* src_mask */ |
+ 0xffffffff, /* dst_mask */ |
+ FALSE), /* pcrel_offset */ |
+ |
+ HOWTO (R_MN10300_TLS_LD, /* type */ |
+ 0, /* rightshift */ |
+ 2, /* size (0 = byte, 1 = short, 2 = long) */ |
+ 32, /* bitsize */ |
+ FALSE, /* pc_relative */ |
+ 0, /* bitpos */ |
+ complain_overflow_bitfield, /* complain_on_overflow */ |
+ bfd_elf_generic_reloc, /* */ |
+ "R_MN10300_TLS_LD", /* name */ |
+ FALSE, /* partial_inplace */ |
+ 0xffffffff, /* src_mask */ |
+ 0xffffffff, /* dst_mask */ |
+ FALSE), /* pcrel_offset */ |
+ |
+ HOWTO (R_MN10300_TLS_LDO, /* type */ |
+ 0, /* rightshift */ |
+ 2, /* size (0 = byte, 1 = short, 2 = long) */ |
+ 32, /* bitsize */ |
+ FALSE, /* pc_relative */ |
+ 0, /* bitpos */ |
+ complain_overflow_bitfield, /* complain_on_overflow */ |
+ bfd_elf_generic_reloc, /* */ |
+ "R_MN10300_TLS_LDO", /* name */ |
+ FALSE, /* partial_inplace */ |
+ 0xffffffff, /* src_mask */ |
+ 0xffffffff, /* dst_mask */ |
+ FALSE), /* pcrel_offset */ |
+ |
+ HOWTO (R_MN10300_TLS_GOTIE, /* type */ |
+ 0, /* rightshift */ |
+ 2, /* size (0 = byte, 1 = short, 2 = long) */ |
+ 32, /* bitsize */ |
+ FALSE, /* pc_relative */ |
+ 0, /* bitpos */ |
+ complain_overflow_bitfield, /* complain_on_overflow */ |
+ bfd_elf_generic_reloc, /* */ |
+ "R_MN10300_TLS_GOTIE", /* name */ |
+ FALSE, /* partial_inplace */ |
+ 0xffffffff, /* src_mask */ |
+ 0xffffffff, /* dst_mask */ |
+ FALSE), /* pcrel_offset */ |
+ |
+ HOWTO (R_MN10300_TLS_IE, /* type */ |
+ 0, /* rightshift */ |
+ 2, /* size (0 = byte, 1 = short, 2 = long) */ |
+ 32, /* bitsize */ |
+ FALSE, /* pc_relative */ |
+ 0, /* bitpos */ |
+ complain_overflow_bitfield, /* complain_on_overflow */ |
+ bfd_elf_generic_reloc, /* */ |
+ "R_MN10300_TLS_IE", /* name */ |
+ FALSE, /* partial_inplace */ |
+ 0xffffffff, /* src_mask */ |
+ 0xffffffff, /* dst_mask */ |
+ FALSE), /* pcrel_offset */ |
+ |
+ HOWTO (R_MN10300_TLS_LE, /* type */ |
+ 0, /* rightshift */ |
+ 2, /* size (0 = byte, 1 = short, 2 = long) */ |
+ 32, /* bitsize */ |
+ FALSE, /* pc_relative */ |
+ 0, /* bitpos */ |
+ complain_overflow_bitfield, /* complain_on_overflow */ |
+ bfd_elf_generic_reloc, /* */ |
+ "R_MN10300_TLS_LE", /* name */ |
+ FALSE, /* partial_inplace */ |
+ 0xffffffff, /* src_mask */ |
+ 0xffffffff, /* dst_mask */ |
+ FALSE), /* pcrel_offset */ |
+ |
+ HOWTO (R_MN10300_TLS_DTPMOD, /* type */ |
+ 0, /* rightshift */ |
+ 2, /* size (0 = byte, 1 = short, 2 = long) */ |
+ 32, /* bitsize */ |
+ FALSE, /* pc_relative */ |
+ 0, /* bitpos */ |
+ complain_overflow_bitfield, /* complain_on_overflow */ |
+ bfd_elf_generic_reloc, /* */ |
+ "R_MN10300_TLS_DTPMOD", /* name */ |
+ FALSE, /* partial_inplace */ |
+ 0xffffffff, /* src_mask */ |
+ 0xffffffff, /* dst_mask */ |
+ FALSE), /* pcrel_offset */ |
+ |
+ HOWTO (R_MN10300_TLS_DTPOFF, /* type */ |
+ 0, /* rightshift */ |
+ 2, /* size (0 = byte, 1 = short, 2 = long) */ |
+ 32, /* bitsize */ |
+ FALSE, /* pc_relative */ |
+ 0, /* bitpos */ |
+ complain_overflow_bitfield, /* complain_on_overflow */ |
+ bfd_elf_generic_reloc, /* */ |
+ "R_MN10300_TLS_DTPOFF", /* name */ |
+ FALSE, /* partial_inplace */ |
+ 0xffffffff, /* src_mask */ |
+ 0xffffffff, /* dst_mask */ |
+ FALSE), /* pcrel_offset */ |
+ |
+ HOWTO (R_MN10300_TLS_TPOFF, /* type */ |
+ 0, /* rightshift */ |
+ 2, /* size (0 = byte, 1 = short, 2 = long) */ |
+ 32, /* bitsize */ |
+ FALSE, /* pc_relative */ |
+ 0, /* bitpos */ |
+ complain_overflow_bitfield, /* complain_on_overflow */ |
+ bfd_elf_generic_reloc, /* */ |
+ "R_MN10300_TLS_TPOFF", /* name */ |
+ FALSE, /* partial_inplace */ |
+ 0xffffffff, /* src_mask */ |
+ 0xffffffff, /* dst_mask */ |
+ FALSE), /* pcrel_offset */ |
HOWTO (R_MN10300_SYM_DIFF, /* type */ |
0, /* rightshift */ |
@@ -519,6 +666,15 @@ static const struct mn10300_reloc_map mn10300_reloc_map[] = |
{ BFD_RELOC_MN10300_GLOB_DAT, R_MN10300_GLOB_DAT }, |
{ BFD_RELOC_MN10300_JMP_SLOT, R_MN10300_JMP_SLOT }, |
{ BFD_RELOC_MN10300_RELATIVE, R_MN10300_RELATIVE }, |
+ { BFD_RELOC_MN10300_TLS_GD, R_MN10300_TLS_GD }, |
+ { BFD_RELOC_MN10300_TLS_LD, R_MN10300_TLS_LD }, |
+ { BFD_RELOC_MN10300_TLS_LDO, R_MN10300_TLS_LDO }, |
+ { BFD_RELOC_MN10300_TLS_GOTIE, R_MN10300_TLS_GOTIE }, |
+ { BFD_RELOC_MN10300_TLS_IE, R_MN10300_TLS_IE }, |
+ { BFD_RELOC_MN10300_TLS_LE, R_MN10300_TLS_LE }, |
+ { BFD_RELOC_MN10300_TLS_DTPMOD, R_MN10300_TLS_DTPMOD }, |
+ { BFD_RELOC_MN10300_TLS_DTPOFF, R_MN10300_TLS_DTPOFF }, |
+ { BFD_RELOC_MN10300_TLS_TPOFF, R_MN10300_TLS_TPOFF }, |
{ BFD_RELOC_MN10300_SYM_DIFF, R_MN10300_SYM_DIFF }, |
{ BFD_RELOC_MN10300_ALIGN, R_MN10300_ALIGN } |
}; |
@@ -534,10 +690,12 @@ _bfd_mn10300_elf_create_got_section (bfd * abfd, |
asection * s; |
struct elf_link_hash_entry * h; |
const struct elf_backend_data * bed = get_elf_backend_data (abfd); |
+ struct elf_link_hash_table *htab; |
int ptralign; |
/* This function may be called more than once. */ |
- if (bfd_get_section_by_name (abfd, ".got") != NULL) |
+ htab = elf_hash_table (info); |
+ if (htab->sgot != NULL) |
return TRUE; |
switch (bed->s->arch_size) |
@@ -565,7 +723,8 @@ _bfd_mn10300_elf_create_got_section (bfd * abfd, |
if (bed->plt_readonly) |
pltflags |= SEC_READONLY; |
- s = bfd_make_section_with_flags (abfd, ".plt", pltflags); |
+ s = bfd_make_section_anyway_with_flags (abfd, ".plt", pltflags); |
+ htab->splt = s; |
if (s == NULL |
|| ! bfd_set_section_alignment (abfd, s, bed->plt_alignment)) |
return FALSE; |
@@ -576,19 +735,21 @@ _bfd_mn10300_elf_create_got_section (bfd * abfd, |
{ |
h = _bfd_elf_define_linkage_sym (abfd, info, s, |
"_PROCEDURE_LINKAGE_TABLE_"); |
- elf_hash_table (info)->hplt = h; |
+ htab->hplt = h; |
if (h == NULL) |
return FALSE; |
} |
- s = bfd_make_section_with_flags (abfd, ".got", flags); |
+ s = bfd_make_section_anyway_with_flags (abfd, ".got", flags); |
+ htab->sgot = s; |
if (s == NULL |
|| ! bfd_set_section_alignment (abfd, s, ptralign)) |
return FALSE; |
if (bed->want_got_plt) |
{ |
- s = bfd_make_section_with_flags (abfd, ".got.plt", flags); |
+ s = bfd_make_section_anyway_with_flags (abfd, ".got.plt", flags); |
+ htab->sgotplt = s; |
if (s == NULL |
|| ! bfd_set_section_alignment (abfd, s, ptralign)) |
return FALSE; |
@@ -599,7 +760,7 @@ _bfd_mn10300_elf_create_got_section (bfd * abfd, |
because we don't want to define the symbol if we are not creating |
a global offset table. */ |
h = _bfd_elf_define_linkage_sym (abfd, info, s, "_GLOBAL_OFFSET_TABLE_"); |
- elf_hash_table (info)->hgot = h; |
+ htab->hgot = h; |
if (h == NULL) |
return FALSE; |
@@ -650,6 +811,223 @@ mn10300_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, |
cache_ptr->howto = elf_mn10300_howto_table + r_type; |
} |
+static int |
+elf_mn10300_tls_transition (struct bfd_link_info * info, |
+ int r_type, |
+ struct elf_link_hash_entry * h, |
+ asection * sec, |
+ bfd_boolean counting) |
+{ |
+ bfd_boolean is_local; |
+ |
+ if (r_type == R_MN10300_TLS_GD |
+ && h != NULL |
+ && elf_mn10300_hash_entry (h)->tls_type == GOT_TLS_IE) |
+ return R_MN10300_TLS_GOTIE; |
+ |
+ if (info->shared) |
+ return r_type; |
+ |
+ if (! (sec->flags & SEC_CODE)) |
+ return r_type; |
+ |
+ if (! counting && h != NULL && ! elf_hash_table (info)->dynamic_sections_created) |
+ is_local = TRUE; |
+ else |
+ is_local = SYMBOL_CALLS_LOCAL (info, h); |
+ |
+ /* For the main program, these are the transitions we do. */ |
+ switch (r_type) |
+ { |
+ case R_MN10300_TLS_GD: return is_local ? R_MN10300_TLS_LE : R_MN10300_TLS_GOTIE; |
+ case R_MN10300_TLS_LD: return R_MN10300_NONE; |
+ case R_MN10300_TLS_LDO: return R_MN10300_TLS_LE; |
+ case R_MN10300_TLS_IE: |
+ case R_MN10300_TLS_GOTIE: return is_local ? R_MN10300_TLS_LE : r_type; |
+ } |
+ |
+ return r_type; |
+} |
+ |
+/* Return the relocation value for @tpoff relocation |
+ if STT_TLS virtual address is ADDRESS. */ |
+ |
+static bfd_vma |
+dtpoff (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; |
+ return address - htab->tls_sec->vma; |
+} |
+ |
+/* Return the relocation value for @tpoff relocation |
+ if STT_TLS virtual address is ADDRESS. */ |
+ |
+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; |
+ return address - (htab->tls_size + htab->tls_sec->vma); |
+} |
+ |
+/* Returns nonzero if there's a R_MN10300_PLT32 reloc that we now need |
+ to skip, after this one. The actual value is the offset between |
+ this reloc and the PLT reloc. */ |
+ |
+static int |
+mn10300_do_tls_transition (bfd * input_bfd, |
+ unsigned int r_type, |
+ unsigned int tls_r_type, |
+ bfd_byte * contents, |
+ bfd_vma offset) |
+{ |
+ bfd_byte *op = contents + offset; |
+ int gotreg = 0; |
+ |
+#define TLS_PAIR(r1,r2) ((r1) * R_MN10300_MAX + (r2)) |
+ |
+ /* This is common to all GD/LD transitions, so break it out. */ |
+ if (r_type == R_MN10300_TLS_GD |
+ || r_type == R_MN10300_TLS_LD) |
+ { |
+ op -= 2; |
+ /* mov imm,d0. */ |
+ BFD_ASSERT (bfd_get_8 (input_bfd, op) == 0xFC); |
+ BFD_ASSERT (bfd_get_8 (input_bfd, op + 1) == 0xCC); |
+ /* add aN,d0. */ |
+ BFD_ASSERT (bfd_get_8 (input_bfd, op + 6) == 0xF1); |
+ gotreg = (bfd_get_8 (input_bfd, op + 7) & 0x0c) >> 2; |
+ /* Call. */ |
+ BFD_ASSERT (bfd_get_8 (input_bfd, op + 8) == 0xDD); |
+ } |
+ |
+ switch (TLS_PAIR (r_type, tls_r_type)) |
+ { |
+ case TLS_PAIR (R_MN10300_TLS_GD, R_MN10300_TLS_GOTIE): |
+ { |
+ /* Keep track of which register we put GOTptr in. */ |
+ /* mov (_x@indntpoff,a2),a0. */ |
+ memcpy (op, "\xFC\x20\x00\x00\x00\x00", 6); |
+ op[1] |= gotreg; |
+ /* add e2,a0. */ |
+ memcpy (op+6, "\xF9\x78\x28", 3); |
+ /* or 0x00000000, d0 - six byte nop. */ |
+ memcpy (op+9, "\xFC\xE4\x00\x00\x00\x00", 6); |
+ } |
+ return 7; |
+ |
+ case TLS_PAIR (R_MN10300_TLS_GD, R_MN10300_TLS_LE): |
+ { |
+ /* Register is *always* a0. */ |
+ /* mov _x@tpoff,a0. */ |
+ memcpy (op, "\xFC\xDC\x00\x00\x00\x00", 6); |
+ /* add e2,a0. */ |
+ memcpy (op+6, "\xF9\x78\x28", 3); |
+ /* or 0x00000000, d0 - six byte nop. */ |
+ memcpy (op+9, "\xFC\xE4\x00\x00\x00\x00", 6); |
+ } |
+ return 7; |
+ case TLS_PAIR (R_MN10300_TLS_LD, R_MN10300_NONE): |
+ { |
+ /* Register is *always* a0. */ |
+ /* mov e2,a0. */ |
+ memcpy (op, "\xF5\x88", 2); |
+ /* or 0x00000000, d0 - six byte nop. */ |
+ memcpy (op+2, "\xFC\xE4\x00\x00\x00\x00", 6); |
+ /* or 0x00000000, e2 - seven byte nop. */ |
+ memcpy (op+8, "\xFE\x19\x22\x00\x00\x00\x00", 7); |
+ } |
+ return 7; |
+ |
+ case TLS_PAIR (R_MN10300_TLS_LDO, R_MN10300_TLS_LE): |
+ /* No changes needed, just the reloc change. */ |
+ return 0; |
+ |
+ /* These are a little tricky, because we have to detect which |
+ opcode is being used (they're different sizes, with the reloc |
+ at different offsets within the opcode) and convert each |
+ accordingly, copying the operands as needed. The conversions |
+ we do are as follows (IE,GOTIE,LE): |
+ |
+ 1111 1100 1010 01Dn [-- abs32 --] MOV (x@indntpoff),Dn |
+ 1111 1100 0000 DnAm [-- abs32 --] MOV (x@gotntpoff,Am),Dn |
+ 1111 1100 1100 11Dn [-- abs32 --] MOV x@tpoff,Dn |
+ |
+ 1111 1100 1010 00An [-- abs32 --] MOV (x@indntpoff),An |
+ 1111 1100 0010 AnAm [-- abs32 --] MOV (x@gotntpoff,Am),An |
+ 1111 1100 1101 11An [-- abs32 --] MOV x@tpoff,An |
+ |
+ 1111 1110 0000 1110 Rnnn Xxxx [-- abs32 --] MOV (x@indntpoff),Rn |
+ 1111 1110 0000 1010 Rnnn Rmmm [-- abs32 --] MOV (x@indntpoff,Rm),Rn |
+ 1111 1110 0000 1000 Rnnn Xxxx [-- abs32 --] MOV x@tpoff,Rn |
+ |
+ Since the GOT pointer is always $a2, we assume the last |
+ normally won't happen, but let's be paranoid and plan for the |
+ day that GCC optimizes it somewhow. */ |
+ |
+ case TLS_PAIR (R_MN10300_TLS_IE, R_MN10300_TLS_LE): |
+ if (op[-2] == 0xFC) |
+ { |
+ op -= 2; |
+ if ((op[1] & 0xFC) == 0xA4) /* Dn */ |
+ { |
+ op[1] &= 0x03; /* Leaves Dn. */ |
+ op[1] |= 0xCC; |
+ } |
+ else /* An */ |
+ { |
+ op[1] &= 0x03; /* Leaves An. */ |
+ op[1] |= 0xDC; |
+ } |
+ } |
+ else if (op[-3] == 0xFE) |
+ op[-2] = 0x08; |
+ else |
+ abort (); |
+ break; |
+ |
+ case TLS_PAIR (R_MN10300_TLS_GOTIE, R_MN10300_TLS_LE): |
+ if (op[-2] == 0xFC) |
+ { |
+ op -= 2; |
+ if ((op[1] & 0xF0) == 0x00) /* Dn */ |
+ { |
+ op[1] &= 0x0C; /* Leaves Dn. */ |
+ op[1] >>= 2; |
+ op[1] |= 0xCC; |
+ } |
+ else /* An */ |
+ { |
+ op[1] &= 0x0C; /* Leaves An. */ |
+ op[1] >>= 2; |
+ op[1] |= 0xDC; |
+ } |
+ } |
+ else if (op[-3] == 0xFE) |
+ op[-2] = 0x08; |
+ else |
+ abort (); |
+ break; |
+ |
+ default: |
+ (*_bfd_error_handler) |
+ (_("%s: Unsupported transition from %s to %s"), |
+ bfd_get_filename (input_bfd), |
+ elf_mn10300_howto_table[r_type].name, |
+ elf_mn10300_howto_table[tls_r_type].name); |
+ break; |
+ } |
+#undef TLS_PAIR |
+ return 0; |
+} |
+ |
/* Look through the relocs for a section during the first phase. |
Since we don't do .gots or .plts, we just need to consider the |
virtual table relocs for gc. */ |
@@ -660,6 +1038,7 @@ mn10300_elf_check_relocs (bfd *abfd, |
asection *sec, |
const Elf_Internal_Rela *relocs) |
{ |
+ struct elf32_mn10300_link_hash_table * htab = elf32_mn10300_hash_table (info); |
bfd_boolean sym_diff_reloc_seen; |
Elf_Internal_Shdr *symtab_hdr; |
Elf_Internal_Sym * isymbuf = NULL; |
@@ -694,6 +1073,7 @@ mn10300_elf_check_relocs (bfd *abfd, |
struct elf_link_hash_entry *h; |
unsigned long r_symndx; |
unsigned int r_type; |
+ int tls_type = GOT_NORMAL; |
r_symndx = ELF32_R_SYM (rel->r_info); |
if (r_symndx < symtab_hdr->sh_info) |
@@ -707,6 +1087,7 @@ mn10300_elf_check_relocs (bfd *abfd, |
} |
r_type = ELF32_R_TYPE (rel->r_info); |
+ r_type = elf_mn10300_tls_transition (info, r_type, h, sec, TRUE); |
/* Some relocs require a global offset table. */ |
if (dynobj == NULL) |
@@ -721,6 +1102,10 @@ mn10300_elf_check_relocs (bfd *abfd, |
case R_MN10300_GOTOFF16: |
case R_MN10300_GOTPC32: |
case R_MN10300_GOTPC16: |
+ case R_MN10300_TLS_GD: |
+ case R_MN10300_TLS_LD: |
+ case R_MN10300_TLS_GOTIE: |
+ case R_MN10300_TLS_IE: |
elf_hash_table (info)->dynobj = dynobj = abfd; |
if (! _bfd_mn10300_elf_create_got_section (dynobj, info)) |
goto fail; |
@@ -749,53 +1134,101 @@ mn10300_elf_check_relocs (bfd *abfd, |
goto fail; |
break; |
+ case R_MN10300_TLS_LD: |
+ htab->tls_ldm_got.refcount ++; |
+ tls_type = GOT_TLS_LD; |
+ |
+ if (htab->tls_ldm_got.got_allocated) |
+ break; |
+ goto create_got; |
+ |
+ case R_MN10300_TLS_IE: |
+ case R_MN10300_TLS_GOTIE: |
+ if (info->shared) |
+ info->flags |= DF_STATIC_TLS; |
+ /* Fall through */ |
+ |
+ case R_MN10300_TLS_GD: |
case R_MN10300_GOT32: |
case R_MN10300_GOT24: |
case R_MN10300_GOT16: |
+ create_got: |
/* This symbol requires a global offset table entry. */ |
+ switch (r_type) |
+ { |
+ case R_MN10300_TLS_IE: |
+ case R_MN10300_TLS_GOTIE: tls_type = GOT_TLS_IE; break; |
+ case R_MN10300_TLS_GD: tls_type = GOT_TLS_GD; break; |
+ default: tls_type = GOT_NORMAL; break; |
+ } |
+ |
if (sgot == NULL) |
{ |
- sgot = bfd_get_section_by_name (dynobj, ".got"); |
+ sgot = htab->root.sgot; |
BFD_ASSERT (sgot != NULL); |
} |
if (srelgot == NULL |
&& (h != NULL || info->shared)) |
{ |
- srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); |
+ srelgot = bfd_get_linker_section (dynobj, ".rela.got"); |
if (srelgot == NULL) |
{ |
- srelgot = bfd_make_section_with_flags (dynobj, |
- ".rela.got", |
- (SEC_ALLOC |
- | SEC_LOAD |
- | SEC_HAS_CONTENTS |
- | SEC_IN_MEMORY |
- | SEC_LINKER_CREATED |
- | SEC_READONLY)); |
+ flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS |
+ | SEC_IN_MEMORY | SEC_LINKER_CREATED |
+ | SEC_READONLY); |
+ srelgot = bfd_make_section_anyway_with_flags (dynobj, |
+ ".rela.got", |
+ flags); |
if (srelgot == NULL |
|| ! bfd_set_section_alignment (dynobj, srelgot, 2)) |
goto fail; |
} |
} |
- if (h != NULL) |
+ if (r_type == R_MN10300_TLS_LD) |
{ |
+ htab->tls_ldm_got.offset = sgot->size; |
+ htab->tls_ldm_got.got_allocated ++; |
+ } |
+ else if (h != NULL) |
+ { |
+ if (elf_mn10300_hash_entry (h)->tls_type != tls_type |
+ && elf_mn10300_hash_entry (h)->tls_type != GOT_UNKNOWN) |
+ { |
+ if (tls_type == GOT_TLS_IE |
+ && elf_mn10300_hash_entry (h)->tls_type == GOT_TLS_GD) |
+ /* No change - this is ok. */; |
+ else if (tls_type == GOT_TLS_GD |
+ && elf_mn10300_hash_entry (h)->tls_type == GOT_TLS_IE) |
+ /* Transition GD->IE. */ |
+ tls_type = GOT_TLS_IE; |
+ else |
+ (*_bfd_error_handler) |
+ (_("%B: %s' accessed both as normal and thread local symbol"), |
+ abfd, h ? h->root.root.string : "<local>"); |
+ } |
+ |
+ elf_mn10300_hash_entry (h)->tls_type = tls_type; |
+ |
if (h->got.offset != (bfd_vma) -1) |
/* We have already allocated space in the .got. */ |
break; |
h->got.offset = sgot->size; |
- /* Make sure this symbol is output as a dynamic symbol. */ |
- if (h->dynindx == -1) |
+ if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL |
+ /* Make sure this symbol is output as a dynamic symbol. */ |
+ && h->dynindx == -1) |
{ |
if (! bfd_elf_link_record_dynamic_symbol (info, h)) |
goto fail; |
} |
srelgot->size += sizeof (Elf32_External_Rela); |
+ if (r_type == R_MN10300_TLS_GD) |
+ srelgot->size += sizeof (Elf32_External_Rela); |
} |
else |
{ |
@@ -806,13 +1239,15 @@ mn10300_elf_check_relocs (bfd *abfd, |
size_t size; |
unsigned int i; |
- size = symtab_hdr->sh_info * sizeof (bfd_vma); |
+ size = symtab_hdr->sh_info * (sizeof (bfd_vma) + sizeof (char)); |
local_got_offsets = bfd_alloc (abfd, size); |
if (local_got_offsets == NULL) |
goto fail; |
elf_local_got_offsets (abfd) = local_got_offsets; |
+ elf_mn10300_local_got_tls_type (abfd) |
+ = (char *) (local_got_offsets + symtab_hdr->sh_info); |
for (i = 0; i < symtab_hdr->sh_info; i++) |
local_got_offsets[i] = (bfd_vma) -1; |
@@ -825,14 +1260,26 @@ mn10300_elf_check_relocs (bfd *abfd, |
local_got_offsets[r_symndx] = sgot->size; |
if (info->shared) |
- /* If we are generating a shared object, we need to |
- output a R_MN10300_RELATIVE reloc so that the dynamic |
- linker can adjust this GOT entry. */ |
- srelgot->size += sizeof (Elf32_External_Rela); |
+ { |
+ /* If we are generating a shared object, we need to |
+ output a R_MN10300_RELATIVE reloc so that the dynamic |
+ linker can adjust this GOT entry. */ |
+ srelgot->size += sizeof (Elf32_External_Rela); |
+ |
+ if (r_type == R_MN10300_TLS_GD) |
+ /* And a R_MN10300_TLS_DTPOFF reloc as well. */ |
+ srelgot->size += sizeof (Elf32_External_Rela); |
+ } |
+ |
+ elf_mn10300_local_got_tls_type (abfd) [r_symndx] = tls_type; |
} |
sgot->size += 4; |
- break; |
+ if (r_type == R_MN10300_TLS_GD |
+ || r_type == R_MN10300_TLS_LD) |
+ sgot->size += 4; |
+ |
+ goto need_shared_relocs; |
case R_MN10300_PLT32: |
case R_MN10300_PLT16: |
@@ -873,6 +1320,7 @@ mn10300_elf_check_relocs (bfd *abfd, |
if (h != NULL) |
h->non_got_ref = 1; |
+ need_shared_relocs: |
/* If we are creating a shared library, then we |
need to copy the reloc into the shared library. */ |
if (info->shared |
@@ -981,6 +1429,7 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto, |
asection *sym_sec ATTRIBUTE_UNUSED, |
int is_local ATTRIBUTE_UNUSED) |
{ |
+ struct elf32_mn10300_link_hash_table * htab = elf32_mn10300_hash_table (info); |
static asection * sym_diff_section; |
static bfd_vma sym_diff_value; |
bfd_boolean is_sym_diff_reloc; |
@@ -1012,6 +1461,17 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto, |
&& h != NULL |
&& ! SYMBOL_REFERENCES_LOCAL (info, h)) |
return bfd_reloc_dangerous; |
+ case R_MN10300_GOT32: |
+ /* Issue 2052223: |
+ Taking the address of a protected function in a shared library |
+ is illegal. Issue an error message here. */ |
+ if (info->shared |
+ && (input_section->flags & SEC_ALLOC) != 0 |
+ && h != NULL |
+ && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED |
+ && (h->type == STT_FUNC || h->type == STT_GNU_IFUNC) |
+ && ! SYMBOL_REFERENCES_LOCAL (info, h)) |
+ return bfd_reloc_dangerous; |
} |
is_sym_diff_reloc = FALSE; |
@@ -1208,9 +1668,11 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto, |
return bfd_reloc_ok; |
case R_MN10300_GOTPC32: |
+ if (dynobj == NULL) |
+ return bfd_reloc_dangerous; |
+ |
/* Use global offset table as symbol value. */ |
- value = bfd_get_section_by_name (dynobj, |
- ".got")->output_section->vma; |
+ value = htab->root.sgot->output_section->vma; |
value -= (input_section->output_section->vma |
+ input_section->output_offset); |
value -= offset; |
@@ -1220,9 +1682,11 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto, |
return bfd_reloc_ok; |
case R_MN10300_GOTPC16: |
+ if (dynobj == NULL) |
+ return bfd_reloc_dangerous; |
+ |
/* Use global offset table as symbol value. */ |
- value = bfd_get_section_by_name (dynobj, |
- ".got")->output_section->vma; |
+ value = htab->root.sgot->output_section->vma; |
value -= (input_section->output_section->vma |
+ input_section->output_offset); |
value -= offset; |
@@ -1235,16 +1699,20 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto, |
return bfd_reloc_ok; |
case R_MN10300_GOTOFF32: |
- value -= bfd_get_section_by_name (dynobj, |
- ".got")->output_section->vma; |
+ if (dynobj == NULL) |
+ return bfd_reloc_dangerous; |
+ |
+ value -= htab->root.sgot->output_section->vma; |
value += addend; |
bfd_put_32 (input_bfd, value, hit_data); |
return bfd_reloc_ok; |
case R_MN10300_GOTOFF24: |
- value -= bfd_get_section_by_name (dynobj, |
- ".got")->output_section->vma; |
+ if (dynobj == NULL) |
+ return bfd_reloc_dangerous; |
+ |
+ value -= htab->root.sgot->output_section->vma; |
value += addend; |
if ((long) value > 0x7fffff || (long) value < -0x800000) |
@@ -1256,8 +1724,10 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto, |
return bfd_reloc_ok; |
case R_MN10300_GOTOFF16: |
- value -= bfd_get_section_by_name (dynobj, |
- ".got")->output_section->vma; |
+ if (dynobj == NULL) |
+ return bfd_reloc_dangerous; |
+ |
+ value -= htab->root.sgot->output_section->vma; |
value += addend; |
if ((long) value > 0x7fff || (long) value < -0x8000) |
@@ -1272,8 +1742,10 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto, |
&& ELF_ST_VISIBILITY (h->other) != STV_HIDDEN |
&& h->plt.offset != (bfd_vma) -1) |
{ |
- splt = bfd_get_section_by_name (dynobj, ".plt"); |
+ if (dynobj == NULL) |
+ return bfd_reloc_dangerous; |
+ splt = htab->root.splt; |
value = (splt->output_section->vma |
+ splt->output_offset |
+ h->plt.offset) - value; |
@@ -1293,8 +1765,10 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto, |
&& ELF_ST_VISIBILITY (h->other) != STV_HIDDEN |
&& h->plt.offset != (bfd_vma) -1) |
{ |
- splt = bfd_get_section_by_name (dynobj, ".plt"); |
+ if (dynobj == NULL) |
+ return bfd_reloc_dangerous; |
+ splt = htab->root.splt; |
value = (splt->output_section->vma |
+ splt->output_offset |
+ h->plt.offset) - value; |
@@ -1311,41 +1785,100 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto, |
bfd_put_16 (input_bfd, value, hit_data); |
return bfd_reloc_ok; |
+ case R_MN10300_TLS_LDO: |
+ value = dtpoff (info, value); |
+ bfd_put_32 (input_bfd, value + addend, hit_data); |
+ return bfd_reloc_ok; |
+ |
+ case R_MN10300_TLS_LE: |
+ value = tpoff (info, value); |
+ bfd_put_32 (input_bfd, value + addend, hit_data); |
+ return bfd_reloc_ok; |
+ |
+ case R_MN10300_TLS_LD: |
+ if (dynobj == NULL) |
+ return bfd_reloc_dangerous; |
+ |
+ sgot = htab->root.sgot; |
+ BFD_ASSERT (sgot != NULL); |
+ value = htab->tls_ldm_got.offset + sgot->output_offset; |
+ bfd_put_32 (input_bfd, value, hit_data); |
+ |
+ if (!htab->tls_ldm_got.rel_emitted) |
+ { |
+ asection * srelgot = bfd_get_linker_section (dynobj, ".rela.got"); |
+ Elf_Internal_Rela rel; |
+ |
+ BFD_ASSERT (srelgot != NULL); |
+ htab->tls_ldm_got.rel_emitted ++; |
+ rel.r_offset = (sgot->output_section->vma |
+ + sgot->output_offset |
+ + htab->tls_ldm_got.offset); |
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + htab->tls_ldm_got.offset); |
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + htab->tls_ldm_got.offset+4); |
+ rel.r_info = ELF32_R_INFO (0, R_MN10300_TLS_DTPMOD); |
+ rel.r_addend = 0; |
+ bfd_elf32_swap_reloca_out (output_bfd, & rel, |
+ (bfd_byte *) ((Elf32_External_Rela *) srelgot->contents |
+ + srelgot->reloc_count)); |
+ ++ srelgot->reloc_count; |
+ } |
+ |
+ return bfd_reloc_ok; |
+ |
+ case R_MN10300_TLS_GOTIE: |
+ value = tpoff (info, value); |
+ /* Fall Through. */ |
+ |
+ case R_MN10300_TLS_GD: |
+ case R_MN10300_TLS_IE: |
case R_MN10300_GOT32: |
case R_MN10300_GOT24: |
case R_MN10300_GOT16: |
- { |
- sgot = bfd_get_section_by_name (dynobj, ".got"); |
+ if (dynobj == NULL) |
+ return bfd_reloc_dangerous; |
- if (h != NULL) |
- { |
- bfd_vma off; |
+ sgot = htab->root.sgot; |
+ if (r_type == R_MN10300_TLS_GD) |
+ value = dtpoff (info, value); |
+ |
+ if (h != NULL) |
+ { |
+ bfd_vma off; |
+ |
+ off = h->got.offset; |
+ /* Offsets in the GOT are allocated in check_relocs |
+ which is not called for shared libraries... */ |
+ if (off == (bfd_vma) -1) |
+ off = 0; |
+ |
+ if (sgot->contents != NULL |
+ && (! elf_hash_table (info)->dynamic_sections_created |
+ || SYMBOL_REFERENCES_LOCAL (info, h))) |
+ /* This is actually a static link, or it is a |
+ -Bsymbolic link and the symbol is defined |
+ locally, or the symbol was forced to be local |
+ because of a version file. We must initialize |
+ this entry in the global offset table. |
+ |
+ When doing a dynamic link, we create a .rela.got |
+ relocation entry to initialize the value. This |
+ is done in the finish_dynamic_symbol routine. */ |
+ bfd_put_32 (output_bfd, value, |
+ sgot->contents + off); |
+ |
+ value = sgot->output_offset + off; |
+ } |
+ else |
+ { |
+ bfd_vma off; |
- off = h->got.offset; |
- BFD_ASSERT (off != (bfd_vma) -1); |
+ off = elf_local_got_offsets (input_bfd)[symndx]; |
- if (! elf_hash_table (info)->dynamic_sections_created |
- || SYMBOL_REFERENCES_LOCAL (info, h)) |
- /* This is actually a static link, or it is a |
- -Bsymbolic link and the symbol is defined |
- locally, or the symbol was forced to be local |
- because of a version file. We must initialize |
- this entry in the global offset table. |
- |
- When doing a dynamic link, we create a .rela.got |
- relocation entry to initialize the value. This |
- is done in the finish_dynamic_symbol routine. */ |
- bfd_put_32 (output_bfd, value, |
- sgot->contents + off); |
- |
- value = sgot->output_offset + off; |
- } |
+ if (off & 1) |
+ bfd_put_32 (output_bfd, value, sgot->contents + (off & ~ 1)); |
else |
{ |
- bfd_vma off; |
- |
- off = elf_local_got_offsets (input_bfd)[symndx]; |
- |
bfd_put_32 (output_bfd, value, sgot->contents + off); |
if (info->shared) |
@@ -1353,28 +1886,64 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto, |
asection * srelgot; |
Elf_Internal_Rela outrel; |
- srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); |
+ srelgot = bfd_get_linker_section (dynobj, ".rela.got"); |
BFD_ASSERT (srelgot != NULL); |
outrel.r_offset = (sgot->output_section->vma |
+ sgot->output_offset |
+ off); |
- outrel.r_info = ELF32_R_INFO (0, R_MN10300_RELATIVE); |
+ switch (r_type) |
+ { |
+ case R_MN10300_TLS_GD: |
+ outrel.r_info = ELF32_R_INFO (0, R_MN10300_TLS_DTPOFF); |
+ outrel.r_offset = (sgot->output_section->vma |
+ + sgot->output_offset |
+ + off + 4); |
+ bfd_elf32_swap_reloca_out (output_bfd, & outrel, |
+ (bfd_byte *) (((Elf32_External_Rela *) |
+ srelgot->contents) |
+ + srelgot->reloc_count)); |
+ ++ srelgot->reloc_count; |
+ outrel.r_info = ELF32_R_INFO (0, R_MN10300_TLS_DTPMOD); |
+ break; |
+ case R_MN10300_TLS_GOTIE: |
+ case R_MN10300_TLS_IE: |
+ outrel.r_info = ELF32_R_INFO (0, R_MN10300_TLS_TPOFF); |
+ break; |
+ default: |
+ outrel.r_info = ELF32_R_INFO (0, R_MN10300_RELATIVE); |
+ break; |
+ } |
+ |
outrel.r_addend = value; |
bfd_elf32_swap_reloca_out (output_bfd, &outrel, |
(bfd_byte *) (((Elf32_External_Rela *) |
srelgot->contents) |
+ srelgot->reloc_count)); |
++ srelgot->reloc_count; |
+ elf_local_got_offsets (input_bfd)[symndx] |= 1; |
} |
- value = sgot->output_offset + off; |
+ value = sgot->output_offset + (off & ~(bfd_vma) 1); |
} |
- } |
+ } |
value += addend; |
- if (r_type == R_MN10300_GOT32) |
+ if (r_type == R_MN10300_TLS_IE) |
+ { |
+ value += sgot->output_section->vma; |
+ bfd_put_32 (input_bfd, value, hit_data); |
+ return bfd_reloc_ok; |
+ } |
+ else if (r_type == R_MN10300_TLS_GOTIE |
+ || r_type == R_MN10300_TLS_GD |
+ || r_type == R_MN10300_TLS_LD) |
+ { |
+ bfd_put_32 (input_bfd, value, hit_data); |
+ return bfd_reloc_ok; |
+ } |
+ else if (r_type == R_MN10300_GOT32) |
{ |
bfd_put_32 (input_bfd, value, hit_data); |
return bfd_reloc_ok; |
@@ -1419,6 +1988,7 @@ mn10300_elf_relocate_section (bfd *output_bfd, |
Elf_Internal_Shdr *symtab_hdr; |
struct elf_link_hash_entry **sym_hashes; |
Elf_Internal_Rela *rel, *relend; |
+ Elf_Internal_Rela * trel; |
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; |
sym_hashes = elf_sym_hashes (input_bfd); |
@@ -1435,7 +2005,12 @@ mn10300_elf_relocate_section (bfd *output_bfd, |
struct elf32_mn10300_link_hash_entry *h; |
bfd_vma relocation; |
bfd_reloc_status_type r; |
+ int tls_r_type; |
+ bfd_boolean unresolved_reloc = FALSE; |
+ bfd_boolean warned; |
+ struct elf_link_hash_entry * hh; |
+ relocation = 0; |
r_symndx = ELF32_R_SYM (rel->r_info); |
r_type = ELF32_R_TYPE (rel->r_info); |
howto = elf_mn10300_howto_table + r_type; |
@@ -1449,24 +2024,42 @@ mn10300_elf_relocate_section (bfd *output_bfd, |
sym = NULL; |
sec = NULL; |
if (r_symndx < symtab_hdr->sh_info) |
- { |
- sym = local_syms + r_symndx; |
- sec = local_sections[r_symndx]; |
- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); |
- } |
+ hh = NULL; |
else |
{ |
- bfd_boolean unresolved_reloc; |
- bfd_boolean warned; |
- struct elf_link_hash_entry *hh; |
- |
RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, |
r_symndx, symtab_hdr, sym_hashes, |
hh, sec, relocation, |
unresolved_reloc, warned); |
+ } |
+ h = elf_mn10300_hash_entry (hh); |
- h = (struct elf32_mn10300_link_hash_entry *) hh; |
+ tls_r_type = elf_mn10300_tls_transition (info, r_type, hh, input_section, 0); |
+ if (tls_r_type != r_type) |
+ { |
+ bfd_boolean had_plt; |
+ |
+ had_plt = mn10300_do_tls_transition (input_bfd, r_type, tls_r_type, |
+ contents, rel->r_offset); |
+ r_type = tls_r_type; |
+ howto = elf_mn10300_howto_table + r_type; |
+ |
+ if (had_plt) |
+ for (trel = rel+1; trel < relend; trel++) |
+ if ((ELF32_R_TYPE (trel->r_info) == R_MN10300_PLT32 |
+ || ELF32_R_TYPE (trel->r_info) == R_MN10300_PCREL32) |
+ && rel->r_offset + had_plt == trel->r_offset) |
+ trel->r_info = ELF32_R_INFO (0, R_MN10300_NONE); |
+ } |
+ if (r_symndx < symtab_hdr->sh_info) |
+ { |
+ sym = local_syms + r_symndx; |
+ sec = local_sections[r_symndx]; |
+ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); |
+ } |
+ else |
+ { |
if ((h->root.root.type == bfd_link_hash_defined |
|| h->root.root.type == bfd_link_hash_defweak) |
&& ( r_type == R_MN10300_GOTPC32 |
@@ -1478,6 +2071,10 @@ mn10300_elf_relocate_section (bfd *output_bfd, |
&& h->root.plt.offset != (bfd_vma) -1) |
|| (( r_type == R_MN10300_GOT32 |
|| r_type == R_MN10300_GOT24 |
+ || r_type == R_MN10300_TLS_GD |
+ || r_type == R_MN10300_TLS_LD |
+ || r_type == R_MN10300_TLS_GOTIE |
+ || r_type == R_MN10300_TLS_IE |
|| r_type == R_MN10300_GOT16) |
&& elf_hash_table (info)->dynamic_sections_created |
&& !SYMBOL_REFERENCES_LOCAL (info, hh)) |
@@ -1512,9 +2109,9 @@ mn10300_elf_relocate_section (bfd *output_bfd, |
h->root.root.root.string); |
} |
- if (sec != NULL && elf_discarded_section (sec)) |
+ if (sec != NULL && discarded_section (sec)) |
RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, |
- rel, relend, howto, contents); |
+ rel, 1, relend, howto, 0, contents); |
if (info->relocatable) |
continue; |
@@ -1571,6 +2168,9 @@ mn10300_elf_relocate_section (bfd *output_bfd, |
if (r_type == R_MN10300_PCREL32) |
msg = _("error: inappropriate relocation type for shared" |
" library (did you forget -fpic?)"); |
+ else if (r_type == R_MN10300_GOT32) |
+ msg = _("%B: taking the address of protected function" |
+ " '%s' cannot be done when making a shared library"); |
else |
msg = _("internal error: suspicious relocation type used" |
" in shared library"); |
@@ -1581,11 +2181,9 @@ mn10300_elf_relocate_section (bfd *output_bfd, |
/* Fall through. */ |
common_error: |
- if (!((*info->callbacks->warning) |
- (info, msg, name, input_bfd, input_section, |
- rel->r_offset))) |
- return FALSE; |
- break; |
+ _bfd_error_handler (msg, input_bfd, name); |
+ bfd_set_error (bfd_error_bad_value); |
+ return FALSE; |
} |
} |
} |
@@ -2581,6 +3179,7 @@ mn10300_elf_relax_section (bfd *abfd, |
{ |
int bytes = 0; |
bfd_vma symval; |
+ struct elf_link_hash_entry **hh; |
/* Note that we've changed things. */ |
elf_section_data (section)->relocs = internal_relocs; |
@@ -2611,6 +3210,25 @@ mn10300_elf_relax_section (bfd *abfd, |
bytes)) |
goto error_return; |
+ /* There may be other C++ functions symbols with the same |
+ address. If so then mark these as having had their |
+ prologue bytes deleted as well. */ |
+ for (hh = elf_sym_hashes (input_bfd); hh < end_hashes; hh++) |
+ { |
+ struct elf32_mn10300_link_hash_entry *h; |
+ |
+ h = (struct elf32_mn10300_link_hash_entry *) * hh; |
+ |
+ if (h != sym_hash |
+ && (h->root.root.type == bfd_link_hash_defined |
+ || h->root.root.type == bfd_link_hash_defweak) |
+ && h->root.root.u.def.section == section |
+ && ! (h->flags & MN10300_CONVERT_CALL_TO_CALLS) |
+ && h->root.root.u.def.value == symval |
+ && h->root.type == STT_FUNC) |
+ h->flags |= MN10300_DELETED_PROLOGUE_BYTES; |
+ } |
+ |
/* Something changed. Not strictly necessary, but |
may lead to more relaxing opportunities. */ |
*again = TRUE; |
@@ -2766,7 +3384,7 @@ mn10300_elf_relax_section (bfd *abfd, |
isym->st_name); |
if ((sym_sec->flags & SEC_MERGE) |
- && sym_sec->sec_info_type == ELF_INFO_TYPE_MERGE) |
+ && sym_sec->sec_info_type == SEC_INFO_TYPE_MERGE) |
{ |
symval = isym->st_value; |
@@ -2862,9 +3480,7 @@ mn10300_elf_relax_section (bfd *abfd, |
{ |
asection * splt; |
- splt = bfd_get_section_by_name (elf_hash_table (link_info) |
- ->dynobj, ".plt"); |
- |
+ splt = hash_table->root.splt; |
value = ((splt->output_section->vma |
+ splt->output_offset |
+ h->root.plt.offset) |
@@ -3304,9 +3920,7 @@ mn10300_elf_relax_section (bfd *abfd, |
{ |
asection * sgot; |
- sgot = bfd_get_section_by_name (elf_hash_table (link_info) |
- ->dynobj, ".got"); |
- |
+ sgot = hash_table->root.sgot; |
if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_GOT32) |
{ |
value = sgot->output_offset; |
@@ -3949,11 +4563,38 @@ elf32_mn10300_link_hash_newfunc (struct bfd_hash_entry *entry, |
ret->movm_stack_size = 0; |
ret->flags = 0; |
ret->value = 0; |
+ ret->tls_type = GOT_UNKNOWN; |
} |
return (struct bfd_hash_entry *) ret; |
} |
+static void |
+_bfd_mn10300_copy_indirect_symbol (struct bfd_link_info * info, |
+ struct elf_link_hash_entry * dir, |
+ struct elf_link_hash_entry * ind) |
+{ |
+ struct elf32_mn10300_link_hash_entry * edir; |
+ struct elf32_mn10300_link_hash_entry * eind; |
+ |
+ edir = elf_mn10300_hash_entry (dir); |
+ eind = elf_mn10300_hash_entry (ind); |
+ |
+ if (ind->root.type == bfd_link_hash_indirect |
+ && dir->got.refcount <= 0) |
+ { |
+ edir->tls_type = eind->tls_type; |
+ eind->tls_type = GOT_UNKNOWN; |
+ } |
+ edir->direct_calls = eind->direct_calls; |
+ edir->stack_size = eind->stack_size; |
+ edir->movm_args = eind->movm_args; |
+ edir->movm_stack_size = eind->movm_stack_size; |
+ edir->flags = eind->flags; |
+ |
+ _bfd_elf_link_hash_copy_indirect (info, dir, ind); |
+} |
+ |
/* Create an mn10300 ELF linker hash table. */ |
static struct bfd_link_hash_table * |
@@ -3976,6 +4617,11 @@ elf32_mn10300_link_hash_table_create (bfd *abfd) |
} |
ret->flags = 0; |
+ ret->tls_ldm_got.refcount = 0; |
+ ret->tls_ldm_got.offset = -1; |
+ ret->tls_ldm_got.got_allocated = 0; |
+ ret->tls_ldm_got.rel_emitted = 0; |
+ |
amt = sizeof (struct elf_link_hash_table); |
ret->static_hash_table = bfd_malloc (amt); |
if (ret->static_hash_table == NULL) |
@@ -4154,6 +4800,7 @@ _bfd_mn10300_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) |
flagword flags; |
asection * s; |
const struct elf_backend_data * bed = get_elf_backend_data (abfd); |
+ struct elf32_mn10300_link_hash_table *htab = elf32_mn10300_hash_table (info); |
int ptralign = 0; |
switch (bed->s->arch_size) |
@@ -4176,10 +4823,11 @@ _bfd_mn10300_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) |
flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY |
| SEC_LINKER_CREATED); |
- s = bfd_make_section_with_flags (abfd, |
- (bed->default_use_rela_p |
- ? ".rela.plt" : ".rel.plt"), |
- flags | SEC_READONLY); |
+ s = bfd_make_section_anyway_with_flags (abfd, |
+ (bed->default_use_rela_p |
+ ? ".rela.plt" : ".rel.plt"), |
+ flags | SEC_READONLY); |
+ htab->root.srelplt = s; |
if (s == NULL |
|| ! bfd_set_section_alignment (abfd, s, ptralign)) |
return FALSE; |
@@ -4187,32 +4835,6 @@ _bfd_mn10300_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) |
if (! _bfd_mn10300_elf_create_got_section (abfd, info)) |
return FALSE; |
- { |
- const char * secname; |
- char * relname; |
- flagword secflags; |
- asection * sec; |
- |
- for (sec = abfd->sections; sec; sec = sec->next) |
- { |
- secflags = bfd_get_section_flags (abfd, sec); |
- if ((secflags & (SEC_DATA | SEC_LINKER_CREATED)) |
- || ((secflags & SEC_HAS_CONTENTS) != SEC_HAS_CONTENTS)) |
- continue; |
- |
- secname = bfd_get_section_name (abfd, sec); |
- relname = bfd_malloc (strlen (secname) + 6); |
- strcpy (relname, ".rela"); |
- strcat (relname, secname); |
- |
- s = bfd_make_section_with_flags (abfd, relname, |
- flags | SEC_READONLY); |
- if (s == NULL |
- || ! bfd_set_section_alignment (abfd, s, ptralign)) |
- return FALSE; |
- } |
- } |
- |
if (bed->want_dynbss) |
{ |
/* The .dynbss section is a place to put symbols which are defined |
@@ -4221,8 +4843,8 @@ _bfd_mn10300_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) |
image and use a R_*_COPY reloc to tell the dynamic linker to |
initialize them at run time. The linker script puts the .dynbss |
section into the .bss section of the final image. */ |
- s = bfd_make_section_with_flags (abfd, ".dynbss", |
- SEC_ALLOC | SEC_LINKER_CREATED); |
+ s = bfd_make_section_anyway_with_flags (abfd, ".dynbss", |
+ SEC_ALLOC | SEC_LINKER_CREATED); |
if (s == NULL) |
return FALSE; |
@@ -4239,10 +4861,10 @@ _bfd_mn10300_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) |
copy relocs. */ |
if (! info->shared) |
{ |
- s = bfd_make_section_with_flags (abfd, |
- (bed->default_use_rela_p |
- ? ".rela.bss" : ".rel.bss"), |
- flags | SEC_READONLY); |
+ s = bfd_make_section_anyway_with_flags (abfd, |
+ (bed->default_use_rela_p |
+ ? ".rela.bss" : ".rel.bss"), |
+ flags | SEC_READONLY); |
if (s == NULL |
|| ! bfd_set_section_alignment (abfd, s, ptralign)) |
return FALSE; |
@@ -4262,10 +4884,11 @@ static bfd_boolean |
_bfd_mn10300_elf_adjust_dynamic_symbol (struct bfd_link_info * info, |
struct elf_link_hash_entry * h) |
{ |
+ struct elf32_mn10300_link_hash_table *htab = elf32_mn10300_hash_table (info); |
bfd * dynobj; |
asection * s; |
- dynobj = elf_hash_table (info)->dynobj; |
+ dynobj = htab->root.dynobj; |
/* Make sure we know what is going on here. */ |
BFD_ASSERT (dynobj != NULL |
@@ -4301,7 +4924,7 @@ _bfd_mn10300_elf_adjust_dynamic_symbol (struct bfd_link_info * info, |
return FALSE; |
} |
- s = bfd_get_section_by_name (dynobj, ".plt"); |
+ s = htab->root.splt; |
BFD_ASSERT (s != NULL); |
/* If this is the first .plt entry, make room for the special |
@@ -4328,12 +4951,12 @@ _bfd_mn10300_elf_adjust_dynamic_symbol (struct bfd_link_info * info, |
/* We also need to make an entry in the .got.plt section, which |
will be placed in the .got section by the linker script. */ |
- s = bfd_get_section_by_name (dynobj, ".got.plt"); |
+ s = htab->root.sgotplt; |
BFD_ASSERT (s != NULL); |
s->size += 4; |
/* We also need to make an entry in the .rela.plt section. */ |
- s = bfd_get_section_by_name (dynobj, ".rela.plt"); |
+ s = bfd_get_linker_section (dynobj, ".rela.plt"); |
BFD_ASSERT (s != NULL); |
s->size += sizeof (Elf32_External_Rela); |
@@ -4367,13 +4990,6 @@ _bfd_mn10300_elf_adjust_dynamic_symbol (struct bfd_link_info * info, |
if (!h->non_got_ref) |
return TRUE; |
- if (h->size == 0) |
- { |
- (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"), |
- h->root.root.string); |
- return TRUE; |
- } |
- |
/* We must allocate the symbol in our .dynbss section, which will |
become part of the .bss section of the executable. There will be |
an entry for this symbol in the .dynsym section. The dynamic |
@@ -4384,18 +5000,18 @@ _bfd_mn10300_elf_adjust_dynamic_symbol (struct bfd_link_info * info, |
both the dynamic object and the regular object will refer to the |
same memory location for the variable. */ |
- s = bfd_get_section_by_name (dynobj, ".dynbss"); |
+ s = bfd_get_linker_section (dynobj, ".dynbss"); |
BFD_ASSERT (s != NULL); |
/* We must generate a R_MN10300_COPY reloc to tell the dynamic linker to |
copy the initial value out of the dynamic object and into the |
runtime process image. We need to remember the offset into the |
.rela.bss section we are going to use. */ |
- if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) |
+ if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) |
{ |
asection * srel; |
- srel = bfd_get_section_by_name (dynobj, ".rela.bss"); |
+ srel = bfd_get_linker_section (dynobj, ".rela.bss"); |
BFD_ASSERT (srel != NULL); |
srel->size += sizeof (Elf32_External_Rela); |
h->needs_copy = 1; |
@@ -4410,13 +5026,14 @@ static bfd_boolean |
_bfd_mn10300_elf_size_dynamic_sections (bfd * output_bfd, |
struct bfd_link_info * info) |
{ |
+ struct elf32_mn10300_link_hash_table *htab = elf32_mn10300_hash_table (info); |
bfd * dynobj; |
asection * s; |
bfd_boolean plt; |
bfd_boolean relocs; |
bfd_boolean reltext; |
- dynobj = elf_hash_table (info)->dynobj; |
+ dynobj = htab->root.dynobj; |
BFD_ASSERT (dynobj != NULL); |
if (elf_hash_table (info)->dynamic_sections_created) |
@@ -4424,7 +5041,7 @@ _bfd_mn10300_elf_size_dynamic_sections (bfd * output_bfd, |
/* Set the contents of the .interp section to the interpreter. */ |
if (info->executable) |
{ |
- s = bfd_get_section_by_name (dynobj, ".interp"); |
+ s = bfd_get_linker_section (dynobj, ".interp"); |
BFD_ASSERT (s != NULL); |
s->size = sizeof ELF_DYNAMIC_INTERPRETER; |
s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; |
@@ -4437,11 +5054,18 @@ _bfd_mn10300_elf_size_dynamic_sections (bfd * output_bfd, |
not actually use these entries. Reset the size of .rela.got, |
which will cause it to get stripped from the output file |
below. */ |
- s = bfd_get_section_by_name (dynobj, ".rela.got"); |
+ s = htab->root.sgot; |
if (s != NULL) |
s->size = 0; |
} |
+ if (htab->tls_ldm_got.refcount > 0) |
+ { |
+ s = bfd_get_linker_section (dynobj, ".rela.got"); |
+ BFD_ASSERT (s != NULL); |
+ s->size += sizeof (Elf32_External_Rela); |
+ } |
+ |
/* The check_relocs and adjust_dynamic_symbol entry points have |
determined the sizes of the various dynamic sections. Allocate |
memory for them. */ |
@@ -4580,9 +5204,10 @@ _bfd_mn10300_elf_finish_dynamic_symbol (bfd * output_bfd, |
struct elf_link_hash_entry * h, |
Elf_Internal_Sym * sym) |
{ |
+ struct elf32_mn10300_link_hash_table *htab = elf32_mn10300_hash_table (info); |
bfd * dynobj; |
- dynobj = elf_hash_table (info)->dynobj; |
+ dynobj = htab->root.dynobj; |
if (h->plt.offset != (bfd_vma) -1) |
{ |
@@ -4598,9 +5223,9 @@ _bfd_mn10300_elf_finish_dynamic_symbol (bfd * output_bfd, |
BFD_ASSERT (h->dynindx != -1); |
- splt = bfd_get_section_by_name (dynobj, ".plt"); |
- sgot = bfd_get_section_by_name (dynobj, ".got.plt"); |
- srel = bfd_get_section_by_name (dynobj, ".rela.plt"); |
+ splt = htab->root.splt; |
+ sgot = htab->root.sgotplt; |
+ srel = bfd_get_linker_section (dynobj, ".rela.plt"); |
BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL); |
/* Get the index in the procedure linkage table which |
@@ -4677,39 +5302,72 @@ _bfd_mn10300_elf_finish_dynamic_symbol (bfd * output_bfd, |
Elf_Internal_Rela rel; |
/* This symbol has an entry in the global offset table. Set it up. */ |
- sgot = bfd_get_section_by_name (dynobj, ".got"); |
- srel = bfd_get_section_by_name (dynobj, ".rela.got"); |
+ sgot = htab->root.sgot; |
+ srel = bfd_get_linker_section (dynobj, ".rela.got"); |
BFD_ASSERT (sgot != NULL && srel != NULL); |
rel.r_offset = (sgot->output_section->vma |
+ sgot->output_offset |
+ (h->got.offset & ~1)); |
- /* If this is a -Bsymbolic link, and the symbol is defined |
- locally, we just want to emit a RELATIVE reloc. Likewise if |
- the symbol was forced to be local because of a version file. |
- The entry in the global offset table will already have been |
- initialized in the relocate_section function. */ |
- if (info->shared |
- && (info->symbolic || h->dynindx == -1) |
- && h->def_regular) |
- { |
- rel.r_info = ELF32_R_INFO (0, R_MN10300_RELATIVE); |
- rel.r_addend = (h->root.u.def.value |
- + h->root.u.def.section->output_section->vma |
- + h->root.u.def.section->output_offset); |
- } |
- else |
+ switch (elf_mn10300_hash_entry (h)->tls_type) |
{ |
+ case GOT_TLS_GD: |
bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset); |
- rel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_GLOB_DAT); |
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset + 4); |
+ rel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_TLS_DTPMOD); |
rel.r_addend = 0; |
+ bfd_elf32_swap_reloca_out (output_bfd, & rel, |
+ (bfd_byte *) ((Elf32_External_Rela *) srel->contents |
+ + srel->reloc_count)); |
+ ++ srel->reloc_count; |
+ rel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_TLS_DTPOFF); |
+ rel.r_offset += 4; |
+ rel.r_addend = 0; |
+ break; |
+ |
+ case GOT_TLS_IE: |
+ /* We originally stored the addend in the GOT, but at this |
+ point, we want to move it to the reloc instead as that's |
+ where the dynamic linker wants it. */ |
+ rel.r_addend = bfd_get_32 (output_bfd, sgot->contents + h->got.offset); |
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset); |
+ if (h->dynindx == -1) |
+ rel.r_info = ELF32_R_INFO (0, R_MN10300_TLS_TPOFF); |
+ else |
+ rel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_TLS_TPOFF); |
+ break; |
+ |
+ default: |
+ /* If this is a -Bsymbolic link, and the symbol is defined |
+ locally, we just want to emit a RELATIVE reloc. Likewise if |
+ the symbol was forced to be local because of a version file. |
+ The entry in the global offset table will already have been |
+ initialized in the relocate_section function. */ |
+ if (info->shared |
+ && (info->symbolic || h->dynindx == -1) |
+ && h->def_regular) |
+ { |
+ rel.r_info = ELF32_R_INFO (0, R_MN10300_RELATIVE); |
+ rel.r_addend = (h->root.u.def.value |
+ + h->root.u.def.section->output_section->vma |
+ + h->root.u.def.section->output_offset); |
+ } |
+ else |
+ { |
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset); |
+ rel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_GLOB_DAT); |
+ rel.r_addend = 0; |
+ } |
} |
- bfd_elf32_swap_reloca_out (output_bfd, &rel, |
- (bfd_byte *) ((Elf32_External_Rela *) srel->contents |
- + srel->reloc_count)); |
- ++ srel->reloc_count; |
+ if (ELF32_R_TYPE (rel.r_info) != R_MN10300_NONE) |
+ { |
+ bfd_elf32_swap_reloca_out (output_bfd, &rel, |
+ (bfd_byte *) ((Elf32_External_Rela *) srel->contents |
+ + srel->reloc_count)); |
+ ++ srel->reloc_count; |
+ } |
} |
if (h->needs_copy) |
@@ -4722,8 +5380,7 @@ _bfd_mn10300_elf_finish_dynamic_symbol (bfd * output_bfd, |
&& (h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak)); |
- s = bfd_get_section_by_name (h->root.u.def.section->owner, |
- ".rela.bss"); |
+ s = bfd_get_linker_section (dynobj, ".rela.bss"); |
BFD_ASSERT (s != NULL); |
rel.r_offset = (h->root.u.def.value |
@@ -4754,12 +5411,12 @@ _bfd_mn10300_elf_finish_dynamic_sections (bfd * output_bfd, |
bfd * dynobj; |
asection * sgot; |
asection * sdyn; |
+ struct elf32_mn10300_link_hash_table *htab = elf32_mn10300_hash_table (info); |
- dynobj = elf_hash_table (info)->dynobj; |
- |
- sgot = bfd_get_section_by_name (dynobj, ".got.plt"); |
+ dynobj = htab->root.dynobj; |
+ sgot = htab->root.sgotplt; |
BFD_ASSERT (sgot != NULL); |
- sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); |
+ sdyn = bfd_get_linker_section (dynobj, ".dynamic"); |
if (elf_hash_table (info)->dynamic_sections_created) |
{ |
@@ -4824,7 +5481,7 @@ _bfd_mn10300_elf_finish_dynamic_sections (bfd * output_bfd, |
} |
/* Fill in the first entry in the procedure linkage table. */ |
- splt = bfd_get_section_by_name (dynobj, ".plt"); |
+ splt = htab->root.splt; |
if (splt && splt->size > 0) |
{ |
if (info->shared) |
@@ -4846,6 +5503,14 @@ _bfd_mn10300_elf_finish_dynamic_sections (bfd * output_bfd, |
/* UnixWare sets the entsize of .plt to 4, although that doesn't |
really seem like the right value. */ |
elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4; |
+ |
+ /* UnixWare sets the entsize of .plt to 4, but this is incorrect |
+ as it means that the size of the PLT0 section (15 bytes) is not |
+ a multiple of the sh_entsize. Some ELF tools flag this as an |
+ error. We could pad PLT0 to 16 bytes, but that would introduce |
+ compatibilty issues with previous toolchains, so instead we |
+ just set the entry size to 1. */ |
+ elf_section_data (splt->output_section)->this_hdr.sh_entsize = 1; |
} |
} |
@@ -4887,12 +5552,7 @@ _bfd_mn10300_elf_reloc_type_class (const Elf_Internal_Rela *rela) |
static bfd_boolean |
mn10300_elf_mkobject (bfd *abfd) |
{ |
- /* We do not actually need any extra room in the bfd elf data structure. |
- But we do need the object_id of the structure to be set to |
- MN10300_ELF_DATA so that elflink.c:elf_link_add_object_symols() will call |
- our mn10300_elf_check_relocs function which will then allocate space in |
- the .got section for any GOT based relocs. */ |
- return bfd_elf_allocate_object (abfd, sizeof (struct elf_obj_tdata), |
+ return bfd_elf_allocate_object (abfd, sizeof (struct elf_mn10300_obj_tdata), |
MN10300_ELF_DATA); |
} |
@@ -4948,7 +5608,8 @@ mn10300_elf_mkobject (bfd *abfd) |
_bfd_mn10300_elf_finish_dynamic_symbol |
#define elf_backend_finish_dynamic_sections \ |
_bfd_mn10300_elf_finish_dynamic_sections |
- |
+#define elf_backend_copy_indirect_symbol \ |
+ _bfd_mn10300_copy_indirect_symbol |
#define elf_backend_reloc_type_class \ |
_bfd_mn10300_elf_reloc_type_class |