diff --git a/link-section/src/platform/mod.rs b/link-section/src/platform/mod.rs index 94fe402e..a858ec10 100644 --- a/link-section/src/platform/mod.rs +++ b/link-section/src/platform/mod.rs @@ -38,7 +38,7 @@ pub const fn validate_section_name(name: &str) { /// Launder a pointer's provenance so it appears as an "exposed" pointer. pub fn launder_pointer_provenance(ptr: *const T) -> *const T { - #[cfg(not(windows))] + #[cfg(any(not(windows), miri))] { core::ptr::with_exposed_provenance(ptr.expose_provenance()) } @@ -48,20 +48,27 @@ pub fn launder_pointer_provenance(ptr: *const T) -> *const T { // exposed provenance and reverts it, which it then traces to the marker allocation which // it then believes all slice loads come from. // - // Treating this provenance round-trip as a no-op is arguably an LLVM optimization issue - // somewhere between Rust and LLVM. - #[cfg(windows)] + // Treating this provenance round-trip as a no-op is arguably an LLVM optimization issue. + #[cfg(all(windows, not(miri)))] { - core::hint::black_box(core::ptr::with_exposed_provenance(ptr.expose_provenance())) + unsafe extern "C" { + #[link_name = crate::__ls_provenance_symbol!()] + static LS_PROVENANCE_DONOR: u8; + } + + // Copy provenance from a non-Rust symbol ineligible for many + // optimizations to the pointer. It is far less likely for early optimization + // passes to fold the pointer into the marker's allocation. + (&raw const LS_PROVENANCE_DONOR).with_addr(ptr.addr()) as *const T } } /// Constant bounds for a pointer-based section. pub struct PtrBounds { /// Section start address. - pub start: *const (), + start: *const (), /// One byte past the last section byte. - pub end: *const (), + end: *const (), } impl PtrBounds { diff --git a/link-section/src/platform/windows.rs b/link-section/src/platform/windows.rs index 71657862..3710a76a 100644 --- a/link-section/src/platform/windows.rs +++ b/link-section/src/platform/windows.rs @@ -150,3 +150,41 @@ crate::__def_section_name! { HASH_LENGTH = 10; VALID_SECTION_CHARS = "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; } + +/// Linker-visible provenance donor for Windows. +#[doc(hidden)] +#[macro_export] +macro_rules! __ls_provenance_symbol { + () => { + concat!( + "__ls_prov_", + env!("CARGO_CRATE_NAME"), + "_", + env!("CARGO_PKG_VERSION_MAJOR"), + "_", + env!("CARGO_PKG_VERSION_MINOR"), + "_", + env!("CARGO_PKG_VERSION_PATCH"), + ) + }; +} + +// Linker-visible provenance donor for Windows. +#[cfg(all(target_os = "windows", not(miri)))] +core::arch::global_asm!(core::concat!( + // read-only + ".pushsection .rdata$", + __ls_provenance_symbol!(), + // ..."d" = initialized, "r" = read-only + // "discard" = "duplicates OK" + ",\"dr\",discard,", + __ls_provenance_symbol!(), + "\n", + ".globl ", + __ls_provenance_symbol!(), + "\n", + __ls_provenance_symbol!(), + ":\n", + ".byte 0\n", + ".popsection\n", +)); diff --git a/link-section/tests/expand-darwin/link_section.expanded.rs b/link-section/tests/expand-darwin/link_section.expanded.rs index 7b558ab2..cdd5ba85 100644 --- a/link-section/tests/expand-darwin/link_section.expanded.rs +++ b/link-section/tests/expand-darwin/link_section.expanded.rs @@ -19,7 +19,7 @@ impl FOO { { #[allow(missing_unsafe_on_extern)] extern "C" { - #[link_name = "\u{1}section$start$__DATA$FOO74oV7cnUspp"] + #[link_name = "\u{1}section$start$__DATA$FOO6jQ6HDNgQqM"] static __SYMBOL: u8; } unsafe { &raw const __SYMBOL as *const () } @@ -27,14 +27,14 @@ impl FOO { { #[allow(missing_unsafe_on_extern)] extern "C" { - #[link_name = "\u{1}section$end$__DATA$FOO74oV7cnUspp"] + #[link_name = "\u{1}section$end$__DATA$FOO6jQ6HDNgQqM"] static __SYMBOL: u8; } unsafe { &raw const __SYMBOL as *const () } }, ) }; - let name = "__DATA,FOO74oV7cnUspp"; + let name = "__DATA,FOO6jQ6HDNgQqM"; ::link_section::__support::validate_section_name(name); unsafe { >::new(name, section) } }; @@ -76,7 +76,7 @@ fn foo() { type __InSecStoredTy = ::Item; const __LINK_SECTION_CONST_ITEM_VALUE: __InSecStoredTy = foo; #[used] - #[link_section = "__DATA,FOO74oV7cnUspp,regular,no_dead_strip"] + #[link_section = "__DATA,FOO6jQ6HDNgQqM,regular,no_dead_strip"] static __LINK_SECTION_CONST_ITEM: __InSecStoredTy = __LINK_SECTION_CONST_ITEM_VALUE; __LINK_SECTION_CONST_ITEM_VALUE }; diff --git a/link-section/tests/expand-linux/link_section.expanded.rs b/link-section/tests/expand-linux/link_section.expanded.rs index 02034ee1..05adb52b 100644 --- a/link-section/tests/expand-linux/link_section.expanded.rs +++ b/link-section/tests/expand-linux/link_section.expanded.rs @@ -20,7 +20,7 @@ impl FOO { { #[allow(missing_unsafe_on_extern)] extern "C" { - #[link_name = "__start__data_link_section_FOO74oV7cnUspp"] + #[link_name = "__start__data_link_section_FOO6jQ6HDNgQqM"] static __SYMBOL: u8; } unsafe { &raw const __SYMBOL as *const () } @@ -28,14 +28,14 @@ impl FOO { { #[allow(missing_unsafe_on_extern)] extern "C" { - #[link_name = "__stop__data_link_section_FOO74oV7cnUspp"] + #[link_name = "__stop__data_link_section_FOO6jQ6HDNgQqM"] static __SYMBOL: u8; } unsafe { &raw const __SYMBOL as *const () } }, ) }; - let name = "_data_link_section_FOO74oV7cnUspp"; + let name = "_data_link_section_FOO6jQ6HDNgQqM"; ::link_section::__support::validate_section_name(name); unsafe { >::new(name, section) } }; @@ -77,7 +77,7 @@ fn foo() { type __InSecStoredTy = ::Item; const __LINK_SECTION_CONST_ITEM_VALUE: __InSecStoredTy = foo; #[used] - #[link_section = "_data_link_section_FOO74oV7cnUspp"] + #[link_section = "_data_link_section_FOO6jQ6HDNgQqM"] static __LINK_SECTION_CONST_ITEM: __InSecStoredTy = __LINK_SECTION_CONST_ITEM_VALUE; __LINK_SECTION_CONST_ITEM_VALUE }; diff --git a/tests/link_section/copied/Cargo.toml b/tests/link_section/copied/Cargo.toml index 0d2b3da4..01be6481 100644 --- a/tests/link_section/copied/Cargo.toml +++ b/tests/link_section/copied/Cargo.toml @@ -1,13 +1,6 @@ -[package] -name = "tests" -version = "0.1.0" -edition = "2021" -publish = false - -[dependencies] -ctor = { path = "../../../ctor" } -link-section = { path = "../../../link-section" } -libc-print = "0.5" +[workspace] +members = ["copied", "copied-types", "register-a", "register-b"] +resolver = "2" [profile.dev] opt-level = 3 @@ -18,5 +11,3 @@ codegen-units = 1 opt-level = 3 lto = "fat" codegen-units = 1 - -[workspace] diff --git a/tests/link_section/copied/copied-types/Cargo.toml b/tests/link_section/copied/copied-types/Cargo.toml new file mode 100644 index 00000000..75edd73e --- /dev/null +++ b/tests/link_section/copied/copied-types/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "copied-types" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +link-section = { path = "../../../../link-section" } diff --git a/tests/link_section/copied/copied-types/src/lib.rs b/tests/link_section/copied/copied-types/src/lib.rs new file mode 100644 index 00000000..540fe136 --- /dev/null +++ b/tests/link_section/copied/copied-types/src/lib.rs @@ -0,0 +1,27 @@ +//! Shared types and link sections for the `copied` integration test. + +use link_section::section; + +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] +pub struct ComplexType { + pub static_string: &'static str, + pub static_ptr: &'static OtherType, +} + +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] +pub struct OtherType { + pub u32: u32, + pub u64: u64, +} + +pub static OTHER_TYPE: OtherType = OtherType { u32: 1, u64: 2 }; +pub static OTHER_TYPE_2: OtherType = OtherType { u32: 3, u64: 4 }; + +#[section(typed)] +pub static VALUES: link_section::TypedSection<&'static u64>; + +#[section(mutable)] +pub static MUT_LINK_SECTION: link_section::TypedMutableSection; + +#[section(typed)] +pub static IMMUTABLE_LINK_SECTION: link_section::TypedSection; diff --git a/tests/link_section/copied/copied/Cargo.toml b/tests/link_section/copied/copied/Cargo.toml new file mode 100644 index 00000000..0c00ea6c --- /dev/null +++ b/tests/link_section/copied/copied/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "copied" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +copied-types = { path = "../copied-types" } +register-a = { path = "../register-a" } +register-b = { path = "../register-b" } + +[[bin]] +name = "copied" +path = "src/main.rs" diff --git a/tests/link_section/copied/src/main.rs b/tests/link_section/copied/copied/src/main.rs similarity index 73% rename from tests/link_section/copied/src/main.rs rename to tests/link_section/copied/copied/src/main.rs index 78f3a9bb..ef9c3044 100644 --- a/tests/link_section/copied/src/main.rs +++ b/tests/link_section/copied/copied/src/main.rs @@ -1,8 +1,13 @@ -//! Example usage of the `link-section` crate. +//! Cross-crate link-section smoke test under fat LTO. +//! +//! Sections and shared types live in `copied-types`; item registrations are +//! split across `register-a` and `register-b`. -mod sections; +use copied_types::{IMMUTABLE_LINK_SECTION, MUT_LINK_SECTION, VALUES}; -use sections::{IMMUTABLE_LINK_SECTION, MUT_LINK_SECTION, VALUES}; +// Pull registrar object code into the link (no direct API use). +use register_a as _; +use register_b as _; pub fn main() { // LLVM was optimizing these copies into memsets diff --git a/tests/link_section/copied/register-a/Cargo.toml b/tests/link_section/copied/register-a/Cargo.toml new file mode 100644 index 00000000..09b332eb --- /dev/null +++ b/tests/link_section/copied/register-a/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "register-a" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +copied-types = { path = "../copied-types" } +link-section = { path = "../../../../link-section" } diff --git a/tests/link_section/copied/register-a/src/lib.rs b/tests/link_section/copied/register-a/src/lib.rs new file mode 100644 index 00000000..07aeaa95 --- /dev/null +++ b/tests/link_section/copied/register-a/src/lib.rs @@ -0,0 +1,46 @@ +//! Registrations for the `copied` integration test (crate A). + +use copied_types::{ComplexType, IMMUTABLE_LINK_SECTION, MUT_LINK_SECTION, OTHER_TYPE, OTHER_TYPE_2, VALUES}; +use link_section::in_section; + +#[in_section(VALUES)] +const _: &'static u64 = { + static V: u64 = 50; + &V +}; + +#[in_section(VALUES)] +const _: &'static u64 = { + static V: u64 = 10; + &V +}; + +#[in_section(VALUES)] +const _: &'static u64 = { + static V: u64 = 40; + &V +}; + +#[in_section(MUT_LINK_SECTION)] +const _: ComplexType = ComplexType { + static_string: "1", + static_ptr: &OTHER_TYPE, +}; + +#[in_section(MUT_LINK_SECTION)] +const _: ComplexType = ComplexType { + static_string: "2", + static_ptr: &OTHER_TYPE, +}; + +#[in_section(IMMUTABLE_LINK_SECTION)] +const _: ComplexType = ComplexType { + static_string: "1", + static_ptr: &OTHER_TYPE, +}; + +#[in_section(IMMUTABLE_LINK_SECTION)] +const _: ComplexType = ComplexType { + static_string: "9", + static_ptr: &OTHER_TYPE_2, +}; diff --git a/tests/link_section/copied/register-b/Cargo.toml b/tests/link_section/copied/register-b/Cargo.toml new file mode 100644 index 00000000..5c3fe2c2 --- /dev/null +++ b/tests/link_section/copied/register-b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "register-b" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +copied-types = { path = "../copied-types" } +link-section = { path = "../../../../link-section" } diff --git a/tests/link_section/copied/register-b/src/lib.rs b/tests/link_section/copied/register-b/src/lib.rs new file mode 100644 index 00000000..2a69706a --- /dev/null +++ b/tests/link_section/copied/register-b/src/lib.rs @@ -0,0 +1,40 @@ +//! Registrations for the `copied` integration test (crate B). + +use copied_types::{ComplexType, IMMUTABLE_LINK_SECTION, MUT_LINK_SECTION, OTHER_TYPE, OTHER_TYPE_2, VALUES}; +use link_section::in_section; + +#[in_section(VALUES)] +const _: &'static u64 = { + static V: u64 = 20; + &V +}; + +#[in_section(VALUES)] +const _: &'static u64 = { + static V: u64 = 30; + &V +}; + +#[in_section(MUT_LINK_SECTION)] +const _: ComplexType = ComplexType { + static_string: "4", + static_ptr: &OTHER_TYPE_2, +}; + +#[in_section(MUT_LINK_SECTION)] +const _: ComplexType = ComplexType { + static_string: "5", + static_ptr: &OTHER_TYPE, +}; + +#[in_section(MUT_LINK_SECTION)] +const _: ComplexType = ComplexType { + static_string: "3", + static_ptr: &OTHER_TYPE, +}; + +#[in_section(IMMUTABLE_LINK_SECTION)] +const _: ComplexType = ComplexType { + static_string: "4", + static_ptr: &OTHER_TYPE, +}; diff --git a/tests/link_section/copied/src/sections.rs b/tests/link_section/copied/src/sections.rs deleted file mode 100644 index 83c01916..00000000 --- a/tests/link_section/copied/src/sections.rs +++ /dev/null @@ -1,115 +0,0 @@ -use link_section::{in_section, section}; - -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] -pub struct ComplexType { - static_string: &'static str, - static_ptr: &'static OtherType, -} - -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] -pub struct OtherType { - u32: u32, - u64: u64, -} - -static OTHER_TYPE: OtherType = OtherType { u32: 1, u64: 2 }; -static OTHER_TYPE_2: OtherType = OtherType { u32: 3, u64: 4 }; - -#[section(typed)] -pub static VALUES: link_section::TypedSection<&'static u64>; - -// Scatter several `&'static u64` from distinct modules. The values are distinct -// and non-zero so a correct read sorts to a known order; a miscompiled read -// yields nulls. -#[in_section(VALUES)] -const _: &'static u64 = { - static V: u64 = 50; - &V -}; -#[in_section(VALUES)] -const _: &'static u64 = { - static V: u64 = 10; - &V -}; - -mod more { - use link_section::in_section; - - #[in_section(super::VALUES)] - const _: &'static u64 = { - static V: u64 = 40; - &V - }; - #[in_section(super::VALUES)] - const _: &'static u64 = { - static V: u64 = 20; - &V - }; - #[in_section(super::VALUES)] - const _: &'static u64 = { - static V: u64 = 30; - &V - }; -} - -#[section(mutable)] -pub static MUT_LINK_SECTION: link_section::TypedMutableSection; - -#[in_section(MUT_LINK_SECTION)] -const _: ComplexType = ComplexType { - static_string: "1", - static_ptr: &OTHER_TYPE, -}; - -#[in_section(MUT_LINK_SECTION)] -const _: ComplexType = ComplexType { - static_string: "2", - static_ptr: &OTHER_TYPE, -}; - -#[in_section(MUT_LINK_SECTION)] -const _: ComplexType = ComplexType { - static_string: "3", - static_ptr: &OTHER_TYPE, -}; - -mod other { - use super::*; - - #[in_section(MUT_LINK_SECTION)] - const _: ComplexType = ComplexType { - static_string: "4", - static_ptr: &OTHER_TYPE_2, - }; - - #[in_section(MUT_LINK_SECTION)] - const _: ComplexType = ComplexType { - static_string: "5", - static_ptr: &OTHER_TYPE, - }; -} - -#[section(typed)] -pub static IMMUTABLE_LINK_SECTION: link_section::TypedSection; - -#[in_section(IMMUTABLE_LINK_SECTION)] -const _: ComplexType = ComplexType { - static_string: "1", - static_ptr: &OTHER_TYPE, -}; - -mod other_immutable { - use super::*; - - #[in_section(IMMUTABLE_LINK_SECTION)] - const _: ComplexType = ComplexType { - static_string: "9", - static_ptr: &OTHER_TYPE_2, - }; - - #[in_section(IMMUTABLE_LINK_SECTION)] - const _: ComplexType = ComplexType { - static_string: "4", - static_ptr: &OTHER_TYPE, - }; -} diff --git a/tests/link_section/mod.rs b/tests/link_section/mod.rs index d32c70d7..fdbcd5b4 100644 --- a/tests/link_section/mod.rs +++ b/tests/link_section/mod.rs @@ -43,7 +43,7 @@ cd "link_section/copied"; defer { $ cargo clean --quiet } -$ cargo run --quiet +$ cargo run -p copied --quiet """ MUTABLE: [ComplexType { static_string: "1", static_ptr: OtherType { u32: 1, u64: 2 } }, ComplexType { static_string: "2", static_ptr: OtherType { u32: 1, u64: 2 } }, ComplexType { static_string: "3", static_ptr: OtherType { u32: 1, u64: 2 } }, ComplexType { static_string: "4", static_ptr: OtherType { u32: 3, u64: 4 } }, ComplexType { static_string: "5", static_ptr: OtherType { u32: 1, u64: 2 } }] IMMUTABLE: [ComplexType { static_string: "1", static_ptr: OtherType { u32: 1, u64: 2 } }, ComplexType { static_string: "4", static_ptr: OtherType { u32: 1, u64: 2 } }, ComplexType { static_string: "9", static_ptr: OtherType { u32: 3, u64: 4 } }]