diff --git a/README.md b/README.md index 822570e..9a5f320 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,10 @@ use `rustc` or equivalent compiler to generate `.o` files, and then write a shell script that does the linking with the expected flags. I have not tried this method. -## Build steps +> a previous attempt at a Rust APE was done without using the `std` crate. You +can view that in the [`without-std` branch of this repo][without-std-branch]. + +## Building a Rust APE with the `std` crate 1. Download the Cosmopolitan Libc [amalgamation][amalg-download] into the `libcosmo` folder: @@ -24,10 +27,13 @@ unzip cosmopolitan.zip cd ../ ``` -2. Download the necessary *host* toolchain and source code for Rust: +For reference, I used the nightly version of `cosmopolitan.a` from June 22 2022, +which can be built from source if needed from [this commit][cosmo-nightly]. + +2. Download the necessary host toolchain and source code for Rust: ```bash -# I was on Debian, so I did this +# I was on Debian 11, so I did this rustup toolchain install nightly-x86_64-unknown-linux-gnu rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu # on Alpine Linux, you may need to do @@ -35,39 +41,71 @@ rustup toolchain install nightly-x86_64-unknown-linux-musl rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-musl ``` +For reference, I used the nightly version of Rust from June 22 2022. + 3. run `cargo build` to get the debug executable. This uses a bash script that removes unnecessary linker arguments. A recent version of `gcc` and `ld.bfd` is required. ```bash -cargo +nightly build -Zbuild-std=core,libc --target=./x86_64-unknown-linux-cosmo.json +cargo +nightly build -Zbuild-std=panic_abort,std -Zbuild-std-features="" --target=./x86_64-unknown-linux-cosmo.json +``` + +For reference, I used the below versions of `gcc` and `ld.bfd` + +``` +gcc (Debian 10.2.1-6) 10.2.1 20210110 +Copyright (C) 2020 Free Software Foundation, Inc. +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +``` + +``` +GNU ld (GNU Binutils for Debian) 2.35.2 +Copyright (C) 2020 Free Software Foundation, Inc. +This program is free software; you may redistribute it under the terms of +the GNU General Public License version 3 or (at your option) a later version. +This program has absolutely no warranty. ``` 4. run `objcopy` on the debug binary to obtain the APE: ```bash +# objcopy is the same version as ld.bfd above objcopy -SO binary ./target/x86_64-unknown-linux-cosmo/debug/hello_world.com.dbg ./hello_world.com +# run the APE +./hello_world.com +# see syscalls made by the APE +./hello_world.com --strace ``` -## What about the `std` crate? +Now we have an Actually Portable Executable built with Rust! There might some +edge cases that I haven't noticed, so clone/fork the repo and try it out! The +[`without-std` branch][without-std-branch] of this repo might be useful. -1. It needs a few stubs functions so the linker doesn't complain. I wrote them - out in `stubs.c`. +## TODOs -```bash -cd ./libcosmo/ -# compiling a simple stub file via cosmopolitan.h -./compile-stubs.bash -``` +- [ ] figure out build config to avoid using `libunwind` -2. The build command now changes to +The `std` crate relies on +[`backtrace`](https://github.com/rust-lang/backtrace-rs), which depends on +[`libunwind`](https://github.com/libunwind/libunwind) in the default builds for +unix. To work around this, `cosmopolitan.a` currently has stubs for the +functions that `backtrace` relies on. However, it might be easier to provide a +build flag in `Cargo.toml` to use the `noop` module of `backtrace`. -```bash -cargo +nightly build -Zbuild-std=core,alloc,panic_abort,libc,std -Zbuild-std-features= --target=./x86_64-unknown-linux-cosmo.json -``` +A small change needs to be submitted to the source code of `backtrace` (in the +`cfg_if!` +[here](https://github.com/rust-lang/backtrace-rs/blob/4e5a3f72929f152752d5659e95bb15c8f6b41eff/src/backtrace/mod.rs#L128)) +to allow choosing `noop` when building as part of the `std` crate. This +conditional compilation flag should be accessible when building the `std` crate +either via `Cargo.toml` or something like `-Z use-std-backtrace-noop` in the +build command. +[without-std-branch]: https://github.com/ahgamut/rust-ape-example/tree/without-std [rust]: https://rust-lang.org [cosmo]: https://github.com/jart/cosmopolitan +[cosmo-nightly]: https://github.com/jart/cosmopolitan [amalg-download]: https://justine.lol/cosmopolitan/download.html [custom-target]: https://doc.rust-lang.org/rustc/targets/custom.html [custom-embed]: https://docs.rust-embedded.org/embedonomicon/custom-target.html diff --git a/libcosmo/compile-stubs.bash b/libcosmo/compile-stubs.bash deleted file mode 100755 index aa53e4a..0000000 --- a/libcosmo/compile-stubs.bash +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -set -eux - -gcc -g -Os -static -nostdlib -nostdinc \ - -fno-pie -no-pie -mno-red-zone \ - -fno-omit-frame-pointer -pg -mnop-mcount \ - -o ./stubs.o -c ./stubs.c diff --git a/libcosmo/stubs.c b/libcosmo/stubs.c deleted file mode 100644 index adb9b75..0000000 --- a/libcosmo/stubs.c +++ /dev/null @@ -1,98 +0,0 @@ -#include "cosmopolitan.h" - -typedef enum { - _URC_NO_REASON = 0, - _URC_FOREIGN_EXCEPTION_CAUGHT = 1, - _URC_FATAL_PHASE2_ERROR = 2, - _URC_FATAL_PHASE1_ERROR = 3, - _URC_NORMAL_STOP = 4, - _URC_END_OF_STACK = 5, - _URC_HANDLER_FOUND = 6, - _URC_INSTALL_CONTEXT = 7, - _URC_CONTINUE_UNWIND = 8 -} _Unwind_Reason_Code; - -#define UNW_TDEP_CURSOR_LEN 127 - -typedef uint64_t unw_word_t; - -typedef struct unw_cursor { - unw_word_t opaque[UNW_TDEP_CURSOR_LEN]; -} unw_cursor_t; - -struct _Unwind_Context { - unw_cursor_t cursor; - int end_of_stack; -}; - -typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *, - void *); - -uintptr_t _Unwind_GetCFA(struct _Unwind_Context *ctx) { - return 0; -} - -uintptr_t _Unwind_GetIP(struct _Unwind_Context *ctx) { - return 0; -} - -_Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn fn, void *arg) { - return _URC_NORMAL_STOP; -} - -void *_Unwind_FindEnclosingFunction(void *arg) { - return NULL; -} - -#define MAX_KEYS 64 - -typedef unsigned pthread_key_t; -typedef void (*dtor)(void*); - -typedef struct { - pthread_key_t kval; - dtor d; - void *value; -} tls_t; - -static tls_t my_tls[MAX_KEYS] = {0}; -static unsigned thread_avail = 0; - -int pthread_key_create(pthread_key_t *k, dtor destructor) { - for(pthread_key_t i=1; i ! { #![feature(restricted_std)] pub fn main() { - println!("hello pls cosmo rust APE"); + println!("Hello World! This is an APE built with Rust."); } diff --git a/x86_64-unknown-linux-cosmo.json b/x86_64-unknown-linux-cosmo.json index 62e5ae2..63a9a7a 100644 --- a/x86_64-unknown-linux-cosmo.json +++ b/x86_64-unknown-linux-cosmo.json @@ -49,7 +49,6 @@ "-fuse-ld=bfd", "-Wl,-T,./libcosmo/ape.lds", "./libcosmo/crt.o", - "./libcosmo/stubs.o", "./libcosmo/ape-no-modify-self.o", "./libcosmo/cosmopolitan.a" ]