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).