mirror of
https://github.com/rui314/mold.git
synced 2026-11-09 13:01:26 -10:00
Make no output section from an empty section that defines no symbol
An assembler's empty .section, or an emptied coverage section, makes no section in ld-prime's output when no symbol is defined in it; ours carried such sections through. A symbol keeps the section, even a local one: the arm64 assembler starts every section with an ltmp label, so on arm64 an empty .section stays, in ld-prime's output as in ours, while on x86-64 it goes. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
bc4ced43b8
commit
1e65e0cd97
2 files changed
+47
No files matched your search
@@ -3951,6 +3951,39 @@ pub fn create_output_sections<E: Target>(ctx: &mut Context<E>) {
|
||||
ctx.isecs[i].set_output_section(ChunkId::Output(osec_id));
|
||||
}
|
||||
|
||||
// An input section with no bytes and no symbol in it makes no
|
||||
// output section (an assembler's empty .section, an emptied
|
||||
// coverage section): ld-prime drops it, and its subsections with
|
||||
// it. A symbol keeps it, even a local one such as the ltmp label
|
||||
// the arm64 assembler puts at the start of every section.
|
||||
if !relocatable {
|
||||
let is_bare = |&m: &u32| {
|
||||
let isec = &ctx.isecs[m as usize];
|
||||
isec.size == 0
|
||||
&& !ctx.objs[isec.file as usize].nlists.iter().any(|nlist| {
|
||||
!nlist.is_stab()
|
||||
&& nlist.n_type() == N_SECT
|
||||
&& nlist.n_sect as u32 == isec.shndx + 1
|
||||
})
|
||||
};
|
||||
let dropped: Vec<OutputSectionId> = (0..ctx.output_sections.len())
|
||||
.filter(|&i| {
|
||||
let osec = &ctx.output_sections[i];
|
||||
!osec.members.is_empty()
|
||||
&& osec.members.iter().all(is_bare)
|
||||
&& !(osec.hdr.segname == "__TEXT" && osec.hdr.sectname == "__text")
|
||||
})
|
||||
.map(|i| OutputSectionId::new(i as u32))
|
||||
.collect();
|
||||
for id in dropped {
|
||||
for m in std::mem::take(&mut ctx.output_sections[id.index()].members) {
|
||||
ctx.isecs[m as usize].set_alive(false);
|
||||
}
|
||||
ctx.chunks.retain(|&c| c != ChunkId::Output(id));
|
||||
by_out.retain(|_, &mut v| v != id);
|
||||
}
|
||||
}
|
||||
|
||||
// A final image always has a __TEXT,__text section, empty if no
|
||||
// code reached it (a dylib of only data; ld-prime writes one of
|
||||
// size 0, byte-aligned).
|
||||
|
||||
@@ -51,6 +51,8 @@ $t/exe | grep '^5 ok$'
|
||||
cat <<EOF | $CC -o $t/b.o -c -x assembler -
|
||||
.section __DATA,__zero_one
|
||||
.section __DATA,__zero_two
|
||||
.section __DATA,__zero_labeled
|
||||
zero_label:
|
||||
EOF
|
||||
cat <<EOF | $CC -o $t/c.o -c -xc -
|
||||
_Thread_local int tls_var = 3;
|
||||
@@ -58,3 +60,15 @@ int get_tls(void) { return tls_var; }
|
||||
EOF
|
||||
$CC --ld-path=$mold -o $t/exe2 $t/main.o $t/a.o $t/b.o $t/c.o
|
||||
$t/exe2 | grep '^5 ok$'
|
||||
# An empty section with no symbol in it makes no output section, as
|
||||
# with ld-prime. The arm64 assembler gives every section an ltmp
|
||||
# symbol, so there all three stay.
|
||||
otool -l $t/exe2 > $t/lc2
|
||||
grep -q '__zero_labeled' $t/lc2
|
||||
if [ $ARCH = x86_64 ]; then
|
||||
not grep -q '__zero_one' $t/lc2
|
||||
not grep -q '__zero_two' $t/lc2
|
||||
else
|
||||
grep -q '__zero_one' $t/lc2
|
||||
grep -q '__zero_two' $t/lc2
|
||||
fi
|
||||
Reference in new issue
Block a user