|
| 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 "include/sys/syscall.h" |
| 11 | +#include "src/__support/OSUtil/syscall.h" |
| 12 | + |
| 13 | +#include <linux/auxvec.h> |
| 14 | +#include <linux/elf.h> |
| 15 | +#include <stdint.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 | +} |
0 commit comments