diff options
author | Szabolcs Nagy <szabolcs.nagy@arm.com> | 2022-08-31 11:26:46 +0100 |
---|---|---|
committer | Szabolcs Nagy <szabolcs.nagy@arm.com> | 2022-10-12 14:22:03 +0100 |
commit | 11e0080cd54f35d11ed45ba18a52419608203ad8 (patch) | |
tree | 49de2416f70fb2af3df4c049d69ea0bace534fdb | |
parent | bb624b6c4376d3b3a3c4fe3ed5d1cd6366fd3ac6 (diff) | |
download | glibc-11e0080cd54f35d11ed45ba18a52419608203ad8.zip glibc-11e0080cd54f35d11ed45ba18a52419608203ad8.tar.gz glibc-11e0080cd54f35d11ed45ba18a52419608203ad8.tar.bz2 |
aarch64: morello: Use purecap ELF entry ABI in _start
The purecap ELF entry is special: passes separate argc, argv, envp,
auxv in registers instead of on the stack.
The ldso internal _dl_start still expects continuous argc, argv, envp,
auxv, so that's emulated.
-rw-r--r-- | sysdeps/aarch64/morello/dl-start.c | 68 | ||||
-rw-r--r-- | sysdeps/aarch64/morello/start.c | 68 |
2 files changed, 85 insertions, 51 deletions
diff --git a/sysdeps/aarch64/morello/dl-start.c b/sysdeps/aarch64/morello/dl-start.c index b0bedc4..f1b792d 100644 --- a/sysdeps/aarch64/morello/dl-start.c +++ b/sysdeps/aarch64/morello/dl-start.c @@ -28,23 +28,14 @@ asm("" " .cfi_undefined c30\n" " mov c29, czr\n" " mov c30, czr\n" -" mov c0, csp\n" -" bl __real_start\n" - /* Jump to the user's entry point, with original csp. */ -" mov c16, c0\n" -" mov c0, c1\n" -" br c16\n" +" b __real_start\n" " .cfi_endproc\n" " .size _start, .-_start\n"); -typedef void (entry_t) (void (*)(void)); +typedef void (entry_t) (int, char **, char **, void *, void (*)(void)); -typedef struct user_entry { - entry_t *fun; - void (*arg)(void); -}; - -struct user_entry +__attribute__ ((noinline, noreturn)) +void _dl_start_user (uintptr_t *args, entry_t *entry) { /* Setup argv, envp, auxv for the application. */ @@ -64,8 +55,22 @@ _dl_start_user (uintptr_t *args, entry_t *entry) uintptr_t *auxv = __builtin_cheri_bounds_set (p, n * sizeof *p); _dl_init (GL(dl_ns)[LM_ID_BASE]._ns_loaded, argc, argv, envp); - struct user_entry e = {entry, _dl_fini}; - return e; + entry (argc, argv, envp, auxv, _dl_fini); + __builtin_trap (); +} + +/* Count the array length needed for traditional ELF entry. */ +static inline long +count_args (int argc, char **argv, char **envp, uintptr_t *auxv) +{ + char **p; + uintptr_t *q; + long nargs = argc + 2; + for (p = envp; *p != NULL; p++); + nargs += p - envp + 1; + for (q = auxv; *q != AT_NULL; q += 2); + nargs += q - auxv + 2; + return nargs; } /* Generic ld.so start code in rtld.c. */ @@ -73,10 +78,33 @@ uintptr_t _dl_start (void *) attribute_hidden; /* ld.so entry point. */ -struct user_entry -__real_start (uintptr_t *sp) +void +__real_start (int argc, char **argv, char **envp, void *auxv) { - /* Run ls.so setup. */ - entry_t *entry = (entry_t *) _dl_start (sp); - return _dl_start_user (sp, entry); + long nargs = count_args (argc, argv, envp, auxv); + { + /* _dl_start requires continuous argv, envp, auxv. */ + uintptr_t args[nargs]; + long i = 0, j; + args[i++] = argc; + for (j = 0; argv[j] != NULL; j++) + args[i++] = (uintptr_t) argv[j]; + args[i++] = 0; + for (j = 0; envp[j] != NULL; j++) + args[i++] = (uintptr_t) envp[j]; + args[i++] = 0; + uintptr_t *a = auxv; + for (j = 0; a[j] != AT_NULL; j += 2) + { + args[i++] = a[j]; + args[i++] = a[j+1]; + } + args[i++] = AT_NULL; + args[i++] = 0; + assert (i == nargs); + + /* Run ls.so setup. */ + entry_t *entry = (entry_t *) _dl_start (args); + _dl_start_user (args, entry); + } } diff --git a/sysdeps/aarch64/morello/start.c b/sysdeps/aarch64/morello/start.c index fbc9512..de7aeab 100644 --- a/sysdeps/aarch64/morello/start.c +++ b/sysdeps/aarch64/morello/start.c @@ -43,24 +43,24 @@ Note that in case of dynamic linked exe the code in the .init section has already been run. This includes _init and _libc_init. - At this entry point, most registers' values are unspecified, except: - x0/w0 Contains a function pointer to be registered with `atexit'. + x0 argc + + c1 argv + + c2 envp + + c3 auxv + + c4 Contains a function pointer to be registered with `atexit'. This is how the dynamic linker arranges to have DT_FINI functions called for shared libraries that have been loaded - before this code runs. - - sp The stack contains the arguments and environment: - 0(sp) argc - 8(sp) argv[0] - ... - (8*argc)(sp) NULL - (8*(argc+1))(sp) envp[0] - ... - NULL - */ + before this code runs. It is unspecified in a static linked + executable. + csp The stack pointer. + */ asm("" ".global _start\n" ".type _start, %function\n" @@ -69,7 +69,7 @@ asm("" " .cfi_undefined c30\n" " mov c29, czr\n" " mov c30, czr\n" -" mov c1, csp\n" +" mov c5, csp\n" " b __real_start\n" " .cfi_endproc\n" " .size _start, .-_start\n"); @@ -113,14 +113,24 @@ get_rela_dyn_end (void) return p; } -static uintptr_t -get_base (void) +static void +get_caps (uintptr_t *cap_rx, uintptr_t *cap_rw, const uintptr_t *auxv) { - /* The base is always 0: only used for static linking and static pie - is not supported here. */ - uintptr_t p = 0; - asm volatile ("cvtd %0, %x0" : "+r"(p)); - return p; + for (;;) + { + switch ((unsigned long)auxv[0]) + { + case AT_NULL: + return; + case AT_CHERI_EXEC_RX_CAP: + *cap_rx = auxv[1]; + break; + case AT_CHERI_EXEC_RW_CAP: + *cap_rw = auxv[1]; + break; + } + auxv += 2; + } } static void @@ -144,27 +154,23 @@ void __libc_start_main (int main (int, char **, char **, void *), void rtld_fini (void), void *sp); void -__real_start (void rtld_fini (void), uintptr_t *sp) +__real_start (int argc, char **argv, char **envp, void *auxv, + void (*rtld_fini) (void), uintptr_t *sp) { #ifndef SHARED if (is_static_linked ()) { uintptr_t start = get_rela_dyn_start (); uintptr_t end = get_rela_dyn_end (); - uintptr_t base = get_base (); - apply_rel (base, base, start, end); + uintptr_t cap_rx = 0; + uintptr_t cap_rw = 0; + get_caps (&cap_rx, &cap_rw, auxv); + apply_rel (cap_rx, cap_rw, start, end); rtld_fini = 0; } /* Compiler barrier after relocs are processed. */ asm volatile ("" ::: "memory"); #endif - - int argc = *sp; - char **argv = (char **) (sp + 1); - char **envp = argv + argc + 1; - char **p = envp; - while (*p) p++; - void *auxv = p + 1; __libc_start_main (main, argc, argv, envp, auxv, rtld_fini, sp); __builtin_trap (); } |