COFF: Implement Safe SEH support for x86.
An object file compatible with Safe SEH contains a .sxdata section.
The section contains a list of symbol table indices, each of which
is an exception handler function. A safe SEH-enabled executable
contains a list of exception handler RVAs. So, what the linker has
to do to support Safe SEH is basically to read the .sxdata section,
interpret the contents as a list of symbol indices, unique-fy and
sort their RVAs, and then emit that list to .rdata. This patch
implements that feature.
llvm-svn: 243182
diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp
index d9312f6..4e5e34c 100644
--- a/lld/COFF/InputFiles.cpp
+++ b/lld/COFF/InputFiles.cpp
@@ -25,6 +25,7 @@
using namespace llvm::support::endian;
using llvm::RoundUpToAlignment;
using llvm::Triple;
+using llvm::support::ulittle32_t;
using llvm::sys::fs::file_magic;
using llvm::sys::fs::identify_magic;
@@ -112,7 +113,9 @@
// Read section and symbol tables.
if (auto EC = initializeChunks())
return EC;
- return initializeSymbols();
+ if (auto EC = initializeSymbols())
+ return EC;
+ return initializeSEH();
}
std::error_code ObjectFile::initializeChunks() {
@@ -132,6 +135,10 @@
<< EC.message() << "\n";
return make_error_code(LLDError::BrokenFile);
}
+ if (Name == ".sxdata") {
+ SXData = Sec;
+ continue;
+ }
if (Name == ".drectve") {
ArrayRef<uint8_t> Data;
COFFObj->getSectionContents(Sec, Data);
@@ -214,8 +221,14 @@
if (Sym.isAbsolute()) {
COFFObj->getSymbolName(Sym, Name);
// Skip special symbols.
- if (Name == "@comp.id" || Name == "@feat.00")
+ if (Name == "@comp.id")
return nullptr;
+ // COFF spec 5.10.1. The .sxdata section.
+ if (Name == "@feat.00") {
+ if (Sym.getValue() & 1)
+ SEHCompat = true;
+ return nullptr;
+ }
return new (Alloc) DefinedAbsolute(Name, Sym);
}
if (Sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_DEBUG)
@@ -242,6 +255,22 @@
return B;
}
+std::error_code ObjectFile::initializeSEH() {
+ if (!SEHCompat || !SXData)
+ return std::error_code();
+ ArrayRef<uint8_t> A;
+ COFFObj->getSectionContents(SXData, A);
+ if (A.size() % 4 != 0) {
+ llvm::errs() << ".sxdata must be an array of symbol table indices\n";
+ return make_error_code(LLDError::BrokenFile);
+ }
+ auto *I = reinterpret_cast<const ulittle32_t *>(A.data());
+ auto *E = reinterpret_cast<const ulittle32_t *>(A.data() + A.size());
+ for (; I != E; ++I)
+ SEHandlers.insert(SparseSymbolBodies[*I]);
+ return std::error_code();
+}
+
MachineTypes ObjectFile::getMachineType() {
if (COFFObj)
return static_cast<MachineTypes>(COFFObj->getMachine());