I have been doing some quick testing to see how Rust sorts data into D
or R
sections. A subset of these tests are below:
/// Struct with only primitives
pub struct StBasic { pub a: u32, pub b: u32 }
/// Struct with an optional value
pub struct StOpt { pub a: u32, pub b: Option<u32> }
/// Struct with a function pointer
pub struct StWithOptFn { pub a: u32, pub b: Option<fn() -> u32> }
#[no_mangle]
pub static testsym_stbasic: StBasic = StBasic { a: 1234, b: 12345 };
#[no_mangle]
pub static testsym_stopt: StOpt = StOpt { a: 6323, b: Some(1929) };
#[no_mangle]
pub static testsym_stoptfn: StWithOptFn = StWithOptFn { a: 9123, b: Some(make_const_int) };
#[no_mangle]
#[link_section = ".rodata"]
pub static testsym_stoptfn_force_ro: StWithOptFn = StWithOptFn { a: 9123, b: Some(make_const_int) };
And this is the output from nm
:
0000000000000000 R testsym_stbasic
0000000000000000 R testsym_stopt
0000000000000000 D testsym_stoptfn
0000000000000008 D testsym_stoptfn_force_ro
Most is as expected, but why is it that the struct with the function pointer gets placed in .data
instead of .rodata
? Is it possible to force it to be in .rodata
somehow, since it seems like link_section
does not work in this case?
Everything else seems to follow the rule of being in .rodata
unless there is an UnsafeCell
or static mut
is used.
Full test
use std::cell::UnsafeCell;
#[no_mangle]
pub static testsym_u32: u32 = 100;
#[no_mangle]
pub static mut testsym_u32_mut: u32 = 500;
#[no_mangle]
#[link_section = ".rodata"]
pub static mut testsym_u32_force_ro: u32 = 1234;
#[no_mangle]
pub static testsym_u32_from_fn: u32 = make_const_int();
#[no_mangle]
pub static testsym_u32_unsafecell: UnsafeWrapper<u32> = UnsafeWrapper(UnsafeCell::new(1000));
#[no_mangle]
pub static testsym_str: &str = "Hello, world!";
#[no_mangle]
pub static testsym_stbasic: StBasic = StBasic { a: 1234, b: 12345 };
#[no_mangle]
pub static testsym_stbasic_from_fn: StBasic = make_stbasic();
#[no_mangle]
pub static testsym_stopt: StOpt = StOpt { a: 6323, b: Some(1929) };
#[no_mangle]
pub static testsym_stopt_from_fn: StOpt = make_stopt();
#[no_mangle]
pub static testsym_stoptfn: StWithOptFn = StWithOptFn { a: 9123, b: Some(make_const_int) };
#[no_mangle]
#[link_section = ".rodata"]
pub static testsym_stoptfn_force_ro: StWithOptFn = StWithOptFn { a: 9123, b: Some(make_const_int) };
#[no_mangle]
pub static testsym_stoptfn_from_fn: StWithOptFn = make_stoptfn();
pub struct StBasic { pub a: u32, pub b: u32 }
pub struct StOpt { pub a: u32, pub b: Option<u32> }
pub struct StWithOptFn { pub a: u32, pub b: Option<fn() -> u32> }
pub struct UnsafeWrapper<T>(UnsafeCell<T>);
unsafe impl<T> Sync for UnsafeWrapper<T> {}
const fn make_const_int() -> u32 {
20493
}
const fn make_stbasic() -> StBasic {
StBasic { a: 12342, b: 27565 }
}
const fn make_stopt() -> StOpt {
StOpt { a: 3334, b: Some(12111) }
}
const fn make_stoptfn() -> StWithOptFn {
StWithOptFn { a: 9384, b: Some(make_const_int) }
}
Commands
rustc test.rs --crate-type=staticlib -O
nm -gC libtest.a | grep testsym
Output
0000000000000000 R testsym_stbasic
0000000000000000 R testsym_stbasic_from_fn
0000000000000000 R testsym_stopt
0000000000000000 R testsym_stopt_from_fn
0000000000000000 D testsym_stoptfn
0000000000000008 D testsym_stoptfn_force_ro
0000000000000000 D testsym_stoptfn_from_fn
0000000000000000 D testsym_str
0000000000000000 R testsym_u32
0000000000000000 D testsym_u32_force_ro
0000000000000000 R testsym_u32_from_fn
0000000000000000 D testsym_u32_mut
0000000000000000 D testsym_u32_unsafecell