1 //===-- Implementation of crt for aarch64 ---------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "config/linux/app.h"
10 #include "src/__support/OSUtil/syscall.h"
11 
12 #include <linux/auxvec.h>
13 #include <linux/elf.h>
14 #include <stdint.h>
15 #include <sys/syscall.h>
16 
17 extern "C" int main(int, char **, char **);
18 
19 // Source documentation:
20 // https://github.com/ARM-software/abi-aa/tree/main/sysvabi64
21 
22 namespace __llvm_libc {
23 
24 AppProperties app;
25 
26 } // namespace __llvm_libc
27 
28 using __llvm_libc::app;
29 
30 struct Args {
31   // In the ARM64 ABI, arguments are usually passed in registers.  x0 is a
32   // doubleword register, so this is 64 bit.
33   uint64_t argc;
34 
35   // C++ Doesn't have flexible arrays: P1039 proposes to fix this, but for now
36   // we just fake it.  Even if argc is zero, "argv[argc] shall be a null
37   // pointer" (ISO C 5.1.2.2.1) so one is fine.
38   uint64_t argv[1];
39 };
40 
41 // TODO: Would be nice to use the aux entry structure from elf.h when available.
42 struct AuxEntry {
43   uint64_t type;
44   uint64_t value;
45 };
46 
47 extern "C" void _start() {
48   uintptr_t *frame_ptr =
49       reinterpret_cast<uintptr_t *>(__builtin_frame_address(0));
50 
51   // Skip the Frame Pointer and the Link Register
52   // https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst
53   // Section 6.2.3
54 
55   Args *args = reinterpret_cast<Args *>(frame_ptr + 2);
56 
57   // After the argv array, is a 8-byte long NULL value before the array of env
58   // values. The end of the env values is marked by another 8-byte long NULL
59   // value. We step over it (the "+ 1" below) to get to the env values.
60   uint64_t *env_ptr = args->argv + args->argc + 1;
61   uint64_t *env_end_marker = env_ptr;
62   while (*env_end_marker)
63     ++env_end_marker;
64 
65   // After the env array, is the aux-vector. The end of the aux-vector is
66   // denoted by an AT_NULL entry.
67   for (AuxEntry *aux_entry = reinterpret_cast<AuxEntry *>(env_end_marker + 1);
68        aux_entry->type != AT_NULL; ++aux_entry) {
69     switch (aux_entry->type) {
70     case AT_PAGESZ:
71       app.pageSize = aux_entry->value;
72       break;
73     default:
74       break; // TODO: Read other useful entries from the aux vector.
75     }
76   }
77 
78   // TODO: Init TLS
79 
80   __llvm_libc::syscall(SYS_exit,
81                        main(args->argc, reinterpret_cast<char **>(args->argv),
82                             reinterpret_cast<char **>(env_ptr)));
83 }
84