[AArch64] Fix pointer inequality in pointers to the same ifunc symbol#945
[AArch64] Fix pointer inequality in pointers to the same ifunc symbol#945parth-07 wants to merge 1 commit intoqualcomm:mainfrom
Conversation
db53f97 to
9ac9369
Compare
|
|
||
| recordGOT(symInfo, G); | ||
| symInfo->setReserved(symInfo->reserved() | Relocator::ReserveGOT); | ||
| } |
There was a problem hiding this comment.
The GNU linker creates a igot and igot.plt probably it would be useful to follow the pattern for IFUNC symbols.
There was a problem hiding this comment.
This can simplify the ifunc implementation too, probably we can reserve the GOT and PLT slots and later remove the GOT slots not needed.
There was a problem hiding this comment.
The GNU linker creates a igot and igot.plt probably it would be useful to follow the pattern for IFUNC symbols.
This is interesting. I did not observe this during my experimentation of IFunc functionality with gnu ld. Can you please share which GNU version are you using?
$ aarch64-none-linux-gnu-ld.bfd --version
GNU ld (Arm GNU Toolchain 15.2.Rel1 (Build arm-15.86)) 2.45.1.20251203
Copyright (C) 2025 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) a later version.
This program has absolutely no warranty.
$ llvm-readelf -S 1.bfd.out | grep -i .got
[20] .got PROGBITS 000000000001ffb8 00ffb8 000030 08 WA 0 0 8
[21] .got.plt PROGBITS 000000000001ffe8 00ffe8 000048 08 WA 0 0 8This can simplify the ifunc implementation too, probably we can reserve the GOT and PLT slots and later remove the GOT slots not needed.
This would be the same even if we use the normal .got slot instead of the .igot slot, right? I do prefer to have mechanisms in place so that we only create the slots if they are required. Preemptively creating the slots may lead to unnecessary operations, and reverting/removing the slot may silently bring in bugs in the future if we add any new side-effect to the .got slot creation.
9ac9369 to
18af1fd
Compare
18af1fd to
c2f0c2c
Compare
c2f0c2c to
d1cf9a0
Compare
|
Do we need to do anything special to handle dynamic linking, e.g. there's a reference to the function from a different shared library? |
d1cf9a0 to
a9a66ad
Compare
Yes, there would be some differences. We will need to correctly emit dynamic relocations for the IFunc symbols. Currently, we do not correctly emit dynamic relocations for the IFunc functionality in all cases. This being said, Currently, we only completely support static executables with IFunc functionality. |
a9a66ad to
7170dec
Compare
7170dec to
3e70227
Compare
This commit fixes pointer inequality in pointers to the same ifunc
symbol. Let's understand the issue in more detail using the below
example:
```cpp
char *foo_impl() { return "foo"; }
static char *(*foo_resolver())(void) { return foo_impl; }
char *foo() __attribute__((ifunc("foo_resolver")));
char *(*foogp)() = foo;
int main() {
char *(*foop)() = foo;
}
```
`foogp` and `foop` pointers both point to the same function `foo`.
However, their values were different. The root cause was improper
handling of the underlying relocations when the symbol is of type ifunc.
```
char *(*foogp)() = foo; // R_AARCH64_ABS64
// ...
char *(*foop)() = foo; // R_AARCH64_ADR_GOT_PAGE + R_AARCH64_LD64_GOT_LO12_NC
```
Previously, the linker resolved the R_AARCH64_ABS64 relocation here to
the plt slot of foo, let's refer to it as plt[foo], and the
GOT-relocations were resolved to the .got.plt slot of foo, let's refer
to it as .got.plt[foo]. As a result, foogp stores the address of
plt[foo] and foop stores the contents of .got.plt[foo], that is, the
address of the resolved function foo. Clearly, the two values are
different.
We resolve this issue by creating a got slot for foo when the foo has
both an absolute reference and a GOT-reference. The got slot of foo
is filled by the linker and stores the address of plt[foo].
With this, both the absolute-reference and got-reference to an ifunc symbol
results in the same address. Please note that:
- we do not create .got slot of foo when we only have an absolute reference
to foo because .got slot is unnecessary in this case, and
- we do not create .got slot of foo when we only have a GOT-reference
because in this case we can directly use .got.plt slot and access the
function directly without any indirection penalty or the
pointer-inequality bug.
Resolves qualcomm#913
Signed-off-by: Parth Arora <partaror@qti.qualcomm.com>
3e70227 to
cfce1c6
Compare
| case R_AARCH64_ADR_PREL_PG_HI21_NC: { | ||
| std::lock_guard<std::mutex> relocGuard(m_RelocMutex); | ||
| if (rsym->isIFunc() && config().isCodeStatic()) | ||
| rsym->setIFuncAbsRef(); |
There was a problem hiding this comment.
I'm not sure "AbsRef" really captures the rule here... the issue is really whether the reference is direct, i.e. not through the GOT.
Do we also need to handle R_AARCH64_MOVW_UABS_G0 etc.?
This commit fixes pointer inequality in pointers to the same ifunc symbol. Let's understand the issue in more detail using the below example:
foogpandfooppointers both point to the same functionfoo. However, their values were different. The root cause was improper handling of the underlying relocations when the symbol is of type ifunc.Previously, the linker resolved the R_AARCH64_ABS64 relocation here to the plt slot of foo, let's refer to it as plt[foo], and the GOT-relocations were resolved to the .got.plt slot of foo, let's refer to it as .got.plt[foo]. As a result, foogp stores the address of plt[foo] and foop stores the contents of .got.plt[foo], that is, the address of the resolved function foo. Clearly, the two values are different.
We resolve this issue by creating a got slot for foo when the foo has both an absolute reference and a GOT-reference. The got slot of foo is filled by the linker and stores the address of plt[foo]. With this, both the absolute-reference and got-reference to an ifunc symbol results in the same address. Please note that:
Resolves #913