summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRui Ueyama <ruiu@google.com>2015-07-08 01:45:29 +0000
committerRui Ueyama <ruiu@google.com>2015-07-08 01:45:29 +0000
commit11863b4ae1d50a484e739b5889a7ac8710c6ef1e (patch)
tree9f64782055858bce5661055d2008d257e32cae62
parent8c73ba65bbc091e4809786b5c716193805350a61 (diff)
downloadbcm5719-llvm-11863b4ae1d50a484e739b5889a7ac8710c6ef1e.tar.gz
bcm5719-llvm-11863b4ae1d50a484e739b5889a7ac8710c6ef1e.zip
COFF: Support x86 file header and relocations.
llvm-svn: 241657
-rw-r--r--lld/COFF/Chunks.cpp25
-rw-r--r--lld/COFF/Chunks.h1
-rw-r--r--lld/COFF/Writer.cpp30
-rw-r--r--lld/COFF/Writer.h5
-rw-r--r--lld/test/COFF/reloc-x86.test60
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
+...
OpenPOWER on IntegriCloud