mirror of
https://github.com/rui314/mold.git
synced 2026-11-09 04:49:33 -10:00
Preserve LTO symbols only for references from native code
A bitcode function that only other bitcode calls need not survive the internalizer: libLTO resolves that call itself. ld-prime lets such a function go local: linking a bitcode main that calls a bitcode times2(), it exports _main and not _times2. So in an executable only references from non-bitcode objects, the entry point, -u names and the export list pin a symbol defined in bitcode. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
b0d6f41094
commit
97f4c07863
2 files changed
+24
-3
No files matched your search
+19
-3
@@ -987,10 +987,26 @@ pub fn do_lto<E: Target>(ctx: &mut Context<E>) -> bool {
|
||||
// code references (plus the entry point, and everything under
|
||||
// -export_dynamic, which exists exactly to let executables
|
||||
// keep their globals for dlsym) must survive; the rest can be
|
||||
// internalized and dead-stripped inside the module.
|
||||
// internalized and dead-stripped inside the module. A reference
|
||||
// from another bitcode module does not count: libLTO resolves
|
||||
// those itself, and ld-prime lets such a function go local
|
||||
// (_times2, called only from a bitcode main, is not exported).
|
||||
let executable = ctx.args.output_type == MH_EXECUTE;
|
||||
let mut native_refs: hashbrown::HashSet<crate::symbol::SymbolId> =
|
||||
hashbrown::HashSet::new();
|
||||
for obj in &ctx.objs {
|
||||
if !obj.is_alive || obj.lto_module.is_some() {
|
||||
continue;
|
||||
}
|
||||
let r = obj.global_range();
|
||||
for (nlist, &sym_id) in obj.nlists[r.clone()].iter().zip(&obj.symbols[r]) {
|
||||
if !nlist.is_stab() && nlist.n_type() == N_UNDF && !nlist.is_common() {
|
||||
native_refs.insert(sym_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut preserve: Vec<std::ffi::CString> = Vec::new();
|
||||
for sym in &ctx.symbols.syms {
|
||||
for (i, sym) in ctx.symbols.syms.iter().enumerate() {
|
||||
if let Some(FileId::Obj(idx)) = sym.file()
|
||||
&& ctx.objs[idx as usize].is_alive
|
||||
&& ctx.objs[idx as usize].lto_module.is_some()
|
||||
@@ -998,7 +1014,7 @@ pub fn do_lto<E: Target>(ctx: &mut Context<E>) -> bool {
|
||||
{
|
||||
if executable
|
||||
&& !ctx.args.export_dynamic
|
||||
&& !sym.is_used()
|
||||
&& (!sym.is_used() || !native_refs.contains(&(i as u32)))
|
||||
&& sym.name() != ctx.args.entry
|
||||
&& !ctx.args.forced_undefined.iter().any(|n| n == sym.name())
|
||||
&& !ctx
|
||||
|
||||
@@ -15,6 +15,11 @@ EOF2
|
||||
|
||||
$CC -flto --ld-path=$mold -o $t/exe $t/a.o $t/b.o
|
||||
$t/exe | grep '^42$'
|
||||
# A function only other bitcode calls is not kept external: libLTO
|
||||
# resolves that call itself, and ld-prime exports only _main.
|
||||
dyld_info -exports $t/exe > $t/exports
|
||||
grep -q _main $t/exports
|
||||
not grep -q _times2 $t/exports
|
||||
|
||||
# Mixed bitcode and Mach-O, with bitcode in an archive
|
||||
cat <<EOF2 | $CC -flto -o $t/c.o -c -xc -
|
||||
|
||||
Reference in new issue
Block a user