Skip to content

Commit ab4ee70

Browse files
committed
feat(port_riscv): make riscv-rt optional
Fixes linker errors in an application that is linked to `r3_port_riscv` and does not use the `riscv-rt`-compatible startup routine provided by `r3_port_riscv::use_rt!`. Rust implements `rlib`s as static libraries (archives). Linkers treat archives differently from object files: all object files participate in linking, while archives will only participate in linking if they can satisfy at least one undefined reference (version scripts don't count). This means that in an application that does not use `use_rt!`, `libriscv_rt*.rlib` does not participate in linking at all. This behavior also causes `#[no_mangle]` and `#[used]` items to be ignored by the linker (`KEEP` in linker scripts can't keep them either), leading to a long-standing bug in Rust ([rust-lang/rust#47384][2]). The situation changed with the merge of [rust-lang/rust#95604][1]. To fix [rust-lang/rust#47384][2], this PR introduced a synthetic object file containing references to all symbols pertaining to `#[no_mangle]` and `#[used]` items. `libriscv_rt*.rlib` now participates in linking, but the expectation is that `--gc-sections` will remove unused items in the end, unless they are explicitly retained by `KEEP` in linker scripts or other means. This change unexpectedly caused breakage in the tests for `qemu_sifive_u _s_rv(64,32)` targets, which use a custom startup routine instead of `use_rt!`. For some reason, the linker didn't respect `--gc-sections` for some items from `libriscv_rt*.rlib` and decided to include them in the output binary. These items reference symbols that are defined by the `riscv-rt` linker script, which isn't used by `qemu_sifive_u_s_ rv(64,32)` targets, hence the linker error. The thing is, `riscv-rt` outputs these items in the `.init` section[3], which is one of the section names hard-coded in LLD[4] to be excluded from `--gc-sections`. As a result, these items were considered for inclusion despite being referenced from nowhere. This commit works around this problem by making `r3_port_riscv`'s `riscv-rt` dependency optional, ensuring that `riscv-rt` participates in linking only if needed by the application. [1]: rust-lang/rust#95604 [2]: rust-lang/rust#47384 [3]: https://github.com/rust-embedded/riscv-rt/blob/7de3d2744a465ad723519c04f13c56664e138cb9/asm.S#L20 [4]: https://github.com/llvm/llvm-project/blob/b86440ecde5c1dec5b898a3f1bc08ab9853d5ed9/lld/ELF/MarkLive.cpp#L183
1 parent e82d2de commit ab4ee70

File tree

5 files changed

+8
-2
lines changed

5 files changed

+8
-2
lines changed

src/r3_port_riscv/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1010
### Changed
1111

1212
- **Breaking (semver-exempt):** Change the target compiler version to `nightly-2022-03-30`
13+
- **Breaking:** `use_rt!` is now gated behind `riscv-rt` Cargo feature.
1314

1415
### Fixed
1516

src/r3_port_riscv/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ unstringify = { version = "0.1.4" }
2727
seq-macro = { version = "0.3.0" }
2828
svgbobdoc = { version = "0.3.0" }
2929
macropol = { version = "0.1.3" }
30-
riscv-rt = { version = ">= 0.6.0, < 0.9.0" }
30+
riscv-rt = { version = ">= 0.6.0, < 0.9.0", optional = true }
3131
riscv = { version = ">= 0.5.0, < 0.8.0" }
3232

3333
[package.metadata.docs.rs]

src/r3_port_riscv/src/lib.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ The RISC-V port for [the R3 kernel](::r3_kernel).
22

33
# Startup code
44

5-
[`use_rt!`] hooks up the entry points ([`EntryPoint`]) using `#[`[`::riscv_rt::entry`]`]`. If this is not desirable for some reason, you can opt not to use it and call the entry points in other ways.
5+
[`use_rt!`] hooks up the entry points ([`EntryPoint`]) using `#[`[`::riscv_rt::entry`]`]` (requires the **`riscv-rt`** Cargo feature). If this is not desirable for some reason, you can opt not to use it and call the entry points in other ways.
66

77
# Interrupts
88

src/r3_port_riscv/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#![feature(raw_ref_op)]
1010
#![feature(asm_const)]
1111
#![feature(asm_sym)]
12+
#![feature(doc_cfg)]
1213
#![deny(unsafe_op_in_unsafe_fn)]
1314
#![cfg_attr(
1415
feature = "doc",
@@ -55,6 +56,8 @@ pub mod plic {
5556

5657
/// The binding for [`::riscv_rt`].
5758
#[doc(hidden)]
59+
#[cfg(feature = "riscv-rt")]
60+
#[doc(cfg(feature = "riscv-rt"))]
5861
pub mod rt {
5962
pub mod cfg;
6063
#[cfg(target_os = "none")]
@@ -85,6 +88,7 @@ pub mod sbi_timer {
8588

8689
pub use self::mtime::cfg::*;
8790
pub use self::plic::cfg::*;
91+
#[cfg(feature = "riscv-rt")]
8892
pub use self::rt::cfg::*;
8993
pub use self::sbi_timer::cfg::*;
9094
pub use self::threading::cfg::*;

src/r3_port_riscv_test_driver/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ run = [
2424
boot-minimal-s = []
2525
# Use `riscv-rt` for the startup code
2626
boot-rt = [
27+
"r3_port_riscv/riscv-rt",
2728
"riscv-rt",
2829
]
2930

0 commit comments

Comments
 (0)