]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
aarch64: morello: Use purecap ELF entry ABI in _start
authorSzabolcs Nagy <szabolcs.nagy@arm.com>
Wed, 31 Aug 2022 10:26:46 +0000 (11:26 +0100)
committerSzabolcs Nagy <szabolcs.nagy@arm.com>
Wed, 12 Oct 2022 13:22:03 +0000 (14:22 +0100)
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.

sysdeps/aarch64/morello/dl-start.c
sysdeps/aarch64/morello/start.c

index b0bedc4b8c2aebf71cf071b620687686789d28bf..f1b792d957a69e9a9be3584dded794a1bb195f10 100644 (file)
@@ -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);
+  }
 }
index fbc95127899e601bb1e999e65f3b511f7754356a..de7aeab4c924b62a212672df5f1e812673dda46d 100644 (file)
    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 ();
 }