-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[PAC][lld][AArch64][ELF] Support signed GOT #96169
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
Conversation
Support `R_AARCH64_AUTH_ADR_GOT_PAGE`, `R_AARCH64_AUTH_GOT_LO12_NC` and `R_AARCH64_AUTH_GOT_ADD_LO12_NC` GOT-generating relocations. For preemptible symbols, dynamic relocation `R_AARCH64_AUTH_GLOB_DAT` is emitted. Otherwise, we unconditionally emit `R_AARCH64_AUTH_RELATIVE` dynamic relocation since pointers in signed GOT needs to be signed during dynamic link time.
@llvm/pr-subscribers-lld @llvm/pr-subscribers-lld-elf Author: Daniil Kovalev (kovdan01) ChangesDepends on #96164 Support Full diff: https://github.com/llvm/llvm-project/pull/96169.diff 8 Files Affected:
diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index 47e6ea1ff7756..45d21e777f2d8 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -169,11 +169,16 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
case R_AARCH64_LD64_GOT_LO12_NC:
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
return R_GOT;
+ case R_AARCH64_AUTH_GOT_LO12_NC:
+ case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
+ return R_AARCH64_AUTH_GOT;
case R_AARCH64_LD64_GOTPAGE_LO15:
return R_AARCH64_GOT_PAGE;
case R_AARCH64_ADR_GOT_PAGE:
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
return R_AARCH64_GOT_PAGE_PC;
+ case R_AARCH64_AUTH_ADR_GOT_PAGE:
+ return R_AARCH64_AUTH_GOT_PAGE_PC;
case R_AARCH64_GOTPCREL32:
case R_AARCH64_GOT_LD_PREL19:
return R_GOT_PC;
@@ -225,6 +230,7 @@ int64_t AArch64::getImplicitAddend(const uint8_t *buf, RelType type) const {
return read64(buf + 8);
case R_AARCH64_NONE:
case R_AARCH64_GLOB_DAT:
+ case R_AARCH64_AUTH_GLOB_DAT:
case R_AARCH64_JUMP_SLOT:
return 0;
case R_AARCH64_ABS16:
@@ -430,9 +436,11 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
write64(loc, val);
break;
case R_AARCH64_ADD_ABS_LO12_NC:
+ case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
or32AArch64Imm(loc, val);
break;
case R_AARCH64_ADR_GOT_PAGE:
+ case R_AARCH64_AUTH_ADR_GOT_PAGE:
case R_AARCH64_ADR_PREL_PG_HI21:
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
case R_AARCH64_TLSDESC_ADR_PAGE21:
@@ -482,6 +490,7 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
break;
case R_AARCH64_LDST64_ABS_LO12_NC:
case R_AARCH64_LD64_GOT_LO12_NC:
+ case R_AARCH64_AUTH_GOT_LO12_NC:
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
case R_AARCH64_TLSDESC_LD64_LO12:
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index be12218d9948c..f3b54e7f72855 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -694,6 +694,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
case R_ARM_SBREL:
return sym.getVA(a) - getARMStaticBase(sym);
case R_GOT:
+ case R_AARCH64_AUTH_GOT:
case R_RELAX_TLS_GD_TO_IE_ABS:
return sym.getGotVA() + a;
case R_LOONGARCH_GOT:
@@ -721,6 +722,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
return sym.getGotOffset() + a;
case R_AARCH64_GOT_PAGE_PC:
+ case R_AARCH64_AUTH_GOT_PAGE_PC:
case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
return getAArch64Page(sym.getGotVA() + a) - getAArch64Page(p);
case R_AARCH64_GOT_PAGE:
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 1b08339e3996a..5840b8ead5af0 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -209,8 +209,9 @@ static bool needsPlt(RelExpr expr) {
}
bool lld::elf::needsGot(RelExpr expr) {
- return oneof<R_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOT_OFF,
- R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
+ return oneof<R_GOT, R_AARCH64_AUTH_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
+ R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC,
+ R_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
R_AARCH64_GOT_PAGE, R_LOONGARCH_GOT, R_LOONGARCH_GOT_PAGE_PC>(
expr);
}
@@ -924,13 +925,25 @@ void elf::addGotEntry(Symbol &sym) {
// If preemptible, emit a GLOB_DAT relocation.
if (sym.isPreemptible) {
- mainPart->relaDyn->addReloc({target->gotRel, in.got.get(), off,
+ RelType gotRel = target->gotRel;
+ if (sym.hasFlag(NEEDS_GOT_AUTH)) {
+ assert(config->emachine == EM_AARCH64);
+ gotRel = R_AARCH64_AUTH_GLOB_DAT;
+ }
+ mainPart->relaDyn->addReloc({gotRel, in.got.get(), off,
DynamicReloc::AgainstSymbol, sym, 0, R_ABS});
return;
}
// Otherwise, the value is either a link-time constant or the load base
- // plus a constant.
+ // plus a constant. Signed GOT requires dynamic relocation.
+ if (sym.hasFlag(NEEDS_GOT_AUTH)) {
+ in.got->getPartition().relaDyn->addReloc(
+ {R_AARCH64_AUTH_RELATIVE, in.got.get(), off,
+ DynamicReloc::AddendOnlyWithTargetVA, sym, 0, R_ABS});
+ return;
+ }
+
if (!config->isPic || isAbsolute(sym))
in.got->addConstant({R_ABS, target->symbolicRel, off, 0, &sym});
else
@@ -983,10 +996,11 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
// These expressions always compute a constant
if (oneof<R_GOTPLT, R_GOT_OFF, R_RELAX_HINT, R_MIPS_GOT_LOCAL_PAGE,
R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
- R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC,
- R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT, R_GOTPLT_GOTREL, R_GOTPLT_PC,
- R_PPC32_PLTREL, R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, R_RISCV_ADD,
- R_AARCH64_GOT_PAGE, R_LOONGARCH_PLT_PAGE_PC, R_LOONGARCH_GOT,
+ R_AARCH64_GOT_PAGE_PC, R_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC,
+ R_GOTONLY_PC, R_GOTPLTONLY_PC, R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT,
+ R_GOTPLT_GOTREL, R_GOTPLT_PC, R_PPC32_PLTREL, R_PPC64_CALL_PLT,
+ R_PPC64_RELAX_TOC, R_RISCV_ADD, R_AARCH64_GOT_PAGE,
+ R_AARCH64_AUTH_GOT, R_LOONGARCH_PLT_PAGE_PC, R_LOONGARCH_GOT,
R_LOONGARCH_GOT_PAGE_PC>(e))
return true;
@@ -1099,7 +1113,17 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
} else if (!sym.isTls() || config->emachine != EM_LOONGARCH) {
// Many LoongArch TLS relocs reuse the R_LOONGARCH_GOT type, in which
// case the NEEDS_GOT flag shouldn't get set.
- sym.setFlags(NEEDS_GOT);
+ bool needsGotAuth =
+ (expr == R_AARCH64_AUTH_GOT || expr == R_AARCH64_AUTH_GOT_PAGE_PC);
+ if (!sym.hasFlag(NEEDS_GOT)) {
+ sym.setFlags(NEEDS_GOT);
+ if (needsGotAuth)
+ sym.setFlags(NEEDS_GOT_AUTH);
+ } else if (needsGotAuth != sym.hasFlag(NEEDS_GOT_AUTH)) {
+ fatal("both AUTH and non-AUTH GOT entries for '" + sym.getName() +
+ "' requested, but only one type of GOT entry per symbol is "
+ "supported");
+ }
}
} else if (needsPlt(expr)) {
sym.setFlags(NEEDS_PLT);
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index e299d23dd7db3..fb1973b19f485 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -83,7 +83,9 @@ enum RelExpr {
// of a relocation type, there are some relocations whose semantics are
// unique to a target. Such relocation are marked with R_<TARGET_NAME>.
R_AARCH64_GOT_PAGE_PC,
+ R_AARCH64_AUTH_GOT_PAGE_PC,
R_AARCH64_GOT_PAGE,
+ R_AARCH64_AUTH_GOT,
R_AARCH64_PAGE_PC,
R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
R_AARCH64_TLSDESC_PAGE,
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index c65c5d6cd0dca..c8aa3d937af0e 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -54,6 +54,7 @@ enum {
NEEDS_TLSGD_TO_IE = 1 << 6,
NEEDS_GOT_DTPREL = 1 << 7,
NEEDS_TLSIE = 1 << 8,
+ NEEDS_GOT_AUTH = 1 << 9,
};
// Some index properties of a symbol are stored separately in this auxiliary
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index cc423d152e912..b4212b4962634 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -655,6 +655,10 @@ void GotSection::addConstant(const Relocation &r) { relocations.push_back(r); }
void GotSection::addEntry(const Symbol &sym) {
assert(sym.auxIdx == symAux.size() - 1);
symAux.back().gotIdx = numEntries++;
+ if (sym.hasFlag(NEEDS_GOT_AUTH)) {
+ assert(config->emachine == EM_AARCH64);
+ authEntries.push_back({(numEntries - 1) * config->wordsize, sym.isFunc()});
+ }
}
bool GotSection::addTlsDescEntry(const Symbol &sym) {
@@ -718,6 +722,21 @@ void GotSection::writeTo(uint8_t *buf) {
return;
target->writeGotHeader(buf);
target->relocateAlloc(*this, buf);
+ for (const AuthEntryInfo &authEntry : authEntries) {
+ // https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#default-signing-schema
+ // Signed GOT entries use the IA key for symbols of type STT_FUNC and the
+ // DA key for all other symbol types, with the address of the GOT entry as
+ // the modifier. The static linker must encode the signing schema into the
+ // GOT slot.
+ //
+ // https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#encoding-the-signing-schema
+ // If address diversity is set and the discriminator
+ // is 0 then modifier = Place
+ uint8_t *dest = buf + authEntry.offset;
+ uint64_t key = authEntry.isSymbolFunc ? /*IA*/ 0b00 : /*DA*/ 0b10;
+ uint64_t addrDiversity = 1;
+ write64(dest, (addrDiversity << 63) | (key << 60));
+ }
}
static uint64_t getMipsPageAddr(uint64_t addr) {
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 34949025a45f7..7cc6a34c5dc8a 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -131,6 +131,11 @@ class GotSection final : public SyntheticSection {
size_t numEntries = 0;
uint32_t tlsIndexOff = -1;
uint64_t size = 0;
+ struct AuthEntryInfo {
+ size_t offset;
+ bool isSymbolFunc;
+ };
+ SmallVector<AuthEntryInfo> authEntries;
};
// .note.GNU-stack section.
diff --git a/lld/test/ELF/aarch64-auth-got-relocations.s b/lld/test/ELF/aarch64-auth-got-relocations.s
new file mode 100644
index 0000000000000..f04e3d953388c
--- /dev/null
+++ b/lld/test/ELF/aarch64-auth-got-relocations.s
@@ -0,0 +1,94 @@
+# REQUIRES: aarch64
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %p/Inputs/shared.s -o a.o
+# RUN: ld.lld -shared a.o -o a.so
+
+#--- ok.s
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux ok.s -o ok.o
+
+# RUN: ld.lld ok.o a.so -pie -o external
+# RUN: llvm-readelf -r -S -x .got external | FileCheck %s --check-prefix=EXTERNAL
+
+# RUN: ld.lld ok.o a.o -pie -o local
+# RUN: llvm-readelf -r -S -x .got -s local | FileCheck %s --check-prefix=LOCAL
+
+# EXTERNAL: Offset Info Type Symbol's Value Symbol's Name + Addend
+# EXTERNAL-NEXT: 0000000000020380 000000010000e201 R_AARCH64_AUTH_GLOB_DAT 0000000000000000 bar + 0
+# EXTERNAL-NEXT: 0000000000020388 000000020000e201 R_AARCH64_AUTH_GLOB_DAT 0000000000000000 zed + 0
+
+## Symbol's values for bar and zed are equal since they contain no content (see Inputs/shared.s)
+# LOCAL: Offset Info Type Symbol's Value Symbol's Name + Addend
+# LOCAL-NEXT: 0000000000020320 0000000000000411 R_AARCH64_AUTH_RELATIVE 10260
+# LOCAL-NEXT: 0000000000020328 0000000000000411 R_AARCH64_AUTH_RELATIVE 10260
+
+# EXTERNAL: Hex dump of section '.got':
+# EXTERNAL-NEXT: 0x00020380 00000000 00000080 00000000 000000a0
+# ^^
+# 0b10000000 bit 63 address diversity = true, bits 61..60 key = IA
+# ^^
+# 0b10100000 bit 63 address diversity = true, bits 61..60 key = DA
+
+# LOCAL: Symbol table '.symtab' contains {{.*}} entries:
+# LOCAL: Num: Value Size Type Bind Vis Ndx Name
+# LOCAL: 0000000000010260 0 FUNC GLOBAL DEFAULT 6 bar
+# LOCAL: 0000000000010260 0 NOTYPE GLOBAL DEFAULT 6 zed
+
+# LOCAL: Hex dump of section '.got':
+# LOCAL-NEXT: 0x00020320 00000000 00000080 00000000 000000a0
+# ^^
+# 0b10000000 bit 63 address diversity = true, bits 61..60 key = IA
+# ^^
+# 0b10100000 bit 63 address diversity = true, bits 61..60 key = DA
+
+# RUN: llvm-objdump -d external | FileCheck %s --check-prefix=EXTERNAL-ASM
+
+# EXTERNAL-ASM: <_start>:
+# EXTERNAL-ASM-NEXT: adrp x0, 0x20000
+# EXTERNAL-ASM-NEXT: ldr x0, [x0, #0x380]
+# EXTERNAL-ASM-NEXT: adrp x1, 0x20000
+# EXTERNAL-ASM-NEXT: add x1, x1, #0x380
+# EXTERNAL-ASM-NEXT: adrp x0, 0x20000
+# EXTERNAL-ASM-NEXT: ldr x0, [x0, #0x388]
+# EXTERNAL-ASM-NEXT: adrp x1, 0x20000
+# EXTERNAL-ASM-NEXT: add x1, x1, #0x388
+
+# RUN: llvm-objdump -d local | FileCheck %s --check-prefix=LOCAL-ASM
+
+# LOCAL-ASM: <_start>:
+# LOCAL-ASM-NEXT: adrp x0, 0x20000
+# LOCAL-ASM-NEXT: ldr x0, [x0, #0x320]
+# LOCAL-ASM-NEXT: adrp x1, 0x20000
+# LOCAL-ASM-NEXT: add x1, x1, #0x320
+# LOCAL-ASM-NEXT: adrp x0, 0x20000
+# LOCAL-ASM-NEXT: ldr x0, [x0, #0x328]
+# LOCAL-ASM-NEXT: adrp x1, 0x20000
+# LOCAL-ASM-NEXT: add x1, x1, #0x328
+
+.globl _start
+_start:
+ adrp x0, :got_auth:bar
+ ldr x0, [x0, :got_auth_lo12:bar]
+ adrp x1, :got_auth:bar
+ add x1, x1, :got_auth_lo12:bar
+ adrp x0, :got_auth:zed
+ ldr x0, [x0, :got_auth_lo12:zed]
+ adrp x1, :got_auth:zed
+ add x1, x1, :got_auth_lo12:zed
+
+#--- err.s
+
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux err.s -o err.o
+
+# RUN: not ld.lld err.o a.so -pie -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR
+
+# ERR: error: both AUTH and non-AUTH GOT entries for 'bar' requested, but only one type of GOT entry per symbol is supported
+
+.globl _start
+_start:
+ adrp x0, :got_auth:bar
+ ldr x0, [x0, :got_auth_lo12:bar]
+ adrp x0, :got:bar
+ ldr x0, [x0, :got_lo12:bar]
|
@MaskRay Would be glad to see your feedback on the changes |
@MaskRay Would be glad to see your feedback on the changes. Everyone interested is also welcome to leave a review |
1 similar comment
@MaskRay Would be glad to see your feedback on the changes. Everyone interested is also welcome to leave a review |
Sorry for the late reply, but the depended assembler patch hasn't landed yet, making this difficult to review. |
lld/ELF/SyntheticSections.cpp
Outdated
@@ -655,6 +655,10 @@ void GotSection::addConstant(const Relocation &r) { relocations.push_back(r); } | |||
void GotSection::addEntry(const Symbol &sym) { | |||
assert(sym.auxIdx == symAux.size() - 1); | |||
symAux.back().gotIdx = numEntries++; | |||
if (sym.hasFlag(NEEDS_GOT_AUTH)) { | |||
assert(config->emachine == EM_AARCH64); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assert and the above assert are not useful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've deleted the assert, thanks, see dca427b.
Regarding the assertion above - I'll delete that and similar ones in addTlsDescEntry
and addDynTlsEntry
if they are considered useless (I just don't want to mess new features with refactoring existing code).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update. Opened #98028 deleting similar assertions in
GotSection::addEntry
GotSection::addTlsDescEntry
GotSection::addDynTlsEntry
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assert(sym.auxIdx == symAux.size() - 1);
assertions are useful to prevent allocating more than one entries for one symbol. I used the assertions to prevent some failures. NEEDS_GOT_AUTH
is clearly AArch64 specific.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lld/ELF/SyntheticSections.h
Outdated
size_t offset; | ||
bool isSymbolFunc; | ||
}; | ||
SmallVector<AuthEntryInfo> authEntries; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
, 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed, thanks, see dca427b
Assertions in the member functions below are considered not useful. See llvm#96169 (comment) - `GotSection::addEntry` - `GotSection::addTlsDescEntry` - `GotSection::addDynTlsEntry`
I've re-opened this as #113815 since I had to change the source branch to allow stacked PR (lld support for signed GOT with tiny code model #113816 and for signed TLSDESC #113817 depend on this). The new PR is identical to this one in terms of changes. I've decided not to keep the commit history since it mostly contains resolving merge conflicts and addressing trivial review comments. Would be glad to continue discussion in #113815 - closing this one in favor of that. |
Depends on #96164
Support
R_AARCH64_AUTH_ADR_GOT_PAGE
,R_AARCH64_AUTH_GOT_LO12_NC
andR_AARCH64_AUTH_GOT_ADD_LO12_NC
GOT-generating relocations. For preemptible symbols, dynamic relocationR_AARCH64_AUTH_GLOB_DAT
is emitted. Otherwise, we unconditionally emitR_AARCH64_AUTH_RELATIVE
dynamic relocation since pointers in signed GOT needs to be signed during dynamic link time.