1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#![doc = include_str!("../README.md")]
#![deny(missing_docs)]
#![feature(asm)]
#![feature(asm_const)]
#![feature(asm_sym)]
#![feature(naked_functions)]
#![feature(link_llvm_intrinsics)]
#![feature(atomic_mut_ptr)]

mod allocator;
mod mutex;
mod program;
#[cfg(feature = "threads")]
mod threads;

#[cfg(all(target_arch = "aarch64", feature = "threads"))]
#[path = "arch-aarch64.rs"]
mod arch;
#[cfg(all(target_arch = "x86_64", feature = "threads"))]
#[path = "arch-x86_64.rs"]
mod arch;
#[cfg(all(target_arch = "x86", feature = "threads"))]
#[path = "arch-x86.rs"]
mod arch;
#[cfg(all(target_arch = "riscv64", feature = "threads"))]
#[path = "arch-riscv64.rs"]
mod arch;
#[cfg(all(target_arch = "arm", feature = "threads"))]
#[path = "arch-arm.rs"]
mod arch;

use std::ffi::c_void;

pub use program::{at_exit, at_fork, exit, exit_immediately, fork};
#[cfg(feature = "threads")]
pub use threads::{
    at_thread_exit, create_thread, current_thread, current_thread_id, current_thread_tls_addr,
    default_guard_size, default_stack_size, detach_thread, join_thread, thread_stack, Thread,
};

/// The program entry point.
///
/// # Safety
///
/// This function should never be called explicitly. It is the first thing
/// executed in the program, and it assumes that memory is laid out
/// according to the operating system convention for starting a new program.
#[cfg(target_vendor = "mustang")]
#[naked]
#[no_mangle]
unsafe extern "C" fn _start() -> ! {
    use program::entry;

    // Jump to `program`, passing it the initial stack pointer value as an
    // argument, a NULL return address, a NULL frame pointer, and an aligned
    // stack pointer.

    #[cfg(target_arch = "x86_64")]
    asm!("mov rdi, rsp",
         "push rbp",
         "jmp {entry}",
         entry = sym entry,
         options(noreturn));

    #[cfg(target_arch = "aarch64")]
    asm!("mov x0, sp",
         "mov x30, xzr",
         "b {entry}",
         entry = sym entry,
         options(noreturn));

    #[cfg(target_arch = "arm")]
    asm!("mov r0, sp\n",
         "mov lr, #0",
         "b {entry}",
         entry = sym entry,
         options(noreturn));

    #[cfg(target_arch = "riscv64")]
    asm!("mv a0, sp",
         "mv ra, zero",
         "mv fp, zero",
         "tail {entry}",
         entry = sym entry,
         options(noreturn));

    #[cfg(target_arch = "x86")]
    asm!("mov eax, esp",
         "push ebp",
         "push ebp",
         "push ebp",
         "push eax",
         "push ebp",
         "jmp {entry}",
         entry = sym entry,
         options(noreturn));
}

#[repr(transparent)]
struct SendSyncVoidStar(*mut c_void);

unsafe impl Send for SendSyncVoidStar {}
unsafe impl Sync for SendSyncVoidStar {}

/// An ABI-conforming `__dso_handle`.
#[cfg(target_vendor = "mustang")]
#[no_mangle]
static __dso_handle: SendSyncVoidStar = SendSyncVoidStar(&__dso_handle as *const _ as *mut c_void);

/// Initialize logging, if enabled.
#[cfg(target_vendor = "mustang")]
#[cfg(feature = "env_logger")]
#[link_section = ".init_array.00099"]
#[used]
static INIT_ARRAY: unsafe extern "C" fn() = {
    unsafe extern "C" fn function() {
        env_logger::init();

        log::trace!(target: "origin::program", "Program started");

        // Log the thread id. We initialized the main earlier than this, but
        // we couldn't initialize the logger until after the main thread is
        // intialized :-).
        #[cfg(feature = "threads")]
        log::trace!(target: "origin::threads", "Main Thread[{:?}] initialized", current_thread_id());
    }
    function
};

#[cfg(target_vendor = "mustang")]
#[global_allocator]
static GLOBAL_ALLOCATOR: allocator::GlobalAllocator = allocator::GlobalAllocator;