================ @@ -2660,6 +2644,133 @@ void X86AsmPrinter::emitCallInstruction(const llvm::MCInst &MCI) { OutStreamer->emitInstruction(MCI, getSubtargetInfo()); } +// Checks whether a NOP is required after a CALL and inserts the NOP, if +// necessary. +void X86AsmPrinter::emitNopAfterCallForWindowsEH(const MachineInstr *MI) { + if (needsNopAfterCallForWindowsEH(MI)) + EmitAndCountInstruction(MCInstBuilder(X86::NOOP)); +} + +// Determines whether a NOP is required after a CALL, so that Windows EH +// IP2State tables have the correct information. +// +// On most Windows platforms (AMD64, ARM64, ARM32, IA64, but *not* x86-32), +// exception handling works by looking up instruction pointers in lookup +// tables. These lookup tables are stored in .xdata sections in executables. +// One element of the lookup tables are the "IP2State" tables (Instruction +// Pointer to State). +// +// If a function has any instructions that require cleanup during exception +// unwinding, then it will have an IP2State table. Each entry in the IP2State +// table describes a range of bytes in the function's instruction stream, and +// associates an "EH state number" with that range of instructions. A value of +// -1 means "the null state", which does not require any code to execute. +// A value other than -1 is an index into the State table. +// +// The entries in the IP2State table contain byte offsets within the instruction +// stream of the function. The Windows ABI requires that these offsets are +// aligned to instruction boundaries; they are not permitted to point to a byte +// that is not the first byte of an instruction. +// +// Unfortunately, CALL instructions present a problem during unwinding. CALL +// instructions push the address of the instruction after the CALL instruction, +// so that execution can resume after the CALL. If the CALL is the last +// instruction within an IP2State region, then the return address (on the stack) +// points to the *next* IP2State region. This means that the unwinder will +// use the wrong cleanup funclet during unwinding. +// +// To fix this problem, MSVC will insert a NOP after a CALL instruction, if the +// CALL instruction is the last instruction within an IP2State region. The NOP +// is placed within the same IP2State region as the CALL, so that the return +// address points to the NOP and the unwinder will locate the correct region. +// +// Previously, LLVM fixed this by adding 1 to the instruction offsets in the +// IP2State table. This caused the instruction boundary to point *within* the +// instruction after a CALL. This works for the purposes of unwinding, since +// there are no AMD64 instructions that can be encoded in a single byte and +// which throw C++ exceptions. Unfortunately, this violates the Windows ABI +// specification, which requires that the IP2State table entries point to the +// boundaries between exceptions. ---------------- sivadeilra wrote:
It prevents our analysis tools, such as our hot-patch generator, from correctly analyzing binaries. https://github.com/llvm/llvm-project/pull/144745 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits