Skip to content

[PAC][lld][AArch64][ELF] Support signed GOT #113815

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

Merged
merged 16 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions lld/ELF/Arch/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,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_LD64_GOT_LO12_NC:
case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
return RE_AARCH64_AUTH_GOT;
case R_AARCH64_LD64_GOTPAGE_LO15:
return RE_AARCH64_GOT_PAGE;
case R_AARCH64_ADR_GOT_PAGE:
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
return RE_AARCH64_GOT_PAGE_PC;
case R_AARCH64_AUTH_ADR_GOT_PAGE:
return RE_AARCH64_AUTH_GOT_PAGE_PC;
case R_AARCH64_GOTPCREL32:
case R_AARCH64_GOT_LD_PREL19:
return R_GOT_PC;
Expand Down Expand Up @@ -258,6 +263,7 @@ int64_t AArch64::getImplicitAddend(const uint8_t *buf, RelType type) const {
return read64(ctx, 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:
Expand Down Expand Up @@ -528,9 +534,11 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
write32(ctx, loc, val);
break;
case R_AARCH64_ADD_ABS_LO12_NC:
case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
write32Imm12(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:
Expand Down Expand Up @@ -580,6 +588,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_LD64_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:
Expand Down
2 changes: 2 additions & 0 deletions lld/ELF/InputSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
case RE_ARM_SBREL:
return r.sym->getVA(ctx, a) - getARMStaticBase(*r.sym);
case R_GOT:
case RE_AARCH64_AUTH_GOT:
case R_RELAX_TLS_GD_TO_IE_ABS:
return r.sym->getGotVA(ctx) + a;
case RE_LOONGARCH_GOT:
Expand Down Expand Up @@ -810,6 +811,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
return r.sym->getGotOffset(ctx) + a;
case RE_AARCH64_GOT_PAGE_PC:
case RE_AARCH64_AUTH_GOT_PAGE_PC:
case RE_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
return getAArch64Page(r.sym->getGotVA(ctx) + a) - getAArch64Page(p);
case RE_AARCH64_GOT_PAGE:
Expand Down
54 changes: 46 additions & 8 deletions lld/ELF/Relocations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,9 @@ static bool needsPlt(RelExpr expr) {
}

bool lld::elf::needsGot(RelExpr expr) {
return oneof<R_GOT, R_GOT_OFF, RE_MIPS_GOT_LOCAL_PAGE, RE_MIPS_GOT_OFF,
RE_MIPS_GOT_OFF32, RE_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
return oneof<R_GOT, RE_AARCH64_AUTH_GOT, R_GOT_OFF, RE_MIPS_GOT_LOCAL_PAGE,
RE_MIPS_GOT_OFF, RE_MIPS_GOT_OFF32, RE_AARCH64_GOT_PAGE_PC,
RE_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
RE_AARCH64_GOT_PAGE, RE_LOONGARCH_GOT, RE_LOONGARCH_GOT_PAGE_PC>(
expr);
}
Expand Down Expand Up @@ -910,6 +911,25 @@ void elf::addGotEntry(Ctx &ctx, Symbol &sym) {
ctx.target->symbolicRel);
}

static void addGotAuthEntry(Ctx &ctx, Symbol &sym) {
ctx.in.got->addEntry(sym);
ctx.in.got->addAuthEntry(sym);
uint64_t off = sym.getGotOffset(ctx);

// If preemptible, emit a GLOB_DAT relocation.
if (sym.isPreemptible) {
ctx.mainPart->relaDyn->addReloc({R_AARCH64_AUTH_GLOB_DAT, ctx.in.got.get(),
off, DynamicReloc::AgainstSymbol, sym, 0,
R_ABS});
return;
}

// Signed GOT requires dynamic relocation.
ctx.in.got->getPartition(ctx).relaDyn->addReloc(
{R_AARCH64_AUTH_RELATIVE, ctx.in.got.get(), off,
DynamicReloc::AddendOnlyWithTargetVA, sym, 0, R_ABS});
}

static void addTpOffsetGotEntry(Ctx &ctx, Symbol &sym) {
ctx.in.got->addEntry(sym);
uint64_t off = sym.getGotOffset(ctx);
Expand Down Expand Up @@ -956,11 +976,12 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
// These expressions always compute a constant
if (oneof<R_GOTPLT, R_GOT_OFF, R_RELAX_HINT, RE_MIPS_GOT_LOCAL_PAGE,
RE_MIPS_GOTREL, RE_MIPS_GOT_OFF, RE_MIPS_GOT_OFF32,
RE_MIPS_GOT_GP_PC, RE_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
RE_MIPS_GOT_GP_PC, RE_AARCH64_GOT_PAGE_PC,
RE_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, RE_PPC32_PLTREL, RE_PPC64_CALL_PLT,
RE_PPC64_RELAX_TOC, RE_RISCV_ADD, RE_AARCH64_GOT_PAGE,
RE_LOONGARCH_PLT_PAGE_PC, RE_LOONGARCH_GOT,
RE_AARCH64_AUTH_GOT, RE_LOONGARCH_PLT_PAGE_PC, RE_LOONGARCH_GOT,
RE_LOONGARCH_GOT_PAGE_PC>(e))
return true;

Expand Down Expand Up @@ -1075,7 +1096,10 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
} else if (!sym.isTls() || ctx.arg.emachine != EM_LOONGARCH) {
// Many LoongArch TLS relocs reuse the RE_LOONGARCH_GOT type, in which
// case the NEEDS_GOT flag shouldn't get set.
sym.setFlags(NEEDS_GOT);
if (expr == RE_AARCH64_AUTH_GOT || expr == RE_AARCH64_AUTH_GOT_PAGE_PC)
sym.setFlags(NEEDS_GOT | NEEDS_GOT_AUTH);
else
sym.setFlags(NEEDS_GOT | NEEDS_GOT_NONAUTH);
}
} else if (needsPlt(expr)) {
sym.setFlags(NEEDS_PLT);
Expand Down Expand Up @@ -1750,8 +1774,11 @@ static bool handleNonPreemptibleIfunc(Ctx &ctx, Symbol &sym, uint16_t flags) {
// don't try to call the PLT as if it were an ifunc resolver.
d.type = STT_FUNC;

if (flags & NEEDS_GOT)
if (flags & NEEDS_GOT) {
assert(!(flags & NEEDS_GOT_AUTH) &&
"R_AARCH64_AUTH_IRELATIVE is not supported yet");
addGotEntry(ctx, sym);
}
} else if (flags & NEEDS_GOT) {
// Redirect GOT accesses to point to the Igot.
sym.gotInIgot = true;
Expand All @@ -1772,8 +1799,19 @@ void elf::postScanRelocations(Ctx &ctx) {
return;
sym.allocateAux(ctx);

if (flags & NEEDS_GOT)
addGotEntry(ctx, sym);
if (flags & NEEDS_GOT) {
if ((flags & NEEDS_GOT_AUTH) && (flags & NEEDS_GOT_NONAUTH)) {
auto diag = Err(ctx);
diag << "both AUTH and non-AUTH GOT entries for '" << sym.getName()
<< "' requested, but only one type of GOT entry per symbol is "
"supported";
return;
}
if (flags & NEEDS_GOT_AUTH)
addGotAuthEntry(ctx, sym);
else
addGotEntry(ctx, sym);
}
if (flags & NEEDS_PLT)
addPltEntry(ctx, *ctx.in.plt, *ctx.in.gotPlt, *ctx.in.relaPlt,
ctx.target->pltRel, sym);
Expand Down
2 changes: 2 additions & 0 deletions lld/ELF/Relocations.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ enum RelExpr {
// of a relocation type, there are some relocations whose semantics are
// unique to a target. Such relocation are marked with RE_<TARGET_NAME>.
RE_AARCH64_GOT_PAGE_PC,
RE_AARCH64_AUTH_GOT_PAGE_PC,
RE_AARCH64_GOT_PAGE,
RE_AARCH64_AUTH_GOT,
RE_AARCH64_PAGE_PC,
RE_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
RE_AARCH64_TLSDESC_PAGE,
Expand Down
2 changes: 2 additions & 0 deletions lld/ELF/Symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ enum {
NEEDS_TLSGD_TO_IE = 1 << 6,
NEEDS_GOT_DTPREL = 1 << 7,
NEEDS_TLSIE = 1 << 8,
NEEDS_GOT_AUTH = 1 << 9,
NEEDS_GOT_NONAUTH = 1 << 10,
};

// The base class for real symbol classes.
Expand Down
19 changes: 19 additions & 0 deletions lld/ELF/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,10 @@ void GotSection::addEntry(const Symbol &sym) {
ctx.symAux.back().gotIdx = numEntries++;
}

void GotSection::addAuthEntry(const Symbol &sym) {
authEntries.push_back({(numEntries - 1) * ctx.arg.wordsize, sym.isFunc()});
}

bool GotSection::addTlsDescEntry(const Symbol &sym) {
assert(sym.auxIdx == ctx.symAux.size() - 1);
ctx.symAux.back().tlsDescIdx = numEntries;
Expand Down Expand Up @@ -732,6 +736,21 @@ void GotSection::writeTo(uint8_t *buf) {
return;
ctx.target->writeGotHeader(buf);
ctx.target->relocateAlloc(*this, buf);
for (const AuthEntryInfo &authEntry : authEntries) {
// https://github.com/ARM-software/abi-aa/blob/2024Q3/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/2024Q3/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(ctx, dest, (addrDiversity << 63) | (key << 60));
}
}

static uint64_t getMipsPageAddr(uint64_t addr) {
Expand Down
6 changes: 6 additions & 0 deletions lld/ELF/SyntheticSections.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ class GotSection final : public SyntheticSection {

void addConstant(const Relocation &r);
void addEntry(const Symbol &sym);
void addAuthEntry(const Symbol &sym);
bool addTlsDescEntry(const Symbol &sym);
bool addDynTlsEntry(const Symbol &sym);
bool addTlsIndex();
Expand All @@ -131,6 +132,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, 0> authEntries;
};

// .note.GNU-stack section.
Expand Down
90 changes: 90 additions & 0 deletions lld/test/ELF/aarch64-got-relocations-pauth.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# REQUIRES: aarch64

# RUN: rm -rf %t && split-file %s %t && cd %t

# RUN: llvm-mc -filetype=obj -triple=aarch64 %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 ok.s -o ok.o

# RUN: ld.lld ok.o a.so -pie -o ok1
# RUN: llvm-readelf -r -S -x .got ok1 | FileCheck %s --check-prefix=OK1

# RUN: ld.lld ok.o a.o -pie -o ok2
# RUN: llvm-readelf -r -S -x .got -s ok2 | FileCheck %s --check-prefix=OK2

# OK1: Offset Info Type Symbol's Value Symbol's Name + Addend
# OK1-NEXT: 0000000000020380 0000000100000412 R_AARCH64_AUTH_GLOB_DAT 0000000000000000 bar + 0
# OK1-NEXT: 0000000000020388 0000000200000412 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)
# OK2: Offset Info Type Symbol's Value Symbol's Name + Addend
# OK2-NEXT: 0000000000020320 0000000000000411 R_AARCH64_AUTH_RELATIVE 10260
# OK2-NEXT: 0000000000020328 0000000000000411 R_AARCH64_AUTH_RELATIVE 10260

# OK1: Hex dump of section '.got':
# OK1-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

# OK2: Symbol table '.symtab' contains {{.*}} entries:
# OK2: Num: Value Size Type Bind Vis Ndx Name
# OK2: 0000000000010260 0 FUNC GLOBAL DEFAULT 6 bar
# OK2: 0000000000010260 0 NOTYPE GLOBAL DEFAULT 6 zed

# OK2: Hex dump of section '.got':
# OK2-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 ok1 | FileCheck %s --check-prefix=OK1-ASM

# OK1-ASM: <_start>:
# OK1-ASM-NEXT: adrp x0, 0x20000
# OK1-ASM-NEXT: ldr x0, [x0, #0x380]
# OK1-ASM-NEXT: adrp x1, 0x20000
# OK1-ASM-NEXT: add x1, x1, #0x380
# OK1-ASM-NEXT: adrp x0, 0x20000
# OK1-ASM-NEXT: ldr x0, [x0, #0x388]
# OK1-ASM-NEXT: adrp x1, 0x20000
# OK1-ASM-NEXT: add x1, x1, #0x388

# RUN: llvm-objdump -d ok2 | FileCheck %s --check-prefix=OK2-ASM

# OK2-ASM: <_start>:
# OK2-ASM-NEXT: adrp x0, 0x20000
# OK2-ASM-NEXT: ldr x0, [x0, #0x320]
# OK2-ASM-NEXT: adrp x1, 0x20000
# OK2-ASM-NEXT: add x1, x1, #0x320
# OK2-ASM-NEXT: adrp x0, 0x20000
# OK2-ASM-NEXT: ldr x0, [x0, #0x328]
# OK2-ASM-NEXT: adrp x1, 0x20000
# OK2-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 err.s -o err.o
Copy link
Member

Choose a reason for hiding this comment

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

with the ... split-file %s %t && cd %t pattern, you can omit -o /dev/null for not ld.lld commands.

without cd %t, -o /dev/null is needed so that we don't create a temporary file under CWD. Google's internal lit tester relies on this property, and it's generally a good idea to ensure that the tests run regardless of CWD.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Deleted explicit output specification in 78cf14f, thanks. Also applied to #113817

# RUN: not ld.lld err.o a.so -pie 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error:
# 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]
Loading