diff options
-rw-r--r-- | lld/COFF/Config.h | 3 | ||||
-rw-r--r-- | lld/COFF/Driver.cpp | 7 | ||||
-rw-r--r-- | lld/COFF/Driver.h | 1 | ||||
-rw-r--r-- | lld/COFF/DriverUtils.cpp | 41 | ||||
-rw-r--r-- | lld/COFF/Writer.cpp | 18 | ||||
-rw-r--r-- | lld/test/COFF/section.test | 62 |
6 files changed, 132 insertions, 0 deletions
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h index 4e6064a6a23..a5472e937fa 100644 --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -106,6 +106,9 @@ struct Configuration { // Used for /merge:from=to (e.g. /merge:.rdata=.text) std::map<StringRef, StringRef> Merge; + // Used for /section=.name,{DEKPRSW} to set section attributes. + std::map<StringRef, uint32_t> Section; + // Options for manifest files. ManifestKind Manifest = SideBySide; int ManifestID = 1; diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index 6b20c18931b..dd6de03da64 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -119,6 +119,9 @@ void LinkerDriver::parseDirectives(StringRef S) { case OPT_nodefaultlib: Config->NoDefaultLibs.insert(doFindLib(Arg->getValue())); break; + case OPT_section: + parseSection(Arg->getValue()); + break; case OPT_editandcontinue: case OPT_fastfail: case OPT_guardsym: @@ -408,6 +411,10 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) { for (auto *Arg : Args.filtered(OPT_merge)) parseMerge(Arg->getValue()); + // Handle /section + for (auto *Arg : Args.filtered(OPT_section)) + parseSection(Arg->getValue()); + // Handle /manifest if (auto *Arg = Args.getLastArg(OPT_manifest_colon)) parseManifest(Arg->getValue()); diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h index 7b65a230cad..340b940334f 100644 --- a/lld/COFF/Driver.h +++ b/lld/COFF/Driver.h @@ -133,6 +133,7 @@ void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major, void parseAlternateName(StringRef); void parseMerge(StringRef); +void parseSection(StringRef); // Parses a string in the form of "EMBED[,=<integer>]|NO". void parseManifest(StringRef Arg); diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp index ba83f8691b3..ff8729df198 100644 --- a/lld/COFF/DriverUtils.cpp +++ b/lld/COFF/DriverUtils.cpp @@ -175,6 +175,47 @@ void parseMerge(StringRef S) { } } +static uint32_t parseSectionAttributes(StringRef S) { + uint32_t Ret = 0; + for (char C : S.lower()) { + switch (C) { + case 'd': + Ret |= IMAGE_SCN_MEM_DISCARDABLE; + break; + case 'e': + Ret |= IMAGE_SCN_MEM_EXECUTE; + break; + case 'k': + Ret |= IMAGE_SCN_MEM_NOT_CACHED; + break; + case 'p': + Ret |= IMAGE_SCN_MEM_NOT_PAGED; + break; + case 'r': + Ret |= IMAGE_SCN_MEM_READ; + break; + case 's': + Ret |= IMAGE_SCN_MEM_SHARED; + break; + case 'w': + Ret |= IMAGE_SCN_MEM_WRITE; + break; + default: + error(Twine("/section: invalid argument: ") + S); + } + } + return Ret; +} + +// Parses /section option argument. +void parseSection(StringRef S) { + StringRef Name, Attrs; + std::tie(Name, Attrs) = S.split(','); + if (Name.empty() || Attrs.empty()) + error(Twine("/section: invalid argument: ") + S); + Config->Section[Name] = parseSectionAttributes(Attrs); +} + // Parses a string in the form of "EMBED[,=<integer>]|NO". // Results are directly written to Config. void parseManifest(StringRef Arg) { diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index 01dc9f12ba5..fff8f07f9ce 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -59,6 +59,7 @@ private: void openFile(StringRef OutputPath); template <typename PEHeaderTy> void writeHeader(); void fixSafeSEHSymbols(); + void setSectionPermissions(); void writeSections(); void sortExceptionTable(); void applyRelocations(); @@ -114,6 +115,7 @@ public: StringRef getName() { return Name; } std::vector<Chunk *> &getChunks() { return Chunks; } void addPermissions(uint32_t C); + void setPermissions(uint32_t C); uint32_t getPermissions() { return Header.Characteristics & PermMask; } uint32_t getCharacteristics() { return Header.Characteristics; } uint64_t getRVA() { return Header.VirtualAddress; } @@ -176,6 +178,10 @@ void OutputSection::addPermissions(uint32_t C) { Header.Characteristics |= C & PermMask; } +void OutputSection::setPermissions(uint32_t C) { + Header.Characteristics = C & PermMask; +} + // Write the section header to a given buffer. void OutputSection::writeHeaderTo(uint8_t *Buf) { auto *Hdr = reinterpret_cast<coff_section *>(Buf); @@ -222,6 +228,7 @@ void Writer::run() { createSection(".reloc"); assignAddresses(); removeEmptySections(); + setSectionPermissions(); createSymbolAndStringTable(); openFile(Config->OutputFile); if (Config->is64()) { @@ -657,6 +664,17 @@ void Writer::fixSafeSEHSymbols() { Config->SEHCount->setVA(SEHTable->getSize() / 4); } +// Handles /section options to allow users to overwrite +// section attributes. +void Writer::setSectionPermissions() { + for (auto &P : Config->Section) { + StringRef Name = P.first; + uint32_t Perm = P.second; + if (auto *Sec = findSection(Name)) + Sec->setPermissions(Perm); + } +} + // Write section contents to a mmap'ed file. void Writer::writeSections() { uint8_t *Buf = Buffer->getBufferStart(); diff --git a/lld/test/COFF/section.test b/lld/test/COFF/section.test new file mode 100644 index 00000000000..c930de6a0de --- /dev/null +++ b/lld/test/COFF/section.test @@ -0,0 +1,62 @@ +# RUN: yaml2obj < %s > %t.obj +# RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \ +# RUN: /section:.foo,r %t.obj +# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=R %s + +# RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \ +# RUN: /section:.foo,w %t.obj +# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=W %s + +# RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \ +# RUN: /section:.foo,e %t.obj +# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=E %s + +# RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \ +# RUN: /section:.foo,s %t.obj +# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=S %s + +# R: Characteristics [ +# R-NEXT: IMAGE_SCN_MEM_READ +# R-NEXT: ] + +# W: Characteristics [ +# W-NEXT: IMAGE_SCN_MEM_WRITE +# W-NEXT: ] + +# E: Characteristics [ +# E-NEXT: IMAGE_SCN_MEM_EXECUTE +# E-NEXT: ] + +# S: Characteristics [ +# S-NEXT: IMAGE_SCN_MEM_SHARED +# S-NEXT: ] + +--- +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [] +sections: + - Name: .foo + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: 000000000000 +symbols: + - Name: .foo + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 6 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: main + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... |