Skip to content

Commit

Permalink
[PAC][CodeGen][ELF][AArch64] Support signed GOT with tiny code model (l…
Browse files Browse the repository at this point in the history
…lvm#114525)

Support the following relocations and assembly operators:

- `R_AARCH64_AUTH_GOT_ADR_PREL_LO21` (`:got_auth:` for `adr`)
- `R_AARCH64_AUTH_GOT_LD_PREL19` (`:got_auth:` for `ldr`)

`LOADgotAUTH` pseudo-instruction is expanded to actual instruction
sequence like the following.

```
adr x16, :got_auth:sym
ldr x0, [x16]
autia x0, x16
```

Both SelectionDAG and GlobalISel are suppported. For FastISel, we fall
back to SelectionDAG.

Tests starting with 'ptrauth-' have corresponding variants w/o this
prefix.
  • Loading branch information
kovdan01 authored Dec 10, 2024
1 parent b97c447 commit 0ed696e
Show file tree
Hide file tree
Showing 8 changed files with 454 additions and 19 deletions.
47 changes: 29 additions & 18 deletions llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2391,28 +2391,39 @@ void AArch64AsmPrinter::LowerLOADgotAUTH(const MachineInstr &MI) {
const MachineOperand &GAMO = MI.getOperand(1);
assert(GAMO.getOffset() == 0);

MachineOperand GAHiOp(GAMO);
MachineOperand GALoOp(GAMO);
GAHiOp.addTargetFlag(AArch64II::MO_PAGE);
GALoOp.addTargetFlag(AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
if (MI.getMF()->getTarget().getCodeModel() == CodeModel::Tiny) {
MCOperand GAMC;
MCInstLowering.lowerOperand(GAMO, GAMC);
EmitToStreamer(
MCInstBuilder(AArch64::ADR).addReg(AArch64::X17).addOperand(GAMC));
EmitToStreamer(MCInstBuilder(AArch64::LDRXui)
.addReg(AuthResultReg)
.addReg(AArch64::X17)
.addImm(0));
} else {
MachineOperand GAHiOp(GAMO);
MachineOperand GALoOp(GAMO);
GAHiOp.addTargetFlag(AArch64II::MO_PAGE);
GALoOp.addTargetFlag(AArch64II::MO_PAGEOFF | AArch64II::MO_NC);

MCOperand GAMCHi, GAMCLo;
MCInstLowering.lowerOperand(GAHiOp, GAMCHi);
MCInstLowering.lowerOperand(GALoOp, GAMCLo);
MCOperand GAMCHi, GAMCLo;
MCInstLowering.lowerOperand(GAHiOp, GAMCHi);
MCInstLowering.lowerOperand(GALoOp, GAMCLo);

EmitToStreamer(
MCInstBuilder(AArch64::ADRP).addReg(AArch64::X17).addOperand(GAMCHi));
EmitToStreamer(
MCInstBuilder(AArch64::ADRP).addReg(AArch64::X17).addOperand(GAMCHi));

EmitToStreamer(MCInstBuilder(AArch64::ADDXri)
.addReg(AArch64::X17)
.addReg(AArch64::X17)
.addOperand(GAMCLo)
.addImm(0));
EmitToStreamer(MCInstBuilder(AArch64::ADDXri)
.addReg(AArch64::X17)
.addReg(AArch64::X17)
.addOperand(GAMCLo)
.addImm(0));

EmitToStreamer(MCInstBuilder(AArch64::LDRXui)
.addReg(AuthResultReg)
.addReg(AArch64::X17)
.addImm(0));
EmitToStreamer(MCInstBuilder(AArch64::LDRXui)
.addReg(AuthResultReg)
.addReg(AArch64::X17)
.addImm(0));
}

assert(GAMO.isGlobal());
MCSymbol *UndefWeakSym;
Expand Down
8 changes: 7 additions & 1 deletion llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3354,7 +3354,13 @@ ParseStatus AArch64AsmParser::tryParseAdrLabel(OperandVector &Operands) {
// No modifier was specified at all; this is the syntax for an ELF basic
// ADR relocation (unfortunately).
Expr = AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS, getContext());
} else {
} else if (ELFRefKind != AArch64MCExpr::VK_GOT_AUTH_PAGE) {
// For tiny code model, we use :got_auth: operator to fill 21-bit imm of
// adr. It's not actually GOT entry page address but the GOT address
// itself - we just share the same variant kind with :got_auth: operator
// applied for adrp.
// TODO: can we somehow get current TargetMachine object to call
// getCodeModel() on it to ensure we are using tiny code model?
return Error(S, "unexpected adr label");
}
}
Expand Down
18 changes: 18 additions & 0 deletions llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,15 @@ unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx,
}
return ELF::R_AARCH64_PREL64;
case AArch64::fixup_aarch64_pcrel_adr_imm21:
if (SymLoc == AArch64MCExpr::VK_GOT_AUTH) {
if (IsILP32) {
Ctx.reportError(Fixup.getLoc(),
"ILP32 ADR AUTH relocation not supported "
"(LP64 eqv: AUTH_GOT_ADR_PREL_LO21)");
return ELF::R_AARCH64_NONE;
}
return ELF::R_AARCH64_AUTH_GOT_ADR_PREL_LO21;
}
if (SymLoc != AArch64MCExpr::VK_ABS)
Ctx.reportError(Fixup.getLoc(),
"invalid symbol kind for ADR relocation");
Expand Down Expand Up @@ -190,6 +199,15 @@ unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx,
return R_CLS(TLSIE_LD_GOTTPREL_PREL19);
if (SymLoc == AArch64MCExpr::VK_GOT)
return R_CLS(GOT_LD_PREL19);
if (SymLoc == AArch64MCExpr::VK_GOT_AUTH) {
if (IsILP32) {
Ctx.reportError(Fixup.getLoc(),
"ILP32 LDR AUTH relocation not supported "
"(LP64 eqv: AUTH_GOT_LD_PREL19)");
return ELF::R_AARCH64_NONE;
}
return ELF::R_AARCH64_AUTH_GOT_LD_PREL19;
}
return R_CLS(LD_PREL_LO19);
case AArch64::fixup_aarch64_pcrel_branch14:
return R_CLS(TSTBR14);
Expand Down
42 changes: 42 additions & 0 deletions llvm/test/CodeGen/AArch64/ptrauth-extern-weak.ll
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
; RUN: llc -mtriple=aarch64-none-linux-gnu -global-isel=1 -global-isel-abort=1 -relocation-model=pic \
; RUN: -mattr=+pauth -o - %s | FileCheck --check-prefixes=CHECK,TRAP %s

; RUN: llc -mtriple=aarch64-none-linux-gnu -code-model=tiny -mattr=+pauth -mattr=+fpac -o - %s | \
; RUN: FileCheck --check-prefixes=CHECK-TINY,NOTRAP-TINY %s
; RUN: llc -mtriple=aarch64-none-linux-gnu -code-model=tiny -mattr=+pauth -o - %s | \
; RUN: FileCheck --check-prefixes=CHECK-TINY,TRAP-TINY %s

;; Note: for FastISel, we fall back to SelectionDAG

declare extern_weak dso_local i32 @var()
Expand Down Expand Up @@ -41,6 +46,24 @@ define ptr @foo() {
; TRAP-NEXT: .Lauth_success_0:
; TRAP-NEXT: mov x0, x16
; CHECK-NEXT: ret

; CHECK-TINY-LABEL: foo:
; CHECK-TINY: adr x17, :got_auth:var
; NOTRAP-TINY-NEXT: ldr x0, [x17]
; NOTRAP-TINY-NEXT: cbz x0, .Lundef_weak0
; NOTRAP-TINY-NEXT: autia x0, x17
; TRAP-TINY-NEXT: ldr x16, [x17]
; TRAP-TINY-NEXT: cbz x16, .Lundef_weak0
; TRAP-TINY-NEXT: autia x16, x17
; CHECK-TINY-NEXT: .Lundef_weak0:
; TRAP-TINY-NEXT: mov x17, x16
; TRAP-TINY-NEXT: xpaci x17
; TRAP-TINY-NEXT: cmp x16, x17
; TRAP-TINY-NEXT: b.eq .Lauth_success_0
; TRAP-TINY-NEXT: brk #0xc470
; TRAP-TINY-NEXT: .Lauth_success_0:
; TRAP-TINY-NEXT: mov x0, x16
; CHECK-TINY-NEXT: ret
}

@arr_var = extern_weak global [10 x i32]
Expand Down Expand Up @@ -68,6 +91,25 @@ define ptr @bar() {
; TRAP-NEXT: mov x8, x16
; CHECK-NEXT: add x0, x8, #20
; CHECK-NEXT: ret

; CHECK-TINY-LABEL: bar:
; CHECK-TINY: adr x17, :got_auth:arr_var
; NOTRAP-TINY-NEXT: ldr x8, [x17]
; NOTRAP-TINY-NEXT: cbz x8, .Lundef_weak1
; NOTRAP-TINY-NEXT: autda x8, x17
; TRAP-TINY-NEXT: ldr x16, [x17]
; TRAP-TINY-NEXT: cbz x16, .Lundef_weak1
; TRAP-TINY-NEXT: autda x16, x17
; CHECK-TINY-NEXT: .Lundef_weak1:
; TRAP-TINY-NEXT: mov x17, x16
; TRAP-TINY-NEXT: xpacd x17
; TRAP-TINY-NEXT: cmp x16, x17
; TRAP-TINY-NEXT: b.eq .Lauth_success_1
; TRAP-TINY-NEXT: brk #0xc472
; TRAP-TINY-NEXT: .Lauth_success_1:
; TRAP-TINY-NEXT: mov x8, x16
; CHECK-TINY-NEXT: add x0, x8, #20
; CHECK-TINY-NEXT: ret
}

!llvm.module.flags = !{!0}
Expand Down
182 changes: 182 additions & 0 deletions llvm/test/CodeGen/AArch64/ptrauth-tiny-model-pic.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
; RUN: llc -verify-machineinstrs -mtriple=aarch64 -mattr=+pauth -mattr=+fpac -code-model=tiny \
; RUN: -relocation-model=pic < %s | FileCheck --check-prefixes=CHECK,NOTRAP %s
; RUN: llc -verify-machineinstrs -mtriple=aarch64 -mattr=+pauth -code-model=tiny \
; RUN: -relocation-model=pic < %s | FileCheck --check-prefixes=CHECK,TRAP %s

; RUN: llc -verify-machineinstrs -mtriple=aarch64 -mattr=+pauth -mattr=+fpac -code-model=tiny \
; RUN: -relocation-model=pic -fast-isel < %s | FileCheck --check-prefixes=CHECK,NOTRAP %s
; RUN: llc -verify-machineinstrs -mtriple=aarch64 -mattr=+pauth -code-model=tiny \
; RUN: -relocation-model=pic -fast-isel < %s | FileCheck --check-prefixes=CHECK,TRAP %s

; RUN: llc -verify-machineinstrs -mtriple=aarch64 -mattr=+pauth -mattr=+fpac -code-model=tiny \
; RUN: -relocation-model=pic -global-isel -global-isel-abort=1 < %s | FileCheck --check-prefixes=CHECK,NOTRAP %s
; RUN: llc -verify-machineinstrs -mtriple=aarch64 -mattr=+pauth -code-model=tiny \
; RUN: -relocation-model=pic -global-isel -global-isel-abort=1 < %s | FileCheck --check-prefixes=CHECK,TRAP %s

; Note: fast-isel tests here will fall back to isel

@src = external local_unnamed_addr global [65536 x i8], align 1
@dst = external global [65536 x i8], align 1
@ptr = external local_unnamed_addr global ptr, align 8

define dso_preemptable void @foo1() {
; CHECK-LABEL: foo1:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: adr x17, :got_auth:src
; NOTRAP-NEXT: ldr x8, [x17]
; NOTRAP-NEXT: autda x8, x17
; TRAP-NEXT: ldr x16, [x17]
; TRAP-NEXT: autda x16, x17
; TRAP-NEXT: mov x17, x16
; TRAP-NEXT: xpacd x17
; TRAP-NEXT: cmp x16, x17
; TRAP-NEXT: b.eq .Lauth_success_0
; TRAP-NEXT: brk #0xc472
; TRAP-NEXT: .Lauth_success_0:
; TRAP-NEXT: mov x8, x16
; CHECK-NEXT: ldrb w8, [x8]
; CHECK-NEXT: adr x17, :got_auth:dst
; NOTRAP-NEXT: ldr x9, [x17]
; NOTRAP-NEXT: autda x9, x17
; TRAP-NEXT: ldr x16, [x17]
; TRAP-NEXT: autda x16, x17
; TRAP-NEXT: mov x17, x16
; TRAP-NEXT: xpacd x17
; TRAP-NEXT: cmp x16, x17
; TRAP-NEXT: b.eq .Lauth_success_1
; TRAP-NEXT: brk #0xc472
; TRAP-NEXT: .Lauth_success_1:
; TRAP-NEXT: mov x9, x16
; CHECK-NEXT: strb w8, [x9]
; CHECK-NEXT: ret

entry:
%0 = load i8, ptr @src, align 1
store i8 %0, ptr @dst, align 1
ret void
}

define dso_preemptable void @foo2() {
; CHECK-LABEL: foo2:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: adr x17, :got_auth:ptr
; NOTRAP-NEXT: ldr x8, [x17]
; NOTRAP-NEXT: autda x8, x17
; TRAP-NEXT: ldr x16, [x17]
; TRAP-NEXT: autda x16, x17
; TRAP-NEXT: mov x17, x16
; TRAP-NEXT: xpacd x17
; TRAP-NEXT: cmp x16, x17
; TRAP-NEXT: b.eq .Lauth_success_2
; TRAP-NEXT: brk #0xc472
; TRAP-NEXT: .Lauth_success_2:
; TRAP-NEXT: mov x8, x16
; CHECK-NEXT: adr x17, :got_auth:dst
; NOTRAP-NEXT: ldr x9, [x17]
; NOTRAP-NEXT: autda x9, x17
; TRAP-NEXT: ldr x16, [x17]
; TRAP-NEXT: autda x16, x17
; TRAP-NEXT: mov x17, x16
; TRAP-NEXT: xpacd x17
; TRAP-NEXT: cmp x16, x17
; TRAP-NEXT: b.eq .Lauth_success_3
; TRAP-NEXT: brk #0xc472
; TRAP-NEXT: .Lauth_success_3:
; TRAP-NEXT: mov x9, x16
; CHECK-NEXT: str x9, [x8]
; CHECK-NEXT: ret

entry:
store ptr @dst, ptr @ptr, align 8
ret void
}

define dso_preemptable void @foo3() {
; CHECK-LABEL: foo3:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: adr x17, :got_auth:src
; NOTRAP-NEXT: ldr x8, [x17]
; NOTRAP-NEXT: autda x8, x17
; TRAP-NEXT: ldr x16, [x17]
; TRAP-NEXT: autda x16, x17
; TRAP-NEXT: mov x17, x16
; TRAP-NEXT: xpacd x17
; TRAP-NEXT: cmp x16, x17
; TRAP-NEXT: b.eq .Lauth_success_4
; TRAP-NEXT: brk #0xc472
; TRAP-NEXT: .Lauth_success_4:
; TRAP-NEXT: mov x8, x16
; CHECK-NEXT: ldrb w8, [x8]
; CHECK-NEXT: adr x17, :got_auth:ptr
; NOTRAP-NEXT: ldr x9, [x17]
; NOTRAP-NEXT: autda x9, x17
; TRAP-NEXT: ldr x16, [x17]
; TRAP-NEXT: autda x16, x17
; TRAP-NEXT: mov x17, x16
; TRAP-NEXT: xpacd x17
; TRAP-NEXT: cmp x16, x17
; TRAP-NEXT: b.eq .Lauth_success_5
; TRAP-NEXT: brk #0xc472
; TRAP-NEXT: .Lauth_success_5:
; TRAP-NEXT: mov x9, x16
; CHECK-NEXT: ldr x9, [x9]
; CHECK-NEXT: strb w8, [x9]
; CHECK-NEXT: ret

entry:
%0 = load i8, ptr @src, align 1
%1 = load ptr, ptr @ptr, align 8
store i8 %0, ptr %1, align 1
ret void
}

@lsrc = internal global i8 0, align 4
@ldst = internal global i8 0, align 4
@lptr = internal global ptr null, align 8

declare void @func(...)

define dso_preemptable ptr @externfuncaddr() {
; CHECK-LABEL: externfuncaddr:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: adr x17, :got_auth:func
; NOTRAP-NEXT: ldr x0, [x17]
; NOTRAP-NEXT: autia x0, x17
; TRAP-NEXT: ldr x16, [x17]
; TRAP-NEXT: autia x16, x17
; TRAP-NEXT: mov x17, x16
; TRAP-NEXT: xpaci x17
; TRAP-NEXT: cmp x16, x17
; TRAP-NEXT: b.eq .Lauth_success_6
; TRAP-NEXT: brk #0xc470
; TRAP-NEXT: .Lauth_success_6:
; TRAP-NEXT: mov x0, x16
; CHECK-NEXT: ret

entry:
ret ptr @func
}

define dso_preemptable ptr @localfuncaddr() {
; CHECK-LABEL: localfuncaddr:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: adr x17, :got_auth:externfuncaddr
; NOTRAP-NEXT: ldr x0, [x17]
; NOTRAP-NEXT: autia x0, x17
; TRAP-NEXT: ldr x16, [x17]
; TRAP-NEXT: autia x16, x17
; TRAP-NEXT: mov x17, x16
; TRAP-NEXT: xpaci x17
; TRAP-NEXT: cmp x16, x17
; TRAP-NEXT: b.eq .Lauth_success_7
; TRAP-NEXT: brk #0xc470
; TRAP-NEXT: .Lauth_success_7:
; TRAP-NEXT: mov x0, x16
; CHECK-NEXT: ret

entry:
ret ptr @externfuncaddr
}

!llvm.module.flags = !{!0}
!0 = !{i32 8, !"ptrauth-elf-got", i32 1}
Loading

0 comments on commit 0ed696e

Please sign in to comment.