centralize mmap logic

This commit is contained in:
Folkert 2022-09-24 16:55:53 +02:00
parent baa0dcc359
commit 764637594e
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
2 changed files with 40 additions and 83 deletions

View file

@ -13,7 +13,7 @@ use roc_mono::ir::OptLevel;
use std::cmp::Ordering;
use std::convert::TryFrom;
use std::ffi::CStr;
use std::fs::{self, File};
use std::fs;
use std::mem;
use std::os::raw::c_char;
use std::path::Path;
@ -204,11 +204,8 @@ fn dummy_lib_is_up_to_date(
return false;
}
let exec_file = fs::File::open(dummy_lib_path).unwrap_or_else(|e| internal_error!("{}", e));
let exec_mmap = unsafe { Mmap::map(&exec_file).unwrap_or_else(|e| internal_error!("{}", e)) };
let exec_data = &*exec_mmap;
let object = object::File::parse(exec_data).unwrap();
let dummy_lib = open_mmap(dummy_lib_path);
let object = object::File::parse(&*dummy_lib).unwrap();
// the user may have been cross-compiling.
// The dynhost on disk must match our current target
@ -524,9 +521,7 @@ fn preprocess_elf_and_macho(
) {
let total_start = Instant::now();
let exec_parsing_start = total_start;
let exec_file = fs::File::open(host_exe_path).unwrap_or_else(|e| internal_error!("{}", e));
let exec_mmap = unsafe { Mmap::map(&exec_file).unwrap_or_else(|e| internal_error!("{}", e)) };
let exec_data = &*exec_mmap;
let exec_data = &*open_mmap(host_exe_path);
let exec_obj = match object::File::parse(exec_data) {
Ok(obj) => obj,
Err(err) => {
@ -788,7 +783,7 @@ fn preprocess_elf_and_macho(
let scanning_dynamic_deps_duration;
let platform_gen_start;
let (out_mmap, out_file) = match target.binary_format {
let out_mmap = match target.binary_format {
target_lexicon::BinaryFormat::Elf => match target
.endianness()
.unwrap_or(target_lexicon::Endianness::Little)
@ -914,7 +909,6 @@ fn preprocess_elf_and_macho(
.unwrap_or_else(|e| internal_error!("{}", e));
// Also drop files to to ensure data is fully written here.
drop(out_mmap);
drop(out_file);
let flushing_data_duration = flushing_data_start.elapsed();
let total_duration = total_start.elapsed();
@ -954,7 +948,7 @@ fn gen_macho_le(
macho_load_so_offset: usize,
_target: &Triple,
_verbose: bool,
) -> (MmapMut, File) {
) -> MmapMut {
// Just adding some extra context/useful info here.
// I was talking to Jakub from the Zig team about macho linking and here are some useful comments:
// 1) Macho WILL run fine with multiple text segments (and theoretically data segments).
@ -1002,18 +996,7 @@ fn gen_macho_le(
md.exec_len = exec_data.len() as u64 + md.added_byte_count;
let out_file = fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(true)
.open(out_filename)
.unwrap_or_else(|e| internal_error!("{}", e));
out_file
.set_len(md.exec_len)
.unwrap_or_else(|e| internal_error!("{}", e));
let mut out_mmap =
unsafe { MmapMut::map_mut(&out_file).unwrap_or_else(|e| internal_error!("{}", e)) };
let mut out_mmap = open_mmap_mut(out_filename, md.exec_len as usize);
let end_of_cmds = size_of_cmds + mem::size_of_val(exec_header);
// "Delete" the dylib load command - by copying all the bytes before it
@ -1499,7 +1482,7 @@ fn gen_macho_le(
// cmd_loc should be where the last offset ended
md.macho_cmd_loc = offset as u64;
(out_mmap, out_file)
out_mmap
}
#[allow(clippy::too_many_arguments)]
@ -1512,7 +1495,7 @@ fn gen_elf_le(
dynamic_lib_count: usize,
shared_lib_index: usize,
verbose: bool,
) -> (MmapMut, File) {
) -> MmapMut {
let exec_header = load_struct_inplace::<elf::FileHeader64<LittleEndian>>(exec_data, 0);
let ph_offset = exec_header.e_phoff.get(NativeEndian);
let ph_ent_size = exec_header.e_phentsize.get(NativeEndian);
@ -1540,18 +1523,7 @@ fn gen_elf_le(
let physical_shift_start = ph_end as u64;
md.exec_len = exec_data.len() as u64 + md.added_byte_count;
let out_file = fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(true)
.open(preprocessed_path)
.unwrap_or_else(|e| internal_error!("{}", e));
out_file
.set_len(md.exec_len)
.unwrap_or_else(|e| internal_error!("{}", e));
let mut out_mmap =
unsafe { MmapMut::map_mut(&out_file).unwrap_or_else(|e| internal_error!("{}", e)) };
let mut out_mmap = open_mmap_mut(preprocessed_path, md.exec_len as usize);
out_mmap[..ph_end].copy_from_slice(&exec_data[..ph_end]);
@ -1827,7 +1799,7 @@ fn gen_elf_le(
}
file_header.e_phnum = endian::U16::new(LittleEndian, ph_num + added_header_count as u16);
(out_mmap, out_file)
out_mmap
}
// fn scan_macho_dynamic_deps(
@ -2063,8 +2035,7 @@ fn surgery_elf_and_macho(
target: &Triple,
) {
let app_parsing_start = Instant::now();
let app_file = fs::File::open(app_path).unwrap_or_else(|e| internal_error!("{}", e));
let app_mmap = unsafe { Mmap::map(&app_file).unwrap_or_else(|e| internal_error!("{}", e)) };
let app_mmap = open_mmap(app_path);
let app_data = &*app_mmap;
let app_obj = match object::File::parse(app_data) {
Ok(obj) => obj,
@ -2082,19 +2053,8 @@ fn surgery_elf_and_macho(
let loading_metadata_duration = loading_metadata_start.elapsed();
let load_and_mmap_start = Instant::now();
let exec_file = fs::OpenOptions::new()
.read(true)
.write(true)
.open(executable_path)
.unwrap_or_else(|e| internal_error!("{}", e));
let max_out_len = md.exec_len + app_data.len() as u64 + md.load_align_constraint;
exec_file
.set_len(max_out_len)
.unwrap_or_else(|e| internal_error!("{}", e));
let mut exec_mmap =
unsafe { MmapMut::map_mut(&exec_file).unwrap_or_else(|e| internal_error!("{}", e)) };
let mut exec_mmap = open_mmap_mut(executable_path, max_out_len as usize);
let load_and_mmap_duration = load_and_mmap_start.elapsed();
let out_gen_start = Instant::now();
@ -2131,10 +2091,6 @@ fn surgery_elf_and_macho(
// Also drop files to to ensure data is fully written here.
drop(exec_mmap);
exec_file
.set_len(offset as u64 + 1)
.unwrap_or_else(|e| internal_error!("{}", e));
drop(exec_file);
let flushing_data_duration = flushing_data_start.elapsed();
// Make sure the final executable has permision to execute.
@ -3080,6 +3036,29 @@ fn load_structs_inplace_mut<T>(bytes: &mut [u8], offset: usize, count: usize) ->
body
}
pub(crate) fn open_mmap(path: &Path) -> Mmap {
let in_file = std::fs::OpenOptions::new()
.read(true)
.open(path)
.unwrap_or_else(|e| internal_error!("{e}"));
unsafe { Mmap::map(&in_file).unwrap_or_else(|e| internal_error!("{e}")) }
}
pub(crate) fn open_mmap_mut(path: &Path, length: usize) -> MmapMut {
let out_file = std::fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(path)
.unwrap_or_else(|e| internal_error!("{e}"));
out_file
.set_len(length as u64)
.unwrap_or_else(|e| internal_error!("{e}"));
unsafe { MmapMut::map_mut(&out_file).unwrap_or_else(|e| internal_error!("{e}")) }
}
#[cfg(test)]
mod tests {
use super::*;

View file

@ -5,7 +5,7 @@ use std::{
};
use bincode::{deserialize_from, serialize_into};
use memmap2::{Mmap, MmapMut};
use memmap2::MmapMut;
use object::{
pe::{
self, ImageFileHeader, ImageImportDescriptor, ImageNtHeaders64, ImageSectionHeader,
@ -19,7 +19,9 @@ use serde::{Deserialize, Serialize};
use roc_collections::MutMap;
use roc_error_macros::internal_error;
use crate::{generate_dylib::APP_DLL, load_struct_inplace, load_struct_inplace_mut};
use crate::{
generate_dylib::APP_DLL, load_struct_inplace, load_struct_inplace_mut, open_mmap, open_mmap_mut,
};
/// The metadata stores information about/from the host .exe because
///
@ -663,30 +665,6 @@ impl Preprocessor {
}
}
fn open_mmap(path: &Path) -> Mmap {
let in_file = std::fs::OpenOptions::new()
.read(true)
.create(true)
.open(path)
.unwrap_or_else(|e| internal_error!("{e}"));
unsafe { Mmap::map(&in_file).unwrap_or_else(|e| internal_error!("{e}")) }
}
fn open_mmap_mut(path: &Path, length: usize) -> MmapMut {
let out_file = std::fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(path)
.unwrap_or_else(|e| internal_error!("{e}"));
out_file
.set_len(length as u64)
.unwrap_or_else(|e| internal_error!("{e}"));
unsafe { MmapMut::map_mut(&out_file).unwrap_or_else(|e| internal_error!("{e}")) }
}
/// Find the place in the executable where the thunks for our dummy .dll are stored
fn find_thunks_start_offset(
executable: &[u8],