Skip to content

ELF: Only rewrite non-preemptible IFUNCs to IPLT functions if a non-IRELATIVE relocation is needed. #133531

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: users/pcc/spr/main.elf-do-not-rewrite-ifunc-relocations-to-point-to-plt-if-no-gotplt-needed
Choose a base branch
from

Conversation

pcc
Copy link
Contributor

@pcc pcc commented Mar 28, 2025

This is a small optimization if the IFUNC is only address-taken in
globals and never in code, as well as enabling the use of IFUNC to
implement custom relocation types, such as the PAuth relocation types
that will be introduced in a subsequent pull request.

Created using spr 1.3.6-beta.1
@llvmbot
Copy link
Member

llvmbot commented Mar 28, 2025

@llvm/pr-subscribers-lld-elf

@llvm/pr-subscribers-lld

Author: Peter Collingbourne (pcc)

Changes

This enables the use of IFUNC to implement custom relocation types,
such as the PAuth relocation types that will be introduced in a
subsequent pull request.

TODO:

  • Add tests.
  • Fix broken tests.

Full diff: https://github.com/llvm/llvm-project/pull/133531.diff

3 Files Affected:

  • (modified) lld/ELF/Relocations.cpp (+5-3)
  • (modified) lld/ELF/Symbols.h (+2)
  • (modified) lld/ELF/SyntheticSections.cpp (+5-1)
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 629702b45965b..46117a75ccea8 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -869,7 +869,8 @@ static void addRelativeReloc(Ctx &ctx, InputSectionBase &isec,
   // relrDyn sections don't support odd offsets. Also, relrDyn sections
   // don't store the addend values, so we must write it to the relocated
   // address.
-  if (part.relrDyn && isec.addralign >= 2 && offsetInSec % 2 == 0) {
+  if (part.relrDyn && isec.addralign >= 2 && offsetInSec % 2 == 0 &&
+      !sym.isGnuIFunc()) {
     isec.addReloc({expr, type, offsetInSec, addend, &sym});
     if (shard)
       part.relrDyn->relocsVec[parallel::getThreadIndex()].push_back(
@@ -1107,8 +1108,6 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
     }
   } else if (needsPlt(expr)) {
     sym.setFlags(NEEDS_PLT);
-  } else if (LLVM_UNLIKELY(isIfunc)) {
-    sym.setFlags(HAS_DIRECT_RELOC);
   }
 
   // If the relocation is known to be a link-time constant, we know no dynamic
@@ -1194,6 +1193,9 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
     }
   }
 
+  if (LLVM_UNLIKELY(isIfunc && !needsGot(expr) && !needsPlt(expr)))
+    sym.setFlags(HAS_DIRECT_RELOC);
+
   // When producing an executable, we can perform copy relocations (for
   // STT_OBJECT) and canonical PLT (for STT_FUNC) if sym is defined by a DSO.
   // Copy relocations/canonical PLT entries are unsupported for
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index 64f2f6eaa8d09..d4280f367d23b 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -42,6 +42,8 @@ void printTraceSymbol(const Symbol &sym, StringRef name);
 enum {
   NEEDS_GOT = 1 << 0,
   NEEDS_PLT = 1 << 1,
+  // True if this is an ifunc with a direct relocation that cannot be
+  // represented as a RELATIVE relocation.
   HAS_DIRECT_RELOC = 1 << 2,
   // True if this symbol needs a canonical PLT entry, or (during
   // postScanRelocations) a copy relocation.
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index b03c4282ab1aa..afa0482bae3ba 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -1707,9 +1707,13 @@ void RelocationBaseSection::mergeRels() {
 }
 
 void RelocationBaseSection::partitionRels() {
+  const RelType relativeRel = ctx.target->relativeRel;
+  const RelType iRelativeRel = ctx.target->iRelativeRel;
+  for (auto &r : relocs)
+    if (r.type == relativeRel && r.sym->isGnuIFunc())
+      r.type = iRelativeRel;
   if (!combreloc)
     return;
-  const RelType relativeRel = ctx.target->relativeRel;
   numRelativeRelocs =
       std::stable_partition(relocs.begin(), relocs.end(),
                             [=](auto &r) { return r.type == relativeRel; }) -

pcc added a commit to pcc/llvm-project that referenced this pull request Apr 3, 2025
…eeded.

This enables the use of IFUNC to implement custom relocation types,
such as the PAuth relocation types that will be introduced in a
subsequent pull request.

TODO:
- Add tests.
- Fix broken tests.

Pull Request: llvm#133531
pcc added a commit to pcc/llvm-project that referenced this pull request Apr 4, 2025
…eeded.

This enables the use of IFUNC to implement custom relocation types,
such as the PAuth relocation types that will be introduced in a
subsequent pull request.

TODO:
- Add tests.
- Fix broken tests.

Pull Request: llvm#133531
@pcc
Copy link
Contributor Author

pcc commented Apr 9, 2025

This patch has a few problems

  • The check in processAux was moved to the wrong place (it will never get hit because this is after we deal with all symbols not defined locally). This patch moves it to approximately the right place but will need some logic changes to isStaticLinkTimeConstant to recognize ifuncs as not being static link time constants:
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 1439fd859f51..969d71461cb1 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1127,6 +1127,8 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
   // handling of GOT-generating relocations.
   if (isStaticLinkTimeConstant(expr, type, sym, offset) ||
       (!ctx.arg.isPic && sym.isUndefWeak())) {
+    if (LLVM_UNLIKELY(isIfunc && !needsGot(expr) && !needsPlt(expr)))
+      sym.setFlags(HAS_DIRECT_RELOC);
     sec->addReloc({expr, type, offset, addend, &sym});
     return;
   }
@@ -1194,9 +1196,6 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
     }
   }
 
-  if (LLVM_UNLIKELY(isIfunc && !needsGot(expr) && !needsPlt(expr)))
-    sym.setFlags(HAS_DIRECT_RELOC);
-
   // When producing an executable, we can perform copy relocations (for
   // STT_OBJECT) and canonical PLT (for STT_FUNC) if sym is defined by a DSO.
   // Copy relocations/canonical PLT entries are unsupported for
  • Need to adjust how IRELATIVE relocations get emitted. Currently we emit relocations with the wrong type (assuming they will be demoted) and fix up the type in RelocationBaseSection::partitionRels if they turn out to not be demoted. But this isn't good enough for PDEs which need them to be static relocations. Here's what I think we should do instead:
    • Always emit ifunc relocations as IRELATIVE during processAux
    • In handleNonPreemptibleIfunc, when we demote an ifunc to an iplt entry, loop over all irelatives pointing to the symbol and rewrite them as either relative (for PIE/shared) or static relocations (for PDE). It's fine to loop over the irelatives every time because they are rare.

Created using spr 1.3.6-beta.1
@pcc pcc changed the title ELF: Do not rewrite IFUNC relocations to point to PLT if no GOT/PLT needed. ELF: Only rewrite non-preemptible IFUNCs to IPLT functions if a non-IRELATIVE relocation is needed. Apr 10, 2025
@pcc
Copy link
Contributor Author

pcc commented Apr 10, 2025

This patch has a few problems

  • The check in processAux was moved to the wrong place (it will never get hit because this is after we deal with all symbols not defined locally). This patch moves it to approximately the right place but will need some logic changes to isStaticLinkTimeConstant to recognize ifuncs as not being static link time constants:
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 1439fd859f51..969d71461cb1 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1127,6 +1127,8 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
   // handling of GOT-generating relocations.
   if (isStaticLinkTimeConstant(expr, type, sym, offset) ||
       (!ctx.arg.isPic && sym.isUndefWeak())) {
+    if (LLVM_UNLIKELY(isIfunc && !needsGot(expr) && !needsPlt(expr)))
+      sym.setFlags(HAS_DIRECT_RELOC);
     sec->addReloc({expr, type, offset, addend, &sym});
     return;
   }
@@ -1194,9 +1196,6 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
     }
   }
 
-  if (LLVM_UNLIKELY(isIfunc && !needsGot(expr) && !needsPlt(expr)))
-    sym.setFlags(HAS_DIRECT_RELOC);
-
   // When producing an executable, we can perform copy relocations (for
   // STT_OBJECT) and canonical PLT (for STT_FUNC) if sym is defined by a DSO.
   // Copy relocations/canonical PLT entries are unsupported for
  • Need to adjust how IRELATIVE relocations get emitted. Currently we emit relocations with the wrong type (assuming they will be demoted) and fix up the type in RelocationBaseSection::partitionRels if they turn out to not be demoted. But this isn't good enough for PDEs which need them to be static relocations. Here's what I think we should do instead:

    • Always emit ifunc relocations as IRELATIVE during processAux
    • In handleNonPreemptibleIfunc, when we demote an ifunc to an iplt entry, loop over all irelatives pointing to the symbol and rewrite them as either relative (for PIE/shared) or static relocations (for PDE). It's fine to loop over the irelatives every time because they are rare.

All of this is done in the latest change (except that I decided to handle the demotion in a separate loop instead of handleNonPreemptibleIfunc, PTAL

@pcc pcc requested review from MaskRay and smithp35 April 10, 2025 03:20
Created using spr 1.3.6-beta.1
@MaskRay
Copy link
Member

MaskRay commented Apr 10, 2025

I’m worried about the added complexity of ifunc and the extra parameter in isStaticLinkTimeConstant, a key component of relocation scanning where performance is critical. (Our scanning process is already noticeably slower than mold’s, and these factors are contributing to the gap.)

If the security hardening efforts rely on ifunc, I’d strongly suggest reconsidering this approach.

What’s the next PR in line? If the goal of increasing ifunc adoption is to avoid updating rtld/libc, I don’t see that as a practical solution, and I’d strongly push back against linker changes. We should focus on improving rtld/libc instead. See: https://sourceware.org/bugzilla/show_bug.cgi?id=31959"

@pcc
Copy link
Contributor Author

pcc commented Apr 10, 2025

I’m worried about the added complexity of ifunc and the extra parameter in isStaticLinkTimeConstant, a key component of relocation scanning where performance is critical. (Our scanning process is already noticeably slower than mold’s, and these factors are contributing to the gap.)

Fair enough, I will check the performance after this patch.

If the security hardening efforts rely on ifunc, I’d strongly suggest reconsidering this approach.

It's not so much "rely" but that the alternatives have downsides that IMO end up making them worse than the ifunc approach.

What’s the next PR in line?

Here is the list: Structure Protection

If the goal of increasing ifunc adoption is to avoid updating rtld/libc, I don’t see that as a practical solution, and I’d strongly push back against linker changes. We should focus on improving rtld/libc instead. See: https://sourceware.org/bugzilla/show_bug.cgi?id=31959"

On the contrary, I see it as more practical than the alternatives.

If avoiding upgrades were the only reason for this change, I agree with you that we should be looking at a static-pie based approach instead. We may even consider dropping #133532 as it may be possible to develop another solution that uses the static-pie approach.

The main reason for supporting this use case for ifuncs is to decouple the pointer encoding scheme (which is a compiler implementation detail) from the dynamic loader. For pointer field protection we have these requirements:

  • Be able to use deactivation symbols to deactivate pointer encoding in other object files.
  • Be able to use arbitrary pointer encoding schemes as part of the non-arm64 support.

The following alternatives were considered:

  • Have the compiler generate code in .init_array.0 to initialize the fields. This has the downside of making parts of .data.rel.ro writable which goes against the overall goal of improving security. Doing things this way might work if we unprotect relro, apply the pseudo-relocations and protect again, but this would need to be done once for the whole binary to avoid substantial startup overhead, and there may be restrictions such as mseal that prevent this from working. This is probably what I'll do if I get too much pushback from this approach, it looks like glibc will support opting out of mseal.
  • Introduce a new relocation format that would allow specifying a deactivation symbol (two operands to a relocation). This would introduce a substantial burden on linkers due to the new relocation encoding with an additional operand and would still not give us a flexible pointer encoding.
  • Introduce new relocation types for every new encoding that may be used (combined with the new relocation format). This would substantially reduce our velocity as the new encodings would need to be agreed on by every supported non-arm64 psabi, as well as introducing complexity to linkers as they would need to know about every new relocation type used for encodings (this would be basically like introducing a new R_AARCH64_AUTH_ABS64/R_AARCH64_AUTH_RELATIVE pair every time).

Copy link
Collaborator

@smithp35 smithp35 left a comment

Choose a reason for hiding this comment

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

How does this work in the non-PIE (PDE) case when we take the address of an ifunc and pass it to a function in a shared library, which then compares the argument with its own global address take of the ifunc?

For example:
shared lib

typedef void Fptr(void);
extern void ifn(void);

// take address of ifunc ifn defined in application
Fptr* ifp = &ifn;

// compare address of ifn we have calculated in ifp vs
// address calculated by application, passed in fp1.
int compare(Fptr* fp1) {
  return fp1 == ifp;
}

App

typedef void Fptr(void);
extern int compare(Fptr* fp1);
int val = 0;
static void impl(void) { val = 42; }
static void *resolver(void) { return impl; }
__attribute__((ifunc("resolver"))) void *ifn();

extern Fptr* fp;

int main(void) {
  return compare(fp);
}
// separate file so compiler is unaware ifn is an ifunc.
typedef void Fptr(void);
extern void ifn(void);
Fptr* fp = &ifn;

Right now in the application lld produces an iPLT entry for ifn, with fp pointing to the iPLT entry. The dynamic symbol table contains the address of the iPLT entry with type STT_FUNC . The shared library and the argument compare equal.

As I understand it, this patch will change fp to point directly to the result of the ifunc resolver. So unless we also change the value put into the dynamic symbol table we'll stop comparing equal.

I don't think there's a STT_FUNC symbol we can put in the dynamic symbol table that holds the result of the ifunc resolver. GNU ld, puts the address of the resolver function with a STT_GNU_IFUNC symbol type in the dynamic symbol table. If that causes the dynamic loader to call the resolver and replace the value with the result then that would work. I haven't had time to check what glibc does though.

I'll put some more general comments below. Didn't want to make this one too long.

@@ -1761,6 +1761,9 @@ void RelocationBaseSection::computeRels() {
llvm::sort(nonRelative, irelative, [&](auto &a, auto &b) {
return std::tie(a.r_sym, a.r_offset) < std::tie(b.r_sym, b.r_offset);
});
llvm::sort(irelative, relocs.end(), [&](auto &a, auto &b) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could be worth updating the comment on line 1753, which doesn't mention irelative after non-irelative. If the r_offset is not just for readability it will be worth updating that too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For the irelative relocations it's also needed for output determinism. Added a comment explaining that.

@@ -42,6 +42,8 @@ void printTraceSymbol(const Symbol &sym, StringRef name);
enum {
NEEDS_GOT = 1 << 0,
NEEDS_PLT = 1 << 1,
// True if this is an ifunc with a direct relocation that cannot be
Copy link
Collaborator

Choose a reason for hiding this comment

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

Although not new, could be worth expanding on what a direct relocation is in the comment. Could be just direct (non GOT or PLT generating) relocation ...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

// symbols, move IRELATIVE relocations to the right place:
// - Relocations for non-demoted ifuncs are added to .rela.dyn
// - Relocations for demoted ifuncs are turned into RELATIVE relocations
// or static relocations in PDEs
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could you expand the acronym? I think this means Position Dependent Executable (PDE). It isn't used anywhere else in the codebase, and while derivable made me stop and think of alternatives.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@smithp35
Copy link
Collaborator

I have some small reservations about using ifunc resolvers like this. Mostly in that we are using a mechanism invented for a different purpose, and relying on some specific linker behaviour to make this case work.

This is similar to comments made in the Discourse post https://discourse.llvm.org/t/rfc-structure-protection-a-family-of-uaf-mitigation-techniques/85555/9 but repeating them here as this is closest to the implementation.

As I understand it, this has a more limited and more specific use case than ifuncs. Traditional ifuncs which can be address taken or called, possibly in multiple ways, so it makes sense to use a symbol type STT_GNU_IFUNC rather than special relocation directives. The initializers for structure field protection are compiler generated, can not be legally called or address taken from user code, and only have one relocation type R_ABS64 (or 32 on a 32-bit platform). With an addition of a single relocation, something like R_ADDRINIT64 which would target a STT_FUNC resolver symbol. We can isolate the structure field initialization use case from an actual ifunc.

I guess it all comes down to whether structure field initialization needs, or benefits from being distinguished from an ifunc. Ifuncs seem to be quite easy to get wrong so being able to isolate this case has some attraction to me at least. It also handles the structure field that points to an ifunc relatively gracefully.

As you pointed out in your response, this does mean adding 2 relocations to every psABI that supports structure field protection rather than just one. Although I'd expect the alternative of having relocations that alternatively write "directly call" ifunc resolver or take address of function might require new relocations too?

@pcc
Copy link
Contributor Author

pcc commented Apr 10, 2025

How does this work in the non-PIE (PDE) case when we take the address of an ifunc and pass it to a function in a shared library, which then compares the argument with its own global address take of the ifunc?

For example: shared lib

typedef void Fptr(void);
extern void ifn(void);

// take address of ifunc ifn defined in application
Fptr* ifp = &ifn;

// compare address of ifn we have calculated in ifp vs
// address calculated by application, passed in fp1.
int compare(Fptr* fp1) {
  return fp1 == ifp;
}

App

typedef void Fptr(void);
extern int compare(Fptr* fp1);
int val = 0;
static void impl(void) { val = 42; }
static void *resolver(void) { return impl; }
__attribute__((ifunc("resolver"))) void *ifn();

extern Fptr* fp;

int main(void) {
  return compare(fp);
}
// separate file so compiler is unaware ifn is an ifunc.
typedef void Fptr(void);
extern void ifn(void);
Fptr* fp = &ifn;

Right now in the application lld produces an iPLT entry for ifn, with fp pointing to the iPLT entry. The dynamic symbol table contains the address of the iPLT entry with type STT_FUNC . The shared library and the argument compare equal.

As I understand it, this patch will change fp to point directly to the result of the ifunc resolver. So unless we also change the value put into the dynamic symbol table we'll stop comparing equal.

I don't think there's a STT_FUNC symbol we can put in the dynamic symbol table that holds the result of the ifunc resolver. GNU ld, puts the address of the resolver function with a STT_GNU_IFUNC symbol type in the dynamic symbol table. If that causes the dynamic loader to call the resolver and replace the value with the result then that would work. I haven't had time to check what glibc does though.

If a dynamic loader sees a symbol with type STT_GNU_IFUNC it will indeed call the resolver and use the return value when resolving relocations involving that symbol. You can see this behavior in glibc e.g. elf_machine_rela function in sysdeps/aarch64/dl-machine.h and bionic in the resolve_symbol_address function in bionic/linker/linker_soinfo.h. So in your example we will end up with resolver being called twice: once for the R_AARCH64_ABS64 in the ifp initializer and once for the R_AARCH64_IRELATIVE in the fp initializer. So the comparison should still succeed.

@jrtc27
Copy link
Collaborator

jrtc27 commented Apr 10, 2025

The canonical PLT is for

int main(void) {
  return compare(&ifp);
}

in code models where the address is computed inline (absolute or PC-relative) rather than as an indirect load (whether from a global or a GOT entry).

I like to think of canonical PLTs as the function version of copy relocations.

@pcc
Copy link
Contributor Author

pcc commented Apr 10, 2025

I have some small reservations about using ifunc resolvers like this. Mostly in that we are using a mechanism invented for a different purpose, and relying on some specific linker behaviour to make this case work.

This is similar to comments made in the Discourse post https://discourse.llvm.org/t/rfc-structure-protection-a-family-of-uaf-mitigation-techniques/85555/9 but repeating them here as this is closest to the implementation.

As I understand it, this has a more limited and more specific use case than ifuncs. Traditional ifuncs which can be address taken or called, possibly in multiple ways, so it makes sense to use a symbol type STT_GNU_IFUNC rather than special relocation directives. The initializers for structure field protection are compiler generated, can not be legally called or address taken from user code, and only have one relocation type R_ABS64 (or 32 on a 32-bit platform). With an addition of a single relocation, something like R_ADDRINIT64 which would target a STT_FUNC resolver symbol. We can isolate the structure field initialization use case from an actual ifunc.

I see, so the idea would be that an ADDRINIT64 pointing to an STT_FUNC would generate an IRELATIVE pointing to the symbol address if the symbol is non-preemptible and result in a linker error otherwise.

I guess it all comes down to whether structure field initialization needs, or benefits from being distinguished from an ifunc. Ifuncs seem to be quite easy to get wrong so being able to isolate this case has some attraction to me at least. It also handles the structure field that points to an ifunc relatively gracefully.

I don't necessarily see usage errors as a convincing argument for ADDRINIT64. Because the relocations and resolvers are compiler generated (and the resolvers cannot be named by the user due to the use of local symbols) it is hard to commit a usage error if you are not a compiler developer who is expected to know what they are doing.

I do think that there are two convincing arguments for ADDRINIT64:

  • We want linkers that do not support the new behavior to loudly error out instead of silently generating incorrect code. You'll note that this is the same argument that justifies INST32 (or whatever we end up calling it) when ABS32 already exists and could be made to retrofit the semantics that we want.
  • It reduces linker complexity because the IRELATIVE relocations can be added in a single pass.

As you pointed out in your response, this does mean adding 2 relocations to every psABI that supports structure field protection rather than just one. Although I'd expect the alternative of having relocations that alternatively write "directly call" ifunc resolver or take address of function might require new relocations too?

Yes, we'd still the relocation to select between calling the resolver and taking the address unless we decide to not support other use cases for the inner ifuncs (in which case we'd just generate code to take the address and the IPLT would be used as the address of affected ifuncs). This may be fine as it's the status quo for ifuncs referred to by an ABS64.

Created using spr 1.3.6-beta.1
@smithp35
Copy link
Collaborator

I had been assuming that this patch didn't change lld behaviour from the comment in handleNonPreemptibleIfunc()

I've had some time to build and run lld on my example with this change and I notice that with this change I'm seeing the dynamic symbol table use the ifunc resolver.

     7: 0000000000210814    12 IFUNC   GLOBAL DEFAULT    14 ifn

Whereas my old lld uses

     7: 00000000002108d0     0 FUNC    GLOBAL DEFAULT   18 ifn

So as you say this will work and the comparison will go through OK. With that in mind this might be part of the reason why 3 tests are failing (visible in the CI):
lld :: ELF/gnu-ifunc-canon.s
lld :: ELF/ppc32-ifunc-nonpreemptible-pic.s
lld :: ELF/ppc64-toc-relax-ifunc.s
The last one (ppc64...) looks to be crashing.

Will be good to update the comment in handleNonPreemptibleIfunc() https://github.com/llvm/llvm-project/blob/main/lld/ELF/Relocations.cpp#L1759

@smithp35
Copy link
Collaborator

As a FYI, I'll be out of office till after Easter, so I may not be able to respond next week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

5 participants