#include "startup/linux/do_start.h"
#include "config/linux/app.h"
#include "hdr/elf_proxy.h"
#include "hdr/link_macros.h"
#include "hdr/stdint_proxy.h"
#include "src/__support/OSUtil/linux/auxv.h"
#include "src/__support/OSUtil/syscall.h"
#include "src/__support/macros/config.h"
#include "src/__support/threads/thread.h"
#include "src/stdlib/atexit.h"
#include "src/stdlib/exit.h"
#include "src/unistd/environ.h"
#include "startup/linux/gnu_property_section.h"
#include "startup/linux/irelative.h"
#include <sys/mman.h>
#include <sys/syscall.h>
extern "C" int main(int argc, char **argv, char **envp);
extern "C" {
extern uintptr_t __preinit_array_start[];
extern uintptr_t __preinit_array_end[];
extern uintptr_t __init_array_start[];
extern uintptr_t __init_array_end[];
extern uintptr_t __fini_array_start[];
extern uintptr_t __fini_array_end[];
[[gnu::weak,
gnu::visibility("hidden")]] extern const ElfW(Dyn) _DYNAMIC[]; }
namespace LIBC_NAMESPACE_DECL {
AppProperties app;
using InitCallback = void(int, char **, char **);
using FiniCallback = void(void);
static void call_init_array_callbacks(int argc, char **argv, char **env) {
size_t preinit_array_size = __preinit_array_end - __preinit_array_start;
for (size_t i = 0; i < preinit_array_size; ++i)
reinterpret_cast<InitCallback *>(__preinit_array_start[i])(argc, argv, env);
size_t init_array_size = __init_array_end - __init_array_start;
for (size_t i = 0; i < init_array_size; ++i)
reinterpret_cast<InitCallback *>(__init_array_start[i])(argc, argv, env);
}
static void call_fini_array_callbacks() {
size_t fini_array_size = __fini_array_end - __fini_array_start;
for (size_t i = fini_array_size; i > 0; --i)
reinterpret_cast<FiniCallback *>(__fini_array_start[i - 1])();
}
static ThreadAttributes main_thread_attrib;
static TLSDescriptor tls;
[[noreturn]] void do_start() {
auto tid = syscall_impl<long>(SYS_gettid);
if (tid <= 0)
syscall_impl<long>(SYS_exit, 1);
main_thread_attrib.tid = static_cast<int>(tid);
uintptr_t *env_ptr = app.args->argv + app.args->argc + 1;
uintptr_t *env_end_marker = env_ptr;
app.env_ptr = env_ptr;
while (*env_end_marker)
++env_end_marker;
environ = reinterpret_cast<char **>(env_ptr);
ElfW(Phdr) *program_hdr_table = nullptr;
uintptr_t program_hdr_count = 0;
unsigned long hwcap = 0;
unsigned long hwcap2 = 0;
auxv::Vector::initialize_unsafe(
reinterpret_cast<const auxv::Entry *>(env_end_marker + 1));
auxv::Vector auxvec;
for (const auto &aux_entry : auxvec) {
switch (aux_entry.type) {
case AT_PHDR:
program_hdr_table = reinterpret_cast<ElfW(Phdr) *>(aux_entry.val);
break;
case AT_PHNUM:
program_hdr_count = aux_entry.val;
break;
case AT_PAGESZ:
app.page_size = aux_entry.val;
break;
case AT_HWCAP:
hwcap = aux_entry.val;
break;
case AT_HWCAP2:
hwcap2 = aux_entry.val;
break;
default:
break; }
}
intptr_t base = 0;
app.tls.size = 0;
ElfW(Phdr) *tls_phdr = nullptr;
[[maybe_unused]] ElfW(Phdr) *gnu_property_phdr = nullptr;
for (uintptr_t i = 0; i < program_hdr_count; ++i) {
ElfW(Phdr) &phdr = program_hdr_table[i];
if (phdr.p_type == PT_PHDR)
base = reinterpret_cast<intptr_t>(program_hdr_table) - phdr.p_vaddr;
if (phdr.p_type == PT_DYNAMIC && _DYNAMIC)
base = reinterpret_cast<intptr_t>(_DYNAMIC) - phdr.p_vaddr;
if (phdr.p_type == PT_TLS)
tls_phdr = &phdr;
if (phdr.p_type == PT_GNU_PROPERTY)
gnu_property_phdr = &phdr;
}
if (reinterpret_cast<uintptr_t>(__rela_iplt_start) !=
reinterpret_cast<uintptr_t>(__rela_iplt_end))
apply_irelative_relocs(base, hwcap, hwcap2);
app.tls.address = tls_phdr->p_vaddr + base;
app.tls.size = tls_phdr->p_memsz;
app.tls.init_size = tls_phdr->p_filesz;
app.tls.align = tls_phdr->p_align;
init_tls(tls);
if (tls.size != 0 && !set_thread_ptr(tls.tp))
syscall_impl<long>(SYS_exit, 1);
self.attrib = &main_thread_attrib;
main_thread_attrib.atexit_callback_mgr =
internal::get_thread_atexit_callback_mgr();
atexit(&call_fini_array_callbacks);
call_init_array_callbacks(static_cast<int>(app.args->argc),
reinterpret_cast<char **>(app.args->argv),
reinterpret_cast<char **>(env_ptr));
int retval = main(static_cast<int>(app.args->argc),
reinterpret_cast<char **>(app.args->argv),
reinterpret_cast<char **>(env_ptr));
exit(retval);
}
}