blob: 0b8e8a326f6c4f8313baa19a1c246046776dc2a3 [file] [log] [blame]
// Copyright 2025 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ZIRCON_STARTUP_H_
#define ZIRCON_STARTUP_H_
#include <zircon/compiler.h>
#include <zircon/types.h>
__BEGIN_CDECLS
// All Fuchsia ELF executables are position-independent (PIE) executables.
// Most use a dynamic linker via the PT_INTERP mechanism. To use fully static
// linking (aside from the vDSO), each static PIE must perform its own startup
// dynamic linking, including vDSO references for making Zircon system calls.
//
// The standard entry point function (_start), used for both a static PIE and a
// dynamically-linked executable, calls the __libc_start_main function in the C
// library. For the dynamic linking case, this is called after the dynamic
// linker has done its work and of necessity has already used a system
// bootstrap protocol on the handle transferred into the process by
// zx_process_start; the __libc_start_main function is found in the shared C
// library. For a static PIE using the statically-linked C library instead,
// __libc_start_main does the dynamic linking work and then uses the APIs below
// to make use of the process start handle. These can be overridden by a
// static PIE to support a custom bootstrap protocol instead of the standard
// one supported by the C library. They cannot be overridden when using the
// shared C library: __libc_start_main will always use the standard protocols
// appropriate for the Fuchsia API level for which the C library was built.
//
// Either all of these three functions or none of them must be defined by a
// static PIE. They work together.
// The first function is called with, and must use, only the basic machine ABI
// (no thread pointer, no shadow call stack). Dynamic linking is complete and
// it can use system calls from the Zircon vDSO.
//
// **NOTE:** No C library functions can be used here, as they rely on the full
// Fuchsia Compiler ABI. This includes even memcpy and memset calls that may
// be emitted by the compiler. Entirely hermetic code that sticks to the
// basic machine ABI must be used to define this function.
//
// The argument is the initial handle transferred via zx_process_start. This
// function takes ownership of that handle and the C library does not save it
// otherwise. The return value provides the essential Zircon handles the C
// library needs to perform its basic work and complete startup. An opaque
// void* value can be used to communicate any needed state to the second and
// third functions (declared below) without resorting to global variables.
typedef struct {
// The process handle will be installed for zx_process_self() to return.
// The C library is presumed to take ownership of this handle. It never
// closes the handle. What zx_process_self() returns can never be changed.
zx_handle_t process_self;
// The thread handle will be used to manage the initial (calling) thread.
// This is what zx_thread_self() or thrd_get_zx_handle() will return later.
// The C library takes ownership of this handle and will close it if the
// initial thread exits via thrd_exit() or pthread_exit().
zx_handle_t thread_self;
// The VMAR that libc can use for general allocation.
// This is also installed for zx_vmar_root_self() to return.
zx_handle_t allocation_vmar;
// The innermost VMAR covering the load image of the executable itself.
// This is used to apply RELRO protection after dynamic linking, and then
// the handle is closed immediately. It's usually the last handle to that
// VMAR, such that revoking the protection becomes impossible thereafter.
// If this is ZX_HANDLE_INVALID, no RELRO protection will be attempted.
zx_handle_t executable_image_vmar;
// May be ZX_HANDLE_INVALID or may be a handle for a ZX_OBJ_TYPE_DEBUGLOG or
// ZX_OBJ_TYPE_SOCKET object to be used for implicit logging. This will be
// used for __sanitizer_log_write (see <zircon/sanitizer.h>), and also for
// panic messages in early libc startup (if things go unrecoverably wrong
// before constructors run).
zx_handle_t log;
// This is not examined by the C library, but is passed through to the
// _zx_startup_get_arguments function.
void* hook;
} zx_startup_handles_t;
zx_startup_handles_t _zx_startup_get_handles(zx_handle_t process_start_handle);
// This is called with the full Fuchsia Compiler ABI in place. It runs before
// any C++ constructors. Basic C library functions can be used normally, but
// anything using normal memory allocation (malloc et al, C++ non-placement
// new, etc.) should be avoided because the allocator is not initialized yet
// and its setup and may be influenced by the return value (e.g. environment
// variables). The argument is the `hook` value _zx_startup_get_handles just
// returned. The return value provides arguments for `main` and to make
// `getenv` work, etc. Empty values will be replaced with valid pointers.
// Otherwise the invariant `argv[argc] == NULL` most hold.
typedef struct {
int argc;
char** argv; // argc NUL-terminated strings, followed by nullptr.
char** envp; // NUL-terminated environment strings, followed by nullptr.
} zx_startup_arguments_t;
zx_startup_arguments_t _zx_startup_get_arguments(void* hook);
// This is the last thing called before C++ static constructors and the like
// will be called. It can use all normal C library functionality, including
// allocation. The argument is the same pointer value originally returned by
// _zx_startup_get_handles and then passed to _zx_startup_get_handles. It
// should install any global state that should be in place before application
// or library code from constructors or `main` can run. For example, it
// should call `_zx_utc_reference_swap` (<zircon/utc.h>).
void _zx_startup_preinit(void* hook);
__END_CDECLS
#endif // ZIRCON_STARTUP_H_