OSDN Git Service

ldso: fix x86_64 R_X86_64_TPOFF64 and R_X86_64_DTPOFF64 relocations
authorRoman I Khimov <khimov@altell.ru>
Tue, 4 May 2010 10:00:47 +0000 (14:00 +0400)
committerAustin Foxley <austinf@cetoncorp.com>
Wed, 5 May 2010 15:43:22 +0000 (08:43 -0700)
R_X86_64_TPOFF64 revealed by trivial testcase:
===================================================================
 #include <stdio.h>
 #include <errno.h>

int main() {
        void *a = &errno;

        printf("errno addr: %llx\n", a);
        __asm__("movq    errno@gottpoff(%%rip), %0;\n"
                "add    %%fs:0x0,%0;" : "=r"(a) );
        printf("got errno addr: %llx\n", a);

        return 0;
}
===================================================================

The addresses application got with R_X86_64_TPOFF64 was different than the once libc
internal __errno_location returned.

R_X86_64_DTPOFF64 testcase is even simpler than that:
===================================================================
 #include <stdio.h>
 #include <errno.h>
 #include <netdb.h>
 #undef h_errno

extern __thread int h_errno;

int main() {
        printf("h_errno addr: %llx\n", &h_errno);
        printf("__h_errno_location addr: %llx\n", __h_errno_location());
        return 0;
}
===================================================================

but needs to be linked with "-lpthread". This way we've got h_errno relocation via
R_X86_64_TPOFF64 in application and h_errno relocation via R_X86_64_DTPOFF64 in
libpthread which has its own __h_errno_location() (probably we can kill it later?).
And addresses were different again.

The problem is that both relocations resolve symbols in external modules and thus
should use symbol_addr instead of sym->st_value.

Signed-off-by: Roman I Khimov <khimov@altell.ru>
Signed-off-by: Austin Foxley <austinf@cetoncorp.com>
ldso/ldso/x86_64/elfinterp.c

index 54528d3..baf024d 100644 (file)
@@ -226,7 +226,7 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
                case R_X86_64_DTPOFF64:
                        /* During relocation all TLS symbols are defined and used.
                         * Therefore the offset is already correct.  */
-                       *reloc_addr = sym->st_value + rpnt->r_addend;
+                       *reloc_addr = symbol_addr + rpnt->r_addend;
                        break;
                case R_X86_64_TPOFF64:
                        /* The offset is negative, forward from the thread pointer.
@@ -234,7 +234,7 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
                         * It is a negative value which will be added to the
                         * thread pointer.  */
                        CHECK_STATIC_TLS ((struct link_map *) tls_tpnt);
-                       *reloc_addr = sym->st_value - tls_tpnt->l_tls_offset + rpnt->r_addend;
+                       *reloc_addr = symbol_addr - tls_tpnt->l_tls_offset + rpnt->r_addend;
                        break;
                case R_X86_64_32:
                        *(unsigned int *) reloc_addr = symbol_addr + rpnt->r_addend;