Skip to content

Commit fa055e9

Browse files
authored
Support acting as startup code of a dynamic linker (#108)
* Support acting as startup code of a dynamic linker * Fix confusion in computing relocation offset * Move computation of _DYNAMIC from _entry to a function called by relocate * Disable the option to act as dynamic linker on x86 for now
1 parent f90633c commit fa055e9

13 files changed

Lines changed: 387 additions & 70 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[package]
2+
name = "origin-start"
3+
version = "0.0.0"
4+
edition = "2021"
5+
publish = false
6+
7+
[lib]
8+
crate-type = ["cdylib"]
9+
10+
[dependencies]
11+
# Origin can be depended on just like any other crate. For no_std, disable
12+
# the default features, and the desired features.
13+
origin = { path = "../..", default-features = false, features = ["origin-thread", "origin-start", "thread", "alloc", "experimental-relocate"] }
14+
15+
# Crates to help writing no_std code.
16+
atomic-dbg = { version = "0.1.8", default-features = false }
17+
rustix-dlmalloc = { version = "0.1.0", features = ["global"] }
18+
compiler_builtins = { version = "0.1.101", features = ["mem"] }
19+
20+
# This is just an example crate, and not part of the origin workspace.
21+
[workspace]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
This crate demonstrates the use of origin as a plain library API using
2+
`#![no_std]` and `#![no_main]`.
3+
4+
This version uses `-nostartfiles` and origin is in control from the very
5+
beginning. This uses origin in an "origin-start" configuration.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
fn main() {
2+
// Pass -nostartfiles to the linker. In the future this could be obviated
3+
// by a `no_entry` feature: <https://github.com/rust-lang/rfcs/pull/2735>
4+
println!("cargo:rustc-link-arg=-nostartfiles");
5+
// Set entry point for the dynamic library, making it capable of being
6+
// executed like an executable and being used as dynamic linker.
7+
println!("cargo:rustc-link-arg=-Wl,-e,_start");
8+
// Prevent non R_RELATIVE relocations by forcing all references to global
9+
// symbols to be resolved locally.
10+
println!("cargo:rustc-link-arg=-Wl,-Bsymbolic");
11+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//! A simple example acting as dynamic linker using `no_std` and `no_main` and origin's start.
2+
3+
#![no_std]
4+
#![no_main]
5+
#![allow(internal_features)]
6+
#![feature(lang_items)]
7+
#![feature(core_intrinsics)]
8+
9+
extern crate alloc;
10+
extern crate compiler_builtins;
11+
12+
use alloc::boxed::Box;
13+
use atomic_dbg::{dbg, eprintln};
14+
use origin::{program, thread};
15+
16+
#[panic_handler]
17+
fn panic(panic: &core::panic::PanicInfo<'_>) -> ! {
18+
dbg!(panic);
19+
core::intrinsics::abort();
20+
}
21+
22+
#[lang = "eh_personality"]
23+
extern "C" fn eh_personality() {}
24+
25+
#[global_allocator]
26+
static GLOBAL_ALLOCATOR: rustix_dlmalloc::GlobalDlmalloc = rustix_dlmalloc::GlobalDlmalloc;
27+
28+
#[no_mangle]
29+
unsafe fn origin_main(_argc: usize, _argv: *mut *mut u8, _envp: *mut *mut u8) -> i32 {
30+
eprintln!("Hello from main thread");
31+
32+
program::at_exit(Box::new(|| {
33+
eprintln!("Hello from an `program::at_exit` handler")
34+
}));
35+
thread::at_exit(Box::new(|| {
36+
eprintln!("Hello from a main-thread `thread::at_exit` handler")
37+
}));
38+
39+
let thread = thread::create(
40+
|_args| {
41+
eprintln!("Hello from child thread");
42+
thread::at_exit(Box::new(|| {
43+
eprintln!("Hello from child thread's `thread::at_exit` handler")
44+
}));
45+
None
46+
},
47+
&[],
48+
thread::default_stack_size(),
49+
thread::default_guard_size(),
50+
)
51+
.unwrap();
52+
53+
thread::join(thread);
54+
55+
eprintln!("Goodbye from main");
56+
program::exit(0);
57+
}

src/arch/aarch64.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
//! Architecture-specific assembly code.
22
33
use core::arch::asm;
4+
#[cfg(all(feature = "experimental-relocate", feature = "origin-start"))]
5+
#[cfg(relocation_model = "pic")]
6+
use linux_raw_sys::elf::Elf_Dyn;
47
#[cfg(feature = "origin-signal")]
58
use linux_raw_sys::general::__NR_rt_sigreturn;
69
#[cfg(all(feature = "experimental-relocate", feature = "origin-start"))]
@@ -37,6 +40,23 @@ pub(super) unsafe extern "C" fn _start() -> ! {
3740
)
3841
}
3942

43+
/// Compute the dynamic address of `_DYNAMIC`.
44+
#[cfg(all(feature = "experimental-relocate", feature = "origin-start"))]
45+
#[cfg(relocation_model = "pic")]
46+
pub(super) fn dynamic_table_addr() -> *const Elf_Dyn {
47+
let addr;
48+
unsafe {
49+
asm!(
50+
".weak _DYNAMIC",
51+
".hidden _DYNAMIC",
52+
"adrp x0, _DYNAMIC",
53+
"add x0, x0, #:lo12:_DYNAMIC",
54+
out("x0") addr,
55+
);
56+
}
57+
addr
58+
}
59+
4060
/// Perform a single load operation, outside the Rust memory model.
4161
///
4262
/// This function conceptually casts `ptr` to a `*const *mut c_void` and loads

src/arch/arm.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
use core::arch::asm;
44
#[cfg(all(feature = "experimental-relocate", feature = "origin-start"))]
55
#[cfg(relocation_model = "pic")]
6+
use linux_raw_sys::elf::Elf_Dyn;
7+
#[cfg(all(feature = "experimental-relocate", feature = "origin-start"))]
8+
#[cfg(relocation_model = "pic")]
69
use linux_raw_sys::general::{__NR_mprotect, PROT_READ};
710
#[cfg(feature = "origin-signal")]
811
use linux_raw_sys::general::{__NR_rt_sigreturn, __NR_sigreturn};
@@ -37,6 +40,27 @@ pub(super) unsafe extern "C" fn _start() -> ! {
3740
)
3841
}
3942

43+
/// Compute the dynamic address of `_DYNAMIC`.
44+
#[cfg(all(feature = "experimental-relocate", feature = "origin-start"))]
45+
#[cfg(relocation_model = "pic")]
46+
pub(super) fn dynamic_table_addr() -> *const Elf_Dyn {
47+
let addr;
48+
unsafe {
49+
asm!(
50+
".weak _DYNAMIC",
51+
".hidden _DYNAMIC",
52+
"ldr r0, 2f",
53+
"1: add r0, pc, r0",
54+
"b 3f",
55+
".align 2",
56+
"2: .word _DYNAMIC-(1b+8)",
57+
"3:",
58+
out("r0") addr,
59+
);
60+
}
61+
addr
62+
}
63+
4064
/// Perform a single load operation, outside the Rust memory model.
4165
///
4266
/// This function conceptually casts `ptr` to a `*const *mut c_void` and loads

src/arch/riscv64.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
use core::arch::asm;
88
#[cfg(all(feature = "experimental-relocate", feature = "origin-start"))]
99
#[cfg(relocation_model = "pic")]
10+
use linux_raw_sys::elf::Elf_Dyn;
11+
#[cfg(all(feature = "experimental-relocate", feature = "origin-start"))]
12+
#[cfg(relocation_model = "pic")]
1013
use linux_raw_sys::general::{__NR_mprotect, PROT_READ};
1114
#[cfg(all(feature = "origin-thread", feature = "thread"))]
1215
use {
@@ -40,6 +43,22 @@ pub(super) unsafe extern "C" fn _start() -> ! {
4043
)
4144
}
4245

46+
/// Compute the dynamic address of `_DYNAMIC`.
47+
#[cfg(all(feature = "experimental-relocate", feature = "origin-start"))]
48+
#[cfg(relocation_model = "pic")]
49+
pub(super) fn dynamic_table_addr() -> *const Elf_Dyn {
50+
let addr;
51+
unsafe {
52+
asm!(
53+
".weak _DYNAMIC",
54+
".hidden _DYNAMIC",
55+
"lla a0, _DYNAMIC",
56+
out("a0") addr,
57+
);
58+
}
59+
addr
60+
}
61+
4362
/// Perform a single load operation, outside the Rust memory model.
4463
///
4564
/// This function conceptually casts `ptr` to a `*const *mut c_void` and loads

src/arch/x86.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
use core::arch::asm;
44
#[cfg(all(feature = "experimental-relocate", feature = "origin-start"))]
55
#[cfg(relocation_model = "pic")]
6+
use linux_raw_sys::elf::Elf_Dyn;
7+
#[cfg(all(feature = "experimental-relocate", feature = "origin-start"))]
8+
#[cfg(relocation_model = "pic")]
69
use linux_raw_sys::general::{__NR_mprotect, PROT_READ};
710
#[cfg(feature = "origin-signal")]
811
use linux_raw_sys::general::{__NR_rt_sigreturn, __NR_sigreturn};
@@ -42,6 +45,29 @@ pub(super) unsafe extern "C" fn _start() -> ! {
4245
)
4346
}
4447

48+
/// Compute the dynamic address of `_DYNAMIC`.
49+
#[cfg(all(feature = "experimental-relocate", feature = "origin-start"))]
50+
#[cfg(relocation_model = "pic")]
51+
pub(super) fn dynamic_table_addr() -> *const Elf_Dyn {
52+
panic!("acting as dynamic linker not yet supported on 32-bit x86");
53+
// FIXME somehow get LLVM to accept `add dword ptr [esp], _DYNAMIC-1b` or
54+
// some other way to emit an `R_386_PC32` relocation against `_DYNAMIC`.
55+
/*
56+
let addr;
57+
unsafe {
58+
asm!(
59+
".weak _DYNAMIC",
60+
".hidden _DYNAMIC",
61+
"call 1f",
62+
"1: add dword ptr [esp], _DYNAMIC-1b",
63+
"pop eax",
64+
out("eax") addr,
65+
);
66+
}
67+
addr
68+
*/
69+
}
70+
4571
/// Perform a single load operation, outside the Rust memory model.
4672
///
4773
/// This function conceptually casts `ptr` to a `*const *mut c_void` and loads

src/arch/x86_64.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
//! Architecture-specific assembly code.
22
33
use core::arch::asm;
4+
#[cfg(all(feature = "experimental-relocate", feature = "origin-start"))]
5+
#[cfg(relocation_model = "pic")]
6+
use linux_raw_sys::elf::Elf_Dyn;
47
#[cfg(feature = "origin-signal")]
58
use linux_raw_sys::general::__NR_rt_sigreturn;
69
#[cfg(all(feature = "experimental-relocate", feature = "origin-start"))]
@@ -37,6 +40,22 @@ pub(super) unsafe extern "C" fn _start() -> ! {
3740
)
3841
}
3942

43+
/// Compute the dynamic address of `_DYNAMIC`.
44+
#[cfg(all(feature = "experimental-relocate", feature = "origin-start"))]
45+
#[cfg(relocation_model = "pic")]
46+
pub(super) fn dynamic_table_addr() -> *const Elf_Dyn {
47+
let addr;
48+
unsafe {
49+
asm!(
50+
".weak _DYNAMIC",
51+
".hidden _DYNAMIC",
52+
"lea rax, [rip + _DYNAMIC]",
53+
out("rax") addr,
54+
);
55+
}
56+
addr
57+
}
58+
4059
/// Perform a single load operation, outside the Rust memory model.
4160
///
4261
/// This function conceptually casts `ptr` to a `*const *mut c_void` and loads

0 commit comments

Comments
 (0)