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());