0.3.0: converge relibc to upstream 0.6.0 + Red Bear patches
This commit is contained in:
+144
-68
@@ -1,11 +1,17 @@
|
||||
use alloc::vec::Vec;
|
||||
use core::{intrinsics, ptr};
|
||||
//! Startup code.
|
||||
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
use core::ptr;
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
use generic_rt::ExpectTlsFree;
|
||||
|
||||
use crate::{
|
||||
header::{stdio, stdlib},
|
||||
ld_so,
|
||||
platform::{self, new_mspace, types::*, Pal, Sys},
|
||||
ALLOCATOR,
|
||||
header::{libgen, stdio, stdlib},
|
||||
ld_so::{self, linker::Linker},
|
||||
platform::{self, Pal, Sys, get_auxvs, types::*},
|
||||
sync::mutex::Mutex,
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
@@ -16,7 +22,7 @@ pub struct Stack {
|
||||
|
||||
impl Stack {
|
||||
pub fn argv(&self) -> *const *const c_char {
|
||||
&self.argv0 as *const _
|
||||
ptr::from_ref(&self.argv0)
|
||||
}
|
||||
|
||||
pub fn envp(&self) -> *const *const c_char {
|
||||
@@ -29,25 +35,39 @@ impl Stack {
|
||||
while !(*envp).is_null() {
|
||||
envp = envp.add(1);
|
||||
}
|
||||
envp.add(1) as *const (usize, usize)
|
||||
envp.add(1).cast::<(usize, usize)>()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn copy_string_array(array: *const *const c_char, len: usize) -> Vec<*mut c_char> {
|
||||
use crate::header::string::strlen;
|
||||
|
||||
let mut vec = Vec::with_capacity(len + 1);
|
||||
let mut lengths = Vec::with_capacity(len);
|
||||
let mut size = 0;
|
||||
for i in 0..len {
|
||||
let item = *array.add(i);
|
||||
let mut len = 0;
|
||||
while *item.add(len) != 0 {
|
||||
len += 1;
|
||||
let item = unsafe { *array.add(i) };
|
||||
lengths.push(unsafe { strlen(item) } + 1);
|
||||
size += lengths[i];
|
||||
}
|
||||
|
||||
// Programs unfortunately rely on the strings being contiguous in memory. For example:
|
||||
// https://github.com/libuv/libuv/blob/12d0dd48e3c6baf1e2f0d9f85f11f0ef58285d6f/src/unix/proctitle.c#L87
|
||||
let mut offset = 0;
|
||||
let buf = unsafe { platform::alloc(size).cast::<c_char>() };
|
||||
|
||||
for i in 0..len {
|
||||
let dest_buf = unsafe { buf.add(offset) };
|
||||
let item = unsafe { *array.add(i) };
|
||||
let len = lengths[i];
|
||||
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(item, dest_buf, len);
|
||||
}
|
||||
|
||||
let buf = platform::alloc(len + 1) as *mut c_char;
|
||||
for i in 0..=len {
|
||||
*buf.add(i) = *item.add(i);
|
||||
}
|
||||
vec.push(buf);
|
||||
vec.push(dest_buf);
|
||||
offset += len;
|
||||
}
|
||||
vec.push(ptr::null_mut());
|
||||
vec
|
||||
@@ -55,28 +75,33 @@ unsafe fn copy_string_array(array: *const *const c_char, len: usize) -> Vec<*mut
|
||||
|
||||
// Since Redox and Linux are so similar, it is easy to accidentally run a binary from one on the
|
||||
// other. This will test that the current system is compatible with the current binary
|
||||
#[no_mangle]
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe fn relibc_verify_host() {
|
||||
if !Sys::verify() {
|
||||
intrinsics::abort();
|
||||
unsafe { stdlib::abort() };
|
||||
}
|
||||
}
|
||||
#[link_section = ".init_array"]
|
||||
#[unsafe(link_section = ".init_array")]
|
||||
#[used]
|
||||
static INIT_ARRAY: [extern "C" fn(); 1] = [init_array];
|
||||
|
||||
static mut init_complete: bool = false;
|
||||
static mut INIT_COMPLETE: bool = false;
|
||||
|
||||
#[used]
|
||||
#[unsafe(no_mangle)]
|
||||
static mut __relibc_init_environ: *mut *mut c_char = ptr::null_mut();
|
||||
|
||||
fn alloc_init() {
|
||||
unsafe {
|
||||
if let Some(tcb) = ld_so::tcb::Tcb::current() {
|
||||
if tcb.mspace != 0 {
|
||||
ALLOCATOR.set_book_keeper(tcb.mspace);
|
||||
} else if ALLOCATOR.get_book_keeper() == 0 {
|
||||
ALLOCATOR.set_book_keeper(new_mspace());
|
||||
}
|
||||
} else if ALLOCATOR.get_book_keeper() == 0 {
|
||||
ALLOCATOR.set_book_keeper(new_mspace());
|
||||
if INIT_COMPLETE {
|
||||
return;
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
if let Some(tcb) = ld_so::tcb::Tcb::current()
|
||||
&& !tcb.mspace.is_null()
|
||||
{
|
||||
ALLOCATOR.set(tcb.mspace);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,7 +113,7 @@ extern "C" fn init_array() {
|
||||
// memory allocator before doing anything else.
|
||||
|
||||
unsafe {
|
||||
if init_complete {
|
||||
if INIT_COMPLETE {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -96,88 +121,139 @@ extern "C" fn init_array() {
|
||||
alloc_init();
|
||||
io_init();
|
||||
|
||||
extern "C" {
|
||||
fn pthread_init();
|
||||
}
|
||||
unsafe {
|
||||
pthread_init();
|
||||
init_complete = true
|
||||
if platform::environ.is_null() {
|
||||
platform::environ = __relibc_init_environ;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
crate::pthread::init();
|
||||
INIT_COMPLETE = true
|
||||
}
|
||||
}
|
||||
|
||||
fn io_init() {
|
||||
unsafe {
|
||||
// Initialize stdin/stdout/stderr, see https://github.com/rust-lang/rust/issues/51718
|
||||
stdio::stdin = stdio::default_stdin.get();
|
||||
stdio::stdout = stdio::default_stdout.get();
|
||||
stdio::stderr = stdio::default_stderr.get();
|
||||
// Initialize stdin/stdout/stderr.
|
||||
// TODO: const fn initialization of FILE
|
||||
stdio::stdin = stdio::default_stdin().get();
|
||||
stdio::stdout = stdio::default_stdout().get();
|
||||
stdio::stderr = stdio::default_stderr().get();
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! {
|
||||
extern "C" {
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn relibc_start_v1(
|
||||
sp: &'static Stack,
|
||||
main: unsafe extern "C" fn(
|
||||
argc: isize,
|
||||
argv: *mut *mut c_char,
|
||||
envp: *mut *mut c_char,
|
||||
) -> c_int,
|
||||
) -> ! {
|
||||
unsafe extern "C" {
|
||||
static __preinit_array_start: extern "C" fn();
|
||||
static __preinit_array_end: extern "C" fn();
|
||||
static __init_array_start: extern "C" fn();
|
||||
static __init_array_end: extern "C" fn();
|
||||
|
||||
fn _init();
|
||||
fn main(argc: isize, argv: *mut *mut c_char, envp: *mut *mut c_char) -> c_int;
|
||||
}
|
||||
|
||||
// Ensure correct host system before executing more system calls
|
||||
relibc_verify_host();
|
||||
unsafe { relibc_verify_host() };
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
let thr_fd = redox_rt::proc::FdGuard::new(
|
||||
unsafe {
|
||||
crate::platform::get_auxv_raw(sp.auxv().cast(), redox_rt::auxv_defs::AT_REDOX_THR_FD)
|
||||
}
|
||||
.expect_notls("no thread fd present"),
|
||||
)
|
||||
.to_upper()
|
||||
.expect_notls("failed to move thread fd to upper table");
|
||||
|
||||
// Initialize TLS, if necessary
|
||||
ld_so::init(sp);
|
||||
unsafe {
|
||||
ld_so::init(
|
||||
sp,
|
||||
#[cfg(target_os = "redox")]
|
||||
thr_fd,
|
||||
)
|
||||
};
|
||||
|
||||
// Set up the right allocator...
|
||||
// if any memory rust based memory allocation happen before this step .. we are doomed.
|
||||
alloc_init();
|
||||
|
||||
if let Some(tcb) = unsafe { ld_so::tcb::Tcb::current() } {
|
||||
// Update TCB mspace
|
||||
if tcb.mspace.is_null() {
|
||||
tcb.mspace = ALLOCATOR.get();
|
||||
}
|
||||
|
||||
// Set linker pointer if necessary
|
||||
if tcb.linker_ptr.is_null() {
|
||||
//TODO: get ld path
|
||||
let linker = Linker::new(ld_so::linker::Config::default());
|
||||
//TODO: load root object
|
||||
tcb.linker_ptr = Box::into_raw(Box::new(Mutex::new(linker)));
|
||||
}
|
||||
#[cfg(target_os = "redox")]
|
||||
redox_rt::signal::setup_sighandler(&tcb.os_specific, true);
|
||||
}
|
||||
|
||||
// Set up argc and argv
|
||||
let argc = sp.argc;
|
||||
let argv = sp.argv();
|
||||
platform::inner_argv = copy_string_array(argv, argc as usize);
|
||||
platform::argv = platform::inner_argv.as_mut_ptr();
|
||||
|
||||
// Set up envp
|
||||
let envp = sp.envp();
|
||||
let mut len = 0;
|
||||
while !(*envp.add(len)).is_null() {
|
||||
len += 1;
|
||||
unsafe { platform::inner_argv.unsafe_set(copy_string_array(argv, argc as usize)) };
|
||||
unsafe { platform::argv = platform::inner_argv.unsafe_mut().as_mut_ptr() };
|
||||
// Special code for program_invocation_name and program_invocation_short_name
|
||||
if let Some(arg) = unsafe { platform::inner_argv.unsafe_ref() }.first() {
|
||||
unsafe { platform::program_invocation_name = *arg };
|
||||
unsafe { platform::program_invocation_short_name = libgen::basename(*arg) };
|
||||
}
|
||||
// We check for NULL here since ld.so might already have initialized it for us, and we don't
|
||||
// want to overwrite it if constructors in .init_array of dependency libraries have called
|
||||
// setenv.
|
||||
if unsafe { platform::environ }.is_null() {
|
||||
// Set up envp
|
||||
let envp = sp.envp();
|
||||
let mut len = 0;
|
||||
while !(unsafe { *envp.add(len) }).is_null() {
|
||||
len += 1;
|
||||
}
|
||||
unsafe { platform::OUR_ENVIRON.unsafe_set(copy_string_array(envp, len)) };
|
||||
unsafe { platform::environ = platform::OUR_ENVIRON.unsafe_mut().as_mut_ptr() };
|
||||
}
|
||||
platform::inner_environ = copy_string_array(envp, len);
|
||||
platform::environ = platform::inner_environ.as_mut_ptr();
|
||||
|
||||
let auxvs = unsafe { get_auxvs(sp.auxv().cast()) };
|
||||
unsafe { crate::platform::init(auxvs) };
|
||||
init_array();
|
||||
unsafe { crate::platform::logger::init() };
|
||||
|
||||
// Run preinit array
|
||||
{
|
||||
let mut f = &__preinit_array_start as *const _;
|
||||
let mut f = unsafe { &__preinit_array_start } as *const _;
|
||||
#[allow(clippy::op_ref)]
|
||||
while f < &__preinit_array_end {
|
||||
(*f)();
|
||||
f = f.offset(1);
|
||||
while f < &raw const __preinit_array_end {
|
||||
(unsafe { *f })();
|
||||
f = unsafe { f.offset(1) };
|
||||
}
|
||||
}
|
||||
|
||||
// Call init section
|
||||
_init();
|
||||
|
||||
// Run init array
|
||||
{
|
||||
let mut f = &__init_array_start as *const _;
|
||||
let mut f = unsafe { &__init_array_start } as *const _;
|
||||
#[allow(clippy::op_ref)]
|
||||
while f < &__init_array_end {
|
||||
(*f)();
|
||||
f = f.offset(1);
|
||||
while f < &raw const __init_array_end {
|
||||
(unsafe { *f })();
|
||||
f = unsafe { f.offset(1) };
|
||||
}
|
||||
}
|
||||
|
||||
// not argv or envp, because programs like bash try to modify this *const* pointer :|
|
||||
stdlib::exit(main(argc, platform::argv, platform::environ));
|
||||
unsafe { stdlib::exit(main(argc, platform::argv, platform::environ)) };
|
||||
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user