Index: lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp =================================================================== --- lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp +++ lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp @@ -140,14 +140,18 @@ bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, uint64_t &Target) const override { - if (Inst.getNumOperands() == 0 || - Info->get(Inst.getOpcode()).OpInfo[0].OperandType != - MCOI::OPERAND_PCREL) - return false; - - int64_t Imm = Inst.getOperand(0).getImm() * 4; - Target = Addr + Imm; - return true; + // Search for a PC-relative argument. + // This will handle instructions like bcc (where the first argument is the + // condition code) and cbz (where it is a register). + const auto &Desc = Info->get(Inst.getOpcode()); + for (unsigned i = 0, e = Inst.getNumOperands(); i != e; i++) { + if (Desc.OpInfo[i].OperandType == MCOI::OPERAND_PCREL) { + int64_t Imm = Inst.getOperand(i).getImm() * 4; + Target = Addr + Imm; + return true; + } + } + return false; } }; Index: test/tools/llvm-cfi-verify/AArch64/tiny.s =================================================================== --- /dev/null +++ test/tools/llvm-cfi-verify/AArch64/tiny.s @@ -0,0 +1,183 @@ +# RUN: llvm-mc %s -filetype obj -triple aarch64-- -o %t.o +# RUN: llvm-cfi-verify %t.o | FileCheck %s + +# CHECK-LABEL: {{^Instruction: .* \(PROTECTED\)}} +# CHECK-NEXT: tiny.cc:9 + +# CHECK: Expected Protected: 1 (100.00%) +# CHECK: Unexpected Protected: 0 (0.00%) +# CHECK: Expected Unprotected: 0 (0.00%) +# CHECK: Unexpected Unprotected (BAD): 0 (0.00%) + +# Source (tiny.cc): +# void a() {} +# void b() {} +# int main(int argc, char** argv) { +# void(*ptr)(); +# if (argc == 1) +# ptr = &a; +# else +# ptr = &b; +# ptr(); +# } + .text + .file "ld-temp.o" + .p2align 2 + .type _Z1av.cfi,@function +_Z1av.cfi: +.Lfunc_begin0: + .file 1 "/tmp/tiny.cc" + .loc 1 1 0 + .cfi_startproc + .loc 1 1 11 prologue_end + mov w0, wzr + ret +.Ltmp0: +.Lfunc_end0: + .size _Z1av.cfi, .Lfunc_end0-_Z1av.cfi + .cfi_endproc + + .p2align 2 + .type _Z1bv.cfi,@function +_Z1bv.cfi: +.Lfunc_begin1: + .loc 1 2 0 + .cfi_startproc + .loc 1 2 11 prologue_end + orr w0, wzr, #0x1 + ret +.Ltmp1: +.Lfunc_end1: + .size _Z1bv.cfi, .Lfunc_end1-_Z1bv.cfi + .cfi_endproc + + .p2align 2 + .type main,@function +main: +.Lfunc_begin2: + .loc 1 3 0 + .cfi_startproc + sub sp, sp, #48 + stp x29, x30, [sp, #32] + add x29, sp, #32 + .cfi_def_cfa w29, 16 + .cfi_offset w30, -8 + .cfi_offset w29, -16 + stur wzr, [x29, #-4] + stur w0, [x29, #-8] + str x1, [sp, #16] +.Ltmp2: + .loc 1 5 7 prologue_end + ldur w8, [x29, #-8] + cmp w8, #1 + b.ne .LBB2_2 + .loc 1 0 7 is_stmt 0 + adrp x8, _Z1av + add x8, x8, :lo12:_Z1av + .loc 1 6 9 is_stmt 1 + str x8, [sp, #8] + .loc 1 6 5 is_stmt 0 + b .LBB2_3 +.LBB2_2: + .loc 1 0 5 + adrp x8, _Z1bv + add x8, x8, :lo12:_Z1bv + .loc 1 8 9 is_stmt 1 + str x8, [sp, #8] +.LBB2_3: + .loc 1 0 9 is_stmt 0 + adrp x8, .L.cfi.jumptable + add x9, x8, :lo12:.L.cfi.jumptable + .loc 1 9 10 is_stmt 1 + ldr x8, [sp, #8] + sub x9, x8, x9 + lsr x10, x9, #2 + orr x9, x10, x9, lsl #62 + cmp x9, #1 + b.ls .LBB2_5 + brk #0x1 +.LBB2_5: + blr x8 + .loc 1 9 3 is_stmt 0 + ldp x29, x30, [sp, #32] + add sp, sp, #48 + ret +.Ltmp3: +.Lfunc_end2: + .size main, .Lfunc_end2-main + .cfi_endproc + + .p2align 2 + .type .L.cfi.jumptable,@function +.L.cfi.jumptable: +.Lfunc_begin3: + .cfi_startproc + //APP + b _Z1av.cfi + b _Z1bv.cfi + + //NO_APP +.Lfunc_end3: + .size .L.cfi.jumptable, .Lfunc_end3-.L.cfi.jumptable + .cfi_endproc + + .type .L__unnamed_1,@object + .section .rodata,"a",@progbits + .p2align 2 +.L__unnamed_1: + .size .L__unnamed_1, 0 + + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "clang version 7.0.0 (trunk 335774) (llvm/trunk 335775)" +.Linfo_string1: + .asciz "tiny.cc" +.Linfo_string2: + .asciz "" + .section .debug_abbrev,"",@progbits + .byte 1 + .byte 17 + .byte 0 + .byte 37 + .byte 14 + .byte 19 + .byte 5 + .byte 3 + .byte 14 + .byte 16 + .byte 23 + .byte 27 + .byte 14 + .byte 17 + .byte 1 + .byte 18 + .byte 6 + .byte 0 + .byte 0 + .byte 0 + .section .debug_info,"",@progbits +.Lcu_begin0: + .word 38 + .hword 4 + .word .debug_abbrev + .byte 8 + .byte 1 + .word .Linfo_string0 + .hword 4 + .word .Linfo_string1 + .word .Lline_table_start0 + .word .Linfo_string2 + .xword .Lfunc_begin0 + .word .Lfunc_end2-.Lfunc_begin0 + .section .debug_ranges,"",@progbits + .section .debug_macinfo,"",@progbits + .byte 0 + + .type _Z1av,@function +.set _Z1av, .L.cfi.jumptable + .type _Z1bv,@function +.set _Z1bv, .L.cfi.jumptable+4 + .ident "clang version 7.0.0 (trunk 335774) (llvm/trunk 335775)" + .section ".note.GNU-stack","",@progbits + .section .debug_line,"",@progbits +.Lline_table_start0: Index: tools/llvm-cfi-verify/lib/FileAnalysis.cpp =================================================================== --- tools/llvm-cfi-verify/lib/FileAnalysis.cpp +++ tools/llvm-cfi-verify/lib/FileAnalysis.cpp @@ -154,7 +154,8 @@ } bool FileAnalysis::isCFITrap(const Instr &InstrMeta) const { - return MII->getName(InstrMeta.Instruction.getOpcode()) == "TRAP"; + return MII->getName(InstrMeta.Instruction.getOpcode()) == "TRAP" || + MII->getName(InstrMeta.Instruction.getOpcode()) == "BRK"; } bool FileAnalysis::canFallThrough(const Instr &InstrMeta) const { @@ -288,6 +289,10 @@ } assert(RegisterNumbers.size() && "Zero register operands on indirect CF."); + // Some architectures (e.g., AArch64) cannot load in an indirect branch, so we + // allow them one load. + bool canLoad = !MII->get(IndirectCF.Instruction.getOpcode()).mayLoad(); + // Now check all branches to indirect CFs and ensure no clobbering happens. for (const auto &Branch : Graph.ConditionalBranchNodes) { uint64_t Node; @@ -296,20 +301,41 @@ else Node = Branch.Fallthrough; + // We walk backwards from the indirect CF. + SmallVector Nodes; while (Node != Graph.BaseAddress) { + Nodes.push_back(Node); + const auto &KV = Graph.IntermediateNodes.find(Node); + assert((KV != Graph.IntermediateNodes.end()) && + "Could not get next node."); + Node = KV->second; + } + DenseSet CurRegisterNumbers = RegisterNumbers; + for (auto I = Nodes.rbegin(), E = Nodes.rend(); I != E; ++I) { + Node = *I; const Instr &NodeInstr = getInstructionOrDie(Node); const auto &InstrDesc = MII->get(NodeInstr.Instruction.getOpcode()); - for (unsigned RegNum : RegisterNumbers) { + for (auto RI = CurRegisterNumbers.begin(), RE = CurRegisterNumbers.end(); + RI != RE; ++RI) { + unsigned RegNum = *RI; if (InstrDesc.hasDefOfPhysReg(NodeInstr.Instruction, RegNum, - *RegisterInfo)) - return Node; + *RegisterInfo)) { + if (canLoad && InstrDesc.mayLoad()) { + canLoad = false; + CurRegisterNumbers.erase(RI); + // Add the registers this load reads to those we check for clobbers. + for (unsigned i = InstrDesc.getNumDefs(), + e = InstrDesc.getNumOperands(); i != e; i++) { + const auto Operand = NodeInstr.Instruction.getOperand(i); + if (Operand.isReg()) + CurRegisterNumbers.insert(Operand.getReg()); + } + break; + } else + return Node; + } } - - const auto &KV = Graph.IntermediateNodes.find(Node); - assert((KV != Graph.IntermediateNodes.end()) && - "Could not get next node."); - Node = KV->second; } } @@ -456,6 +482,9 @@ if (!usesRegisterOperand(InstrMeta)) continue; + if (InstrDesc.isReturn()) + continue; + // Check if this instruction exists in the range of the DWARF metadata. if (!IgnoreDWARFFlag) { auto LineInfo =