summaryrefslogtreecommitdiffstats
path: root/lld/lib/ReaderWriter/PECOFF/LoadConfigPass.cpp
diff options
context:
space:
mode:
authorRui Ueyama <ruiu@google.com>2014-02-26 08:27:59 +0000
committerRui Ueyama <ruiu@google.com>2014-02-26 08:27:59 +0000
commit2e09d93f74d8af94c1f345dbcac976a0d8c8c527 (patch)
treefe06ec1123ab774f39e4a82159674d8c2729fbea /lld/lib/ReaderWriter/PECOFF/LoadConfigPass.cpp
parent286d87ed38d8038090b1ae08a26f2d0ead49fcf9 (diff)
downloadbcm5719-llvm-2e09d93f74d8af94c1f345dbcac976a0d8c8c527.tar.gz
bcm5719-llvm-2e09d93f74d8af94c1f345dbcac976a0d8c8c527.zip
[PECOFF] Emit Load Configuration and SEH Table for x86.
If all input files are compatible with Structured Exception Handling, linker is supposed to create an exectuable with a table for SEH handlers. The table consists of exception handlers entry point addresses. The basic idea of SEH in x86 Microsoft ABI is to list all valid entry points of exception handlers in an read-only memory, so that an attacker cannot override the addresses in it. In x86 ABI, data for exception handling is mostly on stack, so it's volnerable to stack overflow attack. In order to protect against it, Windows runtime uses the table to check a return address, to ensure that the address is really an valid entry point for an exception handler. Compiler emits a list of exception handler functions to .sxdata section. It also emits a marker symbol "@feat.00" to indicate that the object is compatible with SEH. SEH is a relatively new feature for COFF, and mixing SEH-compatible and SEH-incompatible objects will result in an invalid executable, so is the marker. If all input files are compatible with SEH, LLD emits a SEH table. SEH table needs to be pointed by Load Configuration strucutre, so when emitting a SEH table LLD emits it too. The address of a Load Configuration will be stored to the file header. llvm-svn: 202248
Diffstat (limited to 'lld/lib/ReaderWriter/PECOFF/LoadConfigPass.cpp')
-rw-r--r--lld/lib/ReaderWriter/PECOFF/LoadConfigPass.cpp76
1 files changed, 76 insertions, 0 deletions
diff --git a/lld/lib/ReaderWriter/PECOFF/LoadConfigPass.cpp b/lld/lib/ReaderWriter/PECOFF/LoadConfigPass.cpp
new file mode 100644
index 00000000000..1463c47ba98
--- /dev/null
+++ b/lld/lib/ReaderWriter/PECOFF/LoadConfigPass.cpp
@@ -0,0 +1,76 @@
+//===- lib/ReaderWriter/PECOFF/LoadConfigPass.cpp -------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A Load Configuration is a data structure for x86 containing an address of the
+// SEH handler table. The Data Directory in the file header points to a load
+// configuration. Technically that indirection is not needed but exists for
+// historical reasons.
+//
+// If the file being handled has .sxdata section containing SEH handler table,
+// this pass will create a Load Configuration atom.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Pass.h"
+#include "LoadConfigPass.h"
+
+#include "lld/Core/File.h"
+#include "lld/Core/Pass.h"
+#include "lld/ReaderWriter/Simple.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Path.h"
+
+#include <climits>
+#include <ctime>
+#include <utility>
+
+using llvm::object::coff_load_configuration32;
+
+namespace lld {
+namespace pecoff {
+namespace loadcfg {
+
+LoadConfigAtom::LoadConfigAtom(VirtualFile &file, const DefinedAtom *sxdata,
+ int count)
+ : COFFLinkerInternalAtom(
+ file, file.getNextOrdinal(),
+ std::vector<uint8_t>(sizeof(coff_load_configuration32))) {
+ addDir32Reloc(this, sxdata, offsetof(llvm::object::coff_load_configuration32,
+ SEHandlerTable));
+ auto *data = getContents<llvm::object::coff_load_configuration32>();
+ data->SEHandlerCount = count;
+}
+
+} // namespace loadcfg
+
+void LoadConfigPass::perform(std::unique_ptr<MutableFile> &file) {
+ if (_ctx.noSEH())
+ return;
+
+ // Find the first atom in .sxdata section.
+ const DefinedAtom *sxdata = nullptr;
+ int sectionSize = 0;
+ for (const DefinedAtom *atom : file->defined()) {
+ if (atom->customSectionName() == ".sxdata") {
+ if (!sxdata)
+ sxdata = atom;
+ sectionSize += sxdata->size();
+ }
+ }
+ if (!sxdata)
+ return;
+
+ auto *loadcfg = new (_alloc)
+ loadcfg::LoadConfigAtom(_file, sxdata, sectionSize / sizeof(uint32_t));
+ file->addAtom(*loadcfg);
+}
+
+} // namespace pecoff
+} // namespace lld
OpenPOWER on IntegriCloud