Description
I tried this code:
fn main() {
println!("Hello from main!");
foo1();
foo2();
}
#[link_section = "__TEXT,__foo1"]
fn foo1() {
println!("Hello from foo1 in __TEXT!")
}
#[link_section = "__TEXT2,__foo2"]
fn foo2() {
println!("Hello from foo2 in __TEXT2!");
}
I expected to see this happen: all three functions are executed and their statements printed.
Instead, this happened:
Hello from main!
Hello from foo1 in __TEXT!
zsh: bus error ./t
In Console.app:
Data/Stack execution not permitted: t[pid ___] at virtual address 0x108dde000, protections were read-write
foo1 works because it is located in the __TEXT
segment, which is necessarily assigned rx
permissions. foo2 does not, because the linker by default assigns rw
permissions to new segments, which means that code cannot be executed from these segments.
Meta
rustc --version --verbose
:
rustc 1.71.0-nightly (39c6804b9 2023-04-19)
binary: rustc
commit-hash: 39c6804b92aa202369e402525cee329556bc1db0
commit-date: 2023-04-19
host: x86_64-apple-darwin
release: 1.71.0-nightly
LLVM version: 16.0.2
I realize that this is may not be a proper bug (link_section
is unsafe now). However, it is still problematic that new segments can only have the default rw
permissions, when a user might want one to contain executable code or read-only data.
My current solution is to use -segprot
in a build script's link arguments, but this only works on the root crate (rust-lang/cargo#9554).
Having an attribute or other transitive method of assigning segment permissions on mach-o targets is therefore necessary for the link_section
attribute to be usable.