mirror of
https://github.com/ahgamut/rust-ape-example.git
synced 2024-12-04 06:16:39 +00:00
std now builds with latest nightly of cosmo
This commit is contained in:
parent
f6ae82160c
commit
2f9973a168
5 changed files with 55 additions and 123 deletions
70
README.md
70
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
|
shell script that does the linking with the expected flags. I have not tried
|
||||||
this method.
|
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:
|
1. Download the Cosmopolitan Libc [amalgamation][amalg-download] into the `libcosmo` folder:
|
||||||
|
|
||||||
|
@ -24,10 +27,13 @@ unzip cosmopolitan.zip
|
||||||
cd ../
|
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
|
```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 toolchain install nightly-x86_64-unknown-linux-gnu
|
||||||
rustup component add rust-src --toolchain 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
|
# 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
|
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
|
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`
|
removes unnecessary linker arguments. A recent version of `gcc` and `ld.bfd`
|
||||||
is required.
|
is required.
|
||||||
|
|
||||||
```bash
|
```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:
|
4. run `objcopy` on the debug binary to obtain the APE:
|
||||||
|
|
||||||
```bash
|
```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
|
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
|
## TODOs
|
||||||
out in `stubs.c`.
|
|
||||||
|
|
||||||
```bash
|
- [ ] figure out build config to avoid using `libunwind`
|
||||||
cd ./libcosmo/
|
|
||||||
# compiling a simple stub file via cosmopolitan.h
|
|
||||||
./compile-stubs.bash
|
|
||||||
```
|
|
||||||
|
|
||||||
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
|
A small change needs to be submitted to the source code of `backtrace` (in the
|
||||||
cargo +nightly build -Zbuild-std=core,alloc,panic_abort,libc,std -Zbuild-std-features= --target=./x86_64-unknown-linux-cosmo.json
|
`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
|
[rust]: https://rust-lang.org
|
||||||
[cosmo]: https://github.com/jart/cosmopolitan
|
[cosmo]: https://github.com/jart/cosmopolitan
|
||||||
|
[cosmo-nightly]: https://github.com/jart/cosmopolitan
|
||||||
[amalg-download]: https://justine.lol/cosmopolitan/download.html
|
[amalg-download]: https://justine.lol/cosmopolitan/download.html
|
||||||
[custom-target]: https://doc.rust-lang.org/rustc/targets/custom.html
|
[custom-target]: https://doc.rust-lang.org/rustc/targets/custom.html
|
||||||
[custom-embed]: https://docs.rust-embedded.org/embedonomicon/custom-target.html
|
[custom-embed]: https://docs.rust-embedded.org/embedonomicon/custom-target.html
|
||||||
|
|
|
@ -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
|
|
|
@ -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<MAX_KEYS; i++) {
|
|
||||||
if(my_tls[i].kval == 0) {
|
|
||||||
*k = i;
|
|
||||||
my_tls[i].kval = i;
|
|
||||||
my_tls[i].d = destructor;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* pthread_getspecific(pthread_key_t k) {
|
|
||||||
if(k < MAX_KEYS) {
|
|
||||||
return my_tls[k].value;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pthread_setspecific(pthread_key_t k, const void* value) {
|
|
||||||
if(k < MAX_KEYS) {
|
|
||||||
my_tls[k].value = value;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pthread_key_delete(pthread_key_t k) {
|
|
||||||
if (k < MAX_KEYS) {
|
|
||||||
my_tls[k].kval = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int __xpg_strerror_r(int a, char *b, size_t c) {
|
|
||||||
return strerror_r(a, b, c);
|
|
||||||
}
|
|
|
@ -26,5 +26,5 @@ fn my_panic(_info: &core::panic::PanicInfo) -> ! {
|
||||||
#![feature(restricted_std)]
|
#![feature(restricted_std)]
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
println!("hello pls cosmo rust APE");
|
println!("Hello World! This is an APE built with Rust.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,6 @@
|
||||||
"-fuse-ld=bfd",
|
"-fuse-ld=bfd",
|
||||||
"-Wl,-T,./libcosmo/ape.lds",
|
"-Wl,-T,./libcosmo/ape.lds",
|
||||||
"./libcosmo/crt.o",
|
"./libcosmo/crt.o",
|
||||||
"./libcosmo/stubs.o",
|
|
||||||
"./libcosmo/ape-no-modify-self.o",
|
"./libcosmo/ape-no-modify-self.o",
|
||||||
"./libcosmo/cosmopolitan.a"
|
"./libcosmo/cosmopolitan.a"
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in a new issue