libc: add openlibm, hide compiler_builtins in static lib

This commit is contained in:
Mark Poliakov 2024-11-13 15:58:29 +02:00
parent 0b9f1c0fac
commit 9e187a4e94
18 changed files with 299 additions and 171 deletions

14
test.c
View File

@ -1,13 +1,11 @@
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
#include <math.h>
int main(int argc, const char **argv) {
int x = 1234;
printf("Hello %d!!!\n", x);
double x = round(1234.123);
assert(fabs(x - 1234.000) < 0.00001);
double y = round(1234.5678);
assert(fabs(y - 1235.000) < 0.00001);
return 0;
}

View File

@ -65,14 +65,13 @@ fn compile_crt0(arch: &str, output_dir: impl AsRef<Path>) {
command
.arg(format!("--target={}-unknown-none", arch))
.arg("-nostdlib")
.arg("-nostdinc")
.arg("-c")
.arg("-o")
.arg(output_dir.join("crt0.o"))
.arg(format!("crt/{}/crt0.S", arch));
.arg(format!("crt/{}/crt0.c", arch));
if !command.status().unwrap().success() {
panic!("Couldn't compile crt0.S");
panic!("Couldn't compile crt0.o");
}
}

View File

@ -1,11 +0,0 @@
.section .text
.global _start
.extern __ygglibc_entry
.type _start, %function
_start:
// %rdi -- kernel argument
leaq __ygglibc_entry(%rip), %rax
jmp *%rax
.size _start, . - _start

View File

@ -0,0 +1,15 @@
#include <stddef.h>
extern __attribute__((noreturn)) void __ygglibc_entry(const void *);
// // rust's shlib export breaks memset symbol
// void *memset(void *dst, int val, size_t len) __attribute__((weak)) {
// for (size_t i = 0; i < len; ++i) {
// ((char *) dst)[i] = (char) val;
// }
// return dst;
// }
[[noreturn]] void _start(const void *arg) {
__ygglibc_entry(arg);
}

View File

@ -7,7 +7,7 @@
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
"max-atomic-width": 64,
"target-pointer-width": "64",
"features": "-avx,-sse,+soft-float",
"features": "+sse",
"disable-redzone": true,
"executables": true,
@ -22,6 +22,11 @@
"linker": "rust-lld",
"linker-flavor": "ld.lld",
"late-link-args-static": {
"ld.lld": [
"--gc-sections"
]
},
"late-link-args-dynamic": {
"ld.lld": [
"--dynamic-linker=/libexec/dyn-loader"

View File

@ -0,0 +1,20 @@
#include <openlibm_math.h>
typedef float float_t;
typedef double double_t;
#ifndef M_PI
#define M_PI 3.14159265358979323846 /* pi */
#endif
#ifndef M_PI_2
#define M_PI_2 1.57079632679489661923 /* pi/2 */
#endif
#ifndef M_PI_4
#define M_PI_4 0.78539816339744830962 /* pi/4 */
#endif
#ifndef M_2_PI
#define M_2_PI 0.63661977236758134308 /* 2/pi */
#endif

View File

@ -7,13 +7,7 @@ use core::{
use libyalloc::{allocator::BucketAllocator, sys::PageProvider};
use yggdrasil_rt::{mem::MappingSource, sys as syscall};
use crate::{
error::EResult,
headers::{
errno,
string::{memcpy, memset},
}, sync::Mutex,
};
use crate::{error::EResult, headers::{errno, string::mem::{memcpy, memset}}, sync::Mutex};
struct Allocator;
struct PageProviderImpl;

View File

@ -1,4 +1,4 @@
use core::ffi::c_int;
use core::ffi::{c_int, c_short};
use super::locale::locale_t;
@ -159,3 +159,8 @@ unsafe extern "C" fn tolower_l(_ch: c_int, _locale: locale_t) -> c_int {
unsafe extern "C" fn toupper_l(_ch: c_int, _locale: locale_t) -> c_int {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn __ctype_b_loc() -> *mut *mut c_short {
todo!()
}

View File

@ -1,5 +1,7 @@
use core::{ffi::{c_int, c_void}, ptr::null_mut};
use core::{
ffi::{c_int, c_void},
ptr::null_mut,
};
#[no_mangle]
unsafe extern "C" fn memccpy(
@ -69,3 +71,23 @@ pub(super) unsafe extern "C" fn mempcpy(
}
dst.add(n) as _
}
#[no_mangle]
pub unsafe extern "C" fn memset(dst: *mut c_void, val: c_int, n: usize) -> *mut c_void {
compiler_builtins::mem::memset(dst.cast(), val, n).cast()
}
#[no_mangle]
pub unsafe extern "C" fn memcpy(dst: *mut c_void, src: *const c_void, n: usize) -> *mut c_void {
compiler_builtins::mem::memcpy(dst.cast(), src.cast(), n).cast()
}
#[no_mangle]
pub unsafe extern "C" fn memmove(dst: *mut c_void, src: *const c_void, n: usize) -> *mut c_void {
compiler_builtins::mem::memmove(dst.cast(), src.cast(), n).cast()
}
#[no_mangle]
pub unsafe extern "C" fn memcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int {
compiler_builtins::mem::memcmp(s1.cast(), s2.cast(), n)
}

View File

@ -2,9 +2,3 @@ use core::ffi::{c_char, c_int, c_void};
pub mod mem;
pub mod str;
extern "C" {
pub fn strlen(s: *const c_char) -> usize;
pub fn memset(a: *mut c_void, c: c_int, n: usize) -> *mut c_void;
pub fn memcpy(dst: *mut c_void, src: *const c_void, n: usize) -> *mut c_void;
}

View File

@ -13,7 +13,7 @@ use crate::{
},
};
use super::{mem::mempcpy, memcpy, memset, strlen};
use super::mem::{memcpy, mempcpy, memset};
#[no_mangle]
unsafe extern "C" fn stpcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char {
@ -120,6 +120,11 @@ unsafe extern "C" fn strerror_r(e: c_int, buf: *mut c_char, n: usize) -> *mut c_
strncpy(buf, source, n)
}
#[no_mangle]
unsafe extern "C" fn strlen(s: *const c_char) -> usize {
compiler_builtins::mem::strlen(s.cast())
}
#[no_mangle]
unsafe extern "C" fn strncat(dst: *mut c_char, src: *const c_char, n: usize) -> *mut c_char {
if dst.is_null() || src.is_null() {
@ -336,6 +341,11 @@ unsafe extern "C" fn strxfrm(_a: *mut c_char, _b: *const c_char, _n: usize) -> u
}
#[no_mangle]
unsafe extern "C" fn strxfrm_l(_a: *mut c_char, _b: *const c_char, _n: usize, _l: locale_t) -> usize {
unsafe extern "C" fn strxfrm_l(
_a: *mut c_char,
_b: *const c_char,
_n: usize,
_l: locale_t,
) -> usize {
unimplemented!()
}

View File

@ -6,13 +6,17 @@
c_variadic,
arbitrary_self_types_pointers,
maybe_uninit_slice,
slice_internals
slice_internals,
linkage,
rustc_private
)]
#![allow(internal_features)]
#![cfg_attr(not(test), no_std)]
extern crate alloc;
extern crate compiler_builtins;
#[cfg(test)]
extern crate std;

186
xtask/src/build/c.rs Normal file
View File

@ -0,0 +1,186 @@
use std::{
fs,
path::{Path, PathBuf},
process::Command,
};
use crate::{env::BuildEnv, error::Error, util};
use super::cargo::CargoBuilder;
pub struct Llvm {
root: PathBuf,
}
pub struct Ygglibc {
static_lib_file: PathBuf,
shared_lib_file: PathBuf,
crt0_file: PathBuf,
include_paths: Vec<PathBuf>,
}
pub struct Openlibm {
shared_lib_file: PathBuf,
static_lib_file: PathBuf,
include_path: PathBuf,
}
impl Llvm {
pub fn c_clang(&self, env: &BuildEnv) -> Command {
let mut command = Command::new(self.root.join("bin/clang"));
command.arg(format!("--target={}-unknown-yggdrasil", env.arch.name()));
command.arg(format!("--sysroot={}", env.llvm_sysroot.display()));
command
}
pub fn clang(&self) -> PathBuf {
self.root.join("bin/clang")
}
}
fn build_test_c_program(
env: &BuildEnv,
llvm: &Llvm,
install: &mut Vec<(PathBuf, PathBuf)>,
) -> Result<(), Error> {
log::info!("Building a test C program");
let target_dir = &env.userspace_output_dir;
let mut command = llvm.c_clang(env);
command
.args([
"-Bdynamic",
"-fpie",
"-O0",
"-ggdb",
"-lm",
"-fstack-protector-strong",
])
.arg("-o")
.arg(target_dir.join("c-test"))
.arg(env.workspace_root.join("test.c"));
if !command.status()?.success() {
return Err(Error::ExternalCommandFailed);
}
let mut command = llvm.c_clang(env);
command
.args(["-static", "-O0", "-ggdb", "-fstack-protector-strong", "-lm"])
.arg("-o")
.arg(target_dir.join("c-test-static"))
.arg(env.workspace_root.join("test.c"));
if !command.status()?.success() {
return Err(Error::ExternalCommandFailed);
}
install.push((target_dir.join("c-test"), "c-test".into()));
install.push((target_dir.join("c-test-static"), "c-test-static".into()));
Ok(())
}
fn install_ygglibc(env: &BuildEnv, ygglibc: &Ygglibc) -> Result<(), Error> {
log::info!("Installing ygglibc into LLVM sysroot");
let dst_lib_dir = env.llvm_sysroot.join("lib");
let dst_include_dir = env.llvm_sysroot.join("usr/include");
fs::create_dir_all(&dst_lib_dir)?;
fs::create_dir_all(&dst_include_dir)?;
fs::copy(&ygglibc.static_lib_file, dst_lib_dir.join("libygglibc.a"))?;
fs::copy(&ygglibc.shared_lib_file, dst_lib_dir.join("libygglibc.so"))?;
fs::copy(&ygglibc.crt0_file, dst_lib_dir.join("crt0.o"))?;
for path in ygglibc.include_paths.iter() {
util::copy_dir_recursive(path, &dst_include_dir)?;
}
Ok(())
}
fn build_ygglibc(env: &BuildEnv) -> Result<Ygglibc, Error> {
let ygglibc_dir = env.workspace_root.join("userspace/lib/ygglibc");
let target_dir = ygglibc_dir.join(format!(
"target/{}-unknown-none/{}",
env.arch.name(),
env.profile.dir()
));
CargoBuilder::Ygglibc(env).build(&ygglibc_dir)?;
let static_lib_file = target_dir.join("libygglibc.a");
let shared_lib_file = target_dir.join("libygglibc.so");
let crt0_file = target_dir.join("crt0.o");
let generated_includes = target_dir.join("include");
let static_includes = ygglibc_dir.join("include");
Ok(Ygglibc {
static_lib_file,
shared_lib_file,
crt0_file,
include_paths: vec![generated_includes, static_includes],
})
}
// TODO clone openlibm
fn build_openlibm(env: &BuildEnv, llvm: &Llvm) -> Result<Openlibm, Error> {
fn make(env: &BuildEnv, llvm: &Llvm, libm_path: &Path) -> Command {
let mut command = Command::new("make");
command.env("SYSROOT", &env.llvm_sysroot);
command.env("ARCH", env.arch.name());
command.env("TRIPLE", format!("{}-unknown-yggdrasil", env.arch.name()));
command.env("USEGCC", "0");
command.env("USECLANG", "1");
command.env("CC", llvm.clang());
command.current_dir(&libm_path);
command
}
log::info!("Building openlibm");
let libm_path = env.workspace_root.join("toolchain-c/libs/openlibm");
let mut command = make(env, llvm, &libm_path);
if !command.status()?.success() {
return Err(Error::ExternalCommandFailed);
}
Ok(Openlibm {
shared_lib_file: libm_path.join("libopenlibm.so.4.0"),
static_lib_file: libm_path.join("libopenlibm.a"),
include_path: libm_path.join("include"),
})
}
fn install_openlibm(env: &BuildEnv, libm: &Openlibm) -> Result<(), Error> {
fs::copy(&libm.static_lib_file, env.llvm_sysroot.join("lib/libm.a"))?;
fs::copy(&libm.shared_lib_file, env.llvm_sysroot.join("lib/libm.so"))?;
util::copy_dir_recursive(&libm.include_path, env.llvm_sysroot.join("usr/include"))?;
Ok(())
}
fn build_llvm(env: &BuildEnv) -> Result<Llvm, Error> {
// TODO actually build and install LLVM
Ok(Llvm {
root: env.workspace_root.join("toolchain-c/prefix/host"),
})
}
pub fn build_c(env: &BuildEnv, install: &mut Vec<(PathBuf, PathBuf)>) -> Result<(), Error> {
let llvm = build_llvm(env)?;
let ygglibc = build_ygglibc(env)?;
install_ygglibc(env, &ygglibc)?;
let libm = build_openlibm(env, &llvm)?;
install_openlibm(env, &libm)?;
build_test_c_program(env, &llvm, install)?;
install.push((ygglibc.shared_lib_file, "lib/libygglibc.so".into()));
install.push((libm.shared_lib_file, "lib/libopenlibm.so.4".into()));
Ok(())
}

View File

@ -90,7 +90,8 @@ impl<'e> CargoBuilder<'e> {
command
.arg(arg)
.arg("-Zbuild-std=core,alloc,compiler_builtins")
.arg("-Zbuild-std=core,alloc")
.arg("-Zbuild-std-features=compiler-builtins-mangled-names,compiler-builtins-mem")
.arg(&format!("--target={target}"));
if env.verbose {

View File

@ -1,23 +0,0 @@
use std::{path::PathBuf, process::Command};
use crate::{env::BuildEnv, error::Error};
pub struct Llvm {
root: PathBuf,
}
impl Llvm {
pub fn c_clang(&self, env: &BuildEnv) -> Command {
let mut command = Command::new(self.root.join("bin/clang"));
command.arg(format!("--target={}-unknown-yggdrasil", env.arch.name()));
command.arg(format!("--sysroot={}", env.llvm_sysroot.display()));
command
}
}
pub fn build_llvm(env: &BuildEnv) -> Result<Llvm, Error> {
// TODO actually build and install LLVM
Ok(Llvm {
root: env.workspace_root.join("toolchain-c/prefix/host"),
})
}

View File

@ -13,8 +13,8 @@ use crate::{
pub mod i686;
pub mod x86_64;
pub mod c;
mod cargo;
pub mod llvm;
mod module;
pub mod toolchain;
mod userspace;

View File

@ -7,21 +7,14 @@ use std::{
use walkdir::WalkDir;
use crate::{
build::{cargo::CargoBuilder, llvm},
build::{c, cargo::CargoBuilder},
check::AllOk,
env::BuildEnv,
error::Error,
util,
};
use super::{llvm::Llvm, InitrdGenerated};
pub struct Ygglibc {
static_lib_file: PathBuf,
shared_lib_file: PathBuf,
crt0_file: PathBuf,
include_paths: Vec<PathBuf>,
}
use super::InitrdGenerated;
const PROGRAMS: &[(&str, &str)] = &[
// init
@ -73,102 +66,22 @@ const PROGRAMS: &[(&str, &str)] = &[
("c-test-static", "c-test-static"),
];
fn build_test_c_program(env: &BuildEnv, llvm: &Llvm) -> Result<(), Error> {
log::info!("Building a test C program");
let target_dir = &env.userspace_output_dir;
let mut command = llvm.c_clang(env);
command
.args([
"-v",
"-Bdynamic",
"-fpie",
"-O0",
"-ggdb",
"-fstack-protector-strong",
])
.arg("-o")
.arg(target_dir.join("c-test"))
.arg(env.workspace_root.join("test.c"));
if !command.status()?.success() {
return Err(Error::ExternalCommandFailed);
}
let mut command = llvm.c_clang(env);
command
.args(["-v", "-static", "-O0", "-ggdb", "-fstack-protector-strong"])
.arg("-o")
.arg(target_dir.join("c-test-static"))
.arg(env.workspace_root.join("test.c"));
if !command.status()?.success() {
return Err(Error::ExternalCommandFailed);
}
Ok(())
}
fn install_ygglibc(env: &BuildEnv, ygglibc: &Ygglibc) -> Result<(), Error> {
log::info!("Installing ygglibc into LLVM sysroot");
let dst_lib_dir = env.llvm_sysroot.join("lib");
let dst_include_dir = env.llvm_sysroot.join("usr/include");
fs::create_dir_all(&dst_lib_dir)?;
fs::create_dir_all(&dst_include_dir)?;
fs::copy(&ygglibc.static_lib_file, dst_lib_dir.join("libygglibc.a"))?;
fs::copy(&ygglibc.shared_lib_file, dst_lib_dir.join("libygglibc.so"))?;
fs::copy(&ygglibc.crt0_file, dst_lib_dir.join("crt0.o"))?;
for path in ygglibc.include_paths.iter() {
util::copy_dir_recursive(path, &dst_include_dir)?;
}
Ok(())
}
fn build_ygglibc(env: &BuildEnv) -> Result<Ygglibc, Error> {
let ygglibc_dir = env.workspace_root.join("userspace/lib/ygglibc");
let target_dir = ygglibc_dir.join(format!(
"target/{}-unknown-none/{}",
env.arch.name(),
env.profile.dir()
));
CargoBuilder::Ygglibc(env).build(&ygglibc_dir)?;
let static_lib_file = target_dir.join("libygglibc.a");
let shared_lib_file = target_dir.join("libygglibc.so");
let crt0_file = target_dir.join("crt0.o");
let generated_includes = target_dir.join("include");
let static_includes = ygglibc_dir.join("include");
Ok(Ygglibc {
static_lib_file,
shared_lib_file,
crt0_file,
include_paths: vec![generated_includes, static_includes],
})
}
fn build_userspace(env: &BuildEnv, _: AllOk) -> Result<Ygglibc, Error> {
fn build_userspace(
env: &BuildEnv,
extra: &mut Vec<(PathBuf, PathBuf)>,
_: AllOk,
) -> Result<(), Error> {
log::info!("Building userspace");
CargoBuilder::Userspace(env).build(env.workspace_root.join("userspace"))?;
CargoBuilder::Userspace(env).build(env.workspace_root.join("userspace/dynload-program"))?;
c::build_c(env, extra)?;
let ygglibc = build_ygglibc(env)?;
let llvm = llvm::build_llvm(env)?;
install_ygglibc(env, &ygglibc)?;
build_test_c_program(env, &llvm)?;
Ok(ygglibc)
Ok(())
}
fn build_rootfs<S: AsRef<Path>, D: AsRef<Path>>(
env: &BuildEnv,
install_extra: Vec<(PathBuf, PathBuf)>,
ygglibc: &Ygglibc,
build_dir: S,
rootfs_dir: D,
_: AllOk,
@ -218,11 +131,6 @@ fn build_rootfs<S: AsRef<Path>, D: AsRef<Path>>(
log::info!("Installing ygglibc");
util::copy_file(
&ygglibc.shared_lib_file,
rootfs_dir.join("lib/libygglibc.so"),
)?;
log::info!("Installing extras");
for (src, dst) in install_extra {
util::copy_file(src, rootfs_dir.join(dst))?;
@ -281,16 +189,16 @@ fn pack_initrd<P: AsRef<Path>>(env: &BuildEnv, rootfs_dir: P) -> Result<InitrdGe
pub fn build_initrd(
env: &BuildEnv,
install_extra: Vec<(PathBuf, PathBuf)>,
mut install_extra: Vec<(PathBuf, PathBuf)>,
check: AllOk,
) -> Result<InitrdGenerated, Error> {
let rootfs_dir = env.userspace_output_dir.join("rootfs");
let ygglibc = build_userspace(env, check)?;
build_userspace(env, &mut install_extra, check)?;
build_rootfs(
env,
install_extra,
&ygglibc,
&env.userspace_output_dir,
&rootfs_dir,
check,

View File

@ -41,6 +41,7 @@ fn check_commands_x86_64() -> Result<CommandsOk, Error> {
("mtools", "Install the `mtools` package"),
("mkfs.vfat", "Install the `dosfstools` package"),
("ld64.lld", "Install LLVM"),
("cmake", "Install cmake"),
])
}