Sign extend R_X86_64_DTPOFF64/R_X86_64_TPOFF64
authorH.J. Lu <hjl.tools@gmail.com>
Thu, 10 May 2012 17:05:40 +0000 (10:05 -0700)
committerH.J. Lu <hjl.tools@gmail.com>
Thu, 10 May 2012 17:05:40 +0000 (10:05 -0700)
ChangeLog
sysdeps/x86_64/dl-machine.h

index b418bfe..7fb8d56 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2012-05-10  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * sysdeps/x86_64/dl-machine.h (elf_machine_rela) [__ILP32__]:
+       Sign extend relocation result to 64 bits for R_X86_64_DTPOFF64
+       and R_X86_64_TPOFF64.
+
 2012-05-10  Joseph Myers  <joseph@codesourcery.com>
 
        * sysdeps/unix/sysv/linux/syscalls.list (alarm): Add entry from
index d1906a4..cf49d42 100644 (file)
@@ -328,7 +328,19 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
          /* During relocation all TLS symbols are defined and used.
             Therefore the offset is already correct.  */
          if (sym != NULL)
-           *reloc_addr = sym->st_value + reloc->r_addend;
+           {
+             value = sym->st_value + reloc->r_addend;
+#   ifdef __ILP32__
+             /* This relocation type computes a signed offset that is
+                usually negative.  The symbol and addend values are 32
+                bits but the GOT entry is 64 bits wide and the whole
+                64-bit entry is used as a signed quantity, so we need
+                to sign-extend the computed value to 64 bits.  */
+             *(Elf64_Sxword *) reloc_addr = (Elf64_Sxword) (Elf32_Sxword) value;
+#   else
+             *reloc_addr = value;
+#   endif
+           }
 #  endif
          break;
        case R_X86_64_TLSDESC:
@@ -378,8 +390,17 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
              /* We know the offset of the object the symbol is contained in.
                 It is a negative value which will be added to the
                 thread pointer.  */
-             *reloc_addr = (sym->st_value + reloc->r_addend
-                            - sym_map->l_tls_offset);
+             value = (sym->st_value + reloc->r_addend
+                      - sym_map->l_tls_offset);
+#  ifdef __ILP32__
+             /* The symbol and addend values are 32 bits but the GOT
+                entry is 64 bits wide and the whole 64-bit entry is used
+                as a signed quantity, so we need to sign-extend the
+                computed value to 64 bits.  */
+             *(Elf64_Sxword *) reloc_addr = (Elf64_Sxword) (Elf32_Sword) value;
+#  else
+             *reloc_addr = value;
+#  endif
            }
          break;
 # endif