diff options
| author | Rui Ueyama <ruiu@google.com> | 2015-07-08 01:45:29 +0000 |
|---|---|---|
| committer | Rui Ueyama <ruiu@google.com> | 2015-07-08 01:45:29 +0000 |
| commit | 11863b4ae1d50a484e739b5889a7ac8710c6ef1e (patch) | |
| tree | 9f64782055858bce5661055d2008d257e32cae62 | |
| parent | 8c73ba65bbc091e4809786b5c716193805350a61 (diff) | |
| download | bcm5719-llvm-11863b4ae1d50a484e739b5889a7ac8710c6ef1e.tar.gz bcm5719-llvm-11863b4ae1d50a484e739b5889a7ac8710c6ef1e.zip | |
COFF: Support x86 file header and relocations.
llvm-svn: 241657
| -rw-r--r-- | lld/COFF/Chunks.cpp | 25 | ||||
| -rw-r--r-- | lld/COFF/Chunks.h | 1 | ||||
| -rw-r--r-- | lld/COFF/Writer.cpp | 30 | ||||
| -rw-r--r-- | lld/COFF/Writer.h | 5 | ||||
| -rw-r--r-- | lld/test/COFF/reloc-x86.test | 60 |
5 files changed, 107 insertions, 14 deletions
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp index 128d09c83fe..0004d1006c9 100644 --- a/lld/COFF/Chunks.cpp +++ b/lld/COFF/Chunks.cpp @@ -67,6 +67,20 @@ void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, uint64_t S, } } +void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, uint64_t S, + uint64_t P) { + switch (Type) { + case IMAGE_REL_I386_ABSOLUTE: break; + case IMAGE_REL_I386_DIR32: add32(Off, S + Config->ImageBase); break; + case IMAGE_REL_I386_DIR32NB: add32(Off, S); break; + case IMAGE_REL_I386_REL32: add32(Off, S - P - 4); break; + case IMAGE_REL_I386_SECTION: add16(Off, Out->getSectionIndex() + 1); break; + case IMAGE_REL_I386_SECREL: add32(Off, S - Out->getRVA()); break; + default: + llvm::report_fatal_error("Unsupported relocation type"); + } +} + void SectionChunk::writeTo(uint8_t *Buf) { if (!hasData()) return; @@ -80,7 +94,16 @@ void SectionChunk::writeTo(uint8_t *Buf) { SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex)->repl(); uint64_t S = cast<Defined>(Body)->getRVA(); uint64_t P = RVA + Rel.VirtualAddress; - applyRelX64(Off, Rel.Type, S, P); + switch (Config->MachineType) { + case IMAGE_FILE_MACHINE_AMD64: + applyRelX64(Off, Rel.Type, S, P); + break; + case IMAGE_FILE_MACHINE_I386: + applyRelX86(Off, Rel.Type, S, P); + break; + default: + llvm_unreachable("unknown machine type"); + } } } diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h index 50fba3c3a4f..67c2c4c4555 100644 --- a/lld/COFF/Chunks.h +++ b/lld/COFF/Chunks.h @@ -137,6 +137,7 @@ public: void getBaserels(std::vector<uint32_t> *Res, Defined *ImageBase) override; bool isCOMDAT() const; void applyRelX64(uint8_t *Off, uint16_t Type, uint64_t S, uint64_t P); + void applyRelX86(uint8_t *Off, uint16_t Type, uint64_t S, uint64_t P); // 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. diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index f9d1663e233..e4a1c1e16d2 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -52,7 +52,11 @@ std::error_code Writer::write(StringRef OutputPath) { removeEmptySections(); if (auto EC = openFile(OutputPath)) return EC; - writeHeader(); + if (Is64) { + writeHeader<pe32plus_header>(); + } else { + writeHeader<pe32_header>(); + } writeSections(); sortExceptionTable(); return Buffer->commit(); @@ -105,6 +109,9 @@ void OutputSection::writeHeaderTo(uint8_t *Buf) { } } +Writer::Writer(SymbolTable *T) + : Symtab(T), Is64(Config->MachineType == IMAGE_FILE_MACHINE_AMD64) {} + // Set live bit on for each reachable chunk. Unmarked (unreachable) // COMDAT chunks will be ignored in the next step, so that they don't // come to the final output file. @@ -278,11 +285,11 @@ void Writer::removeEmptySections() { // Visits all sections to assign incremental, non-overlapping RVAs and // file offsets. void Writer::assignAddresses() { - SizeOfHeaders = RoundUpToAlignment( - DOSStubSize + sizeof(PEMagic) + sizeof(coff_file_header) + - sizeof(pe32plus_header) + - sizeof(data_directory) * NumberfOfDataDirectory + - sizeof(coff_section) * OutputSections.size(), PageSize); + SizeOfHeaders = DOSStubSize + sizeof(PEMagic) + sizeof(coff_file_header) + + sizeof(data_directory) * NumberfOfDataDirectory + + sizeof(coff_section) * OutputSections.size(); + SizeOfHeaders += Is64 ? sizeof(pe32plus_header) : sizeof(pe32_header); + SizeOfHeaders = RoundUpToAlignment(SizeOfHeaders, PageSize); uint64_t RVA = 0x1000; // The first page is kept unmapped. uint64_t FileOff = SizeOfHeaders; for (OutputSection *Sec : OutputSections) { @@ -309,7 +316,7 @@ inferMachineType(const std::vector<ObjectFile *> &Files) { return IMAGE_FILE_MACHINE_UNKNOWN; } -void Writer::writeHeader() { +template <typename PEHeaderTy> void Writer::writeHeader() { // Write DOS stub uint8_t *Buf = Buffer->getBufferStart(); auto *DOS = reinterpret_cast<dos_header *>(Buf); @@ -334,18 +341,19 @@ void Writer::writeHeader() { COFF->Machine = MachineType; COFF->NumberOfSections = OutputSections.size(); COFF->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE; - COFF->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; + if (Is64) + COFF->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; if (Config->DLL) COFF->Characteristics |= IMAGE_FILE_DLL; if (!Config->Relocatable) COFF->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED; COFF->SizeOfOptionalHeader = - sizeof(pe32plus_header) + sizeof(data_directory) * NumberfOfDataDirectory; + sizeof(PEHeaderTy) + sizeof(data_directory) * NumberfOfDataDirectory; // Write PE header - auto *PE = reinterpret_cast<pe32plus_header *>(Buf); + auto *PE = reinterpret_cast<PEHeaderTy *>(Buf); Buf += sizeof(*PE); - PE->Magic = PE32Header::PE32_PLUS; + PE->Magic = Is64 ? PE32Header::PE32_PLUS : PE32Header::PE32; PE->ImageBase = Config->ImageBase; PE->SectionAlignment = SectionAlignment; PE->FileAlignment = FileAlignment; diff --git a/lld/COFF/Writer.h b/lld/COFF/Writer.h index 4d4d0befd2c..ff014afa249 100644 --- a/lld/COFF/Writer.h +++ b/lld/COFF/Writer.h @@ -74,7 +74,7 @@ private: // The writer writes a SymbolTable result to a file. class Writer { public: - explicit Writer(SymbolTable *T) : Symtab(T) {} + explicit Writer(SymbolTable *T); std::error_code write(StringRef Path); private: @@ -87,7 +87,7 @@ private: void assignAddresses(); void removeEmptySections(); std::error_code openFile(StringRef OutputPath); - void writeHeader(); + template <typename PEHeaderTy> void writeHeader(); void writeSections(); void sortExceptionTable(); void applyRelocations(); @@ -109,6 +109,7 @@ private: DelayLoadContents DelayIdata; EdataContents Edata; + bool Is64; uint64_t FileSize; uint64_t SizeOfImage; uint64_t SizeOfHeaders; diff --git a/lld/test/COFF/reloc-x86.test b/lld/test/COFF/reloc-x86.test new file mode 100644 index 00000000000..5d06d9866b7 --- /dev/null +++ b/lld/test/COFF/reloc-x86.test @@ -0,0 +1,60 @@ +# RUN: yaml2obj < %s > %t.obj +# RUN: lld -flavor link2 /out:%t.exe /entry:main /base:0x400000 %t.obj +# RUN: llvm-objdump -d %t.exe | FileCheck %s + +# CHECK: .text: +# CHECK: 1000: a1 00 00 00 00 +# CHECK: 1005: a1 00 10 40 00 +# CHECK: 100a: a1 00 10 00 00 +# CHECK: 100f: a1 ec ff ff ff +# CHECK: 1014: a1 00 00 01 00 +# CHECK: 1019: a1 00 00 00 00 + +--- +header: + Machine: IMAGE_FILE_MACHINE_I386 + Characteristics: [] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4096 + SectionData: A100000000A100000000A100000000A100000000A100000000A100000000 + Relocations: + - VirtualAddress: 1 + SymbolName: main + Type: IMAGE_REL_I386_ABSOLUTE + - VirtualAddress: 6 + SymbolName: main + Type: IMAGE_REL_I386_DIR32 + - VirtualAddress: 11 + SymbolName: main + Type: IMAGE_REL_I386_DIR32NB + - VirtualAddress: 16 + SymbolName: main + Type: IMAGE_REL_I386_REL32 + - VirtualAddress: 23 + SymbolName: main + Type: IMAGE_REL_I386_SECTION + - VirtualAddress: 26 + SymbolName: main + Type: IMAGE_REL_I386_SECREL +symbols: + - Name: .text + 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_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... |

