* sysdeps/x86_64/dl-machine.h (elf_machine_rela): For x32, sign extend relocation result to 64bit for R_X86_64_DTPOFF64 and R_X86_64_TPOFF64. diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h index d1906a4..7fe4a59 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) +# 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. */ + Elf32_Sword svalue = sym->st_value + reloc->r_addend; + *(Elf64_Sxword *) reloc_addr = (Elf64_Sxword) svalue; + } +# else *reloc_addr = sym->st_value + reloc->r_addend; +# endif # endif break; case R_X86_64_TLSDESC: @@ -378,8 +390,20 @@ 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. */ +# 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. */ + Elf32_Sword svalue = (sym->st_value + reloc->r_addend + - sym_map->l_tls_offset); + *(Elf64_Sxword *) reloc_addr = (Elf64_Sxword) svalue; + } +# else *reloc_addr = (sym->st_value + reloc->r_addend - sym_map->l_tls_offset); +# endif } break; # endif