[llvm] 37ef743 - [MC] [Win64EH] Avoid producing malformed xdata records
Martin Storsjö via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 27 23:24:48 PDT 2020
Author: Martin Storsjö
Date: 2020-08-28T09:05:36+03:00
New Revision: 37ef743cbf3fb1c56cca8035d9acb0cde83976f9
URL: https://github.com/llvm/llvm-project/commit/37ef743cbf3fb1c56cca8035d9acb0cde83976f9
DIFF: https://github.com/llvm/llvm-project/commit/37ef743cbf3fb1c56cca8035d9acb0cde83976f9.diff
LOG: [MC] [Win64EH] Avoid producing malformed xdata records
If there's no unwinding opcodes, omit writing the xdata/pdata records.
Previously, this generated truncated xdata records, and llvm-readobj
would error out when trying to print them.
If writing of an xdata record is forced via the .seh_handlerdata
directive, skip it if there's no info to make a sensible unwind
info structure out of, and clearly error out if such info appeared
later in the process.
Differential Revision: https://reviews.llvm.org/D86527
Added:
Modified:
llvm/include/llvm/MC/MCWinEH.h
llvm/lib/MC/MCWin64EH.cpp
llvm/test/MC/AArch64/seh.s
Removed:
################################################################################
diff --git a/llvm/include/llvm/MC/MCWinEH.h b/llvm/include/llvm/MC/MCWinEH.h
index b1c28c0ecae7..baeafa3468e2 100644
--- a/llvm/include/llvm/MC/MCWinEH.h
+++ b/llvm/include/llvm/MC/MCWinEH.h
@@ -40,6 +40,7 @@ struct FrameInfo {
bool HandlesUnwind = false;
bool HandlesExceptions = false;
+ bool EmitAttempted = false;
int LastFrameInst = -1;
const FrameInfo *ChainedParent = nullptr;
@@ -53,6 +54,15 @@ struct FrameInfo {
const FrameInfo *ChainedParent)
: Begin(BeginFuncEHLabel), Function(Function),
ChainedParent(ChainedParent) {}
+
+ bool empty() const {
+ if (!Instructions.empty())
+ return false;
+ for (const auto &E : EpilogMap)
+ if (!E.second.empty())
+ return false;
+ return true;
+ }
};
class UnwindEmitter {
diff --git a/llvm/lib/MC/MCWin64EH.cpp b/llvm/lib/MC/MCWin64EH.cpp
index ac288ca08c93..76c82cd176a1 100644
--- a/llvm/lib/MC/MCWin64EH.cpp
+++ b/llvm/lib/MC/MCWin64EH.cpp
@@ -494,6 +494,27 @@ static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) {
// If this UNWIND_INFO already has a symbol, it's already been emitted.
if (info->Symbol)
return;
+ // If there's no unwind info here (not even a terminating UOP_End), the
+ // unwind info is considered bogus and skipped. If this was done in
+ // response to an explicit .seh_handlerdata, the associated trailing
+ // handler data is left orphaned in the xdata section.
+ if (info->empty()) {
+ info->EmitAttempted = true;
+ return;
+ }
+ if (info->EmitAttempted) {
+ // If we tried to emit unwind info before (due to an explicit
+ // .seh_handlerdata directive), but skipped it (because there was no
+ // valid information to emit at the time), and it later got valid unwind
+ // opcodes, we can't emit it here, because the trailing handler data
+ // was already emitted elsewhere in the xdata section.
+ streamer.getContext().reportError(
+ SMLoc(), "Earlier .seh_handlerdata for " + info->Function->getName() +
+ " skipped due to no unwind info at the time "
+ "(.seh_handlerdata too early?), but the function later "
+ "did get unwind info that can't be emitted");
+ return;
+ }
MCContext &context = streamer.getContext();
MCSymbol *Label = context.createTempSymbol();
@@ -657,16 +678,25 @@ static void ARM64EmitRuntimeFunction(MCStreamer &streamer,
void llvm::Win64EH::ARM64UnwindEmitter::Emit(MCStreamer &Streamer) const {
// Emit the unwind info structs first.
for (const auto &CFI : Streamer.getWinFrameInfos()) {
+ WinEH::FrameInfo *Info = CFI.get();
+ if (Info->empty())
+ continue;
MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
Streamer.SwitchSection(XData);
- ARM64EmitUnwindInfo(Streamer, CFI.get());
+ ARM64EmitUnwindInfo(Streamer, Info);
}
// Now emit RUNTIME_FUNCTION entries.
for (const auto &CFI : Streamer.getWinFrameInfos()) {
+ WinEH::FrameInfo *Info = CFI.get();
+ // ARM64EmitUnwindInfo above clears the info struct, so we can't check
+ // empty here. But if a Symbol is set, we should create the corresponding
+ // pdata entry.
+ if (!Info->Symbol)
+ continue;
MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
Streamer.SwitchSection(PData);
- ARM64EmitRuntimeFunction(Streamer, CFI.get());
+ ARM64EmitRuntimeFunction(Streamer, Info);
}
}
diff --git a/llvm/test/MC/AArch64/seh.s b/llvm/test/MC/AArch64/seh.s
index 2f4e3f27255f..878b7ad944cf 100644
--- a/llvm/test/MC/AArch64/seh.s
+++ b/llvm/test/MC/AArch64/seh.s
@@ -1,6 +1,8 @@
// This test checks that the SEH directives don't cause the assembler to fail.
+// Checking that llvm-readobj doesn't bail out on the unwind data, but not
+// really checking the contents yet.
-// RUN: llvm-mc -triple aarch64-pc-win32 -filetype=obj %s | llvm-readobj -S -r - | FileCheck %s
+// RUN: llvm-mc -triple aarch64-pc-win32 -filetype=obj %s | llvm-readobj -S -r -u - | FileCheck %s
// CHECK: Sections [
// CHECK: Section {
@@ -25,7 +27,7 @@
// CHECK-NEXT: }
// CHECK: Section {
// CHECK: Name: .pdata
-// CHECK: RelocationCount: 4
+// CHECK: RelocationCount: 2
// CHECK: Characteristics [
// CHECK-NEXT: ALIGN_4BYTES
// CHECK-NEXT: CNT_INITIALIZED_DATA
@@ -41,8 +43,6 @@
// CHECK-NEXT: Section (5) .pdata {
// CHECK-NEXT: 0x0 IMAGE_REL_ARM64_ADDR32NB func
// CHECK-NEXT: 0x4 IMAGE_REL_ARM64_ADDR32NB .xdata
-// CHECK-NEXT: 0x8 IMAGE_REL_ARM64_ADDR32NB smallFunc
-// CHECK-NEXT: 0xC IMAGE_REL_ARM64_ADDR32NB .xdata
// CHECK-NEXT: }
// CHECK-NEXT: ]
@@ -67,7 +67,8 @@ func:
ret
.seh_endproc
-// Test emission of small functions.
+ // Function with no .seh directives; no pdata/xdata entries are
+ // generated.
.globl smallFunc
.def smallFunc
.scl 2
@@ -77,3 +78,21 @@ func:
smallFunc:
ret
.seh_endproc
+
+ // Function with no .seh directives, but with .seh_handlerdata.
+ // No xdata/pdata entries are generated, but the custom handler data
+ // (the .long after .seh_handlerdata) is left orphaned in the xdata
+ // section.
+ .globl handlerFunc
+ .def handlerFunc
+ .scl 2
+ .type 32
+ .endef
+ .seh_proc handlerFunc
+handlerFunc:
+ ret
+ .seh_handler __C_specific_handler, @except
+ .seh_handlerdata
+ .long 0
+ .text
+ .seh_endproc
More information about the llvm-commits
mailing list