summaryrefslogtreecommitdiff
path: root/ldso
diff options
context:
space:
mode:
authorMax Filippov <jcmvbkbc@gmail.com>2024-06-01 03:39:03 -0700
committerWaldemar Brodkorb <wbx@openadk.org>2024-06-04 16:40:42 +0200
commit138274e92a01be8a98392489b1a2f497ab11c201 (patch)
treef0be841a1e915e86d4215326a13654f8034632a4 /ldso
parent8bb33a2e1f2baec2078581d77e181f1ead5f51aa (diff)
xtensa: add FDPIC support
This change implements Xtensa FDPIC ABI as specified in the first version of the following document: https://github.com/jcmvbkbc/xtensa-abi/blob/master/fdpic-xtensa.txt Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Diffstat (limited to 'ldso')
-rw-r--r--ldso/ldso/xtensa/dl-inlines.h1
-rw-r--r--ldso/ldso/xtensa/dl-startup.h91
-rw-r--r--ldso/ldso/xtensa/dl-sysdep.h66
-rw-r--r--ldso/ldso/xtensa/dl-tlsdesc.S10
-rw-r--r--ldso/ldso/xtensa/elfinterp.c114
5 files changed, 253 insertions, 29 deletions
diff --git a/ldso/ldso/xtensa/dl-inlines.h b/ldso/ldso/xtensa/dl-inlines.h
new file mode 100644
index 000000000..8fdf6eb48
--- /dev/null
+++ b/ldso/ldso/xtensa/dl-inlines.h
@@ -0,0 +1 @@
+#include "../fdpic/dl-inlines.h"
diff --git a/ldso/ldso/xtensa/dl-startup.h b/ldso/ldso/xtensa/dl-startup.h
index c9350c0f2..2a453752a 100644
--- a/ldso/ldso/xtensa/dl-startup.h
+++ b/ldso/ldso/xtensa/dl-startup.h
@@ -7,6 +7,68 @@
* Parts taken from glibc/sysdeps/xtensa/dl-machine.h.
*/
+#if defined(__FDPIC__)
+__asm__ (
+ " .text\n"
+ " .align 4\n"
+ " .literal_position\n"
+ " .global _start\n"
+ " .type _start, @function\n"
+ " .hidden _start\n"
+ "_start:\n"
+ " .begin no-transform\n"
+ " _call0 1f\n"
+ "2:\n"
+ " .end no-transform\n"
+ " .align 4\n"
+ "1:\n"
+#if defined(__XTENSA_CALL0_ABI__)
+ " movi a15, 2b\n"
+ " sub a15, a0, a15\n"
+
+ /* Save FDPIC pointers in callee-saved registers */
+ " mov a12, a4\n"
+ " mov a13, a5\n"
+ " mov a14, a6\n"
+
+ /* Call __self_reloc */
+ " mov a2, a5\n"
+ " movi a3, __ROFIXUP_LIST__\n"
+ " add a3, a3, a15\n"
+ " movi a4, __ROFIXUP_END__\n"
+ " add a4, a4, a15\n"
+ " movi a0, __self_reloc\n"
+ " add a0, a0, a15\n"
+ " callx0 a0\n"
+
+ /* call _dl_start */
+ " mov a3, a12\n"
+ " mov a4, a13\n"
+ " mov a5, a14\n"
+ " mov a7, sp\n"
+ " addi sp, sp, -16\n"
+ " mov a6, sp\n"
+ " mov a11, a2\n"
+ /* a13, interpreter map is no longer needed, save interpreter GOT there */
+ " mov a13, a2\n"
+ " movi a0, _dl_start\n"
+ " add a0, a0, a15\n"
+ " callx0 a0\n"
+
+ /* call main */
+ " l32i a0, sp, 0\n"
+ " l32i a11, sp, 4\n"
+ " addi sp, sp, 16\n"
+ " mov a4, a12\n"
+ " movi a5, _dl_fini@GOTOFFFUNCDESC\n"
+ " add a5, a5, a13\n"
+ " mov a6, a14\n"
+ " jx a0\n"
+#else
+#error Unsupported Xtensa ABI
+#endif
+ );
+#else /* __FDPIC__ */
#ifndef L_rcrt1
__asm__ (
" .text\n"
@@ -83,6 +145,7 @@ __asm__ (
" bnez a6, 3b\n"
" j .Lfixup_stack_ret");
#endif
+#endif /* __FDPIC__ */
/* Get a pointer to the argv value. */
#define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long *) ARGS) + 1)
@@ -90,7 +153,7 @@ __asm__ (
/* Function calls are not safe until the GOT relocations have been done. */
#define NO_FUNCS_BEFORE_BOOTSTRAP
-#if defined(__ARCH_USE_MMU__)
+#if defined(__ARCH_USE_MMU__) && !defined(__FDPIC__)
#define PERFORM_BOOTSTRAP_GOT(tpnt) \
do { \
xtensa_got_location *got_loc; \
@@ -128,3 +191,29 @@ do { \
} \
} while (0)
#endif
+
+#ifdef __FDPIC__
+#undef DL_START
+#define DL_START(X) \
+static void __attribute__ ((used)) \
+_dl_start (Elf32_Addr dl_boot_got_pointer, \
+ struct elf32_fdpic_loadmap *dl_boot_progmap, \
+ struct elf32_fdpic_loadmap *dl_boot_ldsomap, \
+ Elf32_Dyn *dl_boot_ldso_dyn_pointer, \
+ struct funcdesc_value *dl_main_funcdesc, \
+ X)
+
+/*
+ * Transfer control to the user's application, once the dynamic loader
+ * is done. We return the address of the function's entry point to
+ * _dl_boot, see boot1_arch.h.
+ */
+#define START() do { \
+ struct elf_resolve *exec_mod = _dl_loaded_modules; \
+ dl_main_funcdesc->entry_point = _dl_elf_main; \
+ while (exec_mod->libtype != elf_executable) \
+ exec_mod = exec_mod->next; \
+ dl_main_funcdesc->got_value = exec_mod->loadaddr.got_value; \
+ return; \
+} while (0)
+#endif /* __FDPIC__ */
diff --git a/ldso/ldso/xtensa/dl-sysdep.h b/ldso/ldso/xtensa/dl-sysdep.h
index 6b908989a..5aa3e177f 100644
--- a/ldso/ldso/xtensa/dl-sysdep.h
+++ b/ldso/ldso/xtensa/dl-sysdep.h
@@ -26,6 +26,7 @@
in l_info array. */
#define DT_XTENSA(x) (DT_XTENSA_##x - DT_LOPROC + DT_NUM + OS_NUM)
+#ifndef __FDPIC__
typedef struct xtensa_got_location_struct {
Elf32_Off offset;
Elf32_Word length;
@@ -86,6 +87,7 @@ typedef struct xtensa_got_location_struct {
else if (dpnt->d_tag == DT_XTENSA_GOT_LOC_SZ) \
dynamic[DT_XTENSA (GOT_LOC_SZ)] = dpnt->d_un.d_val; \
} while (0)
+#endif
/* Here we define the magic numbers that this dynamic loader should accept. */
#define MAGIC1 EM_XTENSA
@@ -115,10 +117,41 @@ elf_machine_dynamic (void)
return (Elf32_Addr) &_DYNAMIC;
}
+#ifdef __FDPIC__
+
+#define DL_CHECK_LIB_TYPE(epnt, piclib, _dl_progname, libname) \
+do \
+{ \
+ (piclib) = 2; \
+} \
+while (0)
+
+/* We must force strings used early in the bootstrap into the data
+ segment. */
+#undef SEND_EARLY_STDERR
+#define SEND_EARLY_STDERR(S) \
+ do { /* FIXME: implement */; } while (0)
+
+#undef INIT_GOT
+#include "../fdpic/dl-sysdep.h"
+#undef INIT_GOT
+#define INIT_GOT(GOT_BASE,MODULE) \
+{ \
+ (MODULE)->loadaddr.got_value = (GOT_BASE); \
+ GOT_BASE[0] = ((unsigned long *)&_dl_linux_resolve)[0]; \
+ GOT_BASE[1] = ((unsigned long *)&_dl_linux_resolve)[1]; \
+ GOT_BASE[2] = (unsigned long) MODULE; \
+}
+
+#endif /* __FDPIC__ */
+
/* Return the run-time load address of the shared object. */
static __always_inline Elf32_Addr
elf_machine_load_address (void)
{
+#ifdef __FDPIC__
+ return 0;
+#else
Elf32_Addr addr, tmp;
/* At this point, the runtime linker is being bootstrapped and the GOT
@@ -135,17 +168,48 @@ elf_machine_load_address (void)
: "=a" (addr), "=a" (tmp));
return addr - 3;
+#endif
}
+#ifdef __FDPIC__
+
+/* Need bootstrap relocations */
+#define ARCH_NEEDS_BOOTSTRAP_RELOCS
+
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD,SYMTAB) \
+ switch (ELF_R_TYPE((RELP)->r_info)){ \
+ case R_XTENSA_SYM32: \
+ *(REL) = (SYMBOL) + (RELP)->r_addend; \
+ break; \
+ case R_XTENSA_RELATIVE: \
+ case R_XTENSA_NONE: \
+ default: \
+ break; \
+ }
+
static __always_inline void
-elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
+elf_machine_relative (DL_LOADADDR_TYPE load_off, const Elf32_Addr rel_addr,
Elf32_Word relative_count)
{
Elf32_Rela *rpnt = (Elf32_Rela *) rel_addr;
while (relative_count--)
{
+ Elf32_Addr *const reloc_addr = (Elf32_Addr *) DL_RELOC_ADDR(load_off, rpnt->r_offset);
+ *reloc_addr = DL_RELOC_ADDR(load_off, *reloc_addr);
+ rpnt++;
+ }
+}
+#else
+static __always_inline void
+elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
+ Elf32_Word relative_count)
+{
+ Elf32_Rela *rpnt = (Elf32_Rela *) rel_addr;
+ while (relative_count--)
+ {
Elf32_Addr *const reloc_addr = (Elf32_Addr *) (load_off + rpnt->r_offset);
*reloc_addr += load_off + rpnt->r_addend;
rpnt++;
}
}
+#endif
diff --git a/ldso/ldso/xtensa/dl-tlsdesc.S b/ldso/ldso/xtensa/dl-tlsdesc.S
index 426f2180b..1a8eacff2 100644
--- a/ldso/ldso/xtensa/dl-tlsdesc.S
+++ b/ldso/ldso/xtensa/dl-tlsdesc.S
@@ -24,6 +24,9 @@
.text
HIDDEN_ENTRY (_dl_tlsdesc_return)
+#ifdef __FDPIC__
+ l32i a2, a2, 4
+#endif
rur.threadptr a3
add a2, a2, a3
abi_ret
@@ -53,7 +56,9 @@ END (_dl_tlsdesc_return)
*/
HIDDEN_ENTRY (_dl_tlsdesc_dynamic)
-
+#ifdef __FDPIC__
+ l32i a2, a2, 4
+#endif
/* dtv_t *dtv = (dtv_t *)THREAD_DTV(); */
rur.threadptr a3
l32i a4, a3, 0
@@ -86,7 +91,8 @@ HIDDEN_ENTRY (_dl_tlsdesc_dynamic)
#elif defined(__XTENSA_CALL0_ABI__)
addi a1, a1, -16
s32i a0, a1, 0
- movi a0, __tls_get_addr
+ movi a0, JUMPTARGET(__tls_get_addr)
+ FDPIC_LOAD_JUMPTARGET(a0, a11, a0)
callx0 a0
l32i a0, a1, 0
addi a1, a1, 16
diff --git a/ldso/ldso/xtensa/elfinterp.c b/ldso/ldso/xtensa/elfinterp.c
index e38a02666..d97f23435 100644
--- a/ldso/ldso/xtensa/elfinterp.c
+++ b/ldso/ldso/xtensa/elfinterp.c
@@ -36,6 +36,13 @@
#include "tlsdeschtab.h"
#endif
+#ifdef __FDPIC__
+unsigned long
+_dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
+{
+ return 0;
+}
+#else
unsigned long
_dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
{
@@ -83,7 +90,7 @@ _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
return (unsigned long) new_addr;
}
-
+#endif
static int
_dl_parse (struct elf_resolve *tpnt, struct r_scope_elem *scope,
@@ -145,8 +152,8 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
int reloc_type;
int symtab_index;
char *symname;
-#if defined USE_TLS && USE_TLS
- struct elf_resolve *tls_tpnt = NULL;
+#if defined USE_TLS && USE_TLS || defined (__FDPIC__)
+ struct elf_resolve *def_mod = NULL;
#endif
struct symbol_ref sym_ref;
ElfW(Addr) *reloc_addr;
@@ -155,7 +162,7 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
ElfW(Addr) old_val;
#endif
- reloc_addr = (ElfW(Addr) *) (tpnt->loadaddr + rpnt->r_offset);
+ reloc_addr = (ElfW(Addr) *) DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_offset);
reloc_type = ELF_R_TYPE (rpnt->r_info);
symtab_index = ELF_R_SYM (rpnt->r_info);
sym_ref.sym = &symtab[symtab_index];
@@ -164,9 +171,17 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
symname = strtab + sym_ref.sym->st_name;
if (symtab_index) {
- symbol_addr = (ElfW(Addr))
- _dl_find_hash (symname, scope, tpnt,
- elf_machine_type_class (reloc_type), &sym_ref);
+ if (ELF_ST_BIND (sym_ref.sym->st_info) == STB_LOCAL) {
+ symbol_addr = (ElfW(Addr))
+ DL_RELOC_ADDR(tpnt->loadaddr,
+ symtab[symtab_index].st_value);
+ sym_ref.tpnt = tpnt;
+ } else {
+ symbol_addr = (ElfW(Addr))
+ _dl_find_hash (symname, scope, tpnt,
+ elf_machine_type_class (reloc_type),
+ &sym_ref);
+ }
/*
* We want to allow undefined references to weak symbols - this might
@@ -182,13 +197,13 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
_dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
&sym_ref, elf_machine_type_class(reloc_type));
}
-#if defined USE_TLS && USE_TLS
- tls_tpnt = sym_ref.tpnt;
+#if defined USE_TLS && USE_TLS || defined (__FDPIC__)
+ def_mod = sym_ref.tpnt;
#endif
} else {
symbol_addr =symtab[symtab_index].st_value;
-#if defined USE_TLS && USE_TLS
- tls_tpnt = tpnt;
+#if defined USE_TLS && USE_TLS || defined (__FDPIC__)
+ def_mod = tpnt;
#endif
}
@@ -202,6 +217,7 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
case R_XTENSA_GLOB_DAT:
case R_XTENSA_JMP_SLOT:
+ case R_XTENSA_SYM32:
*reloc_addr = symbol_addr + rpnt->r_addend;
break;
@@ -219,19 +235,63 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
break;
case R_XTENSA_RELATIVE:
- *reloc_addr += tpnt->loadaddr + rpnt->r_addend;
+ *reloc_addr += DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_addend);
break;
+#ifdef __FDPIC__
+ case R_XTENSA_FUNCDESC_VALUE:
+ {
+ struct funcdesc_value *dst = (struct funcdesc_value *) reloc_addr;
+
+ dst->entry_point = (void *) (symbol_addr + rpnt->r_addend);
+ dst->got_value = def_mod->loadaddr.got_value;
+ }
+ break;
+ case R_XTENSA_FUNCDESC:
+ if (symbol_addr)
+ *reloc_addr = (unsigned long)
+ _dl_funcdesc_for((void *) (symbol_addr + rpnt->r_addend),
+ sym_ref.tpnt->loadaddr.got_value);
+ else
+ /* Relocation against an undefined weak symbol:
+ set funcdesc to zero. */
+ *reloc_addr = 0;
+ break;
+ case R_XTENSA_TLS_TPOFF:
+ CHECK_STATIC_TLS((struct link_map *) def_mod);
+ *reloc_addr = symbol_addr + rpnt->r_addend + def_mod->l_tls_offset;
+ break;
+ case R_XTENSA_TLSDESC:
+ {
+ struct tlsdesc *td = (struct tlsdesc *) reloc_addr;
+#ifndef SHARED
+ CHECK_STATIC_TLS((struct link_map *) def_mod);
+#else
+ if (!TRY_STATIC_TLS ((struct link_map *) def_mod))
+ {
+ td->entry = _dl_tlsdesc_dynamic;
+ td->argument = _dl_make_tlsdesc_dynamic((struct link_map *) def_mod,
+ symbol_addr + rpnt->r_addend);
+ }
+ else
+#endif
+ {
+ td->entry = _dl_tlsdesc_return;
+ td->argument = (void *) (symbol_addr + rpnt->r_addend + def_mod->l_tls_offset);
+ }
+ }
+ break;
+#else
#if defined USE_TLS && USE_TLS
case R_XTENSA_TLS_TPOFF:
- CHECK_STATIC_TLS((struct link_map *) tls_tpnt);
- *reloc_addr = symbol_addr + tls_tpnt->l_tls_offset + rpnt->r_addend;
+ CHECK_STATIC_TLS((struct link_map *) def_mod);
+ *reloc_addr = symbol_addr + rpnt->r_addend + def_mod->l_tls_offset;
break;
case R_XTENSA_TLSDESC_FN:
#ifndef SHARED
- CHECK_STATIC_TLS((struct link_map *) tls_tpnt);
+ CHECK_STATIC_TLS((struct link_map *) def_mod);
#else
- if (!TRY_STATIC_TLS ((struct link_map *) tls_tpnt))
+ if (!TRY_STATIC_TLS ((struct link_map *) def_mod))
*reloc_addr = (ElfW(Addr)) _dl_tlsdesc_dynamic;
else
#endif
@@ -239,25 +299,25 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
break;
case R_XTENSA_TLSDESC_ARG:
#ifndef SHARED
- CHECK_STATIC_TLS((struct link_map *) tls_tpnt);
+ CHECK_STATIC_TLS((struct link_map *) def_mod);
#else
- if (!TRY_STATIC_TLS ((struct link_map *) tls_tpnt))
+ if (!TRY_STATIC_TLS ((struct link_map *) def_mod))
*reloc_addr = (ElfW(Addr))
- _dl_make_tlsdesc_dynamic((struct link_map *) tls_tpnt,
+ _dl_make_tlsdesc_dynamic((struct link_map *) def_mod,
symbol_addr + rpnt->r_addend);
else
#endif
*reloc_addr = symbol_addr + rpnt->r_addend +
- tls_tpnt->l_tls_offset;
+ def_mod->l_tls_offset;
break;
#endif
-
+#endif
default:
return -1; /* Calls _dl_exit(1). */
}
#if defined (__SUPPORT_LD_DEBUG__)
if (_dl_debug_reloc && _dl_debug_detail)
- _dl_dprintf (_dl_debug_file, "\tpatched: %x ==> %x @ %x\n",
+ _dl_dprintf (_dl_debug_file, "\tpatched: %x ==> %x @ %p\n",
old_val, *reloc_addr, reloc_addr);
#endif
@@ -275,7 +335,7 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
ElfW(Addr) old_val;
#endif
- reloc_addr = (ElfW(Addr) *) (tpnt->loadaddr + rpnt->r_offset);
+ reloc_addr = (ElfW(Addr) *) DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_offset);
reloc_type = ELF_R_TYPE (rpnt->r_info);
#if defined (__SUPPORT_LD_DEBUG__)
@@ -286,7 +346,7 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
case R_XTENSA_JMP_SLOT:
/* Perform a RELATIVE reloc on the GOT entry that transfers
to the stub function. */
- *reloc_addr += tpnt->loadaddr;
+ *reloc_addr = DL_RELOC_ADDR(tpnt->loadaddr, *reloc_addr);
break;
case R_XTENSA_NONE:
break;
@@ -296,7 +356,7 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
#if defined (__SUPPORT_LD_DEBUG__)
if (_dl_debug_reloc && _dl_debug_detail)
- _dl_dprintf (_dl_debug_file, "\tpatched: %x ==> %x @ %x\n",
+ _dl_dprintf (_dl_debug_file, "\tpatched: %x ==> %x @ %p\n",
old_val, *reloc_addr, reloc_addr);
#endif
return 0;
@@ -320,3 +380,7 @@ _dl_parse_relocation_information (struct dyn_elf *rpnt,
return _dl_parse (rpnt->dyn, scope, rel_addr, rel_size,
_dl_do_reloc);
}
+
+#ifndef IS_IN_libdl
+# include "../../libc/sysdeps/linux/xtensa/crtreloc.c"
+#endif