Skip to content

Conversation

@pcc
Copy link
Contributor

@pcc pcc commented Sep 3, 2025

R_AARCH64_FUNCINIT64 is a dynamic relocation type for relocating
word-sized data in the output file using the return value of
a function. An R_AARCH64_FUNCINIT64 shall be relocated as an
R_AARCH64_IRELATIVE with the target symbol address if the target
symbol is non-preemptible, and it shall be a usage error to relocate an
R_AARCH64_FUNCINIT64 with a preemptible or STT_GNU_IFUNC target symbol.

The initial use case for this relocation type shall be for emitting
global variable field initializers for structure protection. With
structure protection, the relocation value computation is tied to the
compiler implementation in such a way that it would not be reasonable to
define a relocation type for it (for example, it may involve computing
a hash using a compiler-determined algorithm), hence the need for the
computation to be implemented as code in the binary.

Part of the AArch64 psABI extension:
ARM-software/abi-aa#340

pcc added 2 commits September 2, 2025 18:27
Created using spr 1.3.6-beta.1

[skip ci]
Created using spr 1.3.6-beta.1
Created using spr 1.3.6-beta.1
pcc added 2 commits October 9, 2025 14:43
Created using spr 1.3.6-beta.1

[skip ci]
Created using spr 1.3.6-beta.1
@llvmbot
Copy link
Member

llvmbot commented Oct 9, 2025

@llvm/pr-subscribers-lld-elf

Author: Peter Collingbourne (pcc)

Changes

R_AARCH64_FUNCINIT64 is a dynamic relocation type for relocating
word-sized data in the output file using the return value of
a function. An R_AARCH64_FUNCINIT64 shall be relocated as an
R_AARCH64_IRELATIVE with the target symbol address if the target
symbol is non-preemptible, and it shall be a usage error to relocate an
R_AARCH64_FUNCINIT64 with a preemptible or STT_GNU_IFUNC target symbol.

The initial use case for this relocation type shall be for emitting
global variable field initializers for structure protection. With
structure protection, the relocation value computation is tied to the
compiler implementation in such a way that it would not be reasonable to
define a relocation type for it (for example, it may involve computing
a hash using a compiler-determined algorithm), hence the need for the
computation to be implemented as code in the binary.

Part of the AArch64 psABI extension:
ARM-software/abi-aa#340


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

5 Files Affected:

  • (modified) lld/ELF/Arch/AArch64.cpp (+4-1)
  • (modified) lld/ELF/Relocations.cpp (+19-2)
  • (modified) lld/ELF/Target.h (+1)
  • (added) lld/test/ELF/aarch64-funcinit64-invalid.s (+18)
  • (added) lld/test/ELF/aarch64-funcinit64.s (+19)
diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index 2a97df4785ecb..7a7b8380fc533 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -114,6 +114,7 @@ AArch64::AArch64(Ctx &ctx) : TargetInfo(ctx) {
   copyRel = R_AARCH64_COPY;
   relativeRel = R_AARCH64_RELATIVE;
   iRelativeRel = R_AARCH64_IRELATIVE;
+  iRelSymbolicRel = R_AARCH64_FUNCINIT64;
   gotRel = R_AARCH64_GLOB_DAT;
   pltRel = R_AARCH64_JUMP_SLOT;
   symbolicRel = R_AARCH64_ABS64;
@@ -137,6 +138,7 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
   case R_AARCH64_ABS16:
   case R_AARCH64_ABS32:
   case R_AARCH64_ABS64:
+  case R_AARCH64_FUNCINIT64:
   case R_AARCH64_ADD_ABS_LO12_NC:
   case R_AARCH64_LDST128_ABS_LO12_NC:
   case R_AARCH64_LDST16_ABS_LO12_NC:
@@ -267,7 +269,8 @@ bool AArch64::usesOnlyLowPageBits(RelType type) const {
 }
 
 RelType AArch64::getDynRel(RelType type) const {
-  if (type == R_AARCH64_ABS64 || type == R_AARCH64_AUTH_ABS64)
+  if (type == R_AARCH64_ABS64 || type == R_AARCH64_AUTH_ABS64 ||
+      type == R_AARCH64_FUNCINIT64)
     return type;
   return R_AARCH64_NONE;
 }
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 84b9b5e983662..e702b6f03fb19 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -968,8 +968,8 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
   // only the low bits are used.
   if (e == R_GOT || e == R_PLT)
     return ctx.target->usesOnlyLowPageBits(type) || !ctx.arg.isPic;
-  // R_AARCH64_AUTH_ABS64 requires a dynamic relocation.
-  if (e == RE_AARCH64_AUTH)
+  // R_AARCH64_AUTH_ABS64 and iRelSymbolicRel require a dynamic relocation.
+  if (e == RE_AARCH64_AUTH || type == ctx.target->iRelSymbolicRel)
     return false;
 
   // The behavior of an undefined weak reference is implementation defined.
@@ -1142,6 +1142,23 @@ void RelocationScanner::process(RelExpr expr, RelType type, uint64_t offset,
         }
         return;
       }
+      if (LLVM_UNLIKELY(type == ctx.target->iRelSymbolicRel)) {
+        if (sym.isPreemptible) {
+          auto diag = Err(ctx);
+          diag << "relocation " << type
+               << " cannot be used against preemptible symbol '" << &sym << "'";
+          printLocation(diag, *sec, sym, offset);
+        } else if (isIfunc) {
+          auto diag = Err(ctx);
+          diag << "relocation " << type
+               << " cannot be used against ifunc symbol '" << &sym << "'";
+          printLocation(diag, *sec, sym, offset);
+        } else {
+          part.relaDyn->addReloc({ctx.target->iRelativeRel, sec, offset, false,
+                                  sym, addend, R_ABS});
+          return;
+        }
+      }
       part.relaDyn->addSymbolReloc(rel, *sec, offset, sym, addend, type);
 
       // MIPS ABI turns using of GOT and dynamic relocations inside out.
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index 9f0605138a4fb..f68ddf0e02a94 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -135,6 +135,7 @@ class TargetInfo {
   RelType relativeRel = 0;
   RelType iRelativeRel = 0;
   RelType symbolicRel = 0;
+  RelType iRelSymbolicRel = 0;
   RelType tlsDescRel = 0;
   RelType tlsGotRel = 0;
   RelType tlsModuleIndexRel = 0;
diff --git a/lld/test/ELF/aarch64-funcinit64-invalid.s b/lld/test/ELF/aarch64-funcinit64-invalid.s
new file mode 100644
index 0000000000000..4577db7429773
--- /dev/null
+++ b/lld/test/ELF/aarch64-funcinit64-invalid.s
@@ -0,0 +1,18 @@
+# REQUIRES: aarch64
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o
+# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck --check-prefix=ERR %s
+
+.rodata
+# ERR: error: relocation R_AARCH64_FUNCINIT64 cannot be used against local symbol
+.8byte func@FUNCINIT
+
+.data
+# ERR: error: relocation R_AARCH64_FUNCINIT64 cannot be used against ifunc symbol 'ifunc'
+.8byte ifunc@FUNCINIT
+
+.text
+func:
+.type ifunc, @gnu_indirect_function
+ifunc:
+ret
diff --git a/lld/test/ELF/aarch64-funcinit64.s b/lld/test/ELF/aarch64-funcinit64.s
new file mode 100644
index 0000000000000..5f2b863ee884b
--- /dev/null
+++ b/lld/test/ELF/aarch64-funcinit64.s
@@ -0,0 +1,19 @@
+# REQUIRES: aarch64
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-readelf -s -r %t | FileCheck %s
+# RUN: ld.lld %t.o -o %t -pie
+# RUN: llvm-readelf -s -r %t | FileCheck %s
+# RUN: not ld.lld %t.o -o %t -shared 2>&1 | FileCheck --check-prefix=ERR %s
+
+.data
+# CHECK: R_AARCH64_IRELATIVE [[FOO:[0-9a-f]*]]
+# ERR: relocation R_AARCH64_FUNCINIT64 cannot be used against preemptible symbol 'foo'
+.8byte foo@FUNCINIT
+
+.text
+# CHECK: {{0*}}[[FOO]] {{.*}} foo
+.globl foo
+foo:
+ret

@llvmbot
Copy link
Member

llvmbot commented Oct 9, 2025

@llvm/pr-subscribers-lld

Author: Peter Collingbourne (pcc)

Changes

R_AARCH64_FUNCINIT64 is a dynamic relocation type for relocating
word-sized data in the output file using the return value of
a function. An R_AARCH64_FUNCINIT64 shall be relocated as an
R_AARCH64_IRELATIVE with the target symbol address if the target
symbol is non-preemptible, and it shall be a usage error to relocate an
R_AARCH64_FUNCINIT64 with a preemptible or STT_GNU_IFUNC target symbol.

The initial use case for this relocation type shall be for emitting
global variable field initializers for structure protection. With
structure protection, the relocation value computation is tied to the
compiler implementation in such a way that it would not be reasonable to
define a relocation type for it (for example, it may involve computing
a hash using a compiler-determined algorithm), hence the need for the
computation to be implemented as code in the binary.

Part of the AArch64 psABI extension:
ARM-software/abi-aa#340


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

5 Files Affected:

  • (modified) lld/ELF/Arch/AArch64.cpp (+4-1)
  • (modified) lld/ELF/Relocations.cpp (+19-2)
  • (modified) lld/ELF/Target.h (+1)
  • (added) lld/test/ELF/aarch64-funcinit64-invalid.s (+18)
  • (added) lld/test/ELF/aarch64-funcinit64.s (+19)
diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index 2a97df4785ecb..7a7b8380fc533 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -114,6 +114,7 @@ AArch64::AArch64(Ctx &ctx) : TargetInfo(ctx) {
   copyRel = R_AARCH64_COPY;
   relativeRel = R_AARCH64_RELATIVE;
   iRelativeRel = R_AARCH64_IRELATIVE;
+  iRelSymbolicRel = R_AARCH64_FUNCINIT64;
   gotRel = R_AARCH64_GLOB_DAT;
   pltRel = R_AARCH64_JUMP_SLOT;
   symbolicRel = R_AARCH64_ABS64;
@@ -137,6 +138,7 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
   case R_AARCH64_ABS16:
   case R_AARCH64_ABS32:
   case R_AARCH64_ABS64:
+  case R_AARCH64_FUNCINIT64:
   case R_AARCH64_ADD_ABS_LO12_NC:
   case R_AARCH64_LDST128_ABS_LO12_NC:
   case R_AARCH64_LDST16_ABS_LO12_NC:
@@ -267,7 +269,8 @@ bool AArch64::usesOnlyLowPageBits(RelType type) const {
 }
 
 RelType AArch64::getDynRel(RelType type) const {
-  if (type == R_AARCH64_ABS64 || type == R_AARCH64_AUTH_ABS64)
+  if (type == R_AARCH64_ABS64 || type == R_AARCH64_AUTH_ABS64 ||
+      type == R_AARCH64_FUNCINIT64)
     return type;
   return R_AARCH64_NONE;
 }
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 84b9b5e983662..e702b6f03fb19 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -968,8 +968,8 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
   // only the low bits are used.
   if (e == R_GOT || e == R_PLT)
     return ctx.target->usesOnlyLowPageBits(type) || !ctx.arg.isPic;
-  // R_AARCH64_AUTH_ABS64 requires a dynamic relocation.
-  if (e == RE_AARCH64_AUTH)
+  // R_AARCH64_AUTH_ABS64 and iRelSymbolicRel require a dynamic relocation.
+  if (e == RE_AARCH64_AUTH || type == ctx.target->iRelSymbolicRel)
     return false;
 
   // The behavior of an undefined weak reference is implementation defined.
@@ -1142,6 +1142,23 @@ void RelocationScanner::process(RelExpr expr, RelType type, uint64_t offset,
         }
         return;
       }
+      if (LLVM_UNLIKELY(type == ctx.target->iRelSymbolicRel)) {
+        if (sym.isPreemptible) {
+          auto diag = Err(ctx);
+          diag << "relocation " << type
+               << " cannot be used against preemptible symbol '" << &sym << "'";
+          printLocation(diag, *sec, sym, offset);
+        } else if (isIfunc) {
+          auto diag = Err(ctx);
+          diag << "relocation " << type
+               << " cannot be used against ifunc symbol '" << &sym << "'";
+          printLocation(diag, *sec, sym, offset);
+        } else {
+          part.relaDyn->addReloc({ctx.target->iRelativeRel, sec, offset, false,
+                                  sym, addend, R_ABS});
+          return;
+        }
+      }
       part.relaDyn->addSymbolReloc(rel, *sec, offset, sym, addend, type);
 
       // MIPS ABI turns using of GOT and dynamic relocations inside out.
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index 9f0605138a4fb..f68ddf0e02a94 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -135,6 +135,7 @@ class TargetInfo {
   RelType relativeRel = 0;
   RelType iRelativeRel = 0;
   RelType symbolicRel = 0;
+  RelType iRelSymbolicRel = 0;
   RelType tlsDescRel = 0;
   RelType tlsGotRel = 0;
   RelType tlsModuleIndexRel = 0;
diff --git a/lld/test/ELF/aarch64-funcinit64-invalid.s b/lld/test/ELF/aarch64-funcinit64-invalid.s
new file mode 100644
index 0000000000000..4577db7429773
--- /dev/null
+++ b/lld/test/ELF/aarch64-funcinit64-invalid.s
@@ -0,0 +1,18 @@
+# REQUIRES: aarch64
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o
+# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck --check-prefix=ERR %s
+
+.rodata
+# ERR: error: relocation R_AARCH64_FUNCINIT64 cannot be used against local symbol
+.8byte func@FUNCINIT
+
+.data
+# ERR: error: relocation R_AARCH64_FUNCINIT64 cannot be used against ifunc symbol 'ifunc'
+.8byte ifunc@FUNCINIT
+
+.text
+func:
+.type ifunc, @gnu_indirect_function
+ifunc:
+ret
diff --git a/lld/test/ELF/aarch64-funcinit64.s b/lld/test/ELF/aarch64-funcinit64.s
new file mode 100644
index 0000000000000..5f2b863ee884b
--- /dev/null
+++ b/lld/test/ELF/aarch64-funcinit64.s
@@ -0,0 +1,19 @@
+# REQUIRES: aarch64
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-readelf -s -r %t | FileCheck %s
+# RUN: ld.lld %t.o -o %t -pie
+# RUN: llvm-readelf -s -r %t | FileCheck %s
+# RUN: not ld.lld %t.o -o %t -shared 2>&1 | FileCheck --check-prefix=ERR %s
+
+.data
+# CHECK: R_AARCH64_IRELATIVE [[FOO:[0-9a-f]*]]
+# ERR: relocation R_AARCH64_FUNCINIT64 cannot be used against preemptible symbol 'foo'
+.8byte foo@FUNCINIT
+
+.text
+# CHECK: {{0*}}[[FOO]] {{.*}} foo
+.globl foo
+foo:
+ret

@pcc
Copy link
Contributor Author

pcc commented Oct 14, 2025

Ping, now unblocked

@pcc pcc requested a review from fmayer October 23, 2025 00:37
Copy link
Contributor

@fmayer fmayer left a comment

Choose a reason for hiding this comment

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

lgtm

Created using spr 1.3.6-beta.1
@pcc pcc changed the base branch from users/pcc/spr/main.elf-add-support-for-relocating-r_aarch64_funcinit64 to main November 19, 2025 19:44
@pcc pcc merged commit 13e09eb into main Nov 19, 2025
2 checks passed
@pcc pcc deleted the users/pcc/spr/elf-add-support-for-relocating-r_aarch64_funcinit64 branch November 19, 2025 19:44
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Nov 19, 2025
R_AARCH64_FUNCINIT64 is a dynamic relocation type for relocating
word-sized data in the output file using the return value of
a function. An R_AARCH64_FUNCINIT64 shall be relocated as an
R_AARCH64_IRELATIVE with the target symbol address if the target
symbol is non-preemptible, and it shall be a usage error to relocate an
R_AARCH64_FUNCINIT64 with a preemptible or STT_GNU_IFUNC target symbol.

The initial use case for this relocation type shall be for emitting
global variable field initializers for structure protection. With
structure protection, the relocation value computation is tied to the
compiler implementation in such a way that it would not be reasonable to
define a relocation type for it (for example, it may involve computing
a hash using a compiler-determined algorithm), hence the need for the
computation to be implemented as code in the binary.

Part of the AArch64 psABI extension:
ARM-software/abi-aa#340

Reviewers: smithp35, fmayer, MaskRay

Reviewed By: fmayer

Pull Request: llvm/llvm-project#156564
@MaskRay
Copy link
Member

MaskRay commented Nov 20, 2025

The patch looks good after the fact. I was waiting on smithp35...

We wish the last few events hadn't played out like this...

requested a review from fmayer last month
fmayer approved these changes 11 hours ago (Nov 19, 2025, 11:23 AM PST)
merged commit into main 11 hours ago (Wed Nov 19 11:44:09 2025)

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.

My apologies I didn't realise it was waiting on me. I may have just missed it. If anyone is waiting on me and I'm not responding, please do give me a ping.

No objections on my side for this.

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

Projects

Development

Successfully merging this pull request may close these issues.

6 participants