public inbox for glibc-cvs@sourceware.org
help / color / mirror / Atom feed
* [glibc/arm/morello/main] aarch64: morello: rewrite start code in C
@ 2022-10-12 14:16 Szabolcs Nagy
  0 siblings, 0 replies; only message in thread
From: Szabolcs Nagy @ 2022-10-12 14:16 UTC (permalink / raw)
  To: glibc-cvs

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=d5f9769d535b795f051cb5d73625f6f4d087d25a

commit d5f9769d535b795f051cb5d73625f6f4d087d25a
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
Date:   Fri Aug 26 09:06:27 2022 +0100

    aarch64: morello: rewrite start code in C

Diff:
---
 sysdeps/aarch64/morello/cheri-rel.h |  36 ++++++
 sysdeps/aarch64/morello/dl-start.S  |  68 ------------
 sysdeps/aarch64/morello/dl-start.c  |  82 ++++++++++++++
 sysdeps/aarch64/morello/start.S     | 216 ------------------------------------
 sysdeps/aarch64/morello/start.c     | 169 ++++++++++++++++++++++++++++
 5 files changed, 287 insertions(+), 284 deletions(-)

diff --git a/sysdeps/aarch64/morello/cheri-rel.h b/sysdeps/aarch64/morello/cheri-rel.h
new file mode 100644
index 0000000000..e5522cec08
--- /dev/null
+++ b/sysdeps/aarch64/morello/cheri-rel.h
@@ -0,0 +1,36 @@
+#include <stdint.h>
+#include <ldsodefs.h>
+#include <cheri_perms.h>
+
+static inline uintptr_t
+morello_relative (uintptr_t base,
+		  const ElfW(Rela) *reloc,
+		  void *reloc_addr)
+{
+  uint64_t *__attribute__((may_alias)) u64_reloc_addr = reloc_addr;
+
+  /* Fragment identified by r_offset has the following information:
+     | 64-bit: address | 56-bits: length | 8-bits: permissions | */
+  unsigned long loc = u64_reloc_addr[0];
+  unsigned long len = u64_reloc_addr[1] & ((1UL << 56) - 1);
+  unsigned long perm = u64_reloc_addr[1] >> 56;
+  uintptr_t value;
+
+  value = base + loc;
+
+  value = __builtin_cheri_bounds_set_exact (value, len);
+
+  value = value + reloc->r_addend;
+
+  if (perm == 1)
+    value = __builtin_cheri_perms_and (value, CAP_PERM_MASK_R);
+  if (perm == 2)
+    value = __builtin_cheri_perms_and (value, CAP_PERM_MASK_RW);
+  if (perm == 4)
+    value = __builtin_cheri_perms_and (value, CAP_PERM_MASK_RX);
+
+  /* Seal executable capabilities with MORELLO_RB.  */
+  if (perm == 4)
+    value = __builtin_cheri_seal_entry (value);
+  return value;
+}
diff --git a/sysdeps/aarch64/morello/dl-start.S b/sysdeps/aarch64/morello/dl-start.S
deleted file mode 100644
index ea8d43522d..0000000000
--- a/sysdeps/aarch64/morello/dl-start.S
+++ /dev/null
@@ -1,68 +0,0 @@
-/* ld.so _start code.
-   Copyright (C) 2022 Free Software Foundation, Inc.
-
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sysdep.h>
-
-ENTRY(_start)
-
-	/* Create an initial frame with 0 LR and FP */
-	cfi_undefined (c30)
-	mov	c29, czr
-	mov	c30, czr
-	mov	c0, csp
-	bl	_dl_start
-	/* Returns user entry point in x0.  */
-	mov	c21, c0
-.globl _dl_start_user
-.type _dl_start_user, %function
-_dl_start_user:
-	/* Get argc.  */
-	ldr	x1, [csp]
-	/* Get argv.  */
-	add	c2, csp, 16
-	/* Compute envp.  */
-	add	c3, c2, x1, lsl 4
-	add	c3, c3, 16
-
-	adrp	c16, capinit_rtld_local
-	ldr	c16, [c16, :lo12:capinit_rtld_local]
-	ldr	c0, [c16]
-	bl	_dl_init
-	/* Load the finalizer function.  */
-	adrp	c0, capinit_dl_fini
-	ldr	c0, [c0, :lo12:capinit_dl_fini]
-	/* Jump to the user's entry point.  */
-	mov     c16, c21
-	br      c16
-END(_start)
-
-	.section	.data.rel.ro.local,"aw"
-	.align	4
-	.type	capinit_rtld_local, %object
-	.size	capinit_rtld_local, 16
-capinit_rtld_local:
-	.capinit	_rtld_local
-	.xword	0
-	.xword	0
-	.type	capinit_dl_fini, %object
-	.size	capinit_dl_fini, 16
-capinit_dl_fini:
-	.capinit	_dl_fini
-	.xword	0
-	.xword	0
diff --git a/sysdeps/aarch64/morello/dl-start.c b/sysdeps/aarch64/morello/dl-start.c
new file mode 100644
index 0000000000..b0bedc4b8c
--- /dev/null
+++ b/sysdeps/aarch64/morello/dl-start.c
@@ -0,0 +1,82 @@
+/* ld.so _start code.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <ldsodefs.h>
+
+asm(""
+".global	_start\n"
+".type		_start, %function\n"
+"_start:\n"
+"	.cfi_startproc\n"
+"	.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"
+"	.cfi_endproc\n"
+"	.size _start, .-_start\n");
+
+typedef void (entry_t) (void (*)(void));
+
+typedef struct user_entry {
+	entry_t *fun;
+	void (*arg)(void);
+};
+
+struct user_entry
+_dl_start_user (uintptr_t *args, entry_t *entry)
+{
+  /* Setup argv, envp, auxv for the application.  */
+  uintptr_t *p;
+  long n;
+  int argc = args[0];
+  p = args + 1;
+  n = argc + 1;
+  char **argv = (char **) __builtin_cheri_bounds_set (p, n * sizeof *p);
+  p += n;
+  for (n = 0; p[n]; n++);
+  n++;
+  char **envp = (char **) __builtin_cheri_bounds_set (p, n * sizeof *p);
+  p += n;
+  for (n = 0; p[n] != AT_NULL; n += 2);
+  n += 2;
+  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;
+}
+
+/* Generic ld.so start code in rtld.c.  */
+uintptr_t
+_dl_start (void *) attribute_hidden;
+
+/* ld.so entry point.  */
+struct user_entry
+__real_start (uintptr_t *sp)
+{
+  /* Run ls.so setup.  */
+  entry_t *entry = (entry_t *) _dl_start (sp);
+  return _dl_start_user (sp, entry);
+}
diff --git a/sysdeps/aarch64/morello/start.S b/sysdeps/aarch64/morello/start.S
deleted file mode 100644
index 27060198f3..0000000000
--- a/sysdeps/aarch64/morello/start.S
+++ /dev/null
@@ -1,216 +0,0 @@
-/* Copyright (C) 2022 Free Software Foundation, Inc.
-
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public License as
-   published by the Free Software Foundation; either version 2.1 of the
-   License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library.  If not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sysdep.h>
-#include <linux/auxvec.h>
-#include <cheri_perms.h>
-
-weak_extern (__rela_dyn_start)
-weak_extern (__rela_dyn_end)
-
-/* This is the canonical entry point, usually the first thing in the text
-   segment.
-
-   Note that 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'.
-		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
- */
-
-	.text
-ENTRY(_start)
-
-	/* Create an initial frame with 0 LR and FP */
-	cfi_undefined (c30)
-	mov	c29, czr
-	mov	c30, czr
-
-	/* TODO: Use the presence of __rela_dyn_start.  */
-	mov	c5, c0
-	cbnz	x0, L(rtld_done)
-
-	/* Initialize capabilities.  */
-#ifndef SHARED
-	/* The GNU Linker emits a R_MORELLO_RELATIVE relocation along with
-	   __rela_dyn_start and __rela_dyn_end symbols around the relocation section.
-	   r_offset contains the location, size and permissions:
-
-		capability location		// offset 0 (64 bits)
-		length				// offset 8 (56 bits)
-		permissions			//           (8 bits)
-		addend (capability offset)	// offset 16
-
-	   according to the ABI document in:
-	   https://github.com/ARM-software/abi-aa/blob/main/aaelf64-morello/aaelf64-morello.rst#dynamic-linking-with-morello
-
-	The addend is the capability offset.
-
-	   Note that this will not work with clang, since lld emits a __cap_relocs
-	   struct that has a different layout.  If we need to support clang+lld, then
-	   we need to copy the capability initialization steps from Bionic, in:
-	   libc/arch-morello/bionic/__morello_init_static.S.  */
-
-	adrp	c0, __rela_dyn_start
-	add 	c0, c0, #:lo12:__rela_dyn_start
-	adrp	c1, __rela_dyn_end
-	add	c1, c1, #:lo12:__rela_dyn_end
-
-1:
-	/* No capabilities to initialize. Skip to stack adjustment.  */
-	cmp	c0, c1
-	b.eq	3f
-
-	/* Load the address of capability.  */
-	ldr	x2, [c0, #0]
-
-	/* Construct capability location from DDC and r_offset.  */
-	cvtd	c2, x2
-
-	/* Base in x3.  */
-	ldr	x3, [c2]
-
-	/* Length + permissions in x5.  */
-	ldr	x5, [c2, #8]
-
-	/* Permissions in x6.  */
-	lsr	x6, x5, #56
-
-	/* Permissions encoded as:
-	   4 = X (executable)
-	   2 = W (read/write)
-	   1 = R (read only)
-
-	   Permissions to clear in x8 and x11.  */
-	mov	x8, (CAP_PERM_STORE_CAP | CAP_PERM_EXECUTE)
-	movk	x8, (CAP_PERM_STORE >> 16), lsl #16
-	mov	x9, (CAP_PERM_EXECUTE)
-	mov	x10, (CAP_PERM_STORE_CAP)
-	movk	x10, (CAP_PERM_STORE >> 16), lsl #16
-	mov	x11, (CAP_PERM_UNSEAL | CAP_PERM_SEAL | CAP_PERM_COMPARTMENT_ID)
-	cmp	x6, #0x2
-	csel	x8, x9, x8, eq
-	cmp	x6, #0x4
-	csel	x8, x10, x8, eq
-
-	/* Length in x5.  */
-	and	x5, x5, #0xffffffffffffff
-
-	/* Offset in x7.  */
-	ldr	x7, [c0, #16]
-
-	/* Construct capability from DDC with value equal to base.  */
-	cvtd	c3, x3
-
-	/* Set bounds to [base ; base + length].  */
-	scbndse c3, c3, x5
-
-	/* Compute the capability value from addend.  */
-	add	c3, c3, x7
-
-	/* Clear permissions.  */
-	clrperm c3, c3, x8
-	clrperm	c3, c3, x11
-
-	/* Seal capabilities, which provide execute permission, with MORELLO_RB */
-	tst	x8, #CAP_PERM_EXECUTE
-	b.ne	2f
-
-	seal	c3, c3, rb
-
-2:
-	/* Store the constructed capability to the target location.  */
-	str	c3, [c2]
-
-	/* Move to the next __rela_dyn entry.  */
-	add	c0, c0, #24
-	b	1b
-
-3:
-#endif /* !SHARED */
-
-	/* Setup rtld_fini in argument register */
-	mov	c5, czr
-
-L(rtld_done):
-
-	/* Load argc and a pointer to argv */
-	ldr	c1, [csp, #0]
-	add	c2, csp, #16
-
-	/* Setup stack limit in argument register */
-	mov	c6, csp
-
-#ifdef PIC
-# ifdef SHARED
-	adrp	c0, :got:main
-	ldr	c0, [c0, #:got_lo12:main]
-# else
-	adrp	c0, __wrap_main
-	add	c0, c0, :lo12:__wrap_main
-# endif /* SHARED */
-#else
-	/* Set up the other arguments in registers */
-	MOVL (0, main)
-	cvtd	c0, x0
-#endif /* PIC */
-
-	mov	x3, #0		/* Used to be init.  */
-	mov	x4, #0		/* Used to be fini.  */
-
-	/* __libc_start_main (main, argc, argv, init, fini, rtld_fini,
-			      stack_end) */
-
-	/* Let the libc call main and exit with its return code.  */
-	bl	__libc_start_main
-
-	/* should never get here....*/
-	bl	abort
-END(_start)
-
-#if defined PIC && !defined SHARED
-	/* When main is not defined in the executable but in a shared library
-	   then a wrapper is needed in crt1.o of the static-pie enabled libc,
-	   because crt1.o and rcrt1.o share code and the later must avoid the
-	   use of GOT relocations before __libc_start_main is called.  */
-ENTRY(__wrap_main)
-	b	main
-END(__wrap_main)
-#endif
-
-	/* Define a symbol for the first piece of initialized data.  */
-	.data
-	.globl __data_start
-__data_start:
-	.long 0
-	.weak data_start
-	data_start = __data_start
diff --git a/sysdeps/aarch64/morello/start.c b/sysdeps/aarch64/morello/start.c
new file mode 100644
index 0000000000..5af010f8c3
--- /dev/null
+++ b/sysdeps/aarch64/morello/start.c
@@ -0,0 +1,169 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file with other
+   programs, and to distribute those programs without any restriction
+   coming from the use of this file. (The GNU Lesser General Public
+   License restrictions do apply in other respects; for example, they
+   cover modification of the file, and distribution when not linked
+   into another program.)
+
+   Note that people who make modified versions of this file are not
+   obligated to grant this special exception for their modified
+   versions; it is their choice whether to do so. The GNU Lesser
+   General Public License gives permission to release a modified
+   version without this exception; this exception also makes it
+   possible to release a modified version which carries forward this
+   exception.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+#include <ldsodefs.h>
+#include <cheri-rel.h>
+
+/* This is the canonical entry point, usually the first thing in the text
+   segment.
+
+   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'.
+		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
+ */
+
+asm(""
+".global	_start\n"
+".type		_start, %function\n"
+"_start:\n"
+"	.cfi_startproc\n"
+"	.cfi_undefined c30\n"
+"	mov	c29, czr\n"
+"	mov	c30, czr\n"
+"	mov	c1, csp\n"
+"	b	__real_start\n"
+"	.cfi_endproc\n"
+"	.size _start, .-_start\n");
+
+#ifndef SHARED
+static int
+is_static_linked (void)
+{
+  unsigned long x;
+  asm (""
+    ".weak __rela_dyn_start\n"
+    ".hidden __rela_dyn_start\n"
+    "movz %0, #:abs_g3:__rela_dyn_start\n"
+    "movk %0, #:abs_g2_nc:__rela_dyn_start\n"
+    "movk %0, #:abs_g1_nc:__rela_dyn_start\n"
+    "movk %0, #:abs_g0_nc:__rela_dyn_start\n" : "=r"(x));
+  return x != 0;
+}
+
+static uintptr_t
+get_rela_dyn_start (void)
+{
+  uintptr_t p;
+  asm (""
+    ".weak __rela_dyn_start\n"
+    ".hidden __rela_dyn_start\n"
+    "adrp %0, __rela_dyn_start\n"
+    "add %0, %0, :lo12:__rela_dyn_start\n" : "=r"(p));
+  return p;
+}
+
+static uintptr_t
+get_rela_dyn_end (void)
+{
+  uintptr_t p;
+  asm (""
+    ".weak __rela_dyn_end\n"
+    ".hidden __rela_dyn_end\n"
+    "adrp %0, __rela_dyn_end\n"
+    "add %0, %0, :lo12:__rela_dyn_end\n" : "=r"(p));
+  return p;
+}
+
+static uintptr_t
+get_base (void)
+{
+  /* 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;
+}
+
+static void
+apply_rel (uintptr_t base, uintptr_t start, uintptr_t end)
+{
+  const ElfW(Rela) *r;
+  for (r = (const ElfW(Rela) *)start; r != (void *)end; r++)
+    {
+      uintptr_t *reloc_addr = base + r->r_offset;
+      uintptr_t value = morello_relative (base, r, reloc_addr);
+      *reloc_addr = value;
+    }
+}
+#endif /* !SHARED */
+
+int main (int argc, char **argv);
+
+void __libc_start_main (int main (int, char **),
+			int argc, char **argv,
+			void *init, void *fini,
+			void rtld_fini (void), void *sp);
+
+void
+__real_start (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, start, end);
+      rtld_fini = 0;
+    }
+  /* Compiler barrier after relocs are processed.  */
+  asm volatile ("" ::: "memory");
+#endif
+
+  int argc = *sp;
+  char **argv = (char **) (sp + 1);
+  __libc_start_main (main, argc, argv, 0, 0, rtld_fini, sp);
+  __builtin_trap ();
+}
+
+int __data_start = 1;
+weak_alias (__data_start, data_start);

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-10-12 14:16 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-12 14:16 [glibc/arm/morello/main] aarch64: morello: rewrite start code in C Szabolcs Nagy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).