mirror of
https://github.com/rui314/mold.git
synced 2026-11-07 09:16:04 -10:00
Keep IFUNCs exported from a shared object preemptible
A shared object's references to an IFUNC that it exports were bound locally with IRELATIVE relocations, so a definition that interposes the IFUNC didn't reach them. They now get JUMP_SLOT and GLOB_DAT relocations against the symbol, as with GNU ld and lld. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
77d78b9a0e
commit
605749d515
6 files changed
+62
-6
No files matched your search
+1
-1
@@ -128,7 +128,7 @@ impl Target for M68k {
|
||||
continue;
|
||||
}
|
||||
let sym = &ctx.symbols[file.base.symbols[rel.r_sym() as usize]];
|
||||
if sym.is_ifunc() {
|
||||
if sym.ty() == STT_GNU_IFUNC {
|
||||
error!("{sym}: GNU ifunc symbol is not supported on m68k");
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -277,7 +277,7 @@ impl<const LE: bool> Target for Sh4Target<LE> {
|
||||
continue;
|
||||
}
|
||||
let sym = &ctx.symbols[file.base.symbols[rel.r_sym() as usize]];
|
||||
if sym.is_ifunc() {
|
||||
if sym.ty() == STT_GNU_IFUNC {
|
||||
error!("{sym}: GNU ifunc symbol is not supported on sh4");
|
||||
}
|
||||
|
||||
|
||||
@@ -1179,7 +1179,7 @@ fn sym_type(sym: &Symbol) -> usize {
|
||||
0
|
||||
} else if !sym.is_imported() {
|
||||
1
|
||||
} else if sym.ty() != STT_FUNC {
|
||||
} else if !matches!(sym.ty(), STT_FUNC | STT_GNU_IFUNC) {
|
||||
2
|
||||
} else {
|
||||
3
|
||||
|
||||
+3
-2
@@ -3028,12 +3028,13 @@ fn is_protected<E: Target>(ctx: &Context<E>, sym: &Symbol) -> bool {
|
||||
if sym.visibility() == STV_PROTECTED {
|
||||
return true;
|
||||
}
|
||||
let is_func = matches!(sym.ty(), STT_FUNC | STT_GNU_IFUNC);
|
||||
match ctx.args.bsymbolic {
|
||||
BsymbolicKind::All => true,
|
||||
BsymbolicKind::None => false,
|
||||
BsymbolicKind::Functions => sym.ty() == STT_FUNC,
|
||||
BsymbolicKind::Functions => is_func,
|
||||
BsymbolicKind::NonWeak => !sym.is_weak(),
|
||||
BsymbolicKind::NonWeakFunctions => !sym.is_weak() && sym.ty() == STT_FUNC,
|
||||
BsymbolicKind::NonWeakFunctions => !sym.is_weak() && is_func,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-1
@@ -952,9 +952,15 @@ impl Symbol {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the symbol is an IFUNC that the output resolves itself
|
||||
/// with IRELATIVE relocations. An imported IFUNC is resolved by the
|
||||
/// dynamic loader through the symbol like any other imported
|
||||
/// function. That includes an IFUNC that the DSO being created
|
||||
/// exports without binding it locally, so that the DSO's own
|
||||
/// references to it reach a definition that interposes it.
|
||||
#[inline]
|
||||
pub fn is_ifunc(&self) -> bool {
|
||||
self.ty() == STT_GNU_IFUNC
|
||||
self.ty() == STT_GNU_IFUNC && !self.is_imported()
|
||||
}
|
||||
|
||||
// A remaining weak undefined symbol is promoted to a dynamic symbol
|
||||
|
||||
Executable
+49
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
. $(dirname $0)/common.inc
|
||||
|
||||
supports_ifunc || skip
|
||||
|
||||
cat <<EOF | $CC -fPIC -o $t/a.o -c -xc -
|
||||
#include <stdio.h>
|
||||
|
||||
typedef void Func(void);
|
||||
|
||||
__attribute__((ifunc("resolve_foo")))
|
||||
void foo(void);
|
||||
|
||||
static void real_foo(void) {
|
||||
printf("dso ");
|
||||
}
|
||||
|
||||
static Func *resolve_foo(void) {
|
||||
return real_foo;
|
||||
}
|
||||
|
||||
void call_foo(void) { foo(); }
|
||||
Func *get_foo(void) { return foo; }
|
||||
Func *foo_ptr = foo;
|
||||
EOF
|
||||
|
||||
$CC -B. -shared -o $t/b.so $t/a.o
|
||||
|
||||
cat <<EOF | $CC -o $t/c.o -c -xc -
|
||||
#include <stdio.h>
|
||||
|
||||
typedef void Func(void);
|
||||
|
||||
void foo(void) {
|
||||
printf("exe ");
|
||||
}
|
||||
|
||||
void call_foo(void);
|
||||
Func *get_foo(void);
|
||||
extern Func *foo_ptr;
|
||||
|
||||
int main() {
|
||||
call_foo();
|
||||
printf("%d %d\n", get_foo() == foo, foo_ptr == foo);
|
||||
}
|
||||
EOF
|
||||
|
||||
$CC -B. -o $t/exe $t/c.o $t/b.so
|
||||
$QEMU $t/exe | grep '^exe 1 1$'
|
||||
Reference in new issue
Block a user