From c8c59454eac603f75e8e037d290e595abeda2af5 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Thu, 10 May 2012 10:05:40 -0700 Subject: [PATCH] Sign extend R_X86_64_DTPOFF64/R_X86_64_TPOFF64 --- ChangeLog | 6 ++++++ sysdeps/x86_64/dl-machine.h | 27 ++++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index b418bfe316..7fb8d569c5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-05-10 H.J. Lu + + * 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 * sysdeps/unix/sysv/linux/syscalls.list (alarm): Add entry from diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h index d1906a4b66..cf49d42925 100644 --- a/sysdeps/x86_64/dl-machine.h +++ b/sysdeps/x86_64/dl-machine.h @@ -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