roc/crates/linker/src/generate_dylib/mod.rs
2022-10-24 18:47:12 -07:00

111 lines
3.6 KiB
Rust

use target_lexicon::Triple;
mod elf64;
mod macho;
mod pe;
#[cfg(test)]
pub(crate) use pe::synthetic_dll;
#[cfg(test)]
pub(crate) use elf64::create_dylib_elf64;
pub(crate) use pe::APP_DLL;
pub fn generate(target: &Triple, custom_names: &[String]) -> object::read::Result<Vec<u8>> {
match target.binary_format {
target_lexicon::BinaryFormat::Elf => elf64::create_dylib_elf64(custom_names),
target_lexicon::BinaryFormat::Macho => macho::create_dylib_macho(custom_names, target),
target_lexicon::BinaryFormat::Coff => Ok(pe::synthetic_dll(custom_names)),
other => unimplemented!("dylib creation for {:?}", other),
}
}
#[cfg(test)]
mod tests {
use super::*;
use object::Object;
fn check_exports(target: &Triple) {
let custom_names = ["foo".to_string(), "bar".to_string()];
let bytes = generate(target, &custom_names).unwrap();
let object = object::File::parse(bytes.as_slice()).unwrap();
let exports = object.exports().unwrap();
for custom in custom_names {
assert!(
exports.iter().any(|e| e.name() == custom.as_bytes()),
"missing {}",
&custom
);
}
}
#[test]
fn check_exports_elf64() {
let target = target_lexicon::Triple {
architecture: target_lexicon::Architecture::X86_64,
operating_system: target_lexicon::OperatingSystem::Linux,
binary_format: target_lexicon::BinaryFormat::Elf,
..target_lexicon::Triple::host()
};
check_exports(&target);
}
#[test]
fn check_exports_coff() {
// NOTE: this does not work
//
// let target = target_lexicon::Triple {
// architecture: target_lexicon::Architecture::X86_64,
// operating_system: target_lexicon::OperatingSystem::Windows,
// binary_format: target_lexicon::BinaryFormat::Coff,
// ..target_lexicon::Triple::host()
// };
//
// check_exports(&target);
//
// Because our exports point back into the .edata section, they are considered "forward"
// exports: they aren't actually defined in this .dll and hence not considered exports by
// the `object` crate.
}
#[test]
fn check_exports_coff_manual() {
let target = target_lexicon::Triple {
architecture: target_lexicon::Architecture::X86_64,
operating_system: target_lexicon::OperatingSystem::Windows,
binary_format: target_lexicon::BinaryFormat::Coff,
..target_lexicon::Triple::host()
};
let custom_names = ["foo".to_string(), "bar".to_string()];
let bytes = generate(&target, &custom_names).unwrap();
let object = object::read::pe::PeFile64::parse(bytes.as_slice()).unwrap();
let exports = {
let mut exports = Vec::new();
if let Some(export_table) = object.export_table().unwrap() {
for (name_pointer, _address_index) in export_table.name_iter() {
let name = export_table.name_from_pointer(name_pointer).unwrap();
// here the standard `.exports()` checks for `if !export_table.is_forward(address)`
exports.push(name)
}
}
exports
};
for custom in custom_names {
assert!(
exports.iter().any(|name| *name == custom.as_bytes()),
"missing {}",
&custom
);
}
}
}