+2007-08-14 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR ld/4918
+ * elf32-i386.c (elf_i386_relocate_section): Allow R_386_PC32
+ on ___tls_get_addr for GD->LE/LD->LE transitions when not
+ building shared library.
+
+ * elf64-x86-64.c (elf64_x86_64_relocate_section): Allow
+ R_X86_64_PC32 on __tls_get_addr for GD->LE/LD->LE transitions
+ when not building shared library.
+
2007-08-14 Jan Kratochvil <jan.kratochvil@redhat.com>
* elfcode.h (NAME(_bfd_elf,bfd_from_remote_memory)): LOADBASE is now
{
unsigned int val, type;
bfd_vma roff;
+ unsigned long tls_r_symndx;
+ struct elf_link_hash_entry *tls_h;
/* GD->LE transition. */
BFD_ASSERT (rel->r_offset >= 2);
contents + rel->r_offset + 4)
== 0xe8);
BFD_ASSERT (rel + 1 < relend);
- BFD_ASSERT (ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32);
+ tls_r_symndx = ELF32_R_SYM (rel[1].r_info);
+ BFD_ASSERT (tls_r_symndx >= symtab_hdr->sh_info);
+ tls_h = sym_hashes[tls_r_symndx - symtab_hdr->sh_info];
+ BFD_ASSERT (tls_h != NULL
+ && tls_h->root.root.string != NULL
+ && strcmp (tls_h->root.root.string,
+ "___tls_get_addr") == 0);
+ BFD_ASSERT ((! info->shared
+ && ELF32_R_TYPE (rel[1].r_info) == R_386_PC32)
+ || ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32);
roff = rel->r_offset + 5;
val = bfd_get_8 (input_bfd,
contents + rel->r_offset - 1);
}
bfd_put_32 (output_bfd, tpoff (info, relocation),
contents + roff);
- /* Skip R_386_PLT32. */
+ /* Skip R_386_PC32/R_386_PLT32. */
rel++;
continue;
}
if (! info->shared)
{
unsigned int val;
+ unsigned long tls_r_symndx;
+ struct elf_link_hash_entry *tls_h;
/* LD->LE transition:
Ensure it is:
BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset + 4)
== 0xe8);
BFD_ASSERT (rel + 1 < relend);
- BFD_ASSERT (ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32);
+ tls_r_symndx = ELF32_R_SYM (rel[1].r_info);
+ BFD_ASSERT (tls_r_symndx >= symtab_hdr->sh_info);
+ tls_h = sym_hashes[tls_r_symndx - symtab_hdr->sh_info];
+ BFD_ASSERT (tls_h != NULL
+ && tls_h->root.root.string != NULL
+ && strcmp (tls_h->root.root.string,
+ "___tls_get_addr") == 0);
+ BFD_ASSERT (ELF32_R_TYPE (rel[1].r_info) == R_386_PC32
+ || ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32);
memcpy (contents + rel->r_offset - 2,
"\x65\xa1\0\0\0\0\x90\x8d\x74\x26", 11);
- /* Skip R_386_PLT32. */
+ /* Skip R_386_PC32/R_386_PLT32. */
rel++;
continue;
}
unsigned int i;
static unsigned char tlsgd[8]
= { 0x66, 0x48, 0x8d, 0x3d, 0x66, 0x66, 0x48, 0xe8 };
+ unsigned long tls_r_symndx;
+ struct elf_link_hash_entry *tls_h;
/* GD->LE transition.
.byte 0x66; leaq foo@tlsgd(%rip), %rdi
- .word 0x6666; rex64; call __tls_get_addr@plt
+ .word 0x6666; rex64; call __tls_get_addr
Change it into:
movq %fs:0, %rax
leaq foo@tpoff(%rax), %rax */
contents + rel->r_offset + 4 + i)
== tlsgd[i+4]);
BFD_ASSERT (rel + 1 < relend);
- BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32);
+ tls_r_symndx = ELF64_R_SYM (rel[1].r_info);
+ BFD_ASSERT (tls_r_symndx >= symtab_hdr->sh_info);
+ tls_h = sym_hashes[tls_r_symndx - symtab_hdr->sh_info];
+ BFD_ASSERT (tls_h != NULL
+ && tls_h->root.root.string != NULL
+ && strcmp (tls_h->root.root.string,
+ "__tls_get_addr") == 0);
+ BFD_ASSERT ((! info->shared
+ && ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PC32)
+ || ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32);
memcpy (contents + rel->r_offset - 4,
"\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
16);
bfd_put_32 (output_bfd, tpoff (info, relocation),
contents + rel->r_offset + 8);
- /* Skip R_X86_64_PLT32. */
+ /* Skip R_X86_64_PC32/R_X86_64_PLT32. */
rel++;
continue;
}
case R_X86_64_TLSLD:
if (! info->shared)
{
+ unsigned long tls_r_symndx;
+ struct elf_link_hash_entry *tls_h;
+
/* LD->LE transition:
Ensure it is:
- leaq foo@tlsld(%rip), %rdi; call __tls_get_addr@plt.
+ leaq foo@tlsld(%rip), %rdi; call __tls_get_addr.
We change it into:
.word 0x6666; .byte 0x66; movl %fs:0, %rax. */
BFD_ASSERT (rel->r_offset >= 3);
BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset + 4)
== 0xe8);
BFD_ASSERT (rel + 1 < relend);
- BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32);
+ tls_r_symndx = ELF64_R_SYM (rel[1].r_info);
+ BFD_ASSERT (tls_r_symndx >= symtab_hdr->sh_info);
+ tls_h = sym_hashes[tls_r_symndx - symtab_hdr->sh_info];
+ BFD_ASSERT (tls_h != NULL
+ && tls_h->root.root.string != NULL
+ && strcmp (tls_h->root.root.string,
+ "__tls_get_addr") == 0);
+ BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PC32
+ || ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32);
memcpy (contents + rel->r_offset - 3,
"\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12);
- /* Skip R_X86_64_PLT32. */
+ /* Skip R_X86_64_PC32/R_X86_64_PLT32. */
rel++;
continue;
}
+2007-08-14 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR ld/4918
+ * ld-i386/i386.exp (i386tests): Add tlsgd1 and tlsld1 tests.
+ * ld-x86-64/x86-64.exp (x86_64tests): Likewise.
+
+ * ld-i386/tlsgd1.dd: New file.
+ * ld-i386/tlsgd1.s: Likewise.
+ * ld-i386/tlsld1.dd: Likewise.
+ * ld-i386/tlsld1.s: Likewise.
+ * ld-x86-64/tlsgd1.dd: Likewise.
+ * ld-x86-64/tlsgd1.s: Likewise.
+ * ld-x86-64/tlsld1.dd: Likewise.
+ * ld-x86-64/tlsld1.s: Likewise.
+
2007-08-13 Richard Sandiford <richard@codesourcery.com>
* ld-mips-elf/vxworks-forced-local-1.d,
{emit-relocs.s} {{readelf --relocs emit-relocs.d}} "emit-relocs.so"}
{"-z combreloc relocation sections" "-shared -melf_i386 -z combreloc"
"--32" {combreloc.s} {{readelf -r combreloc.d}} "combreloc.so"}
+ {"TLS GD->LE transition" "-melf_i386"
+ "--32" {tlsgd1.s}
+ {{objdump -dwr tlsgd1.dd}} "tlsgd1"}
+ {"TLS LD->LE transition" "-melf_i386"
+ "--32" {tlsld1.s}
+ {{objdump -dwr tlsld1.dd}} "tlsld1"}
}
run_ld_link_tests $i386tests
--- /dev/null
+#source: tlsgd1.s
+#as: --32
+#ld: -melf_i386 tmpdir/tlsgd1
+#objdump: -drw
+#target: i?86-*-linux*
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+[a-f0-9]+ <_start>:
+[ ]*[a-f0-9]+: 65 a1 00 00 00 00 mov %gs:0x0,%eax
+[ ]*[a-f0-9]+: 81 e8 04 00 00 00 sub \$0x4,%eax
+#pass
--- /dev/null
+ .text
+ .globl _start
+_start:
+ leal foo@TLSGD(,%ebx,1), %eax
+ call ___tls_get_addr
+ .globl foo
+ .section .tdata,"awT",@progbits
+ .align 4
+ .type foo, @object
+ .size foo, 4
+foo:
+ .long 100
--- /dev/null
+#source: tlsld1.s
+#as: --32
+#ld: -melf_i386 tmpdir/tlsld1
+#objdump: -drw
+#target: i?86-*-linux*
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+[a-f0-9]+ <_start>:
+[ ]*[a-f0-9]+: 65 a1 00 00 00 00 mov %gs:0x0,%eax
+[ ]*[a-f0-9]+: 90 nop
+[ ]*[a-f0-9]+: 8d 74 26 00 lea 0x0\(%esi\),%esi
+#pass
--- /dev/null
+ .text
+ .globl _start
+_start:
+ leal foo@TLSLDM(%ebx), %eax
+ call ___tls_get_addr
+ .globl foo
+ .section .tdata,"awT",@progbits
+ .align 4
+ .type foo, @object
+ .size foo, 4
+foo:
+ .long 100
--- /dev/null
+#source: tlsgd1.s
+#as: --64
+#ld: -melf_x86_64 tmpdir/tlsgd1
+#objdump: -drw
+#target: x86_64-*-linux*
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+[a-f0-9]+ <_start>:
+[ ]*[a-f0-9]+: 64 48 8b 04 25 00 00 00 00 mov %fs:0x0,%rax
+[ ]*[a-f0-9]+: 48 8d 80 fc ff ff ff lea -0x4\(%rax\),%rax
+#pass
--- /dev/null
+ .text
+ .globl _start
+_start:
+ .byte 0x66
+ leaq foo@TLSGD(%rip), %rdi
+ .word 0x6666
+ rex64
+ call __tls_get_addr
+ .globl foo
+ .section .tdata,"awT",@progbits
+ .align 4
+ .type foo, @object
+ .size foo, 4
+foo:
+ .long 100
--- /dev/null
+#source: tlsld1.s
+#as: --64
+#ld: -melf_x86_64 tmpdir/tlsld1
+#objdump: -drw
+#target: x86_64-*-linux*
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+[a-f0-9]+ <_start>:
+[ ]*[a-f0-9]+: 66 66 66 64 48 8b 04 25 00 00 00 00 mov %fs:0x0,%rax
+#pass
--- /dev/null
+ .text
+ .globl _start
+_start:
+ leaq foo@TLSLD(%rip), %rdi
+ call __tls_get_addr
+ .globl foo
+ .section .tdata,"awT",@progbits
+ .align 4
+ .type foo, @object
+ .size foo, 4
+foo:
+ .long 100
{"TLS in debug sections" "-melf_x86_64"
"--64" {tlsg.s}
{{objdump -sj.debug_foobar tlsg.sd}} "tlsg"}
+ {"TLS GD->LE transition" "-melf_x86_64"
+ "--64" {tlsgd1.s}
+ {{objdump -dwr tlsgd1.dd}} "tlsgd1"}
+ {"TLS LD->LE transition" "-melf_x86_64"
+ "--64" {tlsld1.s}
+ {{objdump -dwr tlsld1.dd}} "tlsld1"}
}
run_ld_link_tests $x86_64tests