Merge pull request #4099 from roc-lang/pe-host-to-app

windows surgical linker: call host functions from the app
This commit is contained in:
Folkert de Vries 2022-09-24 12:54:53 +02:00 committed by GitHub
commit 10b8cd299d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 81 additions and 10 deletions

View File

@ -906,6 +906,6 @@ fn import_builtin_in_platform_and_check_app() {
),
];
let result = multiple_modules("issue_2863_module_type_does_not_exist", modules);
let result = multiple_modules("import_builtin_in_platform_and_check_app", modules);
assert!(result.is_ok(), "should check");
}

View File

@ -147,8 +147,7 @@ pub fn synthetic_dll(custom_names: &[String]) -> Vec<u8> {
// we store the export directory in a .rdata section
let rdata_section: (_, Vec<u8>) = {
// not sure if that 0x40 is important, I took it from a .dll that zig produced
let characteristics = object::pe::IMAGE_SCN_MEM_READ | 0x40;
let characteristics = object::pe::IMAGE_SCN_MEM_READ | pe::IMAGE_SCN_CNT_INITIALIZED_DATA;
let range = writer.reserve_section(
*b".rdata\0\0",
characteristics,

View File

@ -97,9 +97,14 @@ pub fn build_and_preprocess_host(
host_input_path.with_file_name("libapp.so")
};
let dynhost = if let target_lexicon::OperatingSystem::Windows = target.operating_system {
host_input_path.with_file_name("dynhost.exe")
} else {
host_input_path.with_file_name("dynhost")
};
generate_dynamic_lib(target, exposed_to_host, exported_closure_types, &dummy_lib);
rebuild_host(opt_level, target, host_input_path, Some(&dummy_lib));
let dynhost = host_input_path.with_file_name("dynhost");
let metadata = host_input_path.with_file_name("metadata");
// let prehost = host_input_path.with_file_name("preprocessedhost");

View File

@ -4,7 +4,7 @@ use memmap2::{Mmap, MmapMut};
use object::{
pe::{ImageImportDescriptor, ImageNtHeaders64, ImageSectionHeader, ImageThunkData64},
read::pe::ImportTable,
LittleEndian as LE, SectionIndex,
LittleEndian as LE, RelocationTarget, SectionIndex,
};
use roc_collections::MutMap;
use roc_error_macros::internal_error;
@ -526,8 +526,8 @@ enum SectionKind {
struct Section {
/// File range of the section (in the app object)
file_range: Range<usize>,
kind: SectionKind,
relocations: MutMap<String, (u64, object::Relocation)>,
}
#[allow(dead_code)]
@ -568,6 +568,24 @@ impl AppSections {
_ => continue,
};
let mut relocations = MutMap::default();
for (offset_in_section, relocation) in section.relocations() {
match relocation.target() {
RelocationTarget::Symbol(symbol_index) => {
use object::ObjectSymbol;
let name = file
.symbol_by_index(symbol_index)
.and_then(|s| s.name())
.unwrap_or_default();
relocations.insert(name.to_string(), (offset_in_section, relocation));
}
_ => todo!(),
}
}
let (start, length) = section.file_range().unwrap();
let file_range = start as usize..(start + length) as usize;
@ -585,7 +603,11 @@ impl AppSections {
}
}
let section = Section { file_range, kind };
let section = Section {
file_range,
kind,
relocations,
};
sections.push(section);
}
@ -1009,6 +1031,14 @@ mod test {
extern fn roc_magic1() callconv(.C) u64;
extern fn roc_magic2() callconv(.C) u8;
pub export fn roc_alloc() u64 {
return 123456;
}
pub export fn roc_realloc() u64 {
return 111111;
}
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
try stdout.print("Hello, {} {} {} {}!\n", .{roc_magic1(), roc_magic2(), roc_one, roc_three});
@ -1021,8 +1051,11 @@ mod test {
export const roc_one: u64 = 1;
export const roc_three: u64 = 3;
extern fn roc_alloc() u64;
extern fn roc_realloc() u64;
export fn roc_magic1() u64 {
return 42;
return roc_alloc() + roc_realloc();
}
export fn roc_magic2() u8 {
@ -1045,6 +1078,7 @@ mod test {
"-target",
"x86_64-windows-gnu",
"--strip",
"-rdynamic",
"-OReleaseFast",
])
.output()
@ -1081,6 +1115,7 @@ mod test {
"-lc",
"-target",
"x86_64-windows-gnu",
"-rdynamic",
"--strip",
"-OReleaseFast",
])
@ -1125,6 +1160,18 @@ mod test {
let file = PeFile64::parse(executable.deref()).unwrap();
let last_host_section = file.sections().nth(last_host_section_index).unwrap();
let exports: MutMap<String, i64> = file
.exports()
.unwrap()
.into_iter()
.map(|e| {
(
String::from_utf8(e.name().to_vec()).unwrap(),
(e.address() - image_base) as i64,
)
})
.collect();
let optional_header_offset = file.dos_header().nt_headers_offset() as usize
+ std::mem::size_of::<u32>()
+ std::mem::size_of::<ImageFileHeader>();
@ -1197,6 +1244,26 @@ mod test {
for section in it {
let slice = &roc_app[section.file_range.start..section.file_range.end];
executable[offset..][..slice.len()].copy_from_slice(slice);
for (name, (offset_in_section, relocation)) in section.relocations.iter() {
let destination = exports[name];
match relocation.kind() {
object::RelocationKind::Relative => {
// we implicitly only do 32-bit relocations
debug_assert_eq!(relocation.size(), 32);
let delta =
destination - virtual_address as i64 - *offset_in_section as i64
+ relocation.addend();
executable[offset + *offset_in_section as usize..][..4]
.copy_from_slice(&(delta as i32).to_le_bytes());
}
_ => todo!(),
}
}
offset += slice.len();
}
@ -1253,7 +1320,7 @@ mod test {
let output = String::from_utf8_lossy(&output.stdout);
assert_eq!("Hello, 42 32 1 3!\n", output);
assert_eq!("Hello, 234567 32 1 3!\n", output);
}
#[ignore]
@ -1281,6 +1348,6 @@ mod test {
let output = String::from_utf8_lossy(&output.stdout);
assert_eq!("Hello, 42 32 1 3!\n", output);
assert_eq!("Hello, 234567 32 1 3!\n", output);
}
}