mirror of
https://github.com/ahgamut/rust-ape-example.git
synced 2024-11-23 08:21:01 +00:00
get basic no_std example to build
This commit is contained in:
parent
5a60117dec
commit
c504f3e9c6
7 changed files with 240 additions and 0 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -1,3 +1,10 @@
|
|||
# ignore built APE and debug executables
|
||||
*.com
|
||||
*.com.dbg
|
||||
# download cosmo amalgamation
|
||||
/libcosmo/*
|
||||
!/libcosmo/README.md
|
||||
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
|
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "hello_world"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
111
README.md
Normal file
111
README.md
Normal file
|
@ -0,0 +1,111 @@
|
|||
# Actually Portable Executables with Cosmopolitan Libc and Rust
|
||||
|
||||
This repository contains a simple `Hello world!` example in the [Rust][rust]
|
||||
programming language, that builds with [Cosmopolitan Libc][cosmo].
|
||||
|
||||
I created a [custom compilation target][custom-target] for Rust, called
|
||||
`x86_64-unknown-linux-cosmo`, to provide a build process the Cosmopolitan Libc
|
||||
amalgamation and `cargo`. I followed the documentation in the [Rust
|
||||
Embedonomicon][custom-embed] to create the target.
|
||||
|
||||
An alternative method to build APEs with Rust would be to avoid `cargo`, just
|
||||
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
|
||||
|
||||
1. Download the Cosmopolitan Libc [amalgamation][amalg-download] into the `libcosmo` folder:
|
||||
|
||||
```bash
|
||||
cd libcosmo
|
||||
wget https://justine.lol/cosmopolitan/cosmopolitan.zip
|
||||
unzip cosmopolitan.zip
|
||||
cd ../
|
||||
```
|
||||
|
||||
2. Download the necessary toolchain(s) and source code for Rust:
|
||||
|
||||
```bash
|
||||
rustup toolchain install nightly-x86_64-unknown-linux-gnu
|
||||
rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
|
||||
```
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
4. run `objcopy` on the debug binary to obtain the APE:
|
||||
|
||||
```bash
|
||||
objcopy -SO binary ./target/x86_64-unknown-linux-cosmo/debug/hello_world.com.dbg ./hello_world.com
|
||||
```
|
||||
|
||||
## What about the `std` crate?
|
||||
|
||||
The `std` crate compiles successfully, but fails at the linker stage. Here's how
|
||||
that can be tested:
|
||||
|
||||
1. Change the source code in `src/main.rs` to use the commented out `main`
|
||||
function and `#![restricted_std]`.
|
||||
|
||||
2. In the source code for Rust's `std` crate, change a `cfg_if` in
|
||||
`$HOME/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/backtrace/src/backtrace/mod.rs`
|
||||
to not use the `noop` trace instead of depending on `libunwind`.
|
||||
|
||||
```diff
|
||||
--- mod.rs 2022-06-21 12:52:21.724053459 +0530
|
||||
+++ mod.rs 2022-06-21 13:05:50.948777093 +0530
|
||||
@@ -132,7 +132,7 @@
|
||||
pub(crate) mod miri;
|
||||
use self::miri::trace as trace_imp;
|
||||
pub(crate) use self::miri::Frame as FrameImp;
|
||||
- } else if #[cfg(
|
||||
+ } /* else if #[cfg(
|
||||
any(
|
||||
all(
|
||||
unix,
|
||||
@@ -154,7 +154,7 @@
|
||||
pub(crate) use self::dbghelp::Frame as FrameImp;
|
||||
#[cfg(target_env = "msvc")] // only used in dbghelp symbolize
|
||||
pub(crate) use self::dbghelp::StackFrame;
|
||||
- } else {
|
||||
+ } */ else {
|
||||
mod noop;
|
||||
use self::noop::trace as trace_imp;
|
||||
pub(crate) use self::noop::Frame as FrameImp;
|
||||
```
|
||||
|
||||
I haven't figured out what config I should give to `cargo` so I don't need to do
|
||||
this. I find it surprising that `std` cannot be built without relying on
|
||||
`libunwind`.
|
||||
|
||||
3. The build command now changes to
|
||||
|
||||
```bash
|
||||
cargo +nightly build -Zbuild-std=core,alloc,panic_abort,libc,std -Zbuild-std-features= --target=./x86_64-unknown-linux-cosmo.json
|
||||
```
|
||||
|
||||
4. At the linker stage you might find some of the following symbols are missing:
|
||||
|
||||
- If `Unwind_Backtrace` or similar is missing, you need to check if step 2 is
|
||||
done properly.
|
||||
|
||||
- `open64`, `stat64`, `fstat64`, `__xpg_strerror_r`: these can be added to
|
||||
Cosmopolitan Libc via aliases of the existing functions.
|
||||
|
||||
- `pthread_key_create`,`pthread_setspecific`,`pthread_key_delete`,`pthread_getspecific`
|
||||
-- these functions should not be needed in a single-threaded program, but
|
||||
somehow they are still linked. Support for threads is currently being added
|
||||
to Cosmopolitan Libc, but possibly the related code in the `std` crate can
|
||||
be changed to avoid this issue.
|
||||
|
||||
[rust]: https://rust-lang.org
|
||||
[cosmo]: 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
|
21
gcc-linker-wrapper.bash
Executable file
21
gcc-linker-wrapper.bash
Executable file
|
@ -0,0 +1,21 @@
|
|||
#!/bin/bash
|
||||
set -eu
|
||||
|
||||
declare -a args
|
||||
args=()
|
||||
for o in "$@" ; do
|
||||
case $o in
|
||||
"-lunwind") continue;;
|
||||
"-lutil") continue;;
|
||||
"-lrt") continue;;
|
||||
"-lc") continue;;
|
||||
"-lm") continue;;
|
||||
"-lpthread") continue;;
|
||||
"-lgcc") continue;;
|
||||
"-Wl,-Bdynamic") continue;;
|
||||
"-Wl,-Bstatic") continue;;
|
||||
esac
|
||||
args+=("$o")
|
||||
done
|
||||
|
||||
gcc "${args[@]}"
|
0
libcosmo/README.md
Normal file
0
libcosmo/README.md
Normal file
31
src/main.rs
Normal file
31
src/main.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
#![no_main]
|
||||
#![no_std]
|
||||
#![feature(rustc_private)]
|
||||
|
||||
extern crate libc;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
// Since we are passing a C string the final null character is mandatory
|
||||
const HELLO: &'static str = "Hello, world! %d + %d = %d\n\0";
|
||||
let x: i32 = 1;
|
||||
let y: i32 = 2;
|
||||
unsafe {
|
||||
libc::printf(HELLO.as_ptr() as *const _, x, y, x+y);
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn my_panic(_info: &core::panic::PanicInfo) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
/* std crate requires some external changes
|
||||
|
||||
#![feature(restricted_std)]
|
||||
|
||||
pub fn main() {
|
||||
println!("hello pls cosmo rust APE");
|
||||
}
|
||||
*/
|
62
x86_64-unknown-linux-cosmo.json
Normal file
62
x86_64-unknown-linux-cosmo.json
Normal file
|
@ -0,0 +1,62 @@
|
|||
{
|
||||
"llvm-target": "x86_64-unknown-linux-musl",
|
||||
"target-pointer-width": "64",
|
||||
"arch": "x86_64",
|
||||
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
|
||||
"cpu": "x86-64",
|
||||
"os":"linux",
|
||||
"env": "musl",
|
||||
"panic-strategy":"abort",
|
||||
"requires-uwtable":false,
|
||||
"dynamic-linking": false,
|
||||
"executables": true,
|
||||
"exe-suffix": ".com.dbg",
|
||||
"emit-debug-gdb-scripts":false,
|
||||
"crt-static-default": true,
|
||||
"crt-static-respected": false,
|
||||
"linker-is-gnu":true,
|
||||
"allows-weak-linkage":true,
|
||||
"has-rpath": false,
|
||||
"has-thread-local": false,
|
||||
"is-builtin": false,
|
||||
"trap-unreachable":true,
|
||||
"position-independent-executables": false,
|
||||
"static-position-independent-executables": false,
|
||||
"relocation-model": "static",
|
||||
"disable-redzone":true,
|
||||
"frame-pointer":"always",
|
||||
"requires-lto":false,
|
||||
"eh-frame-header":false,
|
||||
"no-default-libraries":true,
|
||||
"max-atomic-width":64,
|
||||
"linker-flavor":"gcc",
|
||||
"linker": "./gcc-linker-wrapper.bash",
|
||||
"late-link-args": {
|
||||
"gcc": []
|
||||
},
|
||||
"pre-link-args": {
|
||||
"gcc": [
|
||||
"-static",
|
||||
"-nostdinc",
|
||||
"-nostdlib",
|
||||
"-pg",
|
||||
"-mnop-mcount"
|
||||
]
|
||||
},
|
||||
"post-link-args": {
|
||||
"gcc": [
|
||||
"-Wl,--gc-sections",
|
||||
"-fuse-ld=bfd",
|
||||
"-Wl,-T,./libcosmo/ape.lds",
|
||||
"./libcosmo/crt.o",
|
||||
"./libcosmo/ape-no-modify-self.o",
|
||||
"./libcosmo/cosmopolitan.a"
|
||||
]
|
||||
},
|
||||
"stack-probes": {
|
||||
"kind": "none"
|
||||
},
|
||||
"target-family": [
|
||||
"unix"
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue