blob: f13c2315b7c9372dfad93ced8dd3a8b4a32f492e [file] [log] [blame]
Michael J. Spencer84487f12015-07-24 21:03:07 +00001//===- Writer.cpp ---------------------------------------------------------===//
2//
3// The LLVM Linker
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Michael J. Spencer84487f12015-07-24 21:03:07 +000010#include "Chunks.h"
Rui Ueyamacb8474ed2015-08-05 23:51:50 +000011#include "Config.h"
Rafael Espindola192e1fa2015-08-06 15:08:23 +000012#include "Error.h"
Rui Ueyamaafff74e22015-08-05 23:24:46 +000013#include "SymbolTable.h"
14#include "Writer.h"
Rui Ueyamae44524d2015-07-28 00:17:25 +000015#include "llvm/ADT/DenseMap.h"
Rui Ueyamaafff74e22015-08-05 23:24:46 +000016#include "llvm/Support/FileOutputBuffer.h"
Michael J. Spencer84487f12015-07-24 21:03:07 +000017
18using namespace llvm;
19using namespace llvm::ELF;
20using namespace llvm::object;
21
22using namespace lld;
23using namespace lld::elf2;
24
25static const int PageSize = 4096;
26
Rui Ueyamaafff74e22015-08-05 23:24:46 +000027namespace {
Rafael Espindola52a0f1e2015-08-11 23:22:24 +000028// OutputSection represents a section in an output file. It's a
29// container of chunks. OutputSection and Chunk are 1:N relationship.
30// Chunks cannot belong to more than one OutputSections. The writer
31// creates multiple OutputSections and assign them unique,
32// non-overlapping file offsets and VAs.
Rafael Espindola02183402015-08-11 23:34:29 +000033template <class ELFT> class OutputSection {
Rafael Espindola52a0f1e2015-08-11 23:22:24 +000034public:
Rafael Espindola02183402015-08-11 23:34:29 +000035 typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
36 typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
37
Rafael Espindola52a0f1e2015-08-11 23:22:24 +000038 OutputSection(StringRef Name) : Name(Name), Header({}) {}
Rafael Espindola02183402015-08-11 23:34:29 +000039 void setVA(uintX_t);
40 void setFileOffset(uintX_t);
41 void addSectionChunk(SectionChunk<ELFT> *C);
Rafael Espindola52a0f1e2015-08-11 23:22:24 +000042 std::vector<Chunk *> &getChunks() { return Chunks; }
Rafael Espindola02183402015-08-11 23:34:29 +000043 void writeHeaderTo(Elf_Shdr *SHdr);
Rafael Espindola52a0f1e2015-08-11 23:22:24 +000044
45 // Returns the size of the section in the output file.
Rafael Espindola02183402015-08-11 23:34:29 +000046 uintX_t getSize() { return Header.sh_size; }
Rafael Espindola52a0f1e2015-08-11 23:22:24 +000047
48private:
49 StringRef Name;
Rafael Espindola02183402015-08-11 23:34:29 +000050 Elf_Shdr Header;
Rafael Espindola52a0f1e2015-08-11 23:22:24 +000051 std::vector<Chunk *> Chunks;
52};
53
Rui Ueyamaafff74e22015-08-05 23:24:46 +000054// The writer writes a SymbolTable result to a file.
55template <class ELFT> class Writer {
56public:
57 typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
Rui Ueyamacb8474ed2015-08-05 23:51:50 +000058 Writer(SymbolTable *T) : Symtab(T) {}
Rui Ueyamaafff74e22015-08-05 23:24:46 +000059 void run();
60
61private:
62 void createSections();
63 void assignAddresses();
64 void openFile(StringRef OutputPath);
65 void writeHeader();
66 void writeSections();
67
68 SymbolTable *Symtab;
Rui Ueyamaafff74e22015-08-05 23:24:46 +000069 std::unique_ptr<llvm::FileOutputBuffer> Buffer;
Rafael Espindola02183402015-08-11 23:34:29 +000070 llvm::SpecificBumpPtrAllocator<OutputSection<ELFT>> CAlloc;
71 std::vector<OutputSection<ELFT> *> OutputSections;
Rui Ueyamaafff74e22015-08-05 23:24:46 +000072
Rafael Espindola98f6bd02015-08-11 23:14:13 +000073 uintX_t FileSize;
74 uintX_t SizeOfHeaders;
Rui Ueyamaafff74e22015-08-05 23:24:46 +000075 uintX_t SectionHeaderOff;
76
77 std::vector<std::unique_ptr<Chunk>> Chunks;
78};
79} // anonymous namespace
80
81namespace lld {
82namespace elf2 {
83
Rafael Espindola2ffdd4d2015-08-04 14:29:01 +000084template <class ELFT>
Rui Ueyamacb8474ed2015-08-05 23:51:50 +000085void writeResult(SymbolTable *Symtab) { Writer<ELFT>(Symtab).run(); }
Rui Ueyamaafff74e22015-08-05 23:24:46 +000086
Rui Ueyamacb8474ed2015-08-05 23:51:50 +000087template void writeResult<ELF32LE>(SymbolTable *);
88template void writeResult<ELF32BE>(SymbolTable *);
89template void writeResult<ELF64LE>(SymbolTable *);
90template void writeResult<ELF64BE>(SymbolTable *);
Rui Ueyamaafff74e22015-08-05 23:24:46 +000091
92} // namespace elf2
93} // namespace lld
Michael J. Spencer84487f12015-07-24 21:03:07 +000094
95// The main function of the writer.
Rui Ueyamaafff74e22015-08-05 23:24:46 +000096template <class ELFT> void Writer<ELFT>::run() {
Michael J. Spencer84487f12015-07-24 21:03:07 +000097 createSections();
98 assignAddresses();
Rui Ueyamacb8474ed2015-08-05 23:51:50 +000099 openFile(Config->OutputFile);
Michael J. Spencer84487f12015-07-24 21:03:07 +0000100 writeHeader();
101 writeSections();
102 error(Buffer->commit());
103}
104
Rafael Espindola02183402015-08-11 23:34:29 +0000105template <class ELFT> void OutputSection<ELFT>::setVA(uintX_t VA) {
Michael J. Spencer84487f12015-07-24 21:03:07 +0000106 Header.sh_addr = VA;
107 for (Chunk *C : Chunks)
108 C->setVA(C->getVA() + VA);
109}
110
Rafael Espindola02183402015-08-11 23:34:29 +0000111template <class ELFT> void OutputSection<ELFT>::setFileOffset(uintX_t Off) {
Michael J. Spencer84487f12015-07-24 21:03:07 +0000112 if (Header.sh_size == 0)
113 return;
114 Header.sh_offset = Off;
115 for (Chunk *C : Chunks)
116 C->setFileOff(C->getFileOff() + Off);
117}
118
Michael J. Spencer44fc1c02015-07-29 22:14:50 +0000119template <class ELFT>
Rafael Espindola02183402015-08-11 23:34:29 +0000120void OutputSection<ELFT>::addSectionChunk(SectionChunk<ELFT> *C) {
Michael J. Spencer84487f12015-07-24 21:03:07 +0000121 Chunks.push_back(C);
Rafael Espindola98f6bd02015-08-11 23:14:13 +0000122 uintX_t Off = Header.sh_size;
Michael J. Spencer84487f12015-07-24 21:03:07 +0000123 Off = RoundUpToAlignment(Off, C->getAlign());
124 C->setVA(Off);
125 C->setFileOff(Off);
126 Off += C->getSize();
127 Header.sh_size = Off;
Rafael Espindolae7a00e32015-08-05 13:55:34 +0000128 Header.sh_type = C->getSectionHdr()->sh_type;
129 Header.sh_flags |= C->getSectionHdr()->sh_flags;
Michael J. Spencer8039dae22015-07-29 00:30:10 +0000130}
131
Rafael Espindola02183402015-08-11 23:34:29 +0000132template <class ELFT> void OutputSection<ELFT>::writeHeaderTo(Elf_Shdr *SHdr) {
133 *SHdr = Header;
Michael J. Spencer84487f12015-07-24 21:03:07 +0000134}
135
Michael J. Spencer84487f12015-07-24 21:03:07 +0000136// Create output section objects and add them to OutputSections.
137template <class ELFT> void Writer<ELFT>::createSections() {
Rafael Espindola02183402015-08-11 23:34:29 +0000138 SmallDenseMap<StringRef, OutputSection<ELFT> *> Map;
Rafael Espindolae7a00e32015-08-05 13:55:34 +0000139 for (std::unique_ptr<ObjectFileBase> &FileB : Symtab->ObjectFiles) {
140 auto &File = cast<ObjectFile<ELFT>>(*FileB);
141 for (SectionChunk<ELFT> *C : File.getChunks()) {
Rafael Espindola02183402015-08-11 23:34:29 +0000142 OutputSection<ELFT> *&Sec = Map[C->getSectionName()];
Rafael Espindolab8995142015-08-04 13:39:30 +0000143 if (!Sec) {
Rafael Espindola02183402015-08-11 23:34:29 +0000144 Sec = new (CAlloc.Allocate()) OutputSection<ELFT>(C->getSectionName());
Rafael Espindolab8995142015-08-04 13:39:30 +0000145 OutputSections.push_back(Sec);
146 }
Rafael Espindola02183402015-08-11 23:34:29 +0000147 Sec->addSectionChunk(C);
Michael J. Spencer84487f12015-07-24 21:03:07 +0000148 }
Michael J. Spencer84487f12015-07-24 21:03:07 +0000149 }
150}
151
152// Visits all sections to assign incremental, non-overlapping RVAs and
153// file offsets.
154template <class ELFT> void Writer<ELFT>::assignAddresses() {
Michael J. Spencer8039dae22015-07-29 00:30:10 +0000155 SizeOfHeaders = RoundUpToAlignment(sizeof(Elf_Ehdr_Impl<ELFT>), PageSize);
Rafael Espindola98f6bd02015-08-11 23:14:13 +0000156 uintX_t VA = 0x1000; // The first page is kept unmapped.
157 uintX_t FileOff = SizeOfHeaders;
Rafael Espindola02183402015-08-11 23:34:29 +0000158 for (OutputSection<ELFT> *Sec : OutputSections) {
Michael J. Spencer84487f12015-07-24 21:03:07 +0000159 Sec->setVA(VA);
160 Sec->setFileOffset(FileOff);
161 VA += RoundUpToAlignment(Sec->getSize(), PageSize);
162 FileOff += RoundUpToAlignment(Sec->getSize(), 8);
163 }
Michael J. Spencer8039dae22015-07-29 00:30:10 +0000164 // Add space for section headers.
165 SectionHeaderOff = FileOff;
166 FileOff += (OutputSections.size() + 1) * sizeof(Elf_Shdr_Impl<ELFT>);
Michael J. Spencer84487f12015-07-24 21:03:07 +0000167 FileSize = SizeOfHeaders + RoundUpToAlignment(FileOff - SizeOfHeaders, 8);
168}
169
170template <class ELFT> void Writer<ELFT>::writeHeader() {
171 uint8_t *Buf = Buffer->getBufferStart();
172 auto *EHdr = reinterpret_cast<Elf_Ehdr_Impl<ELFT> *>(Buf);
173 EHdr->e_ident[EI_MAG0] = 0x7F;
174 EHdr->e_ident[EI_MAG1] = 0x45;
175 EHdr->e_ident[EI_MAG2] = 0x4C;
176 EHdr->e_ident[EI_MAG3] = 0x46;
Rafael Espindola4b7c2fc2015-08-05 15:08:40 +0000177 EHdr->e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
178 EHdr->e_ident[EI_DATA] = ELFT::TargetEndianness == llvm::support::little
179 ? ELFDATA2LSB
180 : ELFDATA2MSB;
Michael J. Spencer84487f12015-07-24 21:03:07 +0000181 EHdr->e_ident[EI_VERSION] = EV_CURRENT;
Rafael Espindola87ee8dc2015-08-05 11:55:52 +0000182 EHdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
Michael J. Spencer84487f12015-07-24 21:03:07 +0000183
184 EHdr->e_type = ET_EXEC;
Rafael Espindola4b7c2fc2015-08-05 15:08:40 +0000185 auto &FirstObj = cast<ObjectFile<ELFT>>(*Symtab->ObjectFiles[0]);
186 EHdr->e_machine = FirstObj.getObj()->getHeader()->e_machine;
Michael J. Spencer84487f12015-07-24 21:03:07 +0000187 EHdr->e_version = EV_CURRENT;
188 EHdr->e_entry = 0x401000;
189 EHdr->e_phoff = sizeof(Elf_Ehdr_Impl<ELFT>);
Michael J. Spencer8039dae22015-07-29 00:30:10 +0000190 EHdr->e_shoff = SectionHeaderOff;
Michael J. Spencer84487f12015-07-24 21:03:07 +0000191 EHdr->e_ehsize = sizeof(Elf_Ehdr_Impl<ELFT>);
192 EHdr->e_phentsize = sizeof(Elf_Phdr_Impl<ELFT>);
193 EHdr->e_phnum = 1;
194 EHdr->e_shentsize = sizeof(Elf_Shdr_Impl<ELFT>);
Michael J. Spencer8039dae22015-07-29 00:30:10 +0000195 EHdr->e_shnum = OutputSections.size() + 1;
Michael J. Spencer84487f12015-07-24 21:03:07 +0000196 EHdr->e_shstrndx = 0;
197
198 auto PHdrs = reinterpret_cast<Elf_Phdr_Impl<ELFT> *>(Buf + EHdr->e_phoff);
199 PHdrs->p_type = PT_LOAD;
200 PHdrs->p_flags = PF_R | PF_X;
201 PHdrs->p_offset = 0x0000;
202 PHdrs->p_vaddr = 0x400000;
203 PHdrs->p_paddr = PHdrs->p_vaddr;
204 PHdrs->p_filesz = FileSize;
205 PHdrs->p_memsz = FileSize;
206 PHdrs->p_align = 0x4000;
Michael J. Spencer8039dae22015-07-29 00:30:10 +0000207
208 auto SHdrs = reinterpret_cast<Elf_Shdr_Impl<ELFT> *>(Buf + EHdr->e_shoff);
209 // First entry is null.
210 ++SHdrs;
Rafael Espindola02183402015-08-11 23:34:29 +0000211 for (OutputSection<ELFT> *Sec : OutputSections)
212 Sec->writeHeaderTo(SHdrs++);
Michael J. Spencer84487f12015-07-24 21:03:07 +0000213}
214
215template <class ELFT> void Writer<ELFT>::openFile(StringRef Path) {
216 std::error_code EC = FileOutputBuffer::create(Path, FileSize, Buffer,
217 FileOutputBuffer::F_executable);
218 error(EC, Twine("failed to open ") + Path);
219}
220
221// Write section contents to a mmap'ed file.
222template <class ELFT> void Writer<ELFT>::writeSections() {
223 uint8_t *Buf = Buffer->getBufferStart();
Rafael Espindola02183402015-08-11 23:34:29 +0000224 for (OutputSection<ELFT> *Sec : OutputSections) {
Michael J. Spencer84487f12015-07-24 21:03:07 +0000225 for (Chunk *C : Sec->getChunks())
226 C->writeTo(Buf);
227 }
228}