Index: bfd/elf32-i386.c |
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c |
index d22c99879c22bca113ae264973bfe4041b82690f..f5b3e61f0f30a584a31a51dbc9bfe14eebe78452 100644 |
--- a/bfd/elf32-i386.c |
+++ b/bfd/elf32-i386.c |
@@ -1102,6 +1102,8 @@ elf_i386_check_tls_transition (bfd *abfd, asection *sec, |
if (offset < 2 || (rel + 1) >= relend) |
return FALSE; |
+ /* NACLHACK: we hope for the best and check nothing! */ |
+#if 0 |
type = bfd_get_8 (abfd, contents + offset - 2); |
if (r_type == R_386_TLS_GD) |
{ |
@@ -1151,6 +1153,7 @@ elf_i386_check_tls_transition (bfd *abfd, asection *sec, |
if (bfd_get_8 (abfd, contents + offset + 4) != 0xe8) |
return FALSE; |
+#endif |
r_symndx = ELF32_R_SYM (rel[1].r_info); |
if (r_symndx < symtab_hdr->sh_info) |
@@ -3535,9 +3538,28 @@ elf_i386_relocate_section (bfd *output_bfd, |
Change it into: |
movl %gs:0, %eax; subl $foo@tpoff, %eax |
(6 byte form of subl). */ |
+ /* NACLHACK: handle nops between mov and call. */ |
+ /* Replace lea with movl. */ |
+ memcpy (contents + rel->r_offset - 3, |
+ "\x65\xa1\0\0\0\0", 6); |
+ /* Call is 5 bytes, bundle ends right after the call. |
+ Replace call with one preceeding byte with 6 byte subl, |
+ so that subl does not cross bundle boundary. */ |
+ memcpy (contents + rel[1].r_offset - 2, |
+ "\x81\xe8\0\0\0\0", 6); |
+ roff = rel[1].r_offset; |
+ /* Write nops between movl and subl. */ |
+ { |
+ bfd_vma i = rel->r_offset + 3; |
+ for (; i < rel[1].r_offset - 2; ++i) |
+ bfd_put_8 (output_bfd, 0x90, contents + i); |
+ } |
+#if 0 |
+ /* NACLHACK: original GD->LE transition disabled. */ |
memcpy (contents + rel->r_offset - 3, |
"\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12); |
roff = rel->r_offset + 5; |
+#endif |
} |
else |
{ |
@@ -3545,9 +3567,17 @@ elf_i386_relocate_section (bfd *output_bfd, |
Change it into: |
movl %gs:0, %eax; subl $foo@tpoff, %eax |
(6 byte form of subl). */ |
+ /* NACLHACK: We might be unable to rewrite this one. With |
+ properly aligned call, subl will cross bundle boundary |
+ if no nops in between. |
+ TODO: detect this in elf_i386_check_tls_transition. */ |
+ BFD_ASSERT (FALSE); |
+#if 0 |
+ /* NACLHACK: original GD->LE transition disabled. */ |
memcpy (contents + rel->r_offset - 2, |
"\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12); |
roff = rel->r_offset + 6; |
+#endif |
} |
bfd_put_32 (output_bfd, elf_i386_tpoff (info, relocation), |
contents + roff); |
@@ -3869,6 +3899,45 @@ elf_i386_relocate_section (bfd *output_bfd, |
/* GD->IE transition. */ |
type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2); |
val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1); |
+ /* NACLHACK: handle nops between mov and call. */ |
+ if (type == 0x04) |
+ { |
+ /* leal foo(,%reg,1), %eax; call ___tls_get_addr |
+ Change it into: |
+ movl %gs:0, %eax; subl $foo@gottpoff(%reg), %eax. */ |
+ |
+ /* Replace lea with movl. */ |
+ memcpy (contents + rel->r_offset - 3, |
+ "\x65\xa1\0\0\0\0", 6); |
+ /* Call is 5 bytes, bundle ends right after the call. |
+ Replace call with one preceeding byte with 6 byte subl, |
+ so that subl does not cross bundle boundary. */ |
+ memcpy (contents + rel[1].r_offset - 2, |
+ "\x2b\x80\0\0\0\0", 6); |
+ contents[rel[1].r_offset - 1] = 0x80 | ((val >> 3) & 7); |
+ /* Set roff + 8 to point to relocation target. */ |
+ roff = rel[1].r_offset - 8; |
+ /* Write nops between movl and subl. */ |
+ { |
+ bfd_vma i = rel->r_offset + 3; |
+ for (; i < rel[1].r_offset - 2; ++i) |
+ bfd_put_8 (output_bfd, 0x90, contents + i); |
+ } |
+ } |
+ else |
+ { |
+ /* leal foo(%reg), %eax; call ___tls_get_addr; nop |
+ Change it into: |
+ movl %gs:0, %eax; subl $foo@gottpoff(%reg), %eax. */ |
+ |
+ /* We might be unable to rewrite this one. With properly |
+ aligned call, subl will cross bundle boundary if no |
+ nops in between. |
+ TODO: detect this in elf_i386_check_tls_transition. */ |
+ BFD_ASSERT (FALSE); |
+ } |
+#if 0 |
+ /* NACLHACK: original GD->IE transition disabled. */ |
if (type == 0x04) |
{ |
/* leal foo(,%reg,1), %eax; call ___tls_get_addr |
@@ -3887,6 +3956,7 @@ elf_i386_relocate_section (bfd *output_bfd, |
memcpy (contents + roff, |
"\x65\xa1\0\0\0\0\x2b\x80\0\0\0", 12); |
contents[roff + 7] = 0x80 | (val & 7); |
+#endif |
/* If foo is used only with foo@gotntpoff(%reg) and |
foo@indntpoff, but not with foo@gottpoff(%reg), change |
subl $foo@gottpoff(%reg), %eax |
@@ -3995,8 +4065,17 @@ elf_i386_relocate_section (bfd *output_bfd, |
We change it into: |
movl %gs:0, %eax; nop; leal 0(%esi,1), %esi. */ |
BFD_ASSERT (r_type == R_386_TLS_LE_32); |
+ /* NACLHACK: Replace lea with movl. */ |
+ memcpy (contents + rel->r_offset - 2, |
+ "\x65\xa1\0\0\0\0", 6); |
+ /* Replace call with nop. */ |
+ memcpy (contents + rel[1].r_offset - 1, |
+ "\x0f\x1f\x44\0\0", 5); |
+#if 0 |
+ /* NACLHACK: Original LD->LE transition disabled. */ |
memcpy (contents + rel->r_offset - 2, |
"\x65\xa1\0\0\0\0\x90\x8d\x74\x26", 11); |
+#endif |
/* Skip R_386_PC32/R_386_PLT32. */ |
rel++; |
continue; |