Skip to content
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

[PAC][AArch64][ELF] Support signed TLSDESC #78

Open
wants to merge 3 commits into
base: dkovalev/pauth-signed-got-mainline
Choose a base branch
from
Open
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
8 changes: 8 additions & 0 deletions lld/ELF/Arch/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,14 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
return R_AARCH64_AUTH;
case R_AARCH64_TLSDESC_ADR_PAGE21:
return R_AARCH64_TLSDESC_PAGE;
case R_AARCH64_AUTH_TLSDESC_ADR_PAGE21:
return R_AARCH64_AUTH_TLSDESC_PAGE;
case R_AARCH64_TLSDESC_LD64_LO12:
case R_AARCH64_TLSDESC_ADD_LO12:
return R_TLSDESC;
case R_AARCH64_AUTH_TLSDESC_LD64_LO12:
case R_AARCH64_AUTH_TLSDESC_ADD_LO12:
return RelExpr::R_AARCH64_AUTH_TLSDESC;
case R_AARCH64_TLSDESC_CALL:
return R_TLSDESC_CALL;
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
Expand Down Expand Up @@ -446,6 +451,7 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
case R_AARCH64_ADR_PREL_PG_HI21:
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
case R_AARCH64_TLSDESC_ADR_PAGE21:
case R_AARCH64_AUTH_TLSDESC_ADR_PAGE21:
checkInt(loc, val, 33, rel);
[[fallthrough]];
case R_AARCH64_ADR_PREL_PG_HI21_NC:
Expand Down Expand Up @@ -497,6 +503,7 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
case R_AARCH64_TLSDESC_LD64_LO12:
case R_AARCH64_AUTH_TLSDESC_LD64_LO12:
checkAlignment(loc, val, 8, rel);
or32AArch64Imm(loc, getBits(val, 3, 11));
break;
Expand Down Expand Up @@ -569,6 +576,7 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
break;
case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
case R_AARCH64_TLSDESC_ADD_LO12:
case R_AARCH64_AUTH_TLSDESC_ADD_LO12:
or32AArch64Imm(loc, val);
break;
case R_AARCH64_TLSDESC:
Expand Down
2 changes: 2 additions & 0 deletions lld/ELF/InputSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -870,12 +870,14 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
case R_SIZE:
return sym.getSize() + a;
case R_TLSDESC:
case RelExpr::R_AARCH64_AUTH_TLSDESC:
return in.got->getTlsDescAddr(sym) + a;
case R_TLSDESC_PC:
return in.got->getTlsDescAddr(sym) + a - p;
case R_TLSDESC_GOTPLT:
return in.got->getTlsDescAddr(sym) + a - in.gotPlt->getVA();
case R_AARCH64_TLSDESC_PAGE:
case R_AARCH64_AUTH_TLSDESC_PAGE:
return getAArch64Page(in.got->getTlsDescAddr(sym) + a) - getAArch64Page(p);
case R_TLSGD_GOT:
return in.got->getGlobalDynOffset(sym) + a;
Expand Down
25 changes: 20 additions & 5 deletions lld/ELF/Relocations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1324,14 +1324,25 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym,
return handleMipsTlsRelocation(type, sym, c, offset, addend, expr);
bool isRISCV = config->emachine == EM_RISCV;

if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
if (oneof<R_AARCH64_TLSDESC_PAGE, R_AARCH64_AUTH_TLSDESC_PAGE, R_TLSDESC,
RelExpr::R_AARCH64_AUTH_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
R_TLSDESC_GOTPLT>(expr) &&
config->shared) {
// R_RISCV_TLSDESC_{LOAD_LO12,ADD_LO12_I,CALL} reference a label. Do not
// set NEEDS_TLSDESC on the label.
if (expr != R_TLSDESC_CALL) {
if (!isRISCV || type == R_RISCV_TLSDESC_HI20)
sym.setFlags(NEEDS_TLSDESC);
bool needsTlsDescAuth =
(expr == R_AARCH64_AUTH_TLSDESC_PAGE || expr == RelExpr::R_AARCH64_AUTH_TLSDESC);
if (!sym.hasFlag(NEEDS_TLSDESC)) {
if (!isRISCV || type == R_RISCV_TLSDESC_HI20)
sym.setFlags(NEEDS_TLSDESC);
if (needsTlsDescAuth)
sym.setFlags(NEEDS_TLSDESC_AUTH);
} else if (needsTlsDescAuth != sym.hasFlag(NEEDS_TLSDESC_AUTH)) {
fatal("both AUTH and non-AUTH TLSDESC entries for '" + sym.getName() +
"' requested, but only one type of TLSDESC entry per symbol is "
"supported");
}
c.addReloc({expr, type, offset, addend, &sym});
}
return 1;
Expand Down Expand Up @@ -1788,9 +1799,13 @@ void elf::postScanRelocations() {

if (flags & NEEDS_TLSDESC) {
got->addTlsDescEntry(sym);
RelType tlsDescRel = target->tlsDescRel;
if (flags & NEEDS_TLSDESC_AUTH) {
assert(config->emachine == EM_AARCH64);
tlsDescRel = ELF::R_AARCH64_AUTH_TLSDESC;
}
mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible(
target->tlsDescRel, *got, got->getTlsDescOffset(sym), sym,
target->tlsDescRel);
tlsDescRel, *got, got->getTlsDescOffset(sym), sym, tlsDescRel);
}
if (flags & NEEDS_TLSGD) {
got->addDynTlsEntry(sym);
Expand Down
4 changes: 4 additions & 0 deletions lld/ELF/Relocations.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ enum RelExpr {
R_AARCH64_PAGE_PC,
R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
R_AARCH64_TLSDESC_PAGE,
R_AARCH64_AUTH_TLSDESC_PAGE,
// TODO: maybe it's better to rename this expression
// to avoid name conflict with dynamic reloc
R_AARCH64_AUTH_TLSDESC,
R_AARCH64_AUTH,
R_ARM_PCA,
R_ARM_SBREL,
Expand Down
1 change: 1 addition & 0 deletions lld/ELF/Symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ enum {
NEEDS_GOT_DTPREL = 1 << 7,
NEEDS_TLSIE = 1 << 8,
NEEDS_GOT_AUTH = 1 << 9,
NEEDS_TLSDESC_AUTH = 1 << 10,
};

// Some index properties of a symbol are stored separately in this auxiliary
Expand Down
5 changes: 5 additions & 0 deletions lld/ELF/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,11 @@ bool GotSection::addTlsDescEntry(const Symbol &sym) {
assert(sym.auxIdx == symAux.size() - 1);
symAux.back().tlsDescIdx = numEntries;
numEntries += 2;
if (sym.hasFlag(NEEDS_TLSDESC_AUTH)) {
assert(config->emachine == EM_AARCH64);
authEntries.push_back({(numEntries - 2) * config->wordsize, true});
authEntries.push_back({(numEntries - 1) * config->wordsize, false});
}
return true;
}

Expand Down
106 changes: 106 additions & 0 deletions lld/test/ELF/aarch64-tlsdesc-auth.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// REQUIRES: aarch64
// RUN: rm -rf %t && split-file %s %t && cd %t

//--- ok.s

// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-linux -mattr=+pauth ok.s -o ok.o
// RUN: ld.lld --hash-style=sysv -shared ok.o -o ok.so
// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn ok.so | FileCheck %s
// RUN: llvm-readobj -r -x .got ok.so | FileCheck --check-prefix=REL %s

.text
adrp x0, :tlsdesc_auth:a
ldr x16, [x0, :tlsdesc_auth_lo12:a]
add x0, x0, :tlsdesc_auth_lo12:a
autia x16, x0
.tlsdesccall a
blr x16

// CHECK: 10298: adrp x0, 0x20000
// CHECK-NEXT: 1029c: ldr x16, [x0, #872]
// CHECK-NEXT: 102a0: add x0, x0, #872
// CHECK-NEXT: 102a4: autia x16, x0
// CHECK-NEXT: 102a8: blr x16

// Create relocation against local TLS symbols where linker should
// create target specific dynamic TLSDESC relocation where addend is
// the symbol VMA in tls block.

adrp x0, :tlsdesc_auth:local1
ldr x16, [x0, :tlsdesc_auth_lo12:local1]
add x0, x0, :tlsdesc_auth_lo12:local1
autia x16, x0
.tlsdesccall a
blr x16

// CHECK: 102ac: adrp x0, 0x20000
// CHECK-NEXT: 102b0: ldr x16, [x0, #888]
// CHECK-NEXT: 102b4: add x0, x0, #888
// CHECK-NEXT: 102b8: autia x16, x0
// CHECK-NEXT: 102bc: blr x16

adrp x0, :tlsdesc_auth:local2
ldr x16, [x0, :tlsdesc_auth_lo12:local2]
add x0, x0, :tlsdesc_auth_lo12:local2
autia x16, x0
.tlsdesccall a
blr x16

// CHECK: 102c0: adrp x0, 0x20000
// CHECK-NEXT: 102c4: ldr x16, [x0, #904]
// CHECK-NEXT: 102c8: add x0, x0, #904
// CHECK-NEXT: 102cc: autia x16, x0
// CHECK-NEXT: 102d0: blr x16

.section .tbss,"awT",@nobits
.type local1,@object
.p2align 2
local1:
.word 0
.size local1, 4

.type local2,@object
.p2align 3
local2:
.xword 0
.size local2, 8


// R_AARCH64_AUTH_TLSDESC - 0x0 -> start of tls block
// R_AARCH64_AUTH_TLSDESC - 0x8 -> align (sizeof (local1), 8)

// REL: Relocations [
// REL-NEXT: Section (4) .rela.dyn {
// REL-NEXT: 0x20378 R_AARCH64_AUTH_TLSDESC - 0x0
// REL-NEXT: 0x20388 R_AARCH64_AUTH_TLSDESC - 0x8
// REL-NEXT: 0x20368 R_AARCH64_AUTH_TLSDESC a 0x0
// REL-NEXT: }
// REL-NEXT: ]

// REL: Hex dump of section '.got':
// REL-NEXT: 0x00020368 00000000 00000080 00000000 000000a0
// REL-NEXT: 0x00020378 00000000 00000080 00000000 000000a0
// REL-NEXT: 0x00020388 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

//--- err.s

// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-linux -mattr=+pauth err.s -o err.o
// RUN: not ld.lld --hash-style=sysv -shared err.o -o err.so 2>&1 | FileCheck --check-prefix=ERR %s
// ERR: error: both AUTH and non-AUTH TLSDESC entries for 'a' requested, but only one type of TLSDESC entry per symbol is supported
.text
adrp x0, :tlsdesc_auth:a
ldr x16, [x0, :tlsdesc_auth_lo12:a]
add x0, x0, :tlsdesc_auth_lo12:a
autia x16, x0
.tlsdesccall a
blr x16

adrp x0, :tlsdesc:a
ldr x1, [x0, :tlsdesc_lo12:a]
add x0, x0, :tlsdesc_lo12:a
.tlsdesccall a
blr x1
3 changes: 3 additions & 0 deletions llvm/include/llvm/BinaryFormat/ELFRelocs/AArch64.def
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ ELF_RELOC(R_AARCH64_AUTH_GOT_LO12_NC, 0x811a)
ELF_RELOC(R_AARCH64_AUTH_LD64_GOTPAGE_LO15, 0x811b)
ELF_RELOC(R_AARCH64_AUTH_GOT_ADD_LO12_NC, 0x811c)
ELF_RELOC(R_AARCH64_AUTH_GOT_ADR_PREL21, 0x811d)
ELF_RELOC(R_AARCH64_AUTH_TLSDESC_ADR_PAGE21, 0x811e)
ELF_RELOC(R_AARCH64_AUTH_TLSDESC_LD64_LO12, 0x811f)
ELF_RELOC(R_AARCH64_AUTH_TLSDESC_ADD_LO12, 0x8120)
ELF_RELOC(R_AARCH64_AUTH_GLOB_DAT, 0xe201)
ELF_RELOC(R_AARCH64_AUTH_TLSDESC, 0xe202)
ELF_RELOC(R_AARCH64_AUTH_IRELATIVE, 0xe203)
Expand Down
63 changes: 63 additions & 0 deletions llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1647,6 +1647,69 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
EmitToStreamer(*OutStreamer, TmpInstSB);
return;
}
case AArch64::TLSDESC_AUTH_CALLSEQ: {
// FIXME: use BLRAA instead of AUTIA + BLR. BLRAA is currently explicitly
// unsupported in AArch64SLSHardening pass.
/// lower this to:
/// adrp x0, :tlsdesc:var
/// ldr x16, [x0, #:tlsdesc_lo12:var]
/// add x0, x0, #:tlsdesc_lo12:var
/// autia x16, x0
/// .tlsdesccall var
/// blr x16
/// (TPIDR_EL0 offset now in x0)
const MachineOperand &MO_Sym = MI->getOperand(0);
MachineOperand MO_TLSDESC_LO12(MO_Sym), MO_TLSDESC(MO_Sym);
MCOperand Sym, SymTLSDescLo12, SymTLSDesc;
MO_TLSDESC_LO12.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGEOFF);
MO_TLSDESC.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGE);
MCInstLowering.lowerOperand(MO_Sym, Sym);
MCInstLowering.lowerOperand(MO_TLSDESC_LO12, SymTLSDescLo12);
MCInstLowering.lowerOperand(MO_TLSDESC, SymTLSDesc);

MCInst Adrp;
Adrp.setOpcode(AArch64::ADRP);
Adrp.addOperand(MCOperand::createReg(AArch64::X0));
Adrp.addOperand(SymTLSDesc);
EmitToStreamer(*OutStreamer, Adrp);

MCInst Ldr;
Ldr.setOpcode(AArch64::LDRXui);
Ldr.addOperand(MCOperand::createReg(AArch64::X16));
Ldr.addOperand(MCOperand::createReg(AArch64::X0));
Ldr.addOperand(SymTLSDescLo12);
Ldr.addOperand(MCOperand::createImm(0));
EmitToStreamer(*OutStreamer, Ldr);

MCInst Add;
Add.setOpcode(AArch64::ADDXri);
Add.addOperand(MCOperand::createReg(AArch64::X0));
Add.addOperand(MCOperand::createReg(AArch64::X0));
Add.addOperand(SymTLSDescLo12);
Add.addOperand(MCOperand::createImm(AArch64_AM::getShiftValue(0)));
EmitToStreamer(*OutStreamer, Add);

MCInst Autia;
Autia.setOpcode(AArch64::AUTIA);
Autia.addOperand(MCOperand::createReg(AArch64::X16));
Autia.addOperand(MCOperand::createReg(AArch64::X16));
Autia.addOperand(MCOperand::createReg(AArch64::X0));
EmitToStreamer(*OutStreamer, Autia);

// Emit a relocation-annotation. This expands to no code, but requests
// the following instruction gets an R_AARCH64_TLSDESC_CALL.
MCInst TLSDescCall;
TLSDescCall.setOpcode(AArch64::TLSDESCCALL);
TLSDescCall.addOperand(Sym);
EmitToStreamer(*OutStreamer, TLSDescCall);

MCInst Blr;
Blr.setOpcode(AArch64::BLR);
Blr.addOperand(MCOperand::createReg(AArch64::X16));
EmitToStreamer(*OutStreamer, Blr);

return;
}
case AArch64::TLSDESC_CALLSEQ: {
/// lower this to:
/// adrp x0, :tlsdesc:var
Expand Down
8 changes: 6 additions & 2 deletions llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2428,6 +2428,7 @@ const char *AArch64TargetLowering::getTargetNodeName(unsigned Opcode) const {
MAKE_CASE(AArch64ISD::CSINC)
MAKE_CASE(AArch64ISD::THREAD_POINTER)
MAKE_CASE(AArch64ISD::TLSDESC_CALLSEQ)
MAKE_CASE(AArch64ISD::TLSDESC_AUTH_CALLSEQ)
MAKE_CASE(AArch64ISD::PROBED_ALLOCA)
MAKE_CASE(AArch64ISD::ABDS_PRED)
MAKE_CASE(AArch64ISD::ABDU_PRED)
Expand Down Expand Up @@ -8984,8 +8985,11 @@ SDValue AArch64TargetLowering::LowerELFTLSDescCallSeq(SDValue SymAddr,
SDValue Chain = DAG.getEntryNode();
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);

Chain =
DAG.getNode(AArch64ISD::TLSDESC_CALLSEQ, DL, NodeTys, {Chain, SymAddr});
unsigned Opcode =
DAG.getMachineFunction().getFunction().getParent()->hasELFSignedGOT()
? AArch64ISD::TLSDESC_AUTH_CALLSEQ
: AArch64ISD::TLSDESC_CALLSEQ;
Chain = DAG.getNode(Opcode, DL, NodeTys, {Chain, SymAddr});
SDValue Glue = Chain.getValue(1);

return DAG.getCopyFromReg(Chain, DL, AArch64::X0, PtrVT, Glue);
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/AArch64/AArch64ISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ enum NodeType : unsigned {
// Produces the full sequence of instructions for getting the thread pointer
// offset of a variable into X0, using the TLSDesc model.
TLSDESC_CALLSEQ,
TLSDESC_AUTH_CALLSEQ,
ADRP, // Page address of a TargetGlobalAddress operand.
ADR, // ADR
ADDlow, // Add the low 12 bits of a TargetGlobalAddress operand.
Expand Down
14 changes: 14 additions & 0 deletions llvm/lib/Target/AArch64/AArch64InstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,8 @@ def SDT_AArch64stnp : SDTypeProfile<0, 3, [SDTCisVT<0, v4i32>, SDTCisSameAs<0, 1
// number of operands (the variable)
def SDT_AArch64TLSDescCallSeq : SDTypeProfile<0,1,
[SDTCisPtrTy<0>]>;
def SDT_AArch64TLSDescAuthCallSeq : SDTypeProfile<0,1,
[SDTCisPtrTy<0>]>;

def SDT_AArch64WrapperLarge : SDTypeProfile<1, 4,
[SDTCisVT<0, i64>, SDTCisVT<1, i32>,
Expand Down Expand Up @@ -785,6 +787,10 @@ def AArch64tlsdesc_callseq : SDNode<"AArch64ISD::TLSDESC_CALLSEQ",
[SDNPInGlue, SDNPOutGlue, SDNPHasChain,
SDNPVariadic]>;

def AArch64tlsdesc_auth_callseq : SDNode<"AArch64ISD::TLSDESC_AUTH_CALLSEQ",
SDT_AArch64TLSDescAuthCallSeq,
[SDNPInGlue, SDNPOutGlue, SDNPHasChain,
SDNPVariadic]>;

def AArch64WrapperLarge : SDNode<"AArch64ISD::WrapperLarge",
SDT_AArch64WrapperLarge>;
Expand Down Expand Up @@ -2920,8 +2926,16 @@ def TLSDESC_CALLSEQ
: Pseudo<(outs), (ins i64imm:$sym),
[(AArch64tlsdesc_callseq tglobaltlsaddr:$sym)]>,
Sched<[WriteI, WriteLD, WriteI, WriteBrReg]>;
let isCall = 1, Defs = [NZCV, LR, X0, X16], hasSideEffects = 1, Size = 20,
isCodeGenOnly = 1 in
def TLSDESC_AUTH_CALLSEQ
: Pseudo<(outs), (ins i64imm:$sym),
[(AArch64tlsdesc_auth_callseq tglobaltlsaddr:$sym)]>,
Sched<[WriteI, WriteLD, WriteI, WriteBrReg]>;
def : Pat<(AArch64tlsdesc_callseq texternalsym:$sym),
(TLSDESC_CALLSEQ texternalsym:$sym)>;
def : Pat<(AArch64tlsdesc_auth_callseq texternalsym:$sym),
(TLSDESC_AUTH_CALLSEQ texternalsym:$sym)>;

//===----------------------------------------------------------------------===//
// Conditional branch (immediate) instruction.
Expand Down
Loading