* config/obj-elf.c (elf_frob_symbol): Report S_SET_SIZE symbol
[deliverable/binutils-gdb.git] / bfd / elf64-x86-64.c
index 579f59cd7f1113939d46397698172c58fd39cb82..927b3ed4a5f0f984f78e43174faa4be0c3cb5ccb 100644 (file)
@@ -865,18 +865,34 @@ elf_x86_64_check_tls_transition (bfd *abfd,
 
       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
        {
@@ -913,16 +929,29 @@ elf_x86_64_check_tls_transition (bfd *abfd,
 
     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)
@@ -1179,6 +1208,39 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
            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
@@ -2841,6 +2903,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
            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)
                {
@@ -2904,7 +2967,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
                     internal symbol, we have updated addend.  */
                  continue;
                }
-
+             /* FALLTHROUGH */
            case R_X86_64_PC32:
            case R_X86_64_PC64:
            case R_X86_64_PLT32:
@@ -2966,18 +3029,6 @@ elf_x86_64_relocate_section (bfd *output_bfd,
              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;
            }
        }
@@ -3399,15 +3450,26 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 
              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);
@@ -3472,6 +3534,9 @@ elf_x86_64_relocate_section (bfd *output_bfd,
                      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,
@@ -3484,6 +3549,9 @@ elf_x86_64_relocate_section (bfd *output_bfd,
                      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,
@@ -3495,6 +3563,9 @@ elf_x86_64_relocate_section (bfd *output_bfd,
                      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),
@@ -3626,15 +3697,26 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 
              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
@@ -3703,12 +3785,18 @@ elf_x86_64_relocate_section (bfd *output_bfd,
            {
              /* 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;
@@ -4686,6 +4774,9 @@ elf64_l1om_elf_object_p (bfd *abfd)
 #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.  */
This page took 0.027121 seconds and 4 git commands to generate.