Rework section alignment handling

- Honor splits.txt alignment values when writing ldscript.lcf
- Add alignment values to ldscript_partial.lcf, remove hacky code from rel make
- Guess alignment values in DOL loader

Fixes #27
This commit is contained in:
Luke Street 2024-04-30 18:04:17 -06:00
parent dac2dcfc9e
commit dc7e307c44
4 changed files with 45 additions and 55 deletions

View File

@ -2,13 +2,7 @@ SECTIONS
{ {
GROUP: GROUP:
{ {
.init :{} $SECTIONS
.text :{}
.ctors :{}
.dtors :{}
.rodata :{}
.data :{ *(.data) *(extabindex) *(extab) }
.bss :{}
} }
} }

View File

@ -30,7 +30,7 @@ use crate::{
cmd::dol::{ModuleConfig, ProjectConfig}, cmd::dol::{ModuleConfig, ProjectConfig},
obj::{ObjInfo, ObjReloc, ObjRelocKind, ObjSection, ObjSectionKind, ObjSymbol}, obj::{ObjInfo, ObjReloc, ObjRelocKind, ObjSection, ObjSectionKind, ObjSymbol},
util::{ util::{
config::{is_auto_symbol, read_splits_sections, SectionDef}, config::is_auto_symbol,
dol::process_dol, dol::process_dol,
elf::{to_obj_reloc_kind, write_elf}, elf::{to_obj_reloc_kind, write_elf},
file::{buf_reader, buf_writer, map_file, process_rsp, verify_hash, FileIterator}, file::{buf_reader, buf_writer, map_file, process_rsp, verify_hash, FileIterator},
@ -170,12 +170,7 @@ fn load_rel(module_config: &ModuleConfig) -> Result<RelInfo> {
let mut reader = file.as_reader(); let mut reader = file.as_reader();
let header = process_rel_header(&mut reader)?; let header = process_rel_header(&mut reader)?;
let sections = process_rel_sections(&mut reader, &header)?; let sections = process_rel_sections(&mut reader, &header)?;
let section_defs = if let Some(splits_path) = &module_config.splits { Ok((header, sections))
read_splits_sections(splits_path)?
} else {
None
};
Ok((header, sections, section_defs))
} }
fn resolve_relocations( fn resolve_relocations(
@ -191,8 +186,7 @@ fn resolve_relocations(
if !matches!(section.name(), Ok(name) if PERMITTED_SECTIONS.contains(&name)) { if !matches!(section.name(), Ok(name) if PERMITTED_SECTIONS.contains(&name)) {
continue; continue;
} }
let section_index = let section_index = if let Some((_, sections)) = existing_headers.get(&(module_id as u32)) {
if let Some((_, sections, _)) = existing_headers.get(&(module_id as u32)) {
match_section_index(module, section.index(), sections)? match_section_index(module, section.index(), sections)?
} else { } else {
section.index().0 section.index().0
@ -223,7 +217,7 @@ fn resolve_relocations(
(module_id, reloc_target) (module_id, reloc_target)
}; };
let target_section_index = target_symbol.section_index().unwrap(); let target_section_index = target_symbol.section_index().unwrap();
let target_section = if let Some((_, sections, _)) = let target_section = if let Some((_, sections)) =
existing_headers.get(&(target_module_id as u32)) existing_headers.get(&(target_module_id as u32))
{ {
match_section_index(&modules[target_module_id].0, target_section_index, sections)? match_section_index(&modules[target_module_id].0, target_section_index, sections)?
@ -246,7 +240,7 @@ fn resolve_relocations(
Ok(resolved) Ok(resolved)
} }
type RelInfo = (RelHeader, Vec<RelSectionHeader>, Option<Vec<SectionDef>>); type RelInfo = (RelHeader, Vec<RelSectionHeader>);
fn make(args: MakeArgs) -> Result<()> { fn make(args: MakeArgs) -> Result<()> {
let total = Instant::now(); let total = Instant::now();
@ -347,17 +341,13 @@ fn make(args: MakeArgs) -> Result<()> {
quiet: args.no_warn, quiet: args.no_warn,
section_align: None, section_align: None,
}; };
if let Some((header, _, section_defs)) = existing_headers.get(&(module_id as u32)) { if let Some((header, _)) = existing_headers.get(&(module_id as u32)) {
info.version = header.version; info.version = header.version;
info.name_offset = Some(header.name_offset); info.name_offset = Some(header.name_offset);
info.name_size = Some(header.name_size); info.name_size = Some(header.name_size);
info.align = header.align; info.align = header.align;
info.bss_align = header.bss_align; info.bss_align = header.bss_align;
info.section_count = Some(header.num_sections as usize); info.section_count = Some(header.num_sections as usize);
info.section_align = section_defs
.as_ref()
.map(|defs| defs.iter().map(|def| def.align).collect())
.unwrap_or_default();
} }
let rel_path = path.with_extension("rel"); let rel_path = path.with_extension("rel");
let mut w = buf_writer(&rel_path)?; let mut w = buf_writer(&rel_path)?;

View File

@ -15,6 +15,7 @@ use crate::{
}, },
util::{ util::{
alf::{AlfFile, AlfSymbol, ALF_MAGIC}, alf::{AlfFile, AlfSymbol, ALF_MAGIC},
align_up,
reader::{skip_bytes, Endian, FromReader}, reader::{skip_bytes, Endian, FromReader},
}, },
}; };
@ -555,6 +556,26 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
section.elf_index = idx + 1; section.elf_index = idx + 1;
} }
// Guess section alignment
let mut last_section_end = sections.first().map_or(0, |s| s.address as u32);
for section in &mut sections {
let section_start = section.address as u32;
let mut align = 4;
while align_up(last_section_end, align) < section_start {
align = (align + 1).next_power_of_two();
}
if align_up(last_section_end, align) != section_start {
bail!(
"Couldn't determine alignment for section '{}' ({:#010X} -> {:#010X})",
section.name,
last_section_end,
section_start
);
}
last_section_end = section_start + section.size as u32;
section.align = align as u64;
}
// Create object // Create object
let mut obj = ObjInfo::new( let mut obj = ObjInfo::new(
ObjKind::Executable, ObjKind::Executable,

View File

@ -1,13 +1,10 @@
use std::path::PathBuf; use std::path::PathBuf;
use anyhow::{bail, Result}; use anyhow::Result;
use itertools::Itertools; use itertools::Itertools;
use path_slash::PathBufExt; use path_slash::PathBufExt;
use crate::{ use crate::obj::{ObjInfo, ObjKind};
obj::{ObjInfo, ObjKind},
util::align_up,
};
const LCF_TEMPLATE: &str = include_str!("../../assets/ldscript.lcf"); const LCF_TEMPLATE: &str = include_str!("../../assets/ldscript.lcf");
const LCF_PARTIAL_TEMPLATE: &str = include_str!("../../assets/ldscript_partial.lcf"); const LCF_PARTIAL_TEMPLATE: &str = include_str!("../../assets/ldscript_partial.lcf");
@ -27,32 +24,10 @@ pub fn generate_ldscript(
_ => 65535, // default _ => 65535, // default
}; };
// Guess section alignment
let mut alignments = Vec::with_capacity(obj.sections.count());
let mut last_section_end = origin as u32;
for (_, section) in obj.sections.iter() {
let section_start = section.address as u32;
let mut align = 0x20;
while align_up(last_section_end, align) < section_start {
align = (align + 1).next_power_of_two();
}
if align_up(last_section_end, align) != section_start {
bail!(
"Couldn't determine alignment for section '{}' ({:#010X} -> {:#010X})",
section.name,
last_section_end,
section_start
);
}
last_section_end = section_start + section.size as u32;
alignments.push(align);
}
let section_defs = obj let section_defs = obj
.sections .sections
.iter() .iter()
.zip(alignments) .map(|(_, s)| format!("{} ALIGN({:#X}):{{}}", s.name, s.align))
.map(|((_, s), align)| format!("{} ALIGN({:#X}):{{}}", s.name, align))
.join("\n "); .join("\n ");
let mut force_files = Vec::with_capacity(obj.link_order.len()); let mut force_files = Vec::with_capacity(obj.link_order.len());
@ -89,6 +64,15 @@ pub fn generate_ldscript_partial(
template: Option<&str>, template: Option<&str>,
force_active: &[String], force_active: &[String],
) -> Result<String> { ) -> Result<String> {
let section_defs = obj
.sections
.iter()
.map(|(_, s)| {
let inner = if s.name == ".data" { " *(.data) *(extabindex) *(extab) " } else { "" };
format!("{} ALIGN({:#X}):{{{}}}", s.name, s.align, inner)
})
.join("\n ");
let mut force_files = Vec::with_capacity(obj.link_order.len()); let mut force_files = Vec::with_capacity(obj.link_order.len());
for unit in &obj.link_order { for unit in &obj.link_order {
let obj_path = obj_path_for_unit(&unit.name); let obj_path = obj_path_for_unit(&unit.name);
@ -104,6 +88,7 @@ pub fn generate_ldscript_partial(
let out = template let out = template
.unwrap_or(LCF_PARTIAL_TEMPLATE) .unwrap_or(LCF_PARTIAL_TEMPLATE)
.replace("$SECTIONS", &section_defs)
.replace("$FORCEACTIVE", &force_active.join("\n ")); .replace("$FORCEACTIVE", &force_active.join("\n "));
Ok(out) Ok(out)
} }