Index: COFF/Chunks.h =================================================================== --- COFF/Chunks.h +++ COFF/Chunks.h @@ -150,7 +150,7 @@ void writeTo(uint8_t *Buf) const override; bool hasData() const override; uint32_t getOutputCharacteristics() const override; - StringRef getSectionName() const override { return SectionName; } + StringRef getSectionName() const override; void getBaserels(std::vector *Res) override; bool isCOMDAT() const; void applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, @@ -162,7 +162,7 @@ void applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, uint64_t P) const; - void getRuntimePseudoRelocs(std::vector &Res); + bool getRuntimePseudoRelocs(std::vector &Res); // Called if the garbage collector decides to not include this chunk // in a final output. It's supposed to print out a log message to stdout. @@ -184,6 +184,8 @@ Live = true; } + void forceWritable() { ForceWritable = true; } + // True if this is a codeview debug info chunk. These will not be laid out in // the image. Instead they will end up in the PDB, if one is requested. bool isCodeView() const { @@ -231,6 +233,9 @@ // Used by the garbage collector. bool Live; + // Used for chunks that contain relocations that need runtime fixups. + bool ForceWritable = false; + // Used for ICF (Identical COMDAT Folding) void replace(SectionChunk *Other); uint32_t Class[2] = {0, 0}; Index: COFF/Chunks.cpp =================================================================== --- COFF/Chunks.cpp +++ COFF/Chunks.cpp @@ -508,8 +508,9 @@ // need to be handled at runtime as runtime pseudo relocations (references // to a module local variable, which turned out to actually need to be // imported from another DLL). -void SectionChunk::getRuntimePseudoRelocs( +bool SectionChunk::getRuntimePseudoRelocs( std::vector &Res) { + bool Found = false; for (const coff_relocation &Rel : Relocs) { auto *Target = dyn_cast_or_null( File->getSymbol(Rel.SymbolTableIndex)); @@ -527,7 +528,9 @@ // other flags are defined. Res.emplace_back( RuntimePseudoReloc(Target, this, Rel.VirtualAddress, SizeInBits)); + Found = true; } + return Found; } bool SectionChunk::hasData() const { @@ -535,7 +538,20 @@ } uint32_t SectionChunk::getOutputCharacteristics() const { - return Header->Characteristics & (PermMask | TypeMask); + uint32_t C = Header->Characteristics & (PermMask | TypeMask); + if (ForceWritable) + C |= IMAGE_SCN_MEM_WRITE; + return C; +} + +StringRef SectionChunk::getSectionName() const { + if (ForceWritable) { + if (SectionName == ".rdata") + return ".data"; + if (SectionName == ".text") + return ".wtext"; + } + return SectionName; } bool SectionChunk::isCOMDAT() const { Index: COFF/Writer.cpp =================================================================== --- COFF/Writer.cpp +++ COFF/Writer.cpp @@ -159,6 +159,7 @@ template void writeHeader(); void createSEHTable(); void createRuntimePseudoRelocs(); + void insertRuntimePseudoRelocs(); void createGuardCFTables(); void markSymbolsForRVATable(ObjFile *File, ArrayRef SymIdxChunks, @@ -333,6 +334,11 @@ void Writer::run() { ScopedTimer T1(CodeLayoutTimer); + // Find pseudo relocs early, to allow marking the corresponding + // section chunks as writable, before assigning them to output sections. + if (Config->MinGW) + createRuntimePseudoRelocs(); + createSections(); createMiscChunks(); createImportTables(); @@ -527,7 +533,7 @@ createGuardCFTables(); if (Config->MinGW) - createRuntimePseudoRelocs(); + insertRuntimePseudoRelocs(); } // Create .idata section for the DLL-imported symbol table. @@ -1148,6 +1154,10 @@ // though the code didn't expect it to, produce the table that the runtime // uses for fixing them up, and provide the synthetic symbols that the // runtime uses for finding the table. +// +// Mark sections that need to be written to at runtime as writable, to avoid +// that the runtime has to use VirtualProtect, which isn't available in +// Windows Store/UWP apps. void Writer::createRuntimePseudoRelocs() { std::vector Rels; @@ -1155,15 +1165,14 @@ auto *SC = dyn_cast(C); if (!SC || !SC->isLive()) continue; - SC->getRuntimePseudoRelocs(Rels); + if (SC->getRuntimePseudoRelocs(Rels)) + SC->forceWritable(); } if (!Rels.empty()) log("Writing " + Twine(Rels.size()) + " runtime pseudo relocations"); PseudoRelocTableChunk *Table = make(Rels); - RdataSec->addChunk(Table); EmptyChunk *EndOfList = make(); - RdataSec->addChunk(EndOfList); Symbol *HeadSym = Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__"); Symbol *EndSym = Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__"); @@ -1171,6 +1180,18 @@ replaceSymbol(EndSym, EndSym->getName(), EndOfList); } +// MinGW specific. +void Writer::insertRuntimePseudoRelocs() { + DefinedSynthetic *HeadSym = dyn_cast_or_null( + Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__")); + DefinedSynthetic *EndSym = dyn_cast_or_null( + Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__")); + if (HeadSym) + RdataSec->addChunk(HeadSym->getChunk()); + if (EndSym) + RdataSec->addChunk(EndSym->getChunk()); +} + // Handles /section options to allow users to overwrite // section attributes. void Writer::setSectionPermissions() { Index: test/COFF/autoimport-x86.s =================================================================== --- test/COFF/autoimport-x86.s +++ test/COFF/autoimport-x86.s @@ -10,35 +10,45 @@ # RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s # RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=DISASM %s # RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=CONTENTS %s +# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=SECTIONS %s # IMPORTS: Import { # IMPORTS-NEXT: Name: autoimport-x86.s.tmp-lib.dll -# IMPORTS-NEXT: ImportLookupTableRVA: 0x2050 -# IMPORTS-NEXT: ImportAddressTableRVA: 0x2060 +# IMPORTS-NEXT: ImportLookupTableRVA: 0x1050 +# IMPORTS-NEXT: ImportAddressTableRVA: 0x1060 # IMPORTS-NEXT: Symbol: variable (0) # IMPORTS-NEXT: } -# DISASM: Disassembly of section .text: -# DISASM: .text: -# Relative offset at 0x1002 pointing at the IAT at 0x2060. -# DISASM: 140001000: 8b 05 5a 10 00 00 movl 4186(%rip), %eax -# DISASM: 140001006: c3 retq +# DISASM: Disassembly of section .wtext: +# DISASM: .wtext: +# Relative offset at 0x3002 pointing at the IAT at 0x1060. +# DISASM: 140003000: 8b 05 5a e0 ff ff movl -8102(%rip), %eax +# DISASM: 140003006: c3 retq # Runtime pseudo reloc list header consisting of 0x0, 0x0, 0x1. -# First runtime pseudo reloc, with import from 0x2060, -# applied at 0x1002, with a size of 32 bits. -# Second runtime pseudo reloc, with import from 0x2060, -# applied at 0x3000, with a size of 64 bits. +# First runtime pseudo reloc, with import from 0x1060, +# applied at 0x3002, with a size of 32 bits. +# Second runtime pseudo reloc, with import from 0x1060, +# applied at 0x2000, with a size of 64 bits. # CONTENTS: Contents of section .rdata: -# CONTENTS: 140002000 00000000 00000000 01000000 60200000 -# CONTENTS: 140002010 02100000 20000000 60200000 00300000 -# CONTENTS: 140002020 40000000 -# ptr: pointing at the IAT RVA at 0x2060 +# CONTENTS: 140001000 00000000 00000000 01000000 60100000 +# CONTENTS: 140001010 02300000 20000000 60100000 00200000 +# CONTENTS: 140001020 40000000 +# ptr: pointing at the IAT RVA at 0x1060 # relocs: pointing at the runtime pseudo reloc list at -# 0x2000 - 0x2024. +# 0x1000 - 0x1024. # CONTENTS: Contents of section .data: -# CONTENTS: 140003000 60200040 01000000 00200040 01000000 -# CONTENTS: 140003010 24200040 01000000 +# CONTENTS: 140002000 60100040 01000000 00100040 01000000 +# CONTENTS: 140002010 24100040 01000000 + +# SECTIONS: Name: .wtext (2E 77 74 65 78 74 00 00) +# SECTIONS: VirtualAddress: 0x3000 +# SECTIONS: Characteristics [ (0xE0000020) +# SECTIONS-NEXT: IMAGE_SCN_CNT_CODE (0x20) +# SECTIONS-NEXT: IMAGE_SCN_MEM_EXECUTE (0x20000000) +# SECTIONS-NEXT: IMAGE_SCN_MEM_READ (0x40000000) +# SECTIONS-NEXT: IMAGE_SCN_MEM_WRITE (0x80000000) +# SECTIONS-NEXT: ] .global main .text