Prolog Epilog


Q&A/Top

  • Where is the return address being spilled?
  • Where is the allocated stack frame being ‘destroyed’?

Reference reference

Pass overview

PEI (Prolog Epilog Inserter) pass creation:

// 
void TargetPassConfig::addMachinePasses() {

  //...

  // Insert prolog/epilog code.  Eliminate abstract frame index references...
  if (getOptLevel() != CodeGenOpt::None) {
    addPass(&PostRAMachineSinkingID); // sink COPY instructions which should be handled after RA.
    addPass(&ShrinkWrapID); // determine where the safe point to insert the prologue and epilogue.
  }

  // Prolog/Epilog inserter needs a TargetMachine to instantiate. But only
  // do so if it hasn't been disabled, substituted, or overridden.
  if (!isPassSubstitutedOrOverridden(&PrologEpilogCodeInserterID))
      addPass(createPrologEpilogInserterPass());

}

Terminologies:

  • Register Scavenge.
  • Frame Index Scavenge.
  • Optimization Remark Emitter (ORE).
  • CSR spill/restore.
  • Entry/return block.

Important functions:

  • calculateCallFrameInfo(MF). Caculate the MaxCallFrameSize and AdjustsStack variables for the functions fram information. Also eliminates call frame pseudo instructions.
  • calculateSaveRestoreBlocks(MF). determine the placement of CSR spill/restore code and prolog/epilog code: place all spills in the entry block, all restores in return block.
  • spillCalleeSavedRegs(MF). CSR spilling and restoring, for targets that need it.
  • TFI->processFunctionBeforeFrameFinalized(MF,RS). This allows the target machine to make final modifications to the function before the frame layout is finalized.
  • calculateFrameObjectOffsets(MF). Calculate actual frame offsets for all abstract stack objects.
  • insertPrologEpilogCode(MF). Adding prolog/epilog code to the function.
  • TFI->processFunctionBeforeFrameIndicesReplaced(MF,RS). This allows target machine to make final modifications to the function before the frame layout is finalized.
  • replaceFrameIndices(MF). Replace all MO_FrameIndex operands with physical register references and actual offsets.

Machine Function pass entry:

code runOnMachineFunction

PEI::calculateCallFrameInfo

TODO.

PEI::calculateSaveRestoreBlocks

Compute the lists of blocks.

calculateSaveRestoreBlocks

PEI::spillCalleeSavedRegs

for (MachineBasicBlock *SaveBlock : SaveBlocks) {
  insertCSRSaves(*SaveBlock, CSI);
  // Update the live-in information of all the blocks up to the save
  // point.
  updateLiveness(MF);
}
for (MachineBasicBlock *RestoreBlock : RestoreBlocks)
  insertCSRRestores(*RestoreBlock, CSI);

insertCSRSaves will call target dependent spill function TFI->spillCalleeSavedRegisters(). See Mips for example.

More code tracking:

spillCalleeSavedRegs

TFI->processFunctionBeforeFrameFinalized

PEI::calculateFrameObjectOffsets

Calculate actual frame offsets for all of the abstract stack objects.

Code snippet:

// llvm/lib/CodeGen/PrologEpilogInserter.cpp
// PEI::calculateFrameObjectOffsets

 ... 
 }else if (MaxCSFrameIndex >= MinCSFrameIndex) {
    // Be careful about underflow in comparisons agains MinCSFrameIndex.
    for (unsigned i = MaxCSFrameIndex; i != MinCSFrameIndex - 1; --i) {
      if (MFI.getStackID(i) !=
          TargetStackID::Default) // Only allocate objects on the default stack.
        continue;

      if (MFI.isDeadObjectIndex(i))
        continue;

      // Adjust to alignment boundary
      Offset = alignTo(Offset, MFI.getObjectAlign(i), Skew);

      LLVM_DEBUG(dbgs() << "alloc FI(" << i << ") at SP[" << Offset << "]\n");
      MFI.setObjectOffset(i, Offset);
      Offset += MFI.getObjectSize(i);
    }
  }
...

PEI::insertPrologEpilogCode

  • scan the function for modified callee saved registers
  • insert spill code for these callee saved registers
  • then add prolog and epilog code to the function.

Call

  • TFI.emitPrologue(MF, *SaveBlock)
  • TFI.emitEpilogue(MF, *RestoreBlock)
  • TFI.inlineStackProbe(MF, *SaveBlock)
  • TFI.adjustForHiPEPrologue(MF, *SaveBlock)

See MIPS for target dependent TargetFrameLowering implementation.

insertPrologEpilogCode

Target independent vs dependent passes


More

  • Mips
  • References: reference Target dependent implementation of prologue/epilogue emission. See [../] for callers. MipsSEFrameLowering::emitPrologue Adjust stack pointer: MipsSEFrameLowering::emitPrologue() => TII.adjustStackPtr(SP, -StackSize, MBB, MBBI) MipsSEInstrInfo::adjustStackPtr() => BuildMI // addi sp, sp, amount MipsSEFrameLowering::spillCalleeSavedRegisters The instruction to spill return address $ra register is built here. // search Mips::RA_64, spill RA as callee saved reg MipsSEFrameLowering::spillCalleeSavedRegisters(){ //... DebugLL("before spill callee save: block: "; MBB.dump();); for (unsigned i = 0, e = CSI.

Created Jul 24, 2020 // Last Updated May 18, 2021

If you could revise
the fundmental principles of
computer system design
to improve security...

... what would you change?