2012-03-21 Cary Coutant <ccoutant@google.com>
[binutils-gdb.git] / gold / x86_64.cc
index 3a2cacef483474f4fe4dbb45abf5943649f0a78f..3962e1ea3641687d13186ba0a3b5c1c3975a55dc 100644 (file)
@@ -1,6 +1,7 @@
 // x86_64.cc -- x86_64 target support for gold.
 
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012
+// Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -2475,7 +2476,8 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab,
                 target->copy_reloc(symtab, layout, object,
                                    data_shndx, output_section, gsym, reloc);
               }
-           else if (r_type == elfcpp::R_X86_64_64
+           else if (((size == 64 && r_type == elfcpp::R_X86_64_64)
+                     || (size == 32 && r_type == elfcpp::R_X86_64_32))
                     && gsym->type() == elfcpp::STT_GNU_IFUNC
                     && gsym->can_use_relative_reloc(false)
                     && !gsym->is_from_dynobj()
@@ -2809,8 +2811,8 @@ Target_x86_64<size>::gc_process_relocs(Symbol_table* symtab,
     }
 
    gold::gc_process_relocs<size, false, Target_x86_64<size>, elfcpp::SHT_RELA,
-                           Target_x86_64<size>::Scan,
-                          Target_x86_64<size>::Relocatable_size_for_reloc>(
+                           typename Target_x86_64<size>::Scan,
+                          typename Target_x86_64<size>::Relocatable_size_for_reloc>(
     symtab,
     layout,
     this,
@@ -2848,7 +2850,7 @@ Target_x86_64<size>::scan_relocs(Symbol_table* symtab,
     }
 
   gold::scan_relocs<size, false, Target_x86_64<size>, elfcpp::SHT_RELA,
-      Target_x86_64<size>::Scan>(
+      typename Target_x86_64<size>::Scan>(
     symtab,
     layout,
     this,
@@ -3532,19 +3534,37 @@ Target_x86_64<size>::Relocate::tls_gd_to_ie(
     typename elfcpp::Elf_types<size>::Elf_Addr address,
     section_size_type view_size)
 {
-  // .byte 0x66; leaq foo@tlsgd(%rip),%rdi;
-  // .word 0x6666; rex64; call __tls_get_addr
-  // ==> movq %fs:0,%rax; addq x@gottpoff(%rip),%rax
+  // For SIZE == 64:
+  //   .byte 0x66; leaq foo@tlsgd(%rip),%rdi;
+  //   .word 0x6666; rex64; call __tls_get_addr
+  //   ==> movq %fs:0,%rax; addq x@gottpoff(%rip),%rax
+  // For SIZE == 32:
+  //   leaq foo@tlsgd(%rip),%rdi;
+  //   .word 0x6666; rex64; call __tls_get_addr
+  //   ==> movl %fs:0,%eax; addq x@gottpoff(%rip),%rax
 
-  tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -4);
   tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 12);
-
-  tls::check_tls(relinfo, relnum, rela.get_r_offset(),
-                 (memcmp(view - 4, "\x66\x48\x8d\x3d", 4) == 0));
   tls::check_tls(relinfo, relnum, rela.get_r_offset(),
                  (memcmp(view + 4, "\x66\x66\x48\xe8", 4) == 0));
 
-  memcpy(view - 4, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0\0", 16);
+  if (size == 64)
+    {
+      tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size,
+                      -4);
+      tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+                    (memcmp(view - 4, "\x66\x48\x8d\x3d", 4) == 0));
+      memcpy(view - 4, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0\0",
+            16);
+    }
+  else
+    {
+      tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size,
+                      -3);
+      tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+                    (memcmp(view - 3, "\x48\x8d\x3d", 3) == 0));
+      memcpy(view - 3, "\x64\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0\0",
+            15);
+    }
 
   const elfcpp::Elf_Xword addend = rela.get_r_addend();
   Relocate_functions<size, false>::pcrela32(view + 8, value, addend - 8,
@@ -3570,19 +3590,38 @@ Target_x86_64<size>::Relocate::tls_gd_to_le(
     unsigned char* view,
     section_size_type view_size)
 {
-  // .byte 0x66; leaq foo@tlsgd(%rip),%rdi;
-  // .word 0x6666; rex64; call __tls_get_addr
-  // ==> movq %fs:0,%rax; leaq x@tpoff(%rax),%rax
+  // For SIZE == 64:
+  //   .byte 0x66; leaq foo@tlsgd(%rip),%rdi;
+  //   .word 0x6666; rex64; call __tls_get_addr
+  //   ==> movq %fs:0,%rax; leaq x@tpoff(%rax),%rax
+  // For SIZE == 32:
+  //   leaq foo@tlsgd(%rip),%rdi;
+  //   .word 0x6666; rex64; call __tls_get_addr
+  //   ==> movl %fs:0,%eax; leaq x@tpoff(%rax),%rax
 
-  tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -4);
   tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 12);
-
   tls::check_tls(relinfo, relnum, rela.get_r_offset(),
-                 (memcmp(view - 4, "\x66\x48\x8d\x3d", 4) == 0));
-  tls::check_tls(relinfo, relnum, rela.get_r_offset(),
-                 (memcmp(view + 4, "\x66\x66\x48\xe8", 4) == 0));
+                (memcmp(view + 4, "\x66\x66\x48\xe8", 4) == 0));
+
+  if (size == 64)
+    {
+      tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size,
+                      -4);
+      tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+                    (memcmp(view - 4, "\x66\x48\x8d\x3d", 4) == 0));
+      memcpy(view - 4, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0\0",
+            16);
+    }
+  else
+    {
+      tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size,
+                      -3);
+      tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+                    (memcmp(view - 3, "\x48\x8d\x3d", 3) == 0));
 
-  memcpy(view - 4, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0\0", 16);
+      memcpy(view - 3, "\x64\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0\0",
+            15);
+    }
 
   value -= tls_segment->memsz();
   Relocate_functions<size, false>::rela32(view + 8, value, 0);
@@ -3780,7 +3819,7 @@ Target_x86_64<size>::relocate_section(
   gold_assert(sh_type == elfcpp::SHT_RELA);
 
   gold::relocate_section<size, false, Target_x86_64<size>, elfcpp::SHT_RELA,
-                        Target_x86_64<size>::Relocate>(
+                        typename Target_x86_64<size>::Relocate>(
     relinfo,
     this,
     prelocs,
@@ -3809,7 +3848,7 @@ Target_x86_64<size>::apply_relocation(
     section_size_type view_size)
 {
   gold::apply_relocation<size, false, Target_x86_64<size>,
-                        Target_x86_64<size>::Relocate>(
+                        typename Target_x86_64<size>::Relocate>(
     relinfo,
     this,
     r_offset,
@@ -3991,7 +4030,7 @@ Target_x86_64<size>::do_code_fill(section_size_type length) const
       jmp[0] = 0xe9;
       elfcpp::Swap_unaligned<32, false>::writeval(jmp + 1, length - 5);
       return (std::string(reinterpret_cast<char*>(&jmp[0]), 5)
-              + std::string(length - 5, '\0'));
+              + std::string(length - 5, static_cast<char>(0x90)));
     }
 
   // Nop sequences of various lengths.