diff --git a/libwild/src/elf.rs b/libwild/src/elf.rs index 8b0e2559c..3b7db214e 100644 --- a/libwild/src/elf.rs +++ b/libwild/src/elf.rs @@ -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; @@ -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))?; } @@ -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, memory_offsets: &mut OutputSectionPartMap, ) -> Resolution { @@ -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 @@ -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); @@ -5257,7 +5262,7 @@ impl Resolution { // 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::( symbol_index, addend, @@ -5270,12 +5275,12 @@ impl Resolution { 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)) } } diff --git a/libwild/src/elf_writer.rs b/libwild/src/elf_writer.rs index 8a1b5cb4b..3cfebd3b7 100644 --- a/libwild/src/elf_writer.rs +++ b/libwild/src/elf_writer.rs @@ -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; @@ -744,9 +745,9 @@ impl<'layout, 'out> TableWriter<'layout, 'out> { self.write_ifunc_relocation::(res)?; } else { *got_entry = if res.flags.is_address() && self.output_kind.is_relocatable() { - self.write_address_relocation::(got_address, res.raw_value)? + self.write_address_relocation::(got_address, res.value())? } else { - res.raw_value + res.value() }; } if let Some(plt_address) = res.format_specific.plt_address { @@ -784,7 +785,7 @@ impl<'layout, 'out> TableWriter<'layout, 'out> { *got_entry = 0; return self.write_tpoff_relocation::(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; @@ -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 }; @@ -974,7 +975,7 @@ impl<'layout, 'out> TableWriter<'layout, 'out> { fn write_ifunc_relocation>(&mut self, res: &Resolution) -> 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 @@ -1494,7 +1495,7 @@ fn write_object<'data, A: Arch>( let _span = tracing::trace_span!("Symbol", %symbol_id).entered(); if let Some(res) = resolution { table_writer - .process_resolution::(Some(layout), layout.args(), res) + .process_resolution::(Some(layout), layout.args(), &res) .with_context(|| { format!( "Failed to process `{}` with resolution {res:?}", @@ -1585,7 +1586,7 @@ fn write_thunks<'data, A: Arch>( ) })?; - 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 @@ -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(), @@ -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()); @@ -3427,7 +3428,7 @@ fn apply_debug_relocation<'data, A: Arch, 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(), @@ -3561,7 +3562,7 @@ fn write_absolute_relocation<'data, A: Arch>( && table_writer.output_kind.is_relocatable() { table_writer - .write_ifunc_relocation_for_data::(place, resolution.raw_value as i64 + addend)?; + .write_ifunc_relocation_for_data::(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( @@ -3723,7 +3724,7 @@ fn write_plt_got_entries<'data, A: Arch>( 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), @@ -3745,7 +3746,7 @@ fn write_plt_got_entries<'data, A: Arch>( 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)), @@ -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 @@ -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 {}", @@ -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(); } @@ -5552,7 +5553,7 @@ fn write_dynamic_file<'data, A: Arch>( } table_writer - .process_resolution::(Some(layout), layout.args(), res) + .process_resolution::(Some(layout), layout.args(), &res) .with_context(|| format!("Failed to write {}", layout.symbol_debug(symbol_id)))?; } } @@ -5688,7 +5689,7 @@ fn write_copy_relocation_for_symbol>( .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, diff --git a/libwild/src/expression_eval.rs b/libwild/src/expression_eval.rs index ce9bc2bbe..3932aea0b 100644 --- a/libwild/src/expression_eval.rs +++ b/libwild/src/expression_eval.rs @@ -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; @@ -34,7 +35,7 @@ pub(crate) fn evaluate_assertions<'data, P: Platform>( symbol_db: &SymbolDb<'data, P>, section_layouts: &OutputSectionMap, output_sections: &OutputSections<'data, P>, - resolutions: &[Option>], + resolutions: &mut [Option>], sizeof_headers: u64, memory_regions: &HashMap<&[u8], layout::MemoryRegion>, ) -> Result { @@ -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 { @@ -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))?; @@ -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>, @@ -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, + resolutions: &mut [Option>], + symbol_resolution_callback: &dyn Fn(&[u8], &mut [Option>]) -> Result, ) -> Result { macro_rules! eval { ($e:expr) => { @@ -102,6 +111,7 @@ pub(crate) fn evaluate_expression<'data, P: Platform>( memory_regions, symbol_db, sizeof_headers, + resolutions, symbol_resolution_callback, ) }; @@ -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)?)), @@ -349,7 +359,8 @@ mod tests { &HashMap::new(), symbol_db, 0, - &|_| Ok(1), + &mut [], + &|_, _| Ok(1), ) }) } @@ -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(), @@ -686,8 +697,15 @@ mod tests { }]); symbol_db.add_group(group); assert!( - evaluate_assertions::(symbol_db, layouts, sections, &[], 0, &HashMap::new()) - .is_ok() + evaluate_assertions::( + symbol_db, + layouts, + sections, + &mut [], + 0, + &HashMap::new() + ) + .is_ok() ); }); } @@ -701,9 +719,15 @@ mod tests { remainder: b"", }]); symbol_db.add_group(group); - let err = - evaluate_assertions::(symbol_db, layouts, sections, &[], 0, &HashMap::new()) - .unwrap_err(); + let err = evaluate_assertions::( + symbol_db, + layouts, + sections, + &mut [], + 0, + &HashMap::new(), + ) + .unwrap_err(); assert!(err.to_string().contains("intentional failure")); }); } @@ -738,7 +762,8 @@ mod tests { ®ions, symbol_db, 0, - &|_| Ok(0), + &mut [], + &|_, _| Ok(0), ) }; assert_eq!(eval(&Expression::Origin(b"rom")).unwrap(), 0x08000000); diff --git a/libwild/src/grouping.rs b/libwild/src/grouping.rs index 94413d305..c5f39f850 100644 --- a/libwild/src/grouping.rs +++ b/libwild/src/grouping.rs @@ -350,7 +350,14 @@ impl<'data, P: Platform> SequencedInputObject<'data, P> { impl<'data, P: Platform> SequencedLinkerScript<'data, P> { pub(crate) fn symbol_name(&self, symbol_id: SymbolId) -> UnversionedSymbolName<'data> { let local_index = self.symbol_id_range.id_to_offset(symbol_id); - UnversionedSymbolName::new(self.parsed.symbol_defs[local_index].name) + UnversionedSymbolName::new( + self.parsed + .symbol_defs + .get_index(local_index) + .unwrap() + .1 + .name, + ) } } diff --git a/libwild/src/layout.rs b/libwild/src/layout.rs index 6101efdb4..3ab7600cf 100644 --- a/libwild/src/layout.rs +++ b/libwild/src/layout.rs @@ -280,6 +280,10 @@ pub fn compute<'data, P: Platform, A: Arch>( unreachable!(); }; + let mut symbol_resolutions = SymbolResolutions { + resolutions: Vec::with_capacity(symbol_db.num_symbols()), + }; + let (mut section_part_layouts, mut section_layouts) = layout_section::( §ion_part_sizes, &output_sections, @@ -288,6 +292,7 @@ pub fn compute<'data, P: Platform, A: Arch>( &symbol_db, &mut memory_regions, sizeof_headers, + &mut symbol_resolutions.resolutions, )?; if symbol_db.args.should_relax() && A::supports_size_reduction_relaxations() { @@ -303,6 +308,7 @@ pub fn compute<'data, P: Platform, A: Arch>( &per_symbol_flags, &mut memory_regions, sizeof_headers, + &mut symbol_resolutions.resolutions, )?; } @@ -355,10 +361,6 @@ pub fn compute<'data, P: Platform, A: Arch>( &merged_strings, ); - let mut symbol_resolutions = SymbolResolutions { - resolutions: Vec::with_capacity(symbol_db.num_symbols()), - }; - let mut res_writer = sharded_vec_writer::VecWriter::new(&mut symbol_resolutions.resolutions); let mut per_group_res_writers = group_states @@ -419,7 +421,7 @@ pub fn compute<'data, P: Platform, A: Arch>( &symbol_db, §ion_layouts, &output_sections, - &symbol_resolutions.resolutions, + &mut symbol_resolutions.resolutions, sizeof_headers, &memory_regions, )?; @@ -501,13 +503,14 @@ fn update_redirect_resolutions<'data, P: Platform>( for def_info in &prelude.symbol_definitions { update_defsym_symbol_resolution( symbol_id, - def_info, + def_info.1, symbol_db, resolutions, output_sections, section_layouts, memory_regions, sizeof_headers, + &prelude.symbol_definitions, )?; symbol_id = symbol_id.next(); } @@ -517,13 +520,14 @@ fn update_redirect_resolutions<'data, P: Platform>( for def_info in &script.parsed.symbol_defs { update_defsym_symbol_resolution( symbol_id, - def_info, + def_info.1, symbol_db, resolutions, output_sections, section_layouts, memory_regions, sizeof_headers, + &script.parsed.symbol_defs, )?; symbol_id = symbol_id.next(); } @@ -547,7 +551,9 @@ fn update_defsym_symbol_resolution<'data, P: Platform>( section_layouts: &OutputSectionMap, memory_regions: &HashMap<&[u8], MemoryRegion>, sizeof_headers: u64, -) -> Result { + symbol_definitions: &indexmap::IndexMap<&'data [u8], InternalSymDefInfo<'data, P>>, +) -> Result { + let symbol_id = symbol_db.definition(symbol_id); if let SymbolPlacement::Redirect(redirect) = &def_info.placement { let value = crate::expression_eval::evaluate_expression( &redirect.expression, @@ -557,7 +563,8 @@ fn update_defsym_symbol_resolution<'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 { @@ -567,21 +574,43 @@ fn update_defsym_symbol_resolution<'data, P: Platform>( let canonical_target_id = symbol_db.definition(target_symbol_id); let resolution = resolutions[canonical_target_id.as_usize()] - .as_ref() + .as_mut() .ok_or_else(|| redirect.missing_resolution(name))?; + let value = match resolution.raw_value { + ResolutionState::Unresolved => { + resolution.raw_value = ResolutionState::Pending; + let def = symbol_definitions + .get(name) + .ok_or(redirect.missing_target(name))?; + update_defsym_symbol_resolution( + canonical_target_id, + def, + symbol_db, + resolutions, + output_sections, + section_layouts, + memory_regions, + sizeof_headers, + symbol_definitions, + )? + } + ResolutionState::Pending => return Err(redirect.missing_target(name)), + ResolutionState::Resolved(value) => value, + }; - Ok(resolution.raw_value) + Ok(value) }, )?; let Some(resolution) = &mut resolutions[symbol_id.as_usize()] else { - return Ok(()); + return Ok(0); }; - resolution.raw_value = value; + resolution.raw_value = ResolutionState::Resolved(value); + return Ok(value); } - Ok(()) + Ok(0) } /// Update resolutions for all dynamic symbols that our output file defines. @@ -787,7 +816,7 @@ pub(crate) enum FileLayout<'data, P: Platform> { #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub(crate) struct Resolution { /// An address or absolute value. - pub(crate) raw_value: u64, + pub(crate) raw_value: ResolutionState, pub(crate) dynamic_symbol_index: Option, @@ -796,6 +825,13 @@ pub(crate) struct Resolution { pub(crate) format_specific: P::ResolutionExt, } +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub(crate) enum ResolutionState { + Unresolved, + Pending, + Resolved(u64), +} + /// Address information for a section. #[derive(derive_more::Debug, Clone, Copy, Eq, PartialEq)] pub(crate) struct SectionResolution { @@ -822,7 +858,7 @@ impl SectionResolution { pub(crate) fn full_resolution(self) -> Option> { let address = self.address()?; Some(Resolution { - raw_value: address, + raw_value: ResolutionState::Resolved(address), dynamic_symbol_index: None, flags: ValueFlags::empty(), format_specific: Default::default(), @@ -1602,11 +1638,11 @@ impl<'data, P: Platform> Layout<'data, P> { pub(crate) fn resolutions_in_range( &self, range: SymbolIdRange, - ) -> impl Iterator>)> { + ) -> impl Iterator>)> { self.symbol_resolutions.resolutions[range.as_usize()] .iter() .enumerate() - .map(move |(i, res)| (range.offset_to_id(i), res.as_ref())) + .map(move |(i, res)| (range.offset_to_id(i), *res)) } pub(crate) fn entry_symbol_address(&self) -> Result { @@ -3645,13 +3681,15 @@ fn create_internal_symbol_resolution<'data, P: Platform>( } let raw_value = match def_info.placement { - SymbolPlacement::Undefined | SymbolPlacement::ForceUndefined => 0, + SymbolPlacement::Undefined | SymbolPlacement::ForceUndefined => { + ResolutionState::Resolved(0) + } SymbolPlacement::SectionStart(section_id) => { - resources.section_layouts.get(section_id).mem_offset + ResolutionState::Resolved(resources.section_layouts.get(section_id).mem_offset) } SymbolPlacement::SectionEnd(section_id) => { let sec = resources.section_layouts.get(section_id); - sec.mem_offset + sec.mem_size + ResolutionState::Resolved(sec.mem_offset + sec.mem_size) } SymbolPlacement::SectionGroupEnd(section_id) => { let mut end = { @@ -3670,20 +3708,24 @@ fn create_internal_symbol_resolution<'data, P: Platform>( } } } - end + ResolutionState::Resolved(end) } SymbolPlacement::Redirect(_) => { // For redirects to other symbols, we defer resolution until later when all symbols have // been resolved. This is handled by update_redirect_resolutions() which is called after // layout is complete. - 0 + ResolutionState::Unresolved } - SymbolPlacement::LoadBaseAddress => resources + SymbolPlacement::LoadBaseAddress => match resources .segment_layouts .segments .iter() .find(|seg| resources.program_segments.segment_def(seg.id).is_loadable()) - .map(|seg| seg.sizes.mem_offset)?, + .map(|seg| seg.sizes.mem_offset) + { + Some(offset) => ResolutionState::Resolved(offset), + None => return None, + }, }; Some(P::create_resolution( @@ -4405,7 +4447,7 @@ impl<'data, P: Platform> ObjectLayoutState<'data, P> { Ok(Some(P::create_resolution( flags, - raw_value, + ResolutionState::Resolved(raw_value), dynamic_symbol_index, memory_offsets, ))) @@ -4625,7 +4667,7 @@ impl<'data> StubLibraryLayoutState<'data> { if flags.has_resolution() && resources.symbol_db.is_canonical(symbol_id) { resolutions_out.write(Some(P::create_resolution( flags, - 0, + ResolutionState::Resolved(0), None, memory_offsets, )))?; @@ -4651,7 +4693,7 @@ impl<'data, P: Platform> resolution::ResolvedFile<'data, P> { } resolution::ResolvedFile::NotLoaded(s) => FileLayoutState::NotLoaded(s), resolution::ResolvedFile::LinkerScript(s) => { - FileLayoutState::LinkerScript(LinkerScriptLayoutState::new(s)) + FileLayoutState::LinkerScript(LinkerScriptLayoutState::new(&s)) } resolution::ResolvedFile::SyntheticSymbols(s) => { FileLayoutState::SyntheticSymbols(SyntheticSymbolsLayoutState::new(s)) @@ -4671,18 +4713,25 @@ impl Resolution

{ } pub(crate) fn value(self) -> u64 { - self.raw_value + match self.raw_value { + ResolutionState::Resolved(r) => r, + _ => 0, + } + } + + pub(crate) fn set_value(&mut self, raw_value: u64) { + self.raw_value = ResolutionState::Resolved(raw_value); } pub(crate) fn address(&self) -> Result { if !self.flags.is_address() { bail!("Expected address, found {}", self.flags); } - Ok(self.raw_value) + Ok(self.value()) } pub(crate) fn value_for_symbol_table(&self) -> u64 { - self.raw_value + self.value() } pub(crate) fn is_absolute(&self) -> bool { @@ -5011,6 +5060,7 @@ fn perform_iterative_relaxation<'data, A: Arch>( per_symbol_flags: &PerSymbolFlags, memory_regions: &mut HashMap<&[u8], MemoryRegion>, sizeof_headers: u64, + resolutions: &mut [Option>], ) -> Result { timing_phase!("Iterative relaxation"); @@ -5068,6 +5118,7 @@ fn perform_iterative_relaxation<'data, A: Arch>( symbol_db, memory_regions, sizeof_headers, + resolutions, )?; } Ok(()) @@ -5081,6 +5132,7 @@ fn layout_section<'data, P: Platform>( symbol_db: &SymbolDb<'data, P>, memory_regions: &mut HashMap<&[u8], MemoryRegion>, sizeof_headers: u64, + resolutions: &mut [Option>], ) -> Result<( OutputSectionPartMap, OutputSectionMap, @@ -5096,7 +5148,7 @@ fn layout_section<'data, P: Platform>( let mut section_layouts = OutputSectionMap::with_size(output_sections.num_sections()); - let expression_eval = + let mut expression_eval = |expr: &Expression<'data>, memory_regions: &HashMap<&[u8], MemoryRegion>, section_layouts: &OutputSectionMap| { @@ -5108,7 +5160,8 @@ fn layout_section<'data, P: Platform>( memory_regions, symbol_db, sizeof_headers, - &|_| { + resolutions, + &|_, _| { bail!("Symbols with the set location operation are not yet supported."); }, ) @@ -5488,13 +5541,13 @@ impl<'data, P: Platform> LinkerScriptLayoutState<'data, P> { .finalise_layout(memory_offsets, resolutions_out, resources) } - fn new(input: resolution::ResolvedLinkerScript<'data, P>) -> Self { + fn new(input: &resolution::ResolvedLinkerScript<'data, P>) -> Self { Self { file_id: input.file_id, input: input.input, symbol_id_range: input.symbol_id_range, internal_symbols: InternalSymbols { - symbol_definitions: input.symbol_definitions, + symbol_definitions: input.symbol_definitions.values().cloned().collect(), start_symbol_id: input.symbol_id_range.start(), }, } @@ -5640,6 +5693,7 @@ fn test_no_disallowed_overlaps() { &symbol_db, &mut HashMap::new(), 0, + &mut [], ) .unwrap(); @@ -5754,7 +5808,12 @@ fn verify_consistent_allocation_handling( flags.is_dynamic() || (flags.needs_export_dynamic() && flags.is_interposable()); let dynamic_symbol_index = has_dynamic_symbol.then(|| NonZeroU32::new(1).unwrap()); - let resolution = P::create_resolution(flags, 0, dynamic_symbol_index, &mut memory_offsets); + let resolution = P::create_resolution( + flags, + ResolutionState::Resolved(0), + dynamic_symbol_index, + &mut memory_offsets, + ); P::verify_resolution_allocation( &output_sections, diff --git a/libwild/src/layout_rules.rs b/libwild/src/layout_rules.rs index e8da2bc8f..4f0058493 100644 --- a/libwild/src/layout_rules.rs +++ b/libwild/src/layout_rules.rs @@ -155,7 +155,7 @@ impl<'data> LayoutRulesBuilder<'data> { input: &InputLinkerScript<'data>, output_sections: &mut OutputSections<'data, P>, ) -> Result> { - let mut symbol_defs = Vec::new(); + let mut symbol_defs = indexmap::IndexMap::new(); let mut assertions = Vec::new(); let mut memory_regions = Vec::new(); let mut program_headers = Vec::new(); @@ -170,7 +170,8 @@ impl<'data> LayoutRulesBuilder<'data> { expression: provide.value.clone(), loc: loc_for_global_expr(&provide.value, current_section_id), }); - symbol_defs.push( + symbol_defs.insert( + provide.name, crate::parsing::InternalSymDefInfo::new(placement, provide.name) .with_hidden(provide.hidden), ); @@ -180,7 +181,10 @@ impl<'data> LayoutRulesBuilder<'data> { expression: value.to_owned(), loc: loc_for_global_expr(value, current_section_id), }); - symbol_defs.push(crate::parsing::InternalSymDefInfo::new(placement, name)); + symbol_defs.insert( + name, + crate::parsing::InternalSymDefInfo::new(placement, name), + ); } else if let linker_script::Command::Sections(sections) = cmd { let mut location = None; @@ -274,10 +278,10 @@ impl<'data> LayoutRulesBuilder<'data> { expression: assignment.expr.clone(), loc: last_loc.clone(), }); - symbol_defs.push(InternalSymDefInfo::new( - placement, + symbol_defs.insert( assignment.name, - )); + InternalSymDefInfo::new(placement, assignment.name), + ); } ContentsCommand::Align(a) => extra_min_alignment = *a, ContentsCommand::Provide(provide) => { @@ -286,7 +290,8 @@ impl<'data> LayoutRulesBuilder<'data> { expression: provide.value.clone(), loc: last_loc.clone(), }); - symbol_defs.push( + symbol_defs.insert( + provide.name, InternalSymDefInfo::new(placement, provide.name) .with_hidden(provide.hidden), ); @@ -318,7 +323,8 @@ impl<'data> LayoutRulesBuilder<'data> { expression: provide.value.clone(), loc: loc.clone(), }); - symbol_defs.push( + symbol_defs.insert( + provide.name, InternalSymDefInfo::new(placement, provide.name) .with_hidden(provide.hidden), ); @@ -329,7 +335,10 @@ impl<'data> LayoutRulesBuilder<'data> { expression: assignment.expr.clone(), loc: loc.clone(), }); - symbol_defs.push(InternalSymDefInfo::new(placement, assignment.name)); + symbol_defs.insert( + assignment.name, + InternalSymDefInfo::new(placement, assignment.name), + ); } } } diff --git a/libwild/src/macho.rs b/libwild/src/macho.rs index a873b7db6..0f4cfe5b3 100644 --- a/libwild/src/macho.rs +++ b/libwild/src/macho.rs @@ -1413,7 +1413,7 @@ impl platform::Platform for MachO { fn create_resolution( flags: crate::value_flags::ValueFlags, - raw_value: u64, + raw_value: crate::layout::ResolutionState, dynamic_symbol_index: Option, memory_offsets: &mut crate::output_section_part_map::OutputSectionPartMap, ) -> crate::layout::Resolution { @@ -1429,12 +1429,12 @@ impl platform::Platform for MachO { if flags.needs_plt() { let plt_address = allocate_plt(memory_offsets); - resolution.raw_value = plt_address.get(); + resolution.set_value(plt_address.get()); resolution.format_specific.plt_address = Some(plt_address); resolution.format_specific.got_address = Some(allocate_got(memory_offsets)); } else if flags.needs_got() { let got_address = allocate_got(memory_offsets); - resolution.raw_value = got_address.get(); + resolution.set_value(got_address.get()); resolution.format_specific.got_address = Some(got_address); } diff --git a/libwild/src/macho_writer.rs b/libwild/src/macho_writer.rs index d62741b2d..71ffb7c17 100644 --- a/libwild/src/macho_writer.rs +++ b/libwild/src/macho_writer.rs @@ -16,6 +16,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::macho::CHAINED_FIXUP_PAGE_START_SIZE; @@ -622,17 +623,17 @@ fn apply_relocation<'data, A: Arch>( let mask = get_page_mask(rel_info.mask); let value = match rel_info.kind { - RelocationKind::Absolute => resolution.raw_value.bitand(mask.symbol_plus_addend), - RelocationKind::AbsoluteLowPart => resolution.raw_value.bitand(mask.symbol_plus_addend), + RelocationKind::Absolute => resolution.value().bitand(mask.symbol_plus_addend), + RelocationKind::AbsoluteLowPart => resolution.value().bitand(mask.symbol_plus_addend), RelocationKind::Relative => resolution - .raw_value + .value() .bitand(mask.symbol_plus_addend) .wrapping_sub(place.bitand(mask.place)), RelocationKind::GotRelative => resolution - .raw_value + .value() .bitand(mask.symbol_plus_addend) .wrapping_sub(place.bitand(mask.place)), - RelocationKind::Got => resolution.raw_value.bitand(mask.symbol_plus_addend), + RelocationKind::Got => resolution.value().bitand(mask.symbol_plus_addend), _ => todo!(), }; @@ -701,7 +702,7 @@ fn get_resolution<'data>( let section_address = object_layout.section_resolutions[section_index.0].address()?; Some(Resolution { - raw_value: section_address, + raw_value: ResolutionState::Resolved(section_address), dynamic_symbol_index: None, flags: ValueFlags::empty(), format_specific: Default::default(), diff --git a/libwild/src/parsing.rs b/libwild/src/parsing.rs index 87e3fc28d..fcbd42a67 100644 --- a/libwild/src/parsing.rs +++ b/libwild/src/parsing.rs @@ -35,7 +35,7 @@ pub(crate) fn process_linker_scripts<'data, P: Platform>( #[derive(Debug)] pub(crate) struct Prelude<'data, P: Platform> { - pub(crate) symbol_definitions: Vec>, + pub(crate) symbol_definitions: indexmap::IndexMap<&'data [u8], InternalSymDefInfo<'data, P>>, } #[derive(Debug)] @@ -48,7 +48,7 @@ pub(crate) struct ParsedInputObject<'data, P: Platform> { #[derive(Debug)] pub(crate) struct ProcessedLinkerScript<'data, P: Platform> { pub(crate) input: InputRef<'data>, - pub(crate) symbol_defs: Vec>, + pub(crate) symbol_defs: indexmap::IndexMap<&'data [u8], InternalSymDefInfo<'data, P>>, pub(crate) assertions: Vec>, /// Raw bytes of the linker script file. Used to compute line numbers from /// `AssertCommand::remainder` when reporting errors. @@ -246,7 +246,7 @@ impl<'data, P: Platform> Prelude<'data, P> { #[derive(Default)] pub(crate) struct InternalSymbolsBuilder<'data, P: Platform> { - symbol_definitions: Vec>, + symbol_definitions: indexmap::IndexMap<&'data [u8], InternalSymDefInfo<'data, P>>, } impl<'data, P: Platform> InternalSymbolsBuilder<'data, P> { @@ -255,7 +255,7 @@ impl<'data, P: Platform> InternalSymbolsBuilder<'data, P> { def: InternalSymDefInfo<'data, P>, ) -> &mut InternalSymDefInfo<'data, P> { let index = self.symbol_definitions.len(); - self.symbol_definitions.push(def); + self.symbol_definitions.insert(def.name, def); &mut self.symbol_definitions[index] } diff --git a/libwild/src/platform.rs b/libwild/src/platform.rs index 72879244b..b82f3ea2e 100644 --- a/libwild/src/platform.rs +++ b/libwild/src/platform.rs @@ -16,6 +16,7 @@ use crate::layout::Layout; use crate::layout::ObjectLayoutState; use crate::layout::OutputRecordLayout; use crate::layout::PreludeLayoutState; +use crate::layout::ResolutionState; use crate::layout::SymbolResolutions; use crate::layout_rules; use crate::layout_rules::LayoutRulesBuilder; @@ -686,7 +687,7 @@ pub(crate) trait Platform: fn create_resolution( flags: ValueFlags, - raw_value: u64, + raw_value: ResolutionState, dynamic_symbol_index: Option, memory_offsets: &mut OutputSectionPartMap, ) -> layout::Resolution; diff --git a/libwild/src/resolution.rs b/libwild/src/resolution.rs index dabdcec07..854c1aa27 100644 --- a/libwild/src/resolution.rs +++ b/libwild/src/resolution.rs @@ -280,7 +280,7 @@ fn resolve_group<'data, 'definitions, P: Platform>( ResolvedGroup { files: vec![ResolvedFile::Prelude(ResolvedPrelude { - symbol_definitions: prelude.symbol_definitions.clone(), + symbol_definitions: prelude.symbol_definitions.values().cloned().collect(), })], } } @@ -791,7 +791,7 @@ pub(crate) struct ResolvedLinkerScript<'data, P: Platform> { pub(crate) input: InputRef<'data>, pub(crate) file_id: FileId, pub(crate) symbol_id_range: SymbolIdRange, - pub(crate) symbol_definitions: Vec>, + pub(crate) symbol_definitions: indexmap::IndexMap<&'data [u8], InternalSymDefInfo<'data, P>>, } #[derive(Debug, Clone)] @@ -892,7 +892,7 @@ fn process_object<'scope, 'data: 'scope, 'definitions, P: Platform>( Group::StubLibraries(_) => {} Group::LinkerScripts(scripts) => { for script in scripts { - for sym in &script.parsed.symbol_defs { + for sym in script.parsed.symbol_defs.values() { if let SymbolPlacement::Redirect(redirect) = &sym.placement { load_symbols_in_redirect(resources, scope, redirect); } @@ -945,7 +945,7 @@ fn load_prelude<'scope, 'data, P: Platform>( // Try to resolve any symbols that the user requested be undefined (e.g. via --undefined). If an // object defines such a symbol, request that the object be loaded. Also, point our undefined // symbol record to the definition. - for (def_info, definition_out) in prelude.symbol_definitions.iter().zip(definitions_out) { + for ((_, def_info), definition_out) in prelude.symbol_definitions.iter().zip(definitions_out) { match &def_info.placement { SymbolPlacement::ForceUndefined => { load_symbol_named(resources, definition_out, def_info.name, scope); diff --git a/libwild/src/symbol_db.rs b/libwild/src/symbol_db.rs index 46eca03e3..8d6db88ae 100644 --- a/libwild/src/symbol_db.rs +++ b/libwild/src/symbol_db.rs @@ -1620,7 +1620,7 @@ fn load_linker_script_symbols<'data, P: Platform>( symbols_out: &mut SymbolWriterShard<'_, '_, 'data, P>, outputs: &mut SymbolLoadOutputs<'data>, ) { - for (offset, definition) in script.parsed.symbol_defs.iter().enumerate() { + for (offset, definition) in script.parsed.symbol_defs.values().enumerate() { let symbol_id = script.symbol_id_range.offset_to_id(offset); outputs.add_non_versioned(PendingSymbol::from_prehashed( @@ -2052,7 +2052,7 @@ impl<'data, P: Platform> Prelude<'data, P> { symbols_out: &mut SymbolWriterShard<'_, '_, 'data, P>, outputs: &mut SymbolLoadOutputs<'data>, ) { - for definition in &self.symbol_definitions { + for definition in self.symbol_definitions.values() { let symbol_id = symbols_out.next; let mut flags = match &definition.placement { SymbolPlacement::Undefined | SymbolPlacement::ForceUndefined => { diff --git a/libwild/src/wasm.rs b/libwild/src/wasm.rs index 1ddd0d6ca..5228506f7 100644 --- a/libwild/src/wasm.rs +++ b/libwild/src/wasm.rs @@ -2738,7 +2738,7 @@ impl platform::Platform for Wasm { fn create_resolution( flags: crate::value_flags::ValueFlags, - raw_value: u64, + raw_value: layout::ResolutionState, dynamic_symbol_index: Option, _memory_offsets: &mut crate::output_section_part_map::OutputSectionPartMap, ) -> crate::layout::Resolution { diff --git a/wild/tests/sources/elf/linker-script-symbols/linker-script-symbols.c b/wild/tests/sources/elf/linker-script-symbols/linker-script-symbols.c index 6ded4c0e6..90983e333 100644 --- a/wild/tests/sources/elf/linker-script-symbols/linker-script-symbols.c +++ b/wild/tests/sources/elf/linker-script-symbols/linker-script-symbols.c @@ -1,6 +1,8 @@ //#Config:default //#AugmentLinkerScript:script.ld //#Object:runtime.c +//#ExpectSym:value3 address=0x123 +//#ExpectSym:value4 address=0x123 //#Config:lto:default //#RequiresLinkerPlugin:true @@ -10,6 +12,11 @@ //#LinkArgs:-flto -nostdlib -znow //#DiffIgnore:section.got +//#Config:forward-defs:default +//#SkipLinker:ld +//#LinkerScript:script-forward-defs.ld +//#ExpectError:Symbol 'value5' referenced by linker script does not exist + #include "../common/runtime.h" int value1 = 100; @@ -17,6 +24,8 @@ int value2 = 200; extern int value1a; extern int value2a; +extern int value3; +extern int value4; int foo(void) { return 9; } int foo_alias(void); @@ -36,5 +45,9 @@ void _start(void) { exit_syscall(11); } + if ((unsigned long)&value3 != (unsigned long)&value4) { + exit_syscall(12); + } + exit_syscall(42); } diff --git a/wild/tests/sources/elf/linker-script-symbols/script-forward-defs.ld b/wild/tests/sources/elf/linker-script-symbols/script-forward-defs.ld new file mode 100644 index 000000000..2d82af962 --- /dev/null +++ b/wild/tests/sources/elf/linker-script-symbols/script-forward-defs.ld @@ -0,0 +1 @@ +value5 = value5 + 21; diff --git a/wild/tests/sources/elf/linker-script-symbols/script.ld b/wild/tests/sources/elf/linker-script-symbols/script.ld index a54920a6e..4632db921 100644 --- a/wild/tests/sources/elf/linker-script-symbols/script.ld +++ b/wild/tests/sources/elf/linker-script-symbols/script.ld @@ -1,3 +1,6 @@ PROVIDE(value1a = value1); PROVIDE(value2a = value2); PROVIDE(foo_alias = foo); + +value4 = value3; +value3 = 0x123;