From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1944) id 0C09F3850416; Wed, 12 Oct 2022 14:16:51 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0C09F3850416 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1665584211; bh=V6n9J45FNccMTFD1uxTX8jl7OMNoKKlkroMVKheyFS0=; h=From:To:Subject:Date:From; b=UvEftYw9PDKvoISe8KosefGDzfbuTue7HqnAkgxI15snm2ArjIZ59oVbZ+nIsvtrH JD55ZPfn/TKtiddzutZARvTgQVjhgiV0kmLDdrajqZfn3hCFCjG/6/ulzuy/wjJh2o TfzcY4bjJwhRAeq1jbpM1hgU7gXhhj1hNmKaA5ok= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Szabolcs Nagy To: glibc-cvs@sourceware.org Subject: [glibc/arm/morello/main] aarch64: morello: rewrite start code in C X-Act-Checkin: glibc X-Git-Author: Szabolcs Nagy X-Git-Refname: refs/heads/arm/morello/main X-Git-Oldrev: 009e1fd306a8f3983f65faa51fb2a6175e74d87e X-Git-Newrev: d5f9769d535b795f051cb5d73625f6f4d087d25a Message-Id: <20221012141651.0C09F3850416@sourceware.org> Date: Wed, 12 Oct 2022 14:16:51 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=d5f9769d535b795f051cb5d73625f6f4d087d25a commit d5f9769d535b795f051cb5d73625f6f4d087d25a Author: Szabolcs Nagy 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 +#include +#include + +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 - . */ - -#include - -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 + . */ + +#include +#include + +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 - . */ - -#include -#include -#include - -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 + . */ + +#include +#include +#include + +/* 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);