[lld] r194133 - [PECOFF] Add /section option.

Rui Ueyama ruiu at google.com
Tue Nov 5 23:31:55 PST 2013


Author: ruiu
Date: Wed Nov  6 01:31:55 2013
New Revision: 194133

URL: http://llvm.org/viewvc/llvm-project?rev=194133&view=rev
Log:
[PECOFF] Add /section option.

/section command line option is to set/reset attributes of the Characteristics
field in the section header. You can set non-default values with this option.
You can make .data section executable with this, for example.

This patch implements the parser of the command line option. The code to use
the parsed values will be committed in a separate patch.

Modified:
    lld/trunk/include/lld/ReaderWriter/PECOFFLinkingContext.h
    lld/trunk/lib/Driver/WinLinkDriver.cpp
    lld/trunk/lib/Driver/WinLinkOptions.td
    lld/trunk/unittests/DriverTests/WinLinkDriverTest.cpp

Modified: lld/trunk/include/lld/ReaderWriter/PECOFFLinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/PECOFFLinkingContext.h?rev=194133&r1=194132&r2=194133&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/PECOFFLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/PECOFFLinkingContext.h Wed Nov  6 01:31:55 2013
@@ -18,6 +18,7 @@
 #include "lld/ReaderWriter/Reader.h"
 #include "lld/ReaderWriter/Writer.h"
 
+#include "llvm/ADT/Optional.h"
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/COFF.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -205,6 +206,26 @@ public:
   virtual ErrorOr<Reference::Kind> relocKindFromString(StringRef str) const;
   virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind kind) const;
 
+  void setSectionAttributes(StringRef sectionName, uint32_t flags) {
+    _sectionAttributes[sectionName] = flags;
+  }
+
+  llvm::Optional<uint32_t> getSectionAttributes(StringRef sectionName) const {
+    auto it = _sectionAttributes.find(sectionName);
+    if (it == _sectionAttributes.end())
+      return llvm::None;
+    return it->second;
+  }
+
+  void setSectionAttributeMask(StringRef sectionName, uint32_t flags) {
+    _sectionAttributeMask[sectionName] = flags;
+  }
+
+  uint32_t getSectionAttributeMask(StringRef sectionName) const {
+    auto it = _sectionAttributeMask.find(sectionName);
+    return it == _sectionAttributeMask.end() ? 0 : it->second;
+  }
+
   StringRef allocateString(StringRef ref) const {
     char *x = _allocator.Allocate<char>(ref.size() + 1);
     memcpy(x, ref.data(), ref.size());
@@ -275,6 +296,15 @@ private:
   // merged to .text in the resulting executable.
   std::map<std::string, std::string> _renamedSections;
 
+  // Section attributes specified by /section option. The uint32_t value will be
+  // copied to the Characteristics field of the section header.
+  std::map<std::string, uint32_t> _sectionAttributes;
+
+  // Section attributes specified by /section option in conjunction with the
+  // negative flag "!". The uint32_t value is a mask of section attributes that
+  // should be disabled.
+  std::map<std::string, uint32_t> _sectionAttributeMask;
+
   // List of files that will be removed on destruction.
   std::vector<std::unique_ptr<llvm::FileRemover> > _tempFiles;
 };

Modified: lld/trunk/lib/Driver/WinLinkDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/WinLinkDriver.cpp?rev=194133&r1=194132&r2=194133&view=diff
==============================================================================
--- lld/trunk/lib/Driver/WinLinkDriver.cpp (original)
+++ lld/trunk/lib/Driver/WinLinkDriver.cpp Wed Nov  6 01:31:55 2013
@@ -13,6 +13,7 @@
 ///
 //===----------------------------------------------------------------------===//
 
+#include <cctype>
 #include <sstream>
 #include <map>
 
@@ -149,6 +150,59 @@ llvm::COFF::MachineTypes stringToMachine
       .Default(llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN);
 }
 
+// Parse /section:name,[[!]{DEKPRSW}]
+//
+// /section option is to set non-default bits in the Characteristics fields of
+// the section header. D, E, K, P, R, S, and W represent discardable,
+// not_cachable, not_pageable, shared, execute, read, and write bits,
+// respectively. You can specify multiple flags in one /section option.
+//
+// If the flag starts with "!", the flags represent a mask that should be turned
+// off regardless of the default value. You can even create a section which is
+// not readable, writable nor executable with this -- although it's probably
+// useless.
+bool parseSection(StringRef option, std::string &section,
+                  llvm::Optional<uint32_t> &flags,
+                  llvm::Optional<uint32_t> &mask) {
+  StringRef flagString;
+  llvm::tie(section, flagString) = option.split(",");
+
+  bool negative = false;
+  if (flagString.startswith("!")) {
+    negative = true;
+    flagString = flagString.substr(1);
+  }
+  if (flagString.empty())
+    return false;
+
+  uint32_t attribs = 0;
+  for (size_t i = 0, e = flagString.size(); i < e; ++i) {
+    switch (tolower(flagString[i])) {
+#define CASE(c, flag)                           \
+    case c:                                     \
+      attribs |= flag;                          \
+      break
+    CASE('d', llvm::COFF::IMAGE_SCN_MEM_DISCARDABLE);
+    CASE('e', llvm::COFF::IMAGE_SCN_MEM_NOT_CACHED);
+    CASE('k', llvm::COFF::IMAGE_SCN_MEM_NOT_PAGED);
+    CASE('p', llvm::COFF::IMAGE_SCN_MEM_SHARED);
+    CASE('r', llvm::COFF::IMAGE_SCN_MEM_EXECUTE);
+    CASE('s', llvm::COFF::IMAGE_SCN_MEM_READ);
+    CASE('w', llvm::COFF::IMAGE_SCN_MEM_WRITE);
+#undef CASE
+    default:
+      return false;
+    }
+  }
+
+  if (negative) {
+    mask = attribs;
+  } else {
+    flags = attribs;
+  }
+  return true;
+}
+
 // Parse /manifest:EMBED[,ID=#]|NO.
 bool parseManifest(StringRef option, bool &enable, bool &embed, int &id) {
   if (option.equals_lower("no")) {
@@ -658,6 +712,22 @@ WinLinkDriver::parse(int argc, const cha
       break;
     }
 
+    case OPT_section: {
+      // Parse /section:name,[[!]{DEKPRSW}]
+      std::string section;
+      llvm::Optional<uint32_t> flags, mask;
+      if (!parseSection(inputArg->getValue(), section, flags, mask)) {
+        diagnostics << "Unknown argument for /section: "
+                    << inputArg->getValue() << "\n";
+        return false;
+      }
+      if (flags.hasValue())
+        ctx.setSectionAttributes(section, *flags);
+      if (mask.hasValue())
+        ctx.setSectionAttributeMask(section, *mask);
+      break;
+    }
+
     case OPT_manifest:
       // Do nothing. This is default.
       break;

Modified: lld/trunk/lib/Driver/WinLinkOptions.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/WinLinkOptions.td?rev=194133&r1=194132&r2=194133&view=diff
==============================================================================
--- lld/trunk/lib/Driver/WinLinkOptions.td (original)
+++ lld/trunk/lib/Driver/WinLinkOptions.td Wed Nov  6 01:31:55 2013
@@ -31,6 +31,7 @@ def stack   : P<"stack", "Size of the st
 def machine : P<"machine", "Specify target platform">;
 def version : P<"version", "Specify a version number in the PE header">;
 def merge   : P<"merge", "Combine sections">;
+def section : P<"section", "Specify section attributes">;
 def subsystem : P<"subsystem", "Specify subsystem">;
 
 def manifest : F<"manifest">;

Modified: lld/trunk/unittests/DriverTests/WinLinkDriverTest.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/DriverTests/WinLinkDriverTest.cpp?rev=194133&r1=194132&r2=194133&view=diff
==============================================================================
--- lld/trunk/unittests/DriverTests/WinLinkDriverTest.cpp (original)
+++ lld/trunk/unittests/DriverTests/WinLinkDriverTest.cpp Wed Nov  6 01:31:55 2013
@@ -15,6 +15,7 @@
 #include "DriverTest.h"
 
 #include "lld/ReaderWriter/PECOFFLinkingContext.h"
+#include "llvm/ADT/Optional.h"
 #include "llvm/Support/COFF.h"
 
 #include <vector>
@@ -220,6 +221,37 @@ TEST_F(WinLinkParserTest, SectionAlignme
   EXPECT_EQ(8192U, _context.getSectionAlignment());
 }
 
+TEST_F(WinLinkParserTest, Section) {
+  EXPECT_TRUE(parse("link.exe", "/section:.teXT,dekpRSW", "a.obj", nullptr));
+  uint32_t expect = llvm::COFF::IMAGE_SCN_MEM_DISCARDABLE |
+      llvm::COFF::IMAGE_SCN_MEM_NOT_CACHED |
+      llvm::COFF::IMAGE_SCN_MEM_NOT_PAGED |
+      llvm::COFF::IMAGE_SCN_MEM_SHARED |
+      llvm::COFF::IMAGE_SCN_MEM_EXECUTE |
+      llvm::COFF::IMAGE_SCN_MEM_READ |
+      llvm::COFF::IMAGE_SCN_MEM_WRITE;
+  llvm::Optional<uint32_t> val = _context.getSectionAttributes(".teXT");
+  EXPECT_TRUE(val.hasValue());
+  EXPECT_EQ(expect, *val);
+
+  EXPECT_EQ(0U, _context.getSectionAttributeMask(".teXT"));
+}
+
+TEST_F(WinLinkParserTest, SectionNegative) {
+  EXPECT_TRUE(parse("link.exe", "/section:.teXT,!dekpRSW", "a.obj", nullptr));
+  llvm::Optional<uint32_t> val = _context.getSectionAttributes(".teXT");
+  EXPECT_FALSE(val.hasValue());
+
+  uint32_t expect = llvm::COFF::IMAGE_SCN_MEM_DISCARDABLE |
+      llvm::COFF::IMAGE_SCN_MEM_NOT_CACHED |
+      llvm::COFF::IMAGE_SCN_MEM_NOT_PAGED |
+      llvm::COFF::IMAGE_SCN_MEM_SHARED |
+      llvm::COFF::IMAGE_SCN_MEM_EXECUTE |
+      llvm::COFF::IMAGE_SCN_MEM_READ |
+      llvm::COFF::IMAGE_SCN_MEM_WRITE;
+  EXPECT_EQ(expect, _context.getSectionAttributeMask(".teXT"));
+}
+
 TEST_F(WinLinkParserTest, InvalidAlignment) {
   EXPECT_FALSE(parse("link.exe", "/align:1000", "a.obj", nullptr));
   EXPECT_EQ("Section alignment must be a power of 2, but got 1000\n",





More information about the llvm-commits mailing list