Index: bfd/elf64-x86-64.c |
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c |
index bb76be6e4fa857fd15801fab1e29a06809062fb2..63f1b0be1264d2910bbf379ef4991df72b3bd721 100644 |
--- a/bfd/elf64-x86-64.c |
+++ b/bfd/elf64-x86-64.c |
@@ -900,6 +900,14 @@ elf64_x86_64_check_tls_transition (bfd *abfd, asection *sec, |
if ((rel + 1) >= relend) |
return FALSE; |
+ /* Check transition from GD or LD access model. |
+ lea foo@tlsgd/tlsld(%rip), %rdi |
+ nop* |
+ call __tls_get_addr |
+ can transit to different access model. */ |
+ |
+ /* NACLHACK: we hope for the best and check nothing! */ |
+#if 0 |
if (r_type == R_X86_64_TLSGD) |
{ |
/* Check transition from GD access model. Only |
@@ -933,6 +941,7 @@ elf64_x86_64_check_tls_transition (bfd *abfd, asection *sec, |
if (op.i != ld.i) |
return FALSE; |
} |
+#endif |
r_symndx = ELF64_R_SYM (rel[1].r_info); |
if (r_symndx < symtab_hdr->sh_info) |
@@ -976,6 +985,7 @@ elf64_x86_64_check_tls_transition (bfd *abfd, asection *sec, |
val = bfd_get_8 (abfd, contents + offset - 2); |
if (val != 0x8b && val != 0x03) |
return FALSE; |
+#endif |
val = bfd_get_8 (abfd, contents + offset - 1); |
return (val & 0xc7) == 5; |
@@ -1139,6 +1149,28 @@ elf64_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd, |
return TRUE; |
} |
+/* NACLHACK: add reference to __nacl_add_tp (or __nacl_read_tp) symbol. */ |
+static struct elf_link_hash_entry * |
+nacl_add_tp_symbol (struct bfd_link_info *info, const char* name) |
+{ |
+ struct elf_link_hash_entry *h; |
+ struct bfd_link_hash_entry *bh = NULL; |
+ |
+ if (!(_bfd_generic_link_add_one_symbol |
+ (info, info->output_bfd, name, BSF_GLOBAL, |
+ bfd_und_section_ptr, (bfd_vma) 0, NULL, TRUE, |
+ FALSE, &bh))) |
+ return NULL; |
+ |
+ h = (struct elf_link_hash_entry *) bh; |
+ h->needs_plt = 1; |
+ h->plt.refcount += 1; |
+ return h; |
+} |
+ |
+static struct elf_link_hash_entry *nacl_add_tp_entry = NULL; |
+static struct elf_link_hash_entry *nacl_read_tp_entry = NULL; |
+ |
/* Look through the relocs for a section during the first phase, and |
calculate needed space in the global offset table, procedure |
linkage table, and dynamic reloc sections. */ |
@@ -2660,6 +2692,9 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, |
Elf_Internal_Rela *rel; |
Elf_Internal_Rela *relend; |
+ /* NACLHACK: new variable for NACL rewrites. */ |
+ struct elf_link_hash_entry *h_subst = NULL; |
+ |
BFD_ASSERT (is_x86_64_elf (input_bfd)); |
htab = elf64_x86_64_hash_table (info); |
@@ -2726,6 +2761,27 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, |
h->root.u.def.section = sec; |
} |
} |
+ else if (h_subst) |
+ { |
+ /* NACLHACK: Replace symbol to relocate. |
+ |
+ This is somewhat hacky, as relies on not using r_symndx any more, |
+ which is currently true for R_X86_64_PLT32 involved in NaCl TLS |
+ code sequences. |
+ |
+ Doing this in a more reliable way means either splitting this |
+ glorious function or copy-pasting code that processes relocations |
+ of interest. Any volunteers? */ |
+ |
+ bfd_boolean warned; |
+ |
+ h = h_subst; |
+ h_subst = NULL; |
+ |
+ RELOC_FOR_GLOBAL_SYM_HASH (info, input_bfd, input_section, rel, |
+ h, sec, relocation, |
+ unresolved_reloc, warned); |
+ } |
else |
{ |
bfd_boolean warned; |
@@ -3380,6 +3436,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, |
contents + roff + 8); |
/* Skip R_X86_64_PC32/R_X86_64_PLT32. */ |
rel++; |
+#endif |
continue; |
} |
else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC) |
@@ -3628,6 +3685,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, |
contents + roff + 8); |
/* Skip R_X86_64_PLT32. */ |
rel++; |
+#endif |
continue; |
} |
else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC) |
@@ -3694,6 +3752,15 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, |
if (r_type != R_X86_64_TLSLD) |
{ |
+ /* NACLHACK: use __nacl_add_tp instead of __tls_get_addr. */ |
+ /* Rewrite lea to nop. */ |
+ memcpy (contents + rel->r_offset - 3, |
+ "\x0f\x1f\x80\x00\x00\x00\x00", 7); |
+ |
+ /* Call __nacl_read_tp instead of __tls_get_addr. */ |
+ h_subst = nacl_read_tp_entry; |
+#if 0 |
+ /* NACLHACK: Original LD->LE transition disabled. */ |
/* LD->LE transition: |
leaq foo@tlsld(%rip), %rdi; call __tls_get_addr. |
We change it into: |
@@ -3704,6 +3771,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, |
"\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12); |
/* Skip R_X86_64_PC32/R_X86_64_PLT32. */ |
rel++; |
+#endif |
continue; |
} |