forked from OSchip/llvm-project
[PECOFF] Improve /merge option handling.
/MERGE option is a bit complicated for many reasons. Firstly, it takes both positive and negative arguments. That means we have to have one of three distinctive values (set, clear or unchange) for each permission bit. In this patch we represent the three values using two bitmasks. Secondly, the permissions specified by the parameter is bitwise or-ed with the default permissions of a section. There is an exception for that rule; if one of READ, WRITE or EXECUTE bit is specified, unspecified bits need to be cleared. (So if you specify only WRITE for example, the resulting section will not have WRITE nor EXECUTE bits.) Lastly, multiple /merge options are allowed. llvm-svn: 195882
This commit is contained in:
parent
175e7a8c97
commit
615b200cc2
|
@ -19,7 +19,6 @@
|
|||
#include "lld/ReaderWriter/Writer.h"
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/COFF.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
|
@ -209,25 +208,9 @@ 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;
|
||||
}
|
||||
void setSectionSetMask(StringRef sectionName, uint32_t flags);
|
||||
void setSectionClearMask(StringRef sectionName, uint32_t flags);
|
||||
uint32_t getSectionAttributes(StringRef sectionName, uint32_t flags) const;
|
||||
|
||||
void setDosStub(ArrayRef<uint8_t> data) { _dosStub = data; }
|
||||
ArrayRef<uint8_t> getDosStub() const { return _dosStub; }
|
||||
|
@ -304,14 +287,9 @@ 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;
|
||||
// Section attributes specified by /section option.
|
||||
std::map<std::string, uint32_t> _sectionSetMask;
|
||||
std::map<std::string, uint32_t> _sectionClearMask;
|
||||
|
||||
// List of files that will be removed on destruction.
|
||||
std::vector<std::unique_ptr<llvm::FileRemover> > _tempFiles;
|
||||
|
|
|
@ -723,9 +723,9 @@ WinLinkDriver::parse(int argc, const char *argv[], PECOFFLinkingContext &ctx,
|
|||
return false;
|
||||
}
|
||||
if (flags.hasValue())
|
||||
ctx.setSectionAttributes(section, *flags);
|
||||
ctx.setSectionSetMask(section, *flags);
|
||||
if (mask.hasValue())
|
||||
ctx.setSectionAttributeMask(section, *mask);
|
||||
ctx.setSectionClearMask(section, *mask);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -204,6 +204,34 @@ PECOFFLinkingContext::stringFromRelocKind(Reference::Kind kind) const {
|
|||
return make_error_code(YamlReaderError::illegal_value);
|
||||
}
|
||||
|
||||
void PECOFFLinkingContext::setSectionSetMask(StringRef sectionName,
|
||||
uint32_t newFlags) {
|
||||
_sectionSetMask[sectionName] |= newFlags;
|
||||
_sectionClearMask[sectionName] &= ~newFlags;
|
||||
const uint32_t rwx = (llvm::COFF::IMAGE_SCN_MEM_READ |
|
||||
llvm::COFF::IMAGE_SCN_MEM_WRITE |
|
||||
llvm::COFF::IMAGE_SCN_MEM_EXECUTE);
|
||||
if (newFlags & rwx)
|
||||
_sectionClearMask[sectionName] |= ~_sectionSetMask[sectionName] & rwx;
|
||||
assert((_sectionSetMask[sectionName] & _sectionClearMask[sectionName]) == 0);
|
||||
}
|
||||
|
||||
void PECOFFLinkingContext::setSectionClearMask(StringRef sectionName,
|
||||
uint32_t newFlags) {
|
||||
_sectionClearMask[sectionName] |= newFlags;
|
||||
_sectionSetMask[sectionName] &= ~newFlags;
|
||||
assert((_sectionSetMask[sectionName] & _sectionClearMask[sectionName]) == 0);
|
||||
}
|
||||
|
||||
uint32_t PECOFFLinkingContext::getSectionAttributes(StringRef sectionName,
|
||||
uint32_t flags) const {
|
||||
auto si = _sectionSetMask.find(sectionName);
|
||||
uint32_t setMask = (si == _sectionSetMask.end()) ? 0 : si->second;
|
||||
auto ci = _sectionClearMask.find(sectionName);
|
||||
uint32_t clearMask = (ci == _sectionClearMask.end()) ? 0 : ci->second;
|
||||
return (flags | setMask) & ~clearMask;
|
||||
}
|
||||
|
||||
void PECOFFLinkingContext::addPasses(PassManager &pm) {
|
||||
pm.add(std::unique_ptr<Pass>(new pecoff::SetSubsystemPass(*this)));
|
||||
pm.add(std::unique_ptr<Pass>(new pecoff::GroupedSectionsPass()));
|
||||
|
|
|
@ -275,43 +275,41 @@ const uint32_t execute = llvm::COFF::IMAGE_SCN_MEM_EXECUTE;
|
|||
const uint32_t read = llvm::COFF::IMAGE_SCN_MEM_READ;
|
||||
const uint32_t write = llvm::COFF::IMAGE_SCN_MEM_WRITE;
|
||||
|
||||
TEST_F(WinLinkParserTest, Section) {
|
||||
EXPECT_TRUE(parse("link.exe", "/section:.teXT,dekpRSW", "a.obj", nullptr));
|
||||
uint32_t expect =
|
||||
discardable | not_cached | not_paged | shared | execute | read | 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 =
|
||||
discardable | not_cached | not_paged | shared | execute | read | write;
|
||||
EXPECT_EQ(expect, _context.getSectionAttributeMask(".teXT"));
|
||||
}
|
||||
|
||||
#define TEST_SECTION(testname, arg, expect) \
|
||||
TEST_F(WinLinkParserTest, testname) { \
|
||||
EXPECT_TRUE(parse("link.exe", "/section:.text," arg, "a.obj", nullptr)); \
|
||||
llvm::Optional<uint32_t> val = _context.getSectionAttributes(".text"); \
|
||||
EXPECT_TRUE(val.hasValue()); \
|
||||
EXPECT_EQ(expect, *val); \
|
||||
#define TEST_SECTION(testname, arg, expect) \
|
||||
TEST_F(WinLinkParserTest, testname) { \
|
||||
EXPECT_TRUE(parse("link.exe", "/section:.text," arg, "a.obj", nullptr)); \
|
||||
EXPECT_EQ(expect, _context.getSectionAttributes(".text", execute | read)); \
|
||||
}
|
||||
|
||||
TEST_SECTION(SectionD, "d", discardable);
|
||||
TEST_SECTION(SectionD, "d", execute | read | discardable);
|
||||
TEST_SECTION(SectionE, "e", execute);
|
||||
TEST_SECTION(SectionK, "k", not_cached);
|
||||
TEST_SECTION(SectionP, "p", not_paged);
|
||||
TEST_SECTION(SectionK, "k", execute | read | not_cached);
|
||||
TEST_SECTION(SectionP, "p", execute | read | not_paged);
|
||||
TEST_SECTION(SectionR, "r", read);
|
||||
TEST_SECTION(SectionS, "s", shared);
|
||||
TEST_SECTION(SectionS, "s", execute | read | shared);
|
||||
TEST_SECTION(SectionW, "w", write);
|
||||
|
||||
#undef TEST_SECTION
|
||||
|
||||
TEST_F(WinLinkParserTest, Section) {
|
||||
EXPECT_TRUE(parse("link.exe", "/section:.text,dekprsw",
|
||||
"/section:.text,!dekprsw", "a.obj", nullptr));
|
||||
EXPECT_EQ(0U, _context.getSectionAttributes(".text", execute | read));
|
||||
}
|
||||
|
||||
TEST_F(WinLinkParserTest, SectionNegate) {
|
||||
EXPECT_TRUE(parse("link.exe", "/section:.text,!e", "a.obj", nullptr));
|
||||
EXPECT_EQ(read, _context.getSectionAttributes(".text", execute | read));
|
||||
}
|
||||
|
||||
TEST_F(WinLinkParserTest, SectionMultiple) {
|
||||
EXPECT_TRUE(parse("link.exe", "/section:.foo,e", "/section:.foo,rw",
|
||||
"/section:.foo,!d", "a.obj", nullptr));
|
||||
uint32_t flags = execute | read | not_paged | discardable;
|
||||
uint32_t expected = execute | read | write | not_paged;
|
||||
EXPECT_EQ(expected, _context.getSectionAttributes(".foo", flags));
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
//
|
||||
|
|
Loading…
Reference in New Issue