Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions libwild/src/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use crate::layout::ObjectLayout;
use crate::layout::ObjectLayoutState;
use crate::layout::OutputRecordLayout;
use crate::layout::Resolution;
use crate::layout::ResolutionState;
use crate::layout::SymbolCopyInfo;
use crate::layout::objects_iter;
use crate::layout_rules::SectionKind;
Expand Down Expand Up @@ -654,8 +655,12 @@ impl platform::Platform for Elf {
);
}

let resolution =
Self::create_resolution(flags, address, dynamic_symbol_index, memory_offsets);
let resolution = Self::create_resolution(
flags,
ResolutionState::Resolved(address),
dynamic_symbol_index,
memory_offsets,
);

resolutions_out.write(Some(resolution))?;
}
Expand Down Expand Up @@ -1615,7 +1620,7 @@ impl platform::Platform for Elf {
#[inline(always)]
fn create_resolution(
flags: ValueFlags,
raw_value: u64,
raw_value: ResolutionState,
dynamic_symbol_index: Option<NonZeroU32>,
memory_offsets: &mut OutputSectionPartMap<u64>,
) -> Resolution<Elf> {
Expand All @@ -1633,7 +1638,7 @@ impl platform::Platform for Elf {
let plt_address = allocate_plt(memory_offsets);
resolution.format_specific.plt_address = Some(plt_address);
if flags.is_dynamic() {
resolution.raw_value = plt_address.get();
resolution.raw_value = ResolutionState::Resolved(plt_address.get());
}
// For ifunc with address equality needs, allocate 2 GOT entries
// - First entry: Used by PLT
Expand Down Expand Up @@ -1690,7 +1695,7 @@ impl platform::Platform for Elf {
if resolution.flags.is_dynamic() || resolution.flags.is_ifunc() {
return Ok(());
}
let expected = resolution.raw_value;
let expected = resolution.value();
let address = u64::read_from_bytes(&got_data[start_offset..end_offset]).unwrap();
if expected != address {
let name = String::from_utf8_lossy(name);
Expand Down Expand Up @@ -5257,7 +5262,7 @@ impl Resolution<Elf> {
// For most symbols, `raw_value` won't be zero, so we can save ourselves from looking up the
// section to see if it's a string-merge section. For string-merge symbols with names,
// `raw_value` will have already been computed, so we can avoid computing it again.
if self.raw_value == 0
if self.value() == 0
&& let Some(r) = crate::string_merging::get_merged_string_output_address::<Elf>(
symbol_index,
addend,
Expand All @@ -5270,12 +5275,12 @@ impl Resolution<Elf> {
false,
)?
{
if self.raw_value != 0 {
bail!("Merged string resolution has value 0x{}", self.raw_value);
if self.value() != 0 {
bail!("Merged string resolution has value 0x{}", self.value());
}
return Ok(r);
}
Ok(self.raw_value.wrapping_add(addend as u64))
Ok(self.value().wrapping_add(addend as u64))
}
}

Expand Down
37 changes: 19 additions & 18 deletions libwild/src/elf_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ use crate::layout::ObjectLayout;
use crate::layout::OutputRecordLayout;
use crate::layout::PreludeLayout;
use crate::layout::Resolution;
use crate::layout::ResolutionState;
use crate::layout::Section;
use crate::layout::SymbolCopyInfo;
use crate::layout::SyntheticSymbolsLayout;
Expand Down Expand Up @@ -744,9 +745,9 @@ impl<'layout, 'out> TableWriter<'layout, 'out> {
self.write_ifunc_relocation::<A>(res)?;
} else {
*got_entry = if res.flags.is_address() && self.output_kind.is_relocatable() {
self.write_address_relocation::<A>(got_address, res.raw_value)?
self.write_address_relocation::<A>(got_address, res.value())?
} else {
res.raw_value
res.value()
};
}
if let Some(plt_address) = res.format_specific.plt_address {
Expand Down Expand Up @@ -784,7 +785,7 @@ impl<'layout, 'out> TableWriter<'layout, 'out> {
*got_entry = 0;
return self.write_tpoff_relocation::<A>(got_address, res.dynamic_symbol_index()?, 0);
}
let address = res.raw_value;
let address = res.value();
if address == 0 {
// Resolution is undefined.
*got_entry = 0;
Expand Down Expand Up @@ -878,7 +879,7 @@ impl<'layout, 'out> TableWriter<'layout, 'out> {
res.flags
);
let addend = if res.dynamic_symbol_index.is_none() {
res.raw_value.sub(self.tls.start) as i64
res.value().sub(self.tls.start) as i64
} else {
0
};
Expand Down Expand Up @@ -974,7 +975,7 @@ impl<'layout, 'out> TableWriter<'layout, 'out> {
fn write_ifunc_relocation<A: Arch<Platform = Elf>>(&mut self, res: &Resolution<Elf>) -> Result {
let out = self.rela_plt.split_off_first_mut().unwrap();
let e = LittleEndian;
out.r_addend.set(e, res.raw_value as i64);
out.r_addend.set(e, res.value() as i64);
let got_address = res
.format_specific
.got_address
Expand Down Expand Up @@ -1494,7 +1495,7 @@ fn write_object<'data, A: Arch<Platform = Elf>>(
let _span = tracing::trace_span!("Symbol", %symbol_id).entered();
if let Some(res) = resolution {
table_writer
.process_resolution::<A>(Some(layout), layout.args(), res)
.process_resolution::<A>(Some(layout), layout.args(), &res)
.with_context(|| {
format!(
"Failed to process `{}` with resolution {res:?}",
Expand Down Expand Up @@ -1585,7 +1586,7 @@ fn write_thunks<'data, A: Arch<Platform = Elf>>(
)
})?;

let target_address = res.plt_address().unwrap_or(res.raw_value);
let target_address = res.plt_address().unwrap_or(res.value());

let buf = buffers.get_mut(primary_part_id);
let thunk_buf = buf
Expand Down Expand Up @@ -2640,7 +2641,7 @@ fn get_resolution<'data, R: Relocation>(
);

Some(Resolution {
raw_value: section_address + output_offset,
raw_value: ResolutionState::Resolved(section_address + output_offset),
dynamic_symbol_index: None,
flags: ValueFlags::empty(),
format_specific: Default::default(),
Expand Down Expand Up @@ -2898,7 +2899,7 @@ fn apply_relocation<
flags,
output_kind,
section_info.section_flags,
resolution.raw_value != 0,
resolution.value() != 0,
relax_deltas,
)
.filter(|relaxation| layout.args().relax || relaxation.is_mandatory());
Expand Down Expand Up @@ -3427,7 +3428,7 @@ fn apply_debug_relocation<'data, A: Arch<Platform = Elf>, R: Relocation>(
);

Some(Resolution {
raw_value: section_address + output_offset,
raw_value: ResolutionState::Resolved(section_address + output_offset),
dynamic_symbol_index: None,
flags: ValueFlags::empty(),
format_specific: Default::default(),
Expand Down Expand Up @@ -3561,7 +3562,7 @@ fn write_absolute_relocation<'data, A: Arch<Platform = Elf>>(
&& table_writer.output_kind.is_relocatable()
{
table_writer
.write_ifunc_relocation_for_data::<A>(place, resolution.raw_value as i64 + addend)?;
.write_ifunc_relocation_for_data::<A>(place, resolution.value() as i64 + addend)?;
Ok(0)
} else if table_writer.output_kind.is_relocatable() && !resolution.is_absolute() {
let address = resolution.value_with_addend(
Expand Down Expand Up @@ -3723,7 +3724,7 @@ fn write_plt_got_entries<'data, A: Arch<Platform = Elf>>(
Some(layout),
layout.args(),
&Resolution {
raw_value: crate::elf::CURRENT_EXE_TLS_MOD,
raw_value: ResolutionState::Resolved(crate::elf::CURRENT_EXE_TLS_MOD),
dynamic_symbol_index: None,
format_specific: crate::elf::ResolutionExt {
got_address: Some(got_address),
Expand All @@ -3745,7 +3746,7 @@ fn write_plt_got_entries<'data, A: Arch<Platform = Elf>>(
Some(layout),
layout.args(),
&Resolution {
raw_value,
raw_value: ResolutionState::Resolved(raw_value),
dynamic_symbol_index: None,
format_specific: crate::elf::ResolutionExt {
got_address: Some(got_address.saturating_add(elf::GOT_ENTRY_SIZE)),
Expand Down Expand Up @@ -4569,7 +4570,7 @@ fn write_defsym_dynsym(
let resolution = layout
.local_symbol_resolution(symbol_id)
.with_context(|| format!("Missing resolution for {}", layout.symbol_debug(symbol_id)))?;
let address = resolution.raw_value;
let address = resolution.value();
let name = layout.symbol_db.symbol_name(symbol_id)?;

let entry = dynsym_writer
Expand Down Expand Up @@ -4608,7 +4609,7 @@ fn write_copy_relocation_dynamic_symbol_definition<'data>(
.local_symbol_resolution(sym_def.symbol_id)
.context("Copy relocation for unresolved symbol")?;
dynamic_symbol_writer
.copy_symbol_shndx(sym, name, shndx, res.raw_value, ValueFlags::empty())
.copy_symbol_shndx(sym, name, shndx, res.value(), ValueFlags::empty())
.with_context(|| {
format!(
"Failed to copy dynamic {}",
Expand Down Expand Up @@ -4678,7 +4679,7 @@ fn write_regular_object_dynamic_symbol_definition<'data>(
entry.set_st_info(sym.st_bind(), object::elf::STT_FUNC);
entry.st_other = sym.st_other();
} else {
let mut symbol_value = resolution.raw_value;
let mut symbol_value = resolution.value();
if sym.st_type() == object::elf::STT_TLS {
symbol_value -= layout.tls_start_address();
}
Expand Down Expand Up @@ -5552,7 +5553,7 @@ fn write_dynamic_file<'data, A: Arch<Platform = Elf>>(
}

table_writer
.process_resolution::<A>(Some(layout), layout.args(), res)
.process_resolution::<A>(Some(layout), layout.args(), &res)
.with_context(|| format!("Failed to write {}", layout.symbol_debug(symbol_id)))?;
}
}
Expand Down Expand Up @@ -5688,7 +5689,7 @@ fn write_copy_relocation_for_symbol<A: Arch<Platform = Elf>>(
.context("Internal error: Missing resolution for copy-relocated symbol")?;

table_writer.write_rela_dyn_general(
res.raw_value,
res.value(),
res.dynamic_symbol_index()?,
A::get_dynamic_relocation_type(DynamicRelocationKind::Copy),
0,
Expand Down
55 changes: 40 additions & 15 deletions libwild/src/expression_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::grouping::Group;
use crate::layout;
use crate::layout::OutputRecordLayout;
use crate::layout::Resolution;
use crate::layout::ResolutionState;
use crate::linker_script::Expression;
use crate::output_section_id::OutputSections;
use crate::output_section_id::SectionName;
Expand All @@ -34,7 +35,7 @@ pub(crate) fn evaluate_assertions<'data, P: Platform>(
symbol_db: &SymbolDb<'data, P>,
section_layouts: &OutputSectionMap<OutputRecordLayout>,
output_sections: &OutputSections<'data, P>,
resolutions: &[Option<Resolution<P>>],
resolutions: &mut [Option<Resolution<P>>],
sizeof_headers: u64,
memory_regions: &HashMap<&[u8], layout::MemoryRegion>,
) -> Result {
Expand All @@ -54,7 +55,8 @@ pub(crate) fn evaluate_assertions<'data, P: Platform>(
memory_regions,
symbol_db,
sizeof_headers,
&|name| {
resolutions,
&|name, resolutions| {
let Some(target_symbol_id) =
symbol_db.get_unversioned(&UnversionedSymbolName::prehashed(name))
else {
Expand All @@ -65,9 +67,14 @@ pub(crate) fn evaluate_assertions<'data, P: Platform>(
};

let canonical_target_id = symbol_db.definition(target_symbol_id);
Ok(resolutions[canonical_target_id.as_usize()]
.as_ref()
.map_or(0, |r| r.raw_value))
let resolution =
resolutions[canonical_target_id.as_usize()].map_or(0, |r| {
match r.raw_value {
ResolutionState::Resolved(r) => r,
_ => 0,
}
});
Ok(resolution)
},
)
.with_context(|| format!("{}:{}: Failed to evaluate ASSERT", parsed.input, line))?;
Expand All @@ -82,6 +89,7 @@ pub(crate) fn evaluate_assertions<'data, P: Platform>(
Ok(())
}

#[expect(clippy::type_complexity)]
pub(crate) fn evaluate_expression<'data, P: Platform>(
expr: &Expression<'data>,
expr_loc: &SymbolLoc<'data>,
Expand All @@ -90,7 +98,8 @@ pub(crate) fn evaluate_expression<'data, P: Platform>(
memory_regions: &HashMap<&[u8], layout::MemoryRegion>,
symbol_db: &SymbolDb<'data, P>,
sizeof_headers: u64,
symbol_resolution_callback: &dyn Fn(&[u8]) -> Result<u64>,
resolutions: &mut [Option<Resolution<P>>],
symbol_resolution_callback: &dyn Fn(&[u8], &mut [Option<Resolution<P>>]) -> Result<u64>,
) -> Result<u64> {
macro_rules! eval {
($e:expr) => {
Expand All @@ -102,6 +111,7 @@ pub(crate) fn evaluate_expression<'data, P: Platform>(
memory_regions,
symbol_db,
sizeof_headers,
resolutions,
symbol_resolution_callback,
)
};
Expand All @@ -120,7 +130,7 @@ pub(crate) fn evaluate_expression<'data, P: Platform>(
SymbolLoc::Expression(expr, _) => eval!(expr),
},

Expression::Symbol(name) => symbol_resolution_callback(name),
Expression::Symbol(name) => symbol_resolution_callback(name, resolutions),

Expression::Add(l, r) => Ok(eval!(l)?.wrapping_add(eval!(r)?)),
Expression::Subtract(l, r) => Ok(eval!(l)?.wrapping_sub(eval!(r)?)),
Expand Down Expand Up @@ -349,7 +359,8 @@ mod tests {
&HashMap::new(),
symbol_db,
0,
&|_| Ok(1),
&mut [],
&|_, _| Ok(1),
)
})
}
Expand Down Expand Up @@ -661,7 +672,7 @@ mod tests {
let script = SequencedLinkerScript {
parsed: ProcessedLinkerScript {
input: crate::input_data::InputRef { file, entry: None },
symbol_defs: Vec::new(),
symbol_defs: indexmap::IndexMap::new(),
assertions,
file_bytes: b"",
memory_regions: Vec::new(),
Expand All @@ -686,8 +697,15 @@ mod tests {
}]);
symbol_db.add_group(group);
assert!(
evaluate_assertions::<Elf>(symbol_db, layouts, sections, &[], 0, &HashMap::new())
.is_ok()
evaluate_assertions::<Elf>(
symbol_db,
layouts,
sections,
&mut [],
0,
&HashMap::new()
)
.is_ok()
);
});
}
Expand All @@ -701,9 +719,15 @@ mod tests {
remainder: b"",
}]);
symbol_db.add_group(group);
let err =
evaluate_assertions::<Elf>(symbol_db, layouts, sections, &[], 0, &HashMap::new())
.unwrap_err();
let err = evaluate_assertions::<Elf>(
symbol_db,
layouts,
sections,
&mut [],
0,
&HashMap::new(),
)
.unwrap_err();
assert!(err.to_string().contains("intentional failure"));
});
}
Expand Down Expand Up @@ -738,7 +762,8 @@ mod tests {
&regions,
symbol_db,
0,
&|_| Ok(0),
&mut [],
&|_, _| Ok(0),
)
};
assert_eq!(eval(&Expression::Origin(b"rom")).unwrap(), 0x08000000);
Expand Down
Loading