if (r_type == R_X86_64_TLSGD)
{
- /* Check transition from GD access model. Only
+ /* Check transition from GD access model. For 64bit, only
.byte 0x66; leaq foo@tlsgd(%rip), %rdi
.word 0x6666; rex64; call __tls_get_addr
+ can transit to different access model. For 32bit, only
+ leaq foo@tlsgd(%rip), %rdi
+ .word 0x6666; rex64; call __tls_get_addr
can transit to different access model. */
- static x86_64_opcode32 leaq = { { 0x66, 0x48, 0x8d, 0x3d } },
- call = { { 0x66, 0x66, 0x48, 0xe8 } };
- if (offset < 4
- || (offset + 12) > sec->size
- || bfd_get_32 (abfd, contents + offset - 4) != leaq.i
+ static x86_64_opcode32 call = { { 0x66, 0x66, 0x48, 0xe8 } };
+ if ((offset + 12) > sec->size
|| bfd_get_32 (abfd, contents + offset + 4) != call.i)
return FALSE;
+
+ if (ABI_64_P (abfd))
+ {
+ static x86_64_opcode32 leaq = { { 0x66, 0x48, 0x8d, 0x3d } };
+ if (offset < 4
+ || bfd_get_32 (abfd, contents + offset - 4) != leaq.i)
+ return FALSE;
+ }
+ else
+ {
+ static x86_64_opcode16 lea = { { 0x8d, 0x3d } };
+ if (offset < 3
+ || bfd_get_8 (abfd, contents + offset - 3) != 0x48
+ || bfd_get_16 (abfd, contents + offset - 2) != lea.i)
+ return FALSE;
+ }
}
else
{
case R_X86_64_GOTTPOFF:
/* Check transition from IE access model:
- movq foo@gottpoff(%rip), %reg
- addq foo@gottpoff(%rip), %reg
+ mov foo@gottpoff(%rip), %reg
+ add foo@gottpoff(%rip), %reg
*/
- if (offset < 3 || (offset + 4) > sec->size)
- return FALSE;
-
- val = bfd_get_8 (abfd, contents + offset - 3);
- if (val != 0x48 && val != 0x4c)
- return FALSE;
+ /* Check REX prefix first. */
+ if (offset >= 3 && (offset + 4) <= sec->size)
+ {
+ val = bfd_get_8 (abfd, contents + offset - 3);
+ if (val != 0x48 && val != 0x4c)
+ {
+ /* X32 may have 0x44 REX prefix or no REX prefix. */
+ if (ABI_64_P (abfd))
+ return FALSE;
+ }
+ }
+ else
+ {
+ /* X32 may not have any REX prefix. */
+ if (ABI_64_P (abfd))
+ return FALSE;
+ if (offset < 2 || (offset + 3) > sec->size)
+ return FALSE;
+ }
val = bfd_get_8 (abfd, contents + offset - 2);
if (val != 0x8b && val != 0x03)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
}
+ /* Check invalid x32 relocations. */
+ if (!ABI_64_P (abfd))
+ switch (r_type)
+ {
+ default:
+ break;
+
+ case R_X86_64_64:
+ case R_X86_64_DTPOFF64:
+ case R_X86_64_TPOFF64:
+ case R_X86_64_PC64:
+ case R_X86_64_GOTOFF64:
+ case R_X86_64_GOT64:
+ case R_X86_64_GOTPCREL64:
+ case R_X86_64_GOTPC64:
+ case R_X86_64_GOTPLT64:
+ case R_X86_64_PLTOFF64:
+ {
+ if (h)
+ name = h->root.root.string;
+ else
+ name = bfd_elf_sym_name (abfd, symtab_hdr, isym,
+ NULL);
+ (*_bfd_error_handler)
+ (_("%B: relocation %s against symbol `%s' isn't "
+ "supported in x32 mode"), abfd,
+ x86_64_elf_howto_table[r_type].name, name);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ break;
+ }
+
if (h != NULL)
{
/* Create the ifunc sections for static executables. If we
case R_X86_64_32:
if (ABI_64_P (output_bfd))
goto do_relocation;
+ /* FALLTHROUGH */
case R_X86_64_64:
if (rel->r_addend != 0)
{
internal symbol, we have updated addend. */
continue;
}
-
+ /* FALLTHROUGH */
case R_X86_64_PC32:
case R_X86_64_PC64:
case R_X86_64_PLT32:
relocation = (base_got->output_section->vma
+ base_got->output_offset + off);
- if (r_type != R_X86_64_GOTPCREL
- && r_type != R_X86_64_GOTPCREL64)
- {
- asection *gotplt;
- if (htab->elf.splt != NULL)
- gotplt = htab->elf.sgotplt;
- else
- gotplt = htab->elf.igotplt;
- relocation -= (gotplt->output_section->vma
- - gotplt->output_offset);
- }
-
goto do_relocation;
}
}
if (ELF32_R_TYPE (rel->r_info) == R_X86_64_TLSGD)
{
- /* GD->LE transition.
+ /* GD->LE transition. For 64bit, change
.byte 0x66; leaq foo@tlsgd(%rip), %rdi
.word 0x6666; rex64; call __tls_get_addr
- Change it into:
+ into:
movq %fs:0, %rax
+ leaq foo@tpoff(%rax), %rax
+ For 32bit, change
+ leaq foo@tlsgd(%rip), %rdi
+ .word 0x6666; rex64; call __tls_get_addr
+ into:
+ movl %fs:0, %eax
leaq foo@tpoff(%rax), %rax */
- memcpy (contents + roff - 4,
- "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
- 16);
+ if (ABI_64_P (output_bfd))
+ memcpy (contents + roff - 4,
+ "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
+ 16);
+ else
+ memcpy (contents + roff - 3,
+ "\x64\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
+ 15);
bfd_put_32 (output_bfd,
elf_x86_64_tpoff (info, relocation),
contents + roff + 8);
if (val == 0x4c)
bfd_put_8 (output_bfd, 0x49,
contents + roff - 3);
+ else if (!ABI_64_P (output_bfd) && val == 0x44)
+ bfd_put_8 (output_bfd, 0x41,
+ contents + roff - 3);
bfd_put_8 (output_bfd, 0xc7,
contents + roff - 2);
bfd_put_8 (output_bfd, 0xc0 | reg,
if (val == 0x4c)
bfd_put_8 (output_bfd, 0x49,
contents + roff - 3);
+ else if (!ABI_64_P (output_bfd) && val == 0x44)
+ bfd_put_8 (output_bfd, 0x41,
+ contents + roff - 3);
bfd_put_8 (output_bfd, 0x81,
contents + roff - 2);
bfd_put_8 (output_bfd, 0xc0 | reg,
if (val == 0x4c)
bfd_put_8 (output_bfd, 0x4d,
contents + roff - 3);
+ else if (!ABI_64_P (output_bfd) && val == 0x44)
+ bfd_put_8 (output_bfd, 0x45,
+ contents + roff - 3);
bfd_put_8 (output_bfd, 0x8d,
contents + roff - 2);
bfd_put_8 (output_bfd, 0x80 | reg | (reg << 3),
if (ELF32_R_TYPE (rel->r_info) == R_X86_64_TLSGD)
{
- /* GD->IE transition.
+ /* GD->IE transition. For 64bit, change
.byte 0x66; leaq foo@tlsgd(%rip), %rdi
.word 0x6666; rex64; call __tls_get_addr@plt
- Change it into:
+ into:
movq %fs:0, %rax
+ addq foo@gottpoff(%rip), %rax
+ For 32bit, change
+ leaq foo@tlsgd(%rip), %rdi
+ .word 0x6666; rex64; call __tls_get_addr@plt
+ into:
+ movl %fs:0, %eax
addq foo@gottpoff(%rip), %rax */
- memcpy (contents + roff - 4,
- "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0",
- 16);
+ if (ABI_64_P (output_bfd))
+ memcpy (contents + roff - 4,
+ "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0",
+ 16);
+ else
+ memcpy (contents + roff - 3,
+ "\x64\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0",
+ 15);
relocation = (htab->elf.sgot->output_section->vma
+ htab->elf.sgot->output_offset + off
{
/* LD->LE transition:
leaq foo@tlsld(%rip), %rdi; call __tls_get_addr.
- We change it into:
- .word 0x6666; .byte 0x66; movl %fs:0, %rax. */
+ For 64bit, we change it into:
+ .word 0x6666; .byte 0x66; movq %fs:0, %rax.
+ For 32bit, we change it into:
+ nopl 0x0(%rax); movl %fs:0, %eax. */
BFD_ASSERT (r_type == R_X86_64_TPOFF32);
- memcpy (contents + rel->r_offset - 3,
- "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12);
+ if (ABI_64_P (output_bfd))
+ memcpy (contents + rel->r_offset - 3,
+ "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12);
+ else
+ memcpy (contents + rel->r_offset - 3,
+ "\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0", 12);
/* Skip R_X86_64_PC32/R_X86_64_PLT32. */
rel++;
continue;
#undef elf_backend_post_process_headers
#undef elf_backend_static_tls_alignment
+#undef elf_backend_want_plt_sym
+#define elf_backend_want_plt_sym 0
+
#include "elf64-target.h"
/* FreeBSD L1OM support. */