Overhauled common BSS support & more

- With a map, attempts to detect and handle common BSS automatically
- With a map, attempts to detect and correct inflated common BSS bug (< GC 2.7 linker)
- Support for "stripped" symbols, sometimes required to match inflated common BSS sizes
- Warns on duplicated TUs in a map (other than common BSS)
- Automatically adds `comment:0` to `.s` TUs from a map (avoids linker crash)
This commit is contained in:
2023-11-29 18:14:17 -05:00
parent 5c22c8850e
commit 0cfc5df20b
10 changed files with 269 additions and 95 deletions

View File

@@ -125,6 +125,13 @@ impl ObjSections {
self.iter()
.flat_map(|(idx, s)| s.splits.iter().map(move |(addr, split)| (idx, s, addr, split)))
}
pub fn common_bss_start(&self) -> Option<(usize, u32)> {
let Ok(Some((section_index, section))) = self.by_name(".bss") else {
return None;
};
section.splits.iter().find(|(_, split)| split.common).map(|(addr, _)| (section_index, addr))
}
}
impl Index<usize> for ObjSections {

View File

@@ -26,9 +26,9 @@ pub enum ObjSymbolScope {
}
flags! {
#[repr(u8)]
#[repr(u32)]
#[derive(Deserialize_repr, Serialize_repr)]
pub enum ObjSymbolFlags: u8 {
pub enum ObjSymbolFlags: u32 {
Global,
Local,
Weak,
@@ -39,6 +39,9 @@ flags! {
RelocationIgnore,
/// Symbol won't be written to symbols file
NoWrite,
/// Symbol was stripped from the original object,
/// but is still useful for common BSS matching.
Stripped,
}
}
@@ -83,6 +86,9 @@ impl ObjSymbolFlagSet {
#[inline]
pub fn is_no_write(&self) -> bool { self.0.contains(ObjSymbolFlags::NoWrite) }
#[inline]
pub fn is_stripped(&self) -> bool { self.0.contains(ObjSymbolFlags::Stripped) }
#[inline]
pub fn set_scope(&mut self, scope: ObjSymbolScope) {
match scope {
@@ -119,7 +125,8 @@ impl ObjSymbolFlagSet {
self.0
& (ObjSymbolFlags::ForceActive
| ObjSymbolFlags::NoWrite
| ObjSymbolFlags::RelocationIgnore)
| ObjSymbolFlags::RelocationIgnore
| ObjSymbolFlags::Stripped)
}
}
@@ -212,7 +219,10 @@ impl ObjSymbols {
}
pub fn add(&mut self, in_symbol: ObjSymbol, replace: bool) -> Result<SymbolIndex> {
let opt = if let Some(section_index) = in_symbol.section {
let opt = if in_symbol.flags.is_stripped() {
// Stripped symbols don't overwrite existing symbols
None
} else if let Some(section_index) = in_symbol.section {
self.at_section_address(section_index, in_symbol.address as u32).find(|(_, symbol)| {
symbol.kind == in_symbol.kind ||
// Replace auto symbols with real symbols
@@ -228,7 +238,8 @@ impl ObjSymbols {
let replace = replace || (is_auto_symbol(existing) && !is_auto_symbol(&in_symbol));
let size =
if existing.size_known && in_symbol.size_known && existing.size != in_symbol.size {
log::warn!(
// TODO fix this and restore to warning
log::debug!(
"Conflicting size for {}: was {:#X}, now {:#X}",
existing.name,
existing.size,
@@ -336,6 +347,8 @@ impl ObjSymbols {
.into_iter()
.flatten()
.map(move |&idx| (idx, &self.symbols[idx]))
// "Stripped" symbols don't actually exist at the address
.filter(|(_, sym)| !sym.flags.is_stripped())
}
pub fn kind_at_section_address(
@@ -513,7 +526,7 @@ impl Index<SymbolIndex> for ObjSymbols {
impl ObjSymbol {
/// Whether this symbol can be referenced by the given relocation kind.
pub fn referenced_by(&self, reloc_kind: ObjRelocKind) -> bool {
if self.flags.is_relocation_ignore() {
if self.flags.is_relocation_ignore() || self.flags.is_stripped() {
return false;
}