summaryrefslogtreecommitdiff
path: root/ldso
diff options
context:
space:
mode:
authorKhem Raj <raj.khem@gmail.com>2010-05-05 22:50:19 -0700
committerKhem Raj <raj.khem@gmail.com>2010-05-09 22:53:25 -0700
commite3dec33ba03ef7080a39444388a01e59135bb3aa (patch)
tree9693449a78a556a91ddba349116d9c988399071a /ldso
parentd2ab6ee38dd6ef107bac77f485ab1bb35b177e6c (diff)
powerpc: Add TLS and NPTL support
Signed-off-by: Khem Raj <raj.khem@gmail.com> Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
Diffstat (limited to 'ldso')
-rw-r--r--ldso/include/ldso.h4
-rw-r--r--ldso/ldso/powerpc/dl-sysdep.h2
-rw-r--r--ldso/ldso/powerpc/elfinterp.c55
3 files changed, 45 insertions, 16 deletions
diff --git a/ldso/include/ldso.h b/ldso/include/ldso.h
index 4675dd7f4..69b5dd75a 100644
--- a/ldso/include/ldso.h
+++ b/ldso/include/ldso.h
@@ -78,6 +78,10 @@ extern void _dl_add_to_slotinfo (struct link_map *l);
extern void ** __attribute__ ((const)) _dl_initial_error_catch_tsd (void);
#endif
+#ifdef USE_TLS
+void _dl_add_to_slotinfo (struct link_map *l);
+void ** __attribute__ ((const)) _dl_initial_error_catch_tsd (void);
+#endif
#ifdef __SUPPORT_LD_DEBUG__
extern char *_dl_debug;
extern char *_dl_debug_symbols;
diff --git a/ldso/ldso/powerpc/dl-sysdep.h b/ldso/ldso/powerpc/dl-sysdep.h
index f33214cbe..a665d4e75 100644
--- a/ldso/ldso/powerpc/dl-sysdep.h
+++ b/ldso/ldso/powerpc/dl-sysdep.h
@@ -77,6 +77,8 @@ void _dl_init_got(unsigned long *lpnt,struct elf_resolve *tpnt);
#define elf_machine_type_class(type) \
((((type) == R_PPC_JMP_SLOT \
|| (type) == R_PPC_REL24 \
+ || ((type) >= R_PPC_DTPMOD32 /* contiguous TLS */ \
+ && (type) <= R_PPC_DTPREL32) \
|| (type) == R_PPC_ADDR24) * ELF_RTYPE_CLASS_PLT) \
| (((type) == R_PPC_COPY) * ELF_RTYPE_CLASS_COPY))
diff --git a/ldso/ldso/powerpc/elfinterp.c b/ldso/ldso/powerpc/elfinterp.c
index 0dcb175bf..855c040d3 100644
--- a/ldso/ldso/powerpc/elfinterp.c
+++ b/ldso/ldso/powerpc/elfinterp.c
@@ -30,6 +30,8 @@
*/
#include "ldso.h"
+#define TLS_DTV_OFFSET 0x8000
+#define TLS_TP_OFFSET 0x7000
extern int _dl_linux_resolve(void);
@@ -157,15 +159,15 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
*reloc_addr = OPCODE_BA (finaladdr);
} else {
/* Warning: we don't handle double-sized PLT entries */
- Elf32_Word *plt, *data_words, index, offset;
+ Elf32_Word *plt, *data_words, idx, offset;
plt = (Elf32_Word *)tpnt->dynamic_info[DT_PLTGOT];
offset = reloc_addr - plt;
- index = (offset - PLT_INITIAL_ENTRY_WORDS)/2;
+ idx = (offset - PLT_INITIAL_ENTRY_WORDS)/2;
data_words = (Elf32_Word *)tpnt->data_words;
reloc_addr += 1;
- data_words[index] = finaladdr;
+ data_words[idx] = finaladdr;
PPC_SYNC;
*reloc_addr = OPCODE_B ((PLT_LONGBRANCH_ENTRY_WORDS - (offset+1)) * 4);
}
@@ -185,28 +187,36 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
{
int reloc_type;
int symtab_index;
- char *symname;
+ ElfW(Sym) *sym;
Elf32_Addr *reloc_addr;
Elf32_Addr finaladdr;
-
+ struct elf_resolve *tls_tpnt = NULL;
unsigned long symbol_addr;
+ char *symname;
#if defined (__SUPPORT_LD_DEBUG__)
unsigned long old_val;
#endif
- reloc_addr = (Elf32_Addr *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
- reloc_type = ELF32_R_TYPE(rpnt->r_info);
+
symbol_addr = tpnt->loadaddr; /* For R_PPC_RELATIVE */
+ reloc_addr = (Elf32_Addr *)(intptr_t) (symbol_addr + (unsigned long) rpnt->r_offset);
+ reloc_type = ELF32_R_TYPE(rpnt->r_info);
symtab_index = ELF32_R_SYM(rpnt->r_info);
- symname = strtab + symtab[symtab_index].st_name;
+ sym = &symtab[symtab_index];
+ symname = strtab + sym->st_name;
if (symtab_index) {
symbol_addr = (unsigned long) _dl_find_hash(symname, scope, tpnt,
- elf_machine_type_class(reloc_type), NULL);
+ elf_machine_type_class(reloc_type), &tls_tpnt);
/* We want to allow undefined references to weak symbols - this might
* have been intentional. We should not be linking local symbols
* here, so all bases should be covered.
*/
- if (unlikely(!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK))
+ if (unlikely(!symbol_addr
+ && (ELF32_ST_TYPE(sym->st_info) != STT_TLS
+ && ELF32_ST_BIND(sym->st_info) != STB_WEAK)))
return 1;
+ } else {
+ symbol_addr = sym->st_value;
+ tls_tpnt = tpnt;
}
#if defined (__SUPPORT_LD_DEBUG__)
old_val = *reloc_addr;
@@ -232,15 +242,15 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
*reloc_addr = OPCODE_BA (finaladdr);
} else {
/* Warning: we don't handle double-sized PLT entries */
- Elf32_Word *plt, *data_words, index, offset;
+ Elf32_Word *plt, *data_words, idx, offset;
plt = (Elf32_Word *)tpnt->dynamic_info[DT_PLTGOT];
offset = reloc_addr - plt;
- index = (offset - PLT_INITIAL_ENTRY_WORDS)/2;
+ idx = (offset - PLT_INITIAL_ENTRY_WORDS)/2;
data_words = (Elf32_Word *)tpnt->data_words;
- data_words[index] = finaladdr;
- reloc_addr[0] = OPCODE_LI(11,index*4);
+ data_words[idx] = finaladdr;
+ reloc_addr[0] = OPCODE_LI(11,idx*4);
reloc_addr[1] = OPCODE_B((PLT_LONGBRANCH_ENTRY_WORDS - (offset+1)) * 4);
/* instructions were modified */
@@ -255,10 +265,10 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
#if defined (__SUPPORT_LD_DEBUG__)
if (_dl_debug_move)
_dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
- symname, symtab[symtab_index].st_size,
+ symname, sym->st_size,
symbol_addr, reloc_addr);
#endif
- _dl_memcpy((char *) reloc_addr, (char *) finaladdr, symtab[symtab_index].st_size);
+ _dl_memcpy((char *) reloc_addr, (char *) finaladdr, sym->st_size);
goto out_nocode; /* No code code modified */
case R_PPC_ADDR16_HA:
finaladdr += 0x8000; /* fall through. */
@@ -267,6 +277,19 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
case R_PPC_ADDR16_LO:
*(short *)reloc_addr = finaladdr;
break;
+#if USE_TLS
+ case R_PPC_DTPMOD32:
+ *reloc_addr = tls_tpnt->l_tls_modid;
+ break;
+ case R_PPC_DTPREL32:
+ /* During relocation all TLS symbols are defined and used.
+ Therefore the offset is already correct. */
+ *reloc_addr = finaladdr - TLS_DTV_OFFSET;
+ break;
+ case R_PPC_TPREL32:
+ *reloc_addr = tls_tpnt->l_tls_offset + finaladdr - TLS_TP_OFFSET;
+ break;
+#endif
case R_PPC_REL24:
#if 0
{