@@ -78,6 +78,9 @@ __asm__ (
" addi r10, r10, 8\n"
" bne r11, zero, 4b\n"
"\n"
+" /* Pass our FINI ptr() to the user in r4, as crt1.S expects. */\n"
+" ldw r4, %call(_dl_fini)(r22)\n"
+"\n"
" /* Jump to the user's entry point. */\n"
" jmp r16\n"
);
@@ -64,11 +64,15 @@ static __always_inline void
elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
Elf32_Word relative_count)
{
- Elf32_Rel * rpnt = (void *) rel_addr;
+ Elf32_Rela * rpnt = (void *) rel_addr;
+ --rpnt;
do {
- Elf32_Addr *const reloc_addr = (void *) (load_off + (rpnt)->r_offset);
+ Elf32_Addr *const reloc_addr = (void *) (load_off +
+ (++rpnt)->r_offset);
- *reloc_addr += load_off;
+ /* The linker leaves the slot zeroed; the addend carries the
+ link-time value. */
+ *reloc_addr = load_off + rpnt->r_addend;
} while (--relative_count);
}
@@ -30,6 +30,10 @@
#include "ldso.h"
+/* The nios2 psABI biases both TLS offsets, as powerpc does. */
+#define TLS_DTV_OFFSET 0x8000
+#define TLS_TP_OFFSET 0x7000
+
/* Program to load an ELF binary on a linux system, and run it.
References to symbols in sharable libraries can be resolved by either
an ELF sharable library or a linux style of shared library. */
@@ -209,6 +213,22 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope,
*reloc_addr = (unsigned long)tpnt->loadaddr + rpnt->r_addend;
break;
+#if defined USE_TLS && USE_TLS
+ case R_NIOS2_TLS_DTPMOD:
+ *reloc_addr = tls_tpnt->l_tls_modid;
+ break;
+
+ case R_NIOS2_TLS_DTPREL:
+ *reloc_addr = symbol_addr + rpnt->r_addend - TLS_DTV_OFFSET;
+ break;
+
+ case R_NIOS2_TLS_TPREL:
+ CHECK_STATIC_TLS ((struct link_map *) tls_tpnt);
+ *reloc_addr = tls_tpnt->l_tls_offset + symbol_addr
+ + rpnt->r_addend - TLS_TP_OFFSET;
+ break;
+#endif
+
case R_NIOS2_COPY:
if (symbol_addr) {
#if defined (__SUPPORT_LD_DEBUG__)
@@ -66,6 +66,14 @@ _start:
/* Push rtld_fini */
stw r4, 4(sp)
+ /* Push app_fini, and pass app_init in r7. __uClibc_main() runs the
+ init arrays itself; these two are the legacy .init/.fini sections.
+ They have to be set: after exec the kernel hands us zeroed
+ registers, but ld.so does not, so leaving them alone means calling
+ whatever the loader left behind. */
+ stw zero, 0(sp)
+ mov r7, zero
+
/* Set up the GOT pointer. */
nextpc r22
1: movhi r2, %hiadj(_gp_got - 1b)
@@ -5,8 +5,15 @@
.type _init, @function
_init:
addi sp, sp, -8
- stw ra, 0(sp)
- stw fp, 4(sp)
+ /* The code gcc puts between crti and crtn reaches the GOT through r22,
+ and r22 belongs to the caller here -- ld.so calls _init directly. So
+ set it up ourselves, as glibc's crti.S does. */
+ stw r22, 0(sp)
+ nextpc r22
+1: movhi r8, %hiadj(_gp_got - 1b)
+ addi r8, r8, %lo(_gp_got - 1b)
+ add r22, r22, r8
+ stw ra, 4(sp)
.balign 4
@@ -17,6 +24,13 @@ _init:
.type _fini, @function
_fini:
addi sp, sp, -8
- stw ra, 0(sp)
- stw fp, 4(sp)
+ /* The code gcc puts between crti and crtn reaches the GOT through r22,
+ and r22 belongs to the caller here -- ld.so calls _init directly. So
+ set it up ourselves, as glibc's crti.S does. */
+ stw r22, 0(sp)
+ nextpc r22
+1: movhi r8, %hiadj(_gp_got - 1b)
+ addi r8, r8, %lo(_gp_got - 1b)
+ add r22, r22, r8
+ stw ra, 4(sp)
.balign 4
@@ -1,14 +1,14 @@
.section .init
- ldw ra, 0(sp)
- ldw fp, 4(sp)
+ ldw ra, 4(sp)
+ ldw r22, 0(sp)
addi sp, sp, 8
ret
.section .fini
- ldw ra, 0(sp)
- ldw fp, 4(sp)
+ ldw ra, 4(sp)
+ ldw r22, 0(sp)
addi sp, sp, 8
ret
@@ -16,7 +16,8 @@
<http://www.gnu.org/licenses/>. */
/* Value passed to 'clone' for initialization of the thread register. */
-#define TLS_VALUE (pd + 1)
+#define TLS_VALUE ((void *) (pd) \
+ + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
/* Get the real implementation. */
#include <sysdeps/pthread/createthread.c>