From b5cbc7760ab82c55ee8b340624c9119dfc592e26 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Sun, 19 Nov 2017 01:35:00 +0000 Subject: [PATCH] [bpf] allow direct and indirect calls kernel verifier is becoming smarter and soon will support direct and indirect function calls. Remove obsolete error from BPF backend. Make call to use PCRel_4 fixup. 'bpf to bpf' calls are distinguished from 'bpf to kernel' calls by insn->src_reg == BPF_PSEUDO_CALL == 1 which is used as relocation indicator similar to ld_imm64->src_reg == BPF_PSEUDO_MAP_FD == 1 The actual 'call' instruction remains the same for both 'bpf to kernel' and 'bpf to bpf' calls. Signed-off-by: Alexei Starovoitov git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@318614 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/BPF/BPFISelLowering.cpp | 7 ------- lib/Target/BPF/BPFInstrInfo.td | 14 ++++++++++++++ lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp | 9 +++++++++ lib/Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp | 1 + lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp | 2 +- test/CodeGen/BPF/cc_args.ll | 2 +- test/CodeGen/BPF/cc_args_be.ll | 2 +- test/CodeGen/BPF/cc_ret.ll | 2 +- test/CodeGen/BPF/fi_ri.ll | 2 +- test/CodeGen/BPF/sanity.ll | 2 +- test/CodeGen/BPF/undef.ll | 4 ++-- test/CodeGen/BPF/warn-call.ll | 3 --- 12 files changed, 32 insertions(+), 18 deletions(-) diff --git a/lib/Target/BPF/BPFISelLowering.cpp b/lib/Target/BPF/BPFISelLowering.cpp index 995f206529f..f9078fae028 100644 --- a/lib/Target/BPF/BPFISelLowering.cpp +++ b/lib/Target/BPF/BPFISelLowering.cpp @@ -330,13 +330,6 @@ SDValue BPFTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, // Likewise ExternalSymbol -> TargetExternalSymbol. if (GlobalAddressSDNode *G = dyn_cast(Callee)) { auto GV = G->getGlobal(); - fail(CLI.DL, DAG, - "A call to global function '" + StringRef(GV->getName()) - + "' is not supported. " - + (GV->isDeclaration() ? - "Only calls to predefined BPF helpers are allowed." : - "Please use __attribute__((always_inline) to make sure" - " this function is inlined.")); Callee = DAG.getTargetGlobalAddress(G->getGlobal(), CLI.DL, PtrVT, G->getOffset(), 0); } else if (ExternalSymbolSDNode *E = dyn_cast(Callee)) { diff --git a/lib/Target/BPF/BPFInstrInfo.td b/lib/Target/BPF/BPFInstrInfo.td index 27b26b987fa..126d55fc28d 100644 --- a/lib/Target/BPF/BPFInstrInfo.td +++ b/lib/Target/BPF/BPFInstrInfo.td @@ -400,6 +400,18 @@ class CALL let BPFClass = BPF_JMP; } +class CALLX + : TYPE_ALU_JMP { + bits<32> BrDst; + + let Inst{31-0} = BrDst; + let BPFClass = BPF_JMP; +} + // Jump always let isBranch = 1, isTerminator = 1, hasDelaySlot=0, isBarrier = 1 in { def JMP : BRANCH; @@ -410,6 +422,7 @@ let isCall=1, hasDelaySlot=0, Uses = [R11], // Potentially clobbered registers Defs = [R0, R1, R2, R3, R4, R5] in { def JAL : CALL<"call">; + def JALX : CALLX<"callx">; } class NOP_I @@ -476,6 +489,7 @@ def : Pat<(i64 (and (i64 GPR:$src), 0xffffFFFF)), def : Pat<(BPFcall tglobaladdr:$dst), (JAL tglobaladdr:$dst)>; def : Pat<(BPFcall texternalsym:$dst), (JAL texternalsym:$dst)>; def : Pat<(BPFcall imm:$dst), (JAL imm:$dst)>; +def : Pat<(BPFcall GPR:$dst), (JALX GPR:$dst)>; // Loads def : Pat<(extloadi8 ADDRri:$src), (i64 (LDB ADDRri:$src))>; diff --git a/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp b/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp index 800700d3dad..e6ea92e0836 100644 --- a/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp +++ b/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp @@ -76,6 +76,15 @@ void BPFAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, unsigned Idx = IsLittleEndian ? i : Size - i - 1; Data[Fixup.getOffset() + Idx] = uint8_t(Value >> (i * 8)); } + } else if (Fixup.getKind() == FK_PCRel_4) { + Value = (uint32_t)((Value - 8) / 8); + if (IsLittleEndian) { + Data[Fixup.getOffset() + 1] = 0x10; + support::endian::write32le(&Data[Fixup.getOffset() + 4], Value); + } else { + Data[Fixup.getOffset() + 1] = 0x1; + support::endian::write32be(&Data[Fixup.getOffset() + 4], Value); + } } else { assert(Fixup.getKind() == FK_PCRel_2); Value = (uint16_t)((Value - 8) / 8); diff --git a/lib/Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp b/lib/Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp index 144ea2b697d..f7de612dab1 100644 --- a/lib/Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp +++ b/lib/Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp @@ -44,6 +44,7 @@ unsigned BPFELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, llvm_unreachable("invalid fixup kind!"); case FK_SecRel_8: return ELF::R_BPF_64_64; + case FK_PCRel_4: case FK_SecRel_4: return ELF::R_BPF_64_32; case FK_Data_8: diff --git a/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp b/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp index e8c97447982..b4ecfdee7bf 100644 --- a/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp +++ b/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp @@ -100,7 +100,7 @@ unsigned BPFMCCodeEmitter::getMachineOpValue(const MCInst &MI, if (MI.getOpcode() == BPF::JAL) // func call name - Fixups.push_back(MCFixup::create(0, Expr, FK_SecRel_4)); + Fixups.push_back(MCFixup::create(0, Expr, FK_PCRel_4)); else if (MI.getOpcode() == BPF::LD_imm64) Fixups.push_back(MCFixup::create(0, Expr, FK_SecRel_8)); else diff --git a/test/CodeGen/BPF/cc_args.ll b/test/CodeGen/BPF/cc_args.ll index 6a0a07ae8e8..020992a9fd5 100644 --- a/test/CodeGen/BPF/cc_args.ll +++ b/test/CodeGen/BPF/cc_args.ll @@ -1,4 +1,4 @@ -; RUN: not llc < %s -march=bpfel -show-mc-encoding | FileCheck %s +; RUN: llc < %s -march=bpfel -show-mc-encoding | FileCheck %s define void @test() #0 { entry: diff --git a/test/CodeGen/BPF/cc_args_be.ll b/test/CodeGen/BPF/cc_args_be.ll index a2f1956319e..469556f6c78 100644 --- a/test/CodeGen/BPF/cc_args_be.ll +++ b/test/CodeGen/BPF/cc_args_be.ll @@ -1,4 +1,4 @@ -; RUN: not llc < %s -march=bpfeb -show-mc-encoding | FileCheck %s +; RUN: llc < %s -march=bpfeb -show-mc-encoding | FileCheck %s ; test big endian define void @test() #0 { diff --git a/test/CodeGen/BPF/cc_ret.ll b/test/CodeGen/BPF/cc_ret.ll index be198f5d15f..73e3556c63e 100644 --- a/test/CodeGen/BPF/cc_ret.ll +++ b/test/CodeGen/BPF/cc_ret.ll @@ -1,4 +1,4 @@ -; RUN: not llc < %s -march=bpfel | FileCheck %s +; RUN: llc < %s -march=bpfel | FileCheck %s define void @test() #0 { entry: diff --git a/test/CodeGen/BPF/fi_ri.ll b/test/CodeGen/BPF/fi_ri.ll index 6ecc8267969..12452988e8a 100644 --- a/test/CodeGen/BPF/fi_ri.ll +++ b/test/CodeGen/BPF/fi_ri.ll @@ -1,4 +1,4 @@ -; RUN: not llc < %s -march=bpf | FileCheck %s +; RUN: llc < %s -march=bpf | FileCheck %s %struct.key_t = type { i32, [16 x i8] } diff --git a/test/CodeGen/BPF/sanity.ll b/test/CodeGen/BPF/sanity.ll index ebee851fbfb..33cfc2fb030 100644 --- a/test/CodeGen/BPF/sanity.ll +++ b/test/CodeGen/BPF/sanity.ll @@ -1,4 +1,4 @@ -; RUN: not llc < %s -march=bpfel | FileCheck %s +; RUN: llc < %s -march=bpfel | FileCheck %s @foo_printf.fmt = private unnamed_addr constant [9 x i8] c"hello \0A\00", align 1 diff --git a/test/CodeGen/BPF/undef.ll b/test/CodeGen/BPF/undef.ll index 6b9948619d8..11bc9ebd254 100644 --- a/test/CodeGen/BPF/undef.ll +++ b/test/CodeGen/BPF/undef.ll @@ -1,5 +1,5 @@ -; RUN: not llc < %s -march=bpfel | FileCheck -check-prefixes=CHECK,EL %s -; RUN: not llc < %s -march=bpfeb | FileCheck -check-prefixes=CHECK,EB %s +; RUN: llc < %s -march=bpfel | FileCheck -check-prefixes=CHECK,EL %s +; RUN: llc < %s -march=bpfeb | FileCheck -check-prefixes=CHECK,EB %s %struct.bpf_map_def = type { i32, i32, i32, i32 } %struct.__sk_buff = type opaque diff --git a/test/CodeGen/BPF/warn-call.ll b/test/CodeGen/BPF/warn-call.ll index ae7f78ac1aa..6dadb359cf6 100644 --- a/test/CodeGen/BPF/warn-call.ll +++ b/test/CodeGen/BPF/warn-call.ll @@ -2,9 +2,6 @@ ; CHECK: error: warn_call.c ; CHECK: built-in function 'memcpy' -; CHECK: error: warn_call.c -; CHECK: global function 'foo' -; CHECK: global function 'bar' define i8* @warn(i8* returned, i8*, i64) local_unnamed_addr #0 !dbg !6 { tail call void @llvm.dbg.value(metadata i8* %0, i64 0, metadata !14, metadata !17), !dbg !18 tail call void @llvm.dbg.value(metadata i8* %1, i64 0, metadata !15, metadata !17), !dbg !19 -- 2.11.0