-
-
Notifications
You must be signed in to change notification settings - Fork 480
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Do not emit text relocations for IFUNC symbols in PDEs
IFUNC symbols are resolved at process startup by executing the function that the symbol points to. This is used to select the "best" function at runtime; for instance, the runtime may choose a faster version of memcpy that uses SIMD instructions if they are available on the current system. Thus, an IFUNC symbol has two addresses: the initial address (or the resolver's address) and the resolved address, which is the return value of the resolver. In position-independent executables (PIEs), function pointers are loaded from the GOT indirectly, and symbols are not directly referenced. In such executables, the initial value of the GOT slot for an IFUNC symbol contains the resolver address, and this is overwritten at runtime to the resolved address upon process startup. When user code takes a pointer to an IFUNC, it always reads the resolved address from GOT. In contrast, position-dependent executables (PDEs) may have instructions that directly refer to an IFUNC symbol, such as movabs on x86-64. The GOT entry for an IFUNC holds the resolved address, so any direct reference must also produce the resolved address to maintain pointer equality. (C/C++ standards require that two pointers must be equal if and only if they are taken for the same symbol.) Previously, we emitted text relocations to modify instruction operands. However, text relocations are undesirable and not always reliable. For example, on ARM64, multiple instructions are used to materialize a symbol's address, and it's not feasible to issue a dynamic relocation to alter those instructions since the dynamic loader generally can only modify 32-bit or 64-bit words. In this commit, I have adopted a different strategy. An IFUNC symbol now occupies two consecutive GOT slots in a PDE. The first slot holds the symbol's PLT address, and the second slot holds the resolved address. The PLT address is consistently used as the symbol's address throughout the process, while the second slot is used only by the PLT entry to jump to the resolved address. This method ensures pointer equality without the need to emit text relocations for IFUNC symbols in PDEs.
- Loading branch information
Showing
16 changed files
with
152 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
#!/bin/bash | ||
. $(dirname $0)/common.inc | ||
|
||
supports_ifunc || skip | ||
|
||
cat <<EOF | $CC -c -fPIC -o $t/a.o -xc - | ||
typedef void Func(); | ||
void foo(); | ||
Func *get_foo() { return foo; } | ||
EOF | ||
|
||
$CC -B. -shared -o $t/b.so $t/a.o | ||
|
||
cat <<EOF | $CC -c -fno-PIE -o $t/c.o -xc - | ||
#include <stdio.h> | ||
typedef void Func(); | ||
__attribute__((ifunc("resolve_foo"))) void foo(void); | ||
void real_foo(void) { printf("foo "); } | ||
Func *resolve_foo() { return real_foo; } | ||
Func *get_foo(); | ||
int main() { | ||
printf("%p %p\n", foo, get_foo()); | ||
foo(); | ||
printf("\n"); | ||
} | ||
EOF | ||
|
||
$CC -B. -o $t/exe1 $t/c.o $t/b.so -no-pie | ||
$QEMU $t/exe1 | grep -Eq '^(\S+) \1' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
#!/bin/bash | ||
. $(dirname $0)/common.inc | ||
|
||
supports_ifunc || skip | ||
|
||
cat <<EOF | $CC -c -fno-PIE -o $t/a.o -xc - | ||
#include <stdio.h> | ||
typedef void Func(); | ||
__attribute__((ifunc("resolve_foo"))) void foo(void); | ||
void real_foo(void) { printf("foo "); } | ||
Func *resolve_foo() { return real_foo; } | ||
__attribute__((ifunc("resolve_bar"))) void bar(void); | ||
void real_bar(void) { printf("bar "); } | ||
Func *resolve_bar() { return real_bar; } | ||
EOF | ||
|
||
cat <<EOF | $CC -c -fPIC -o $t/b.o -xc - | ||
typedef void Func(); | ||
void foo(); | ||
void bar(); | ||
Func *get_foo() { return foo; } | ||
Func *get_bar() { return bar; } | ||
EOF | ||
|
||
cat <<EOF | $CC -c -fno-PIE -o $t/c.o -xc - | ||
#include <stdio.h> | ||
typedef void Func(); | ||
void foo(); | ||
void bar(); | ||
Func *get_foo(); | ||
Func *get_bar(); | ||
int main() { | ||
printf("%p %p %p %p\n", foo, get_foo(), bar, get_bar()); | ||
foo(); | ||
bar(); | ||
printf("\n"); | ||
} | ||
EOF | ||
|
||
$CC -B. -o $t/exe1 $t/a.o $t/b.o $t/c.o -no-pie | ||
$QEMU $t/exe1 | grep -Eq '^(\S+) \1 (\S+) \2' | ||
|
||
readelf --dynamic $t/exe1 > $t/log1 | ||
! grep -q TEXTREL $t/log1 || false |