Commit 22467e25 authored by Fangrui Song's avatar Fangrui Song
Browse files

Add function attribute "patchable-function-prefix" to support...

Add function attribute "patchable-function-prefix" to support -fpatchable-function-entry=N,M where M>0

Similar to the function attribute `prefix` (prefix data),
"patchable-function-prefix" inserts data (M NOPs) before the function
entry label.

-fpatchable-function-entry=2,1 (1 NOP before entry, 1 NOP after entry)
will look like:

```
  .type	foo,@function
.Ltmp0:               # @foo
  nop
foo:
.Lfunc_begin0:
  # optional `bti c` (AArch64 Branch Target Identification) or
  # `endbr64` (Intel Indirect Branch Tracking)
  nop

  .section  __patchable_function_entries,"awo",@progbits,get,unique,0
  .p2align  3
  .quad .Ltmp0
```

-fpatchable-function-entry=N,0 + -mbranch-protection=bti/-fcf-protection=branch has two reasonable
placements (https://gcc.gnu.org/ml/gcc-patches/2020-01/msg01185.html):

```
(a)         (b)

func:       func:
.Ltmp0:     bti c
  bti c     .Ltmp0:
  nop       nop
```

(a) needs no additional code. If the consensus is to go for (b), we will
need more code in AArch64BranchTargets.cpp / X86IndirectBranchTracking.cpp .

Differential Revision: https://reviews.llvm.org/D73070
parent f394d22f
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -113,6 +113,9 @@ public:

  ProfileSummaryInfo *PSI;

  /// The symbol for the entry in __patchable_function_entires.
  MCSymbol *CurrentPatchableFunctionEntrySym = nullptr;

  /// The symbol for the current function. This is recalculated at the beginning
  /// of each call to runOnMachineFunction().
  MCSymbol *CurrentFnSym = nullptr;
@@ -449,6 +452,9 @@ public:
  /// instructions in verbose mode.
  virtual void emitImplicitDef(const MachineInstr *MI) const;

  /// Emit N NOP instructions.
  void emitNops(unsigned N);

  //===------------------------------------------------------------------===//
  // Symbol Lowering Routines.
  //===------------------------------------------------------------------===//
+29 −4
Original line number Diff line number Diff line
@@ -706,6 +706,21 @@ void AsmPrinter::EmitFunctionHeader() {
    }
  }

  // Emit M NOPs for -fpatchable-function-entry=N,M where M>0. We arbitrarily
  // place prefix data before NOPs.
  unsigned PatchableFunctionPrefix = 0;
  (void)F.getFnAttribute("patchable-function-prefix")
      .getValueAsString()
      .getAsInteger(10, PatchableFunctionPrefix);
  if (PatchableFunctionPrefix) {
    CurrentPatchableFunctionEntrySym =
        OutContext.createLinkerPrivateTempSymbol();
    OutStreamer->EmitLabel(CurrentPatchableFunctionEntrySym);
    emitNops(PatchableFunctionPrefix);
  } else {
    CurrentPatchableFunctionEntrySym = CurrentFnBegin;
  }

  // Emit the function descriptor. This is a virtual function to allow targets
  // to emit their specific function descriptor.
  if (MAI->needsFunctionDescriptors())
@@ -1157,7 +1172,7 @@ void AsmPrinter::EmitFunctionBody() {
    // unspecified.
    if (Noop.getOpcode()) {
      OutStreamer->AddComment("avoids zero-length function");
      OutStreamer->EmitInstruction(Noop, getSubtargetInfo());
      emitNops(1);
    }
  }

@@ -2787,6 +2802,13 @@ void AsmPrinter::printOffset(int64_t Offset, raw_ostream &OS) const {
    OS << Offset;
}

void AsmPrinter::emitNops(unsigned N) {
  MCInst Nop;
  MF->getSubtarget().getInstrInfo()->getNoop(Nop);
  for (; N; --N)
    EmitToStreamer(*OutStreamer, Nop);
}

//===----------------------------------------------------------------------===//
// Symbol Lowering Routines.
//===----------------------------------------------------------------------===//
@@ -3189,11 +3211,14 @@ void AsmPrinter::recordSled(MCSymbol *Sled, const MachineInstr &MI,

void AsmPrinter::emitPatchableFunctionEntries() {
  const Function &F = MF->getFunction();
  unsigned PatchableFunctionEntry = 0;
  unsigned PatchableFunctionPrefix = 0, PatchableFunctionEntry = 0;
  (void)F.getFnAttribute("patchable-function-prefix")
      .getValueAsString()
      .getAsInteger(10, PatchableFunctionPrefix);
  (void)F.getFnAttribute("patchable-function-entry")
      .getValueAsString()
      .getAsInteger(10, PatchableFunctionEntry);
  if (!PatchableFunctionEntry)
  if (!PatchableFunctionPrefix && !PatchableFunctionEntry)
    return;
  const unsigned PointerSize = getPointerSize();
  if (TM.getTargetTriple().isOSBinFormatELF()) {
@@ -3222,7 +3247,7 @@ void AsmPrinter::emitPatchableFunctionEntries() {
          "__patchable_function_entries", ELF::SHT_PROGBITS, Flags));
    }
    EmitAlignment(Align(PointerSize));
    OutStreamer->EmitSymbolValue(CurrentFnBegin, PointerSize);
    OutStreamer->EmitSymbolValue(CurrentPatchableFunctionEntrySym, PointerSize);
  }
}

+15 −6
Original line number Diff line number Diff line
@@ -1852,16 +1852,25 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
      CheckFailed("invalid value for 'frame-pointer' attribute: " + FP, V);
  }

  if (Attrs.hasFnAttribute("patchable-function-prefix")) {
    StringRef S = Attrs
                      .getAttribute(AttributeList::FunctionIndex,
                                    "patchable-function-prefix")
                      .getValueAsString();
    unsigned N;
    if (S.getAsInteger(10, N))
      CheckFailed(
          "\"patchable-function-prefix\" takes an unsigned integer: " + S, V);
  }
  if (Attrs.hasFnAttribute("patchable-function-entry")) {
    StringRef S0 = Attrs
    StringRef S = Attrs
                      .getAttribute(AttributeList::FunctionIndex,
                                    "patchable-function-entry")
                      .getValueAsString();
    StringRef S = S0;
    unsigned N;
    if (S.getAsInteger(10, N))
      CheckFailed(
          "\"patchable-function-entry\" takes an unsigned integer: " + S0, V);
          "\"patchable-function-entry\" takes an unsigned integer: " + S, V);
  }
}

+1 −2
Original line number Diff line number Diff line
@@ -250,8 +250,7 @@ void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI)
            .getValueAsString()
            .getAsInteger(10, Num))
      return;
    for (; Num; --Num)
      EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
    emitNops(Num);
    return;
  }

+1 −4
Original line number Diff line number Diff line
@@ -207,10 +207,7 @@ void ARMAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind)
  EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::Bcc).addImm(20)
    .addImm(ARMCC::AL).addReg(0));

  MCInst Noop;
  Subtarget->getInstrInfo()->getNoop(Noop);
  for (int8_t I = 0; I < NoopsInSledCount; I++)
    OutStreamer->EmitInstruction(Noop, getSubtargetInfo());
  emitNops(NoopsInSledCount);

  OutStreamer->EmitLabel(Target);
  recordSled(CurSled, MI, Kind);
Loading