Call an input section's contents, visit and kill by mold's names

InputSection read its bytes through data(), set its visited bit with
mark_visited and was marked dead with set_alive(false). mold's
InputSection has contents(), visit() and kill() for these; the
methods are named so here too, and the passes that drop a subsection
call kill(). set_alive stays for dead stripping, which sets the bit
to what its walk found.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Rui UeyamaandClaude Opus 5.5 committed 2026-10-08 17:53:10 +09:00
1 parent 26be971d07
commit fcd1d6aecc
11 files changed
+48 -41

No files matched your search

+1 -1
View File
@@ -133,7 +133,7 @@ pub fn copy_buf<E: Target>(ctx: &Context<E>, id: OutputSectionId, buf: &mut [u8]
// only ever write within their own subsection.
for_each_member(ctx, osec, buf, |m, slice| {
let isec = &ctx.isecs[m];
let data = isec.data();
let data = isec.contents();
if data.is_empty() {
return;
}
+5 -5
View File
@@ -163,7 +163,7 @@ fn collect_root_set<E: Target>(
// the end.
let mut enqueue = |id: usize, root: Root| {
let id = redirects[id];
if ctx.isecs[id].mark_visited() {
if ctx.isecs[id].visit() {
roots.push(id);
if let Some(why) = why.as_deref_mut() {
why[id] = Why::Root(root);
@@ -260,7 +260,7 @@ pub fn native_refs_before_lto<E: Target>(
for (msym, &id) in obj.mach_syms.iter().zip(&obj.symbols) {
if msym.ty() == N_UNDF
&& let Some(isec) = ctx.symbols[id].input_section()
&& ctx.isecs[redirects[isec as usize]].mark_visited()
&& ctx.isecs[redirects[isec as usize]].visit()
{
roots.push(redirects[isec as usize]);
}
@@ -370,7 +370,7 @@ fn visit_section<E: Target>(
for_each_edge(ctx, id, |target| targets.push(target));
for target in targets {
let target = redirects[target];
if ctx.isecs[target].mark_visited() {
if ctx.isecs[target].visit() {
if depth < 3 {
visit_section(ctx, redirects, target, depth + 1, next);
} else {
@@ -429,7 +429,7 @@ fn walk<E: Target>(
while let Some(id) = queue.pop_front() {
for_each_edge(ctx, id, |target| {
let target = redirects[target];
if ctx.isecs[target].mark_visited() {
if ctx.isecs[target].visit() {
if let Some(why) = why.as_deref_mut() {
why[target] = Why::From(id as u32);
}
@@ -466,7 +466,7 @@ fn mark_live_support<E: Target>(
references_live |= ctx.isecs[redirects[target]].is_visited();
});
let id = redirects[id];
if references_live && ctx.isecs[id].mark_visited() {
if references_live && ctx.isecs[id].visit() {
if let Some(why) = why.as_deref_mut() {
why[id] = Why::Root(Root::LiveSupport);
}
+1 -1
View File
@@ -164,7 +164,7 @@ fn create_delay_helpers<E: Target>(
let kind = match how {
LazyRef::Cmp => DelayUse::Cmp,
LazyRef::Load => {
let (reg, own) = E::lazy_load_site(ctx.isecs[isec as usize].data(), offset);
let (reg, own) = E::lazy_load_site(ctx.isecs[isec as usize].contents(), offset);
DelayUse::Load { reg, site: own.then_some((isec, offset)) }
}
_ => continue,
+3 -3
View File
@@ -415,8 +415,8 @@ fn compute_digest<E: Target>(ctx: &Context<E>, cand_index: &[usize], id: usize)
let isec = &ctx.isecs[id];
let mut h = SipHash13_128::new(&KEY);
h.update(&isec.size.to_ne_bytes());
h.update(&isec.data().len().to_ne_bytes());
h.update(isec.data());
h.update(&isec.contents().len().to_ne_bytes());
h.update(isec.contents());
for rel in isec.rels(&ctx.objs[isec.file as usize]) {
h.update(&rel.offset.to_ne_bytes());
h.update(&rel.ty.to_ne_bytes());
@@ -609,7 +609,7 @@ fn verify_leaders<E: Target>(
let equal = |a: usize, b: usize| -> bool {
let (x, y) = (&ctx.isecs[a], &ctx.isecs[b]);
let (xr, yr) = (x.rels(&ctx.objs[x.file as usize]), y.rels(&ctx.objs[y.file as usize]));
x.data() == y.data()
x.contents() == y.contents()
&& xr.len() == yr.len()
&& xr.iter().zip(yr).all(|(r, s)| {
r.offset == s.offset
+8 -3
View File
@@ -231,7 +231,7 @@ pub struct InputSection {
/// The subsection contents, as a bare pointer - the length is
/// `size` - or 0 when there are none (a zero-fill or empty
/// section). Stored as an integer, not a slice, to save 8 bytes and
/// keep the struct trivially Send/Sync; read through `data()`.
/// keep the struct trivially Send/Sync; read through `contents()`.
/// mold likewise keeps `contents` as a bare address.
pub contents: usize,
/// This subsection's relocations: a range in the owning object's
@@ -410,9 +410,14 @@ impl InputSection {
*f &= !IS_ALIVE;
}
}
/// Marks the subsection dead.
#[inline]
pub fn kill(&mut self) {
*self.flags.get_mut() &= !IS_ALIVE;
}
/// Atomically sets the visited bit; true if this call set it.
#[inline]
pub fn mark_visited(&self) -> bool {
pub fn visit(&self) -> bool {
self.flags.fetch_or(IS_VISITED, std::sync::atomic::Ordering::Relaxed) & IS_VISITED == 0
}
/// Clears the visited bit, through a shared reference.
@@ -461,7 +466,7 @@ impl InputSection {
/// otherwise the `size` bytes at `contents` (which point into the
/// mmap'd input, so they live for the whole link).
#[inline]
pub fn data(&self) -> &'static [u8] {
pub fn contents(&self) -> &'static [u8] {
if self.contents == 0 {
&[]
} else {
+2 -2
View File
@@ -90,7 +90,7 @@ pub(crate) fn import_uses<E: Target>(
.filter(|&i| ctx.isecs[i].is_emitted())
.flat_map_iter(|i| {
let isec = &ctx.isecs[i];
let (file, data) = (&ctx.objs[isec.file as usize], isec.data());
let (file, data) = (&ctx.objs[isec.file as usize], isec.contents());
isec.rels(file).iter().filter_map(move |r| {
let id = r.sym(file)?;
is_import(id).then(|| (i as u32, r.offset, id, E::lazy_ref(r, data)))
@@ -215,7 +215,7 @@ fn create_lazy_helpers<E: Target>(
LazyRef::Call => LazyUse::Call,
LazyRef::Cmp => LazyUse::Cmp,
LazyRef::Load => {
let (reg, own) = E::lazy_load_site(ctx.isecs[isec as usize].data(), offset);
let (reg, own) = E::lazy_load_site(ctx.isecs[isec as usize].contents(), offset);
LazyUse::Load { reg, site: own.then_some((isec, offset)) }
}
LazyRef::Slot | LazyRef::Unsupported => continue,
+3 -3
View File
@@ -426,7 +426,7 @@ impl<'a, E: Target> Builder<'a, E> {
Content::Image(out.fileoff + isec.offset as u64)
}
}
_ => Content::Pool(isec.data()),
_ => Content::Pool(isec.contents()),
}
}
@@ -639,7 +639,7 @@ impl<'a, E: Target> Builder<'a, E> {
let arm64 = E::CPUTYPE == CPU_TYPE_ARM64;
let code = isec.hdr(&ctx.objs[obj]).flags & S_ATTR_SOME_INSTRUCTIONS != 0;
let insn = |r: &Reloc| {
u32::from_le_bytes(isec.data()[r.offset as usize..][..4].try_into().unwrap())
u32::from_le_bytes(isec.contents()[r.offset as usize..][..4].try_into().unwrap())
};
// The other references to the slot in the subsection, after or
// before this one.
@@ -774,7 +774,7 @@ impl<'a, E: Target> Builder<'a, E> {
continue;
}
let fixup = if E::CPUTYPE == CPU_TYPE_ARM64 {
arm64_fixup(isec.data(), r, target, addend)
arm64_fixup(isec.contents(), r, target, addend)
} else {
x86_64_fixup(hdr, r, target, addend)
};
+13 -13
View File
@@ -285,7 +285,7 @@ fn objc_class_ro<E: Target>(ctx: &Context<E>, cls: (u32, u64)) -> Option<(u32, u
/// The C string a reference points at, if it is in the image.
fn objc_cstring_at<E: Target>(ctx: &Context<E>, r: Option<ObjcRef>) -> Option<&'static [u8]> {
let (isec, off) = objc_ref_location(ctx, r?)?;
let data = ctx.isecs[isec as usize].data();
let data = ctx.isecs[isec as usize].contents();
let bytes = data.get(off as usize..)?;
let end = bytes.iter().position(|&b| b == 0)?;
Some(&bytes[..end])
@@ -427,7 +427,7 @@ fn ref_key<E: Target>(ctx: &Context<E>, i: usize) -> Option<RefKey> {
targets.sort_by_key(|t| t.0);
// The relocated fields hold per-object addends (x86-64
// embeds the target's address); the targets stand for them.
let mut bytes = isec.data().to_vec();
let mut bytes = isec.contents().to_vec();
for rel in rels {
let (a, b) = (rel.offset as usize, rel.offset as usize + rel.size as usize);
bytes[a..b].fill(0);
@@ -581,7 +581,7 @@ pub fn fold_objc_classrefs<E: Target>(ctx: &mut Context<E>) {
// A pair's halves go together, as its offset half decides.
let mut keep = hashbrown::HashSet::new();
for u in &uses[obj_idx] {
let data = ctx.isecs[u.isec as usize].data();
let data = ctx.isecs[u.isec as usize].contents();
let relocs = &ctx.objs[obj_idx].relocs;
let decider = offset_half[obj_idx].get(&u.k).copied().unwrap_or(u.k);
let (rel, decider) = (relocs[u.k], relocs[decider]);
@@ -621,7 +621,7 @@ pub fn fold_objc_classrefs<E: Target>(ctx: &mut Context<E>) {
ctx.symbols[class].add_flags(NEEDS_GOT);
kept.push((slot, class));
} else {
ctx.isecs[slot as usize].set_alive(false);
ctx.isecs[slot as usize].kill();
}
}
}
@@ -1030,7 +1030,7 @@ fn classic_list_header(data: &[u8]) -> Option<(u32, u64)> {
fn classic_methods<E: Target>(ctx: &Context<E>, list: u32) -> Option<Vec<(u32, ObjcRef, ObjcRef)>> {
// Not in the relative form already (the top flag), and 24 bytes an
// entry.
let (entsize_flags, count) = classic_list_header(ctx.isecs[list as usize].data())?;
let (entsize_flags, count) = classic_list_header(ctx.isecs[list as usize].contents())?;
if entsize_flags & 0x8000_0000 != 0 || entsize_flags & 0xffff != 24 {
return None;
}
@@ -1112,7 +1112,7 @@ pub fn merge_objc_categories<E: Target>(ctx: &mut Context<E>) {
retarget_class_data(ctx, class.meta, meta_ro);
for &ci in &class.cats {
ctx.isecs[cats[ci].isec as usize].set_alive(false);
ctx.isecs[cats[ci].isec as usize].kill();
cats[ci].merged = true;
}
if !class.nonlazy && class.cats.iter().any(|&ci| cats[ci].nonlazy) {
@@ -1398,7 +1398,7 @@ fn read_method_list<E: Target>(
if relative {
return None;
}
let (entsize_flags, count) = classic_list_header(ctx.isecs[isec as usize].data())?;
let (entsize_flags, count) = classic_list_header(ctx.isecs[isec as usize].contents())?;
if entsize_flags != 24 {
return None;
}
@@ -1419,7 +1419,7 @@ fn read_method_list<E: Target>(
fn read_protocol_list<E: Target>(ctx: &Context<E>, list: Option<ObjcRef>) -> Option<Vec<ObjcRef>> {
let Some(r) = list else { return Some(Vec::new()) };
let (isec, off) = objc_ref_location(ctx, r)?;
let data = ctx.isecs[isec as usize].data();
let data = ctx.isecs[isec as usize].contents();
let count = u64::from_le_bytes(data.get(off as usize..off as usize + 8)?.try_into().unwrap());
(0..count).map(|i| objc_pointer_at(ctx, isec, off + 8 + 8 * i)).collect()
}
@@ -1432,7 +1432,7 @@ fn read_property_list<E: Target>(
) -> Option<Vec<(ObjcRef, ObjcRef)>> {
let Some(r) = list else { return Some(Vec::new()) };
let (isec, off) = objc_ref_location(ctx, r)?;
let data = ctx.isecs[isec as usize].data();
let data = ctx.isecs[isec as usize].contents();
let entsize = u32::from_le_bytes(data.get(off as usize..off as usize + 4)?.try_into().unwrap());
let count =
u32::from_le_bytes(data.get(off as usize + 4..off as usize + 8)?.try_into().unwrap())
@@ -1615,7 +1615,7 @@ fn drop_superseded_lists<E: Target>(
fn drop_list<E: Target>(ctx: &mut Context<E>, list: Option<ObjcRef>) {
if let Some((isec, 0)) = list.and_then(|r| objc_ref_location(ctx, r)) {
ctx.isecs[isec as usize].set_alive(false);
ctx.isecs[isec as usize].kill();
}
}
@@ -1635,7 +1635,7 @@ fn rewrite_ro<E: Target>(
protocols: Option<ObjcRef>,
props: Option<ObjcRef>,
) -> u32 {
let data = ctx.isecs[ro.0 as usize].data()[ro.1 as usize..ro.1 as usize + 16].to_vec();
let data = ctx.isecs[ro.0 as usize].contents()[ro.1 as usize..ro.1 as usize + 16].to_vec();
let flags = u32::from_le_bytes(data[0..4].try_into().unwrap());
let len = if flags & (1 << 6) != 0 { 80 } else { 72 };
let mut fields = vec![DataField::Bytes(data)];
@@ -1664,7 +1664,7 @@ fn rewrite_ro<E: Target>(
// The record was a subsection of its own: replace it, so its
// symbol names the new record too (ld64 keeps
// __OBJC_CLASS_RO_$_Foo).
isec.set_alive(false);
isec.kill();
isec.replacement = blob;
}
blob
@@ -1701,7 +1701,7 @@ fn rebuild_category_lists<E: Target>(
if !list.entries.iter().any(|&(_, ci)| merged(ci)) {
continue;
}
ctx.isecs[list.isec as usize].set_alive(false);
ctx.isecs[list.isec as usize].kill();
let survivors: Vec<DataField> = (list.entries.iter())
.filter(|&&(_, ci)| !merged(ci))
.map(|&(r, _)| DataField::Ptr(r))
+1 -1
View File
@@ -803,7 +803,7 @@ fn group_input_sections<E: Target>(
};
let Some(group) = group else {
// Consumed by the link: no output section.
isec.set_alive(false);
isec.kill();
continue;
};
let group = &mut groups[group].1;
+6 -6
View File
@@ -972,7 +972,7 @@ fn retire_bitcode_placeholders<E: Target>(ctx: &mut Context<E>) {
pub fn remove_unreachable_files<E: Target>(ctx: &mut Context<E>) {
for isec in ctx.isecs.iter_mut() {
if !ctx.objs[isec.file as usize].is_alive {
isec.set_alive(false);
isec.kill();
}
}
@@ -996,7 +996,7 @@ pub fn remove_swift_reflection_metadata<E: Target>(ctx: &mut Context<E>) {
})
.collect();
for i in removed {
ctx.isecs[i].set_alive(false);
ctx.isecs[i].kill();
}
}
@@ -1074,7 +1074,7 @@ pub fn convert_init_offsets<E: Target>(ctx: &mut Context<E>) {
};
ctx.init_offsets.init_funcs.push(func);
}
ctx.isecs[i].set_alive(false);
ctx.isecs[i].kill();
}
}
@@ -1287,7 +1287,7 @@ pub fn merge_literals<E: Target>(ctx: &mut Context<E>) {
if !input_files::is_mergeable_literal(hdr, isec) {
return None;
}
Some((xxhash_rust::xxh3::xxh3_64(isec.data()), hdr, i as u32))
Some((xxhash_rust::xxh3::xxh3_64(isec.contents()), hdr, i as u32))
})
.collect();
@@ -1324,13 +1324,13 @@ fn merge_shard(isecs: &[InputSection], shard: Vec<Literal>) -> Vec<(u32, u32)> {
let mut losers: Vec<(u32, u32)> = Vec::new();
let p2align = |i: u32| isecs[i as usize].p2align_at(isecs[i as usize].input_addr as u64);
for (hash, hdr, i) in shard {
let data = isecs[i as usize].data();
let data = isecs[i as usize].contents();
let same = |&(h, other, j, _): &(u64, &MachSection, u32, u32)| {
h == hash
&& other.segname == hdr.segname
&& other.sectname == hdr.sectname
&& other.section_type() == hdr.section_type()
&& isecs[j as usize].data() == data
&& isecs[j as usize].contents() == data
};
match table.entry(hash, same, |e| e.0) {
hashbrown::hash_table::Entry::Occupied(e) => {
+5 -3
View File
@@ -975,19 +975,21 @@ fn copy_section_contents<E: Target>(
let osec = ctx.output_section(osec);
if !osec.hdr.is_zerofill() {
let isecs = osec.members.iter().map(|&id| &ctx.isecs[id]);
jobs.extend(isecs.filter(|isec| !isec.data().is_empty()).map(|isec| (&osec.hdr, isec)));
jobs.extend(
isecs.filter(|isec| !isec.contents().is_empty()).map(|isec| (&osec.hdr, isec)),
);
}
}
let ranges: Vec<std::ops::Range<u64>> = jobs
.iter()
.map(|&(hdr, isec)| {
let start = hdr.fileoff + isec.offset as u64;
start..start + isec.data().len() as u64
start..start + isec.contents().len() as u64
})
.collect();
let slices = output_file::split_ranges(buf, &ranges);
jobs.into_par_iter().zip(slices).for_each(|((hdr, isec), out)| {
out.copy_from_slice(isec.data());
out.copy_from_slice(isec.contents());
for rel in isec.rels(&ctx.objs[isec.file as usize]) {
let here = hdr.addr + isec.offset as u64 + rel.offset as u64;
rewrite_field(targets, isec, rel, here, &mut out[rel.offset as usize..]);