mirror of
https://github.com/ahgamut/rust-ape-example.git
synced 2024-12-03 13:56:40 +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
|
||||
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
|
||||
|
|
|
@ -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)]
|
||||
|
||||
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",
|
||||
"-Wl,-T,./libcosmo/ape.lds",
|
||||
"./libcosmo/crt.o",
|
||||
"./libcosmo/stubs.o",
|
||||
"./libcosmo/ape-no-modify-self.o",
|
||||
"./libcosmo/cosmopolitan.a"
|
||||
]
|
||||
|
|
Loading…
Reference in a new issue