Skip to content

[AArch64] Fix pointer inequality in pointers to the same ifunc symbol#945

Open
parth-07 wants to merge 1 commit intoqualcomm:mainfrom
parth-07:IFuncPointerEquality
Open

[AArch64] Fix pointer inequality in pointers to the same ifunc symbol#945
parth-07 wants to merge 1 commit intoqualcomm:mainfrom
parth-07:IFuncPointerEquality

Conversation

@parth-07
Copy link
Contributor

@parth-07 parth-07 commented Mar 17, 2026

This commit fixes pointer inequality in pointers to the same ifunc symbol. Let's understand the issue in more detail using the below example:

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 #913

@parth-07 parth-07 force-pushed the IFuncPointerEquality branch from f0375c4 to db53f97 Compare March 17, 2026 10:28
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>
@parth-07 parth-07 force-pushed the IFuncPointerEquality branch from db53f97 to 9ac9369 Compare March 17, 2026 12:46

recordGOT(symInfo, G);
symInfo->setReserved(symInfo->reserved() | Relocator::ReserveGOT);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GNU linker creates a igot and igot.plt probably it would be useful to follow the pattern for IFUNC symbols.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can simplify the ifunc implementation too, probably we can reserve the GOT and PLT slots and later remove the GOT slots not needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Different address in pointers to the same ifunc function

2 participants