use std::path::PathBuf;
use std::process::Command;
use object::read::elf::ElfFile32;
use object::{Object, ObjectSection, ObjectSymbol, RelocationTarget};
fn synth() -> &'static str {
env!("CARGO_BIN_EXE_synth")
}
fn fixture() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../..")
.join("scripts/repro/cabi_arena_realloc.wat")
}
#[test]
fn cabi_arena_realloc_emits_undefined_symbol_and_reloc_418() {
let out = "/tmp/cabi_arena_realloc_418.o";
let status = Command::new(synth())
.args([
"compile",
fixture().to_str().unwrap(),
"--target",
"cortex-m4",
"--native-pointer-abi",
"--all-exports",
"--relocatable",
"-o",
out,
])
.output()
.expect("run synth");
assert!(
status.status.success(),
"compile failed: {}",
String::from_utf8_lossy(&status.stderr)
);
let data = std::fs::read(out).expect("read .o");
let obj = ElfFile32::<object::Endianness>::parse(&*data).expect("parse ELF");
let sym = obj
.symbols()
.find(|s| s.name() == Ok("__cabi_arena_realloc"))
.expect("__cabi_arena_realloc symbol present");
assert!(
sym.is_undefined(),
"__cabi_arena_realloc must be UNDEFINED (embedder-bound), not defined in synth's output"
);
let mut reloc_targets_arena = false;
for section in obj.sections() {
for (_off, reloc) in section.relocations() {
if let RelocationTarget::Symbol(idx) = reloc.target()
&& let Ok(s) = obj.symbol_by_index(idx)
&& s.name() == Ok("__cabi_arena_realloc")
{
reloc_targets_arena = true;
}
}
}
assert!(
reloc_targets_arena,
"a relocation must target __cabi_arena_realloc (the import call site), \
so the native link binds it to the TCB allocator"
);
}