ensure sections never have 0 virtual size

This commit is contained in:
Folkert 2022-10-15 20:29:50 +02:00
parent b3cf1c6812
commit b5fb200a91
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C

View file

@ -271,7 +271,8 @@ pub(crate) fn surgery_pe(executable_path: &Path, metadata_path: &Path, roc_app_b
}
}
let virtual_size = length as u32;
// NOTE: sections cannot be zero in size!
let virtual_size = u32::max(1, length as u32);
let size_of_raw_data = next_multiple_of(length, file_alignment) as u32;
match kind {
@ -1924,199 +1925,7 @@ mod test {
std::fs::copy(&dir.join("preprocessedhost"), &dir.join("app.exe")).unwrap();
{
let executable_path: &Path = &dir.join("app.exe");
let metadata_path: &Path = &dir.join("metadata");
let roc_app_bytes = &*roc_app;
let md = PeMetadata::read_from_file(metadata_path);
let app_obj_sections = AppSections::from_data(roc_app_bytes);
let mut symbols = app_obj_sections.roc_symbols;
let image_base: u64 = md.image_base;
let file_alignment = md.file_alignment as usize;
let section_alignment = md.section_alignment as usize;
let app_sections_size: usize = app_obj_sections
.sections
.iter()
.map(|s| {
next_multiple_of(s.file_range.end - s.file_range.start, file_alignment)
})
.sum();
let executable =
&mut open_mmap_mut(executable_path, md.dynhost_file_size + app_sections_size);
let app_code_section_va = md.last_host_section_address
+ next_multiple_of(
md.last_host_section_size as usize,
section_alignment as usize,
) as u64;
let mut section_file_offset = md.dynhost_file_size;
let mut virtual_address = (app_code_section_va - image_base) as u32;
// find the location to write the section headers for our new sections
let mut section_header_start = md.dynamic_relocations.section_headers_offset_in_file
as usize
+ md.host_section_count * std::mem::size_of::<ImageSectionHeader>();
relocate_dummy_dll_entries(executable, &md);
let mut code_bytes_added = 0;
let mut data_bytes_added = 0;
let mut file_bytes_added = 0;
// relocations between the sections of the roc application
// (as opposed to relocations for symbols the app imports from the host)
let inter_app_relocations = process_internal_relocations(
&app_obj_sections.sections,
&app_obj_sections.other_symbols,
(app_code_section_va - image_base) as u32,
section_alignment,
);
for kind in [SectionKind::Text, SectionKind::ReadOnlyData] {
let length: usize = app_obj_sections
.sections
.iter()
.filter(|s| s.kind == kind)
.map(|s| s.file_range.end - s.file_range.start)
.sum();
// offset_in_section now becomes a proper virtual address
for symbol in symbols.iter_mut() {
if symbol.section_kind == kind {
symbol.offset_in_section +=
image_base as usize + virtual_address as usize;
}
}
let virtual_size = u32::max(1, length as u32);
let size_of_raw_data = next_multiple_of(length, file_alignment) as u32;
match kind {
SectionKind::Text => {
code_bytes_added += size_of_raw_data;
write_section_header(
executable,
*b".text1\0\0",
pe::IMAGE_SCN_MEM_READ
| pe::IMAGE_SCN_CNT_CODE
| pe::IMAGE_SCN_MEM_EXECUTE,
section_header_start,
section_file_offset,
virtual_size,
virtual_address,
size_of_raw_data,
);
}
SectionKind::ReadOnlyData => {
data_bytes_added += size_of_raw_data;
write_section_header(
executable,
*b".rdata1\0",
pe::IMAGE_SCN_MEM_READ | pe::IMAGE_SCN_CNT_INITIALIZED_DATA,
section_header_start,
section_file_offset,
virtual_size,
virtual_address,
size_of_raw_data,
);
}
}
let mut offset = section_file_offset;
let it = app_obj_sections.sections.iter().filter(|s| s.kind == kind);
for section in it {
let slice =
&roc_app_bytes[section.file_range.start..section.file_range.end];
executable[offset..][..slice.len()].copy_from_slice(slice);
for (name, app_relocation) in section.relocations.iter() {
let AppRelocation {
offset_in_section,
relocation,
address,
} = app_relocation;
if let Some(destination) = md.exports.get(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!(),
}
} else if let Some(destination) = inter_app_relocations.get(name) {
// 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());
} else {
match relocation.kind() {
object::RelocationKind::Relative => {
// we implicitly only do 32-bit relocations
debug_assert_eq!(relocation.size(), 32);
let delta = *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();
}
section_header_start += std::mem::size_of::<ImageSectionHeader>();
section_file_offset += size_of_raw_data as usize;
virtual_address += next_multiple_of(length, section_alignment) as u32;
file_bytes_added += next_multiple_of(length, section_alignment) as u32;
}
update_optional_header(
executable,
md.optional_header_offset,
code_bytes_added as u32,
file_bytes_added as u32,
data_bytes_added as u32,
);
let mut symbols: Vec<_> = symbols
.into_iter()
.map(|s| (s.name, s.offset_in_section as u64))
.collect();
crate::dbg_hex!(md.thunks_start_offset_in_file);
redirect_dummy_dll_functions(
executable,
&symbols,
&md.imports,
md.thunks_start_offset_in_file,
);
};
surgery_pe(&dir.join("app.exe"), &dir.join("metadata"), &*roc_app);
};
}