xref: /llvm-project-15.0.7/lld/ELF/Writer.cpp (revision 7ff29148)
1 //===- 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 
10 #include "Chunks.h"
11 #include "Config.h"
12 #include "Error.h"
13 #include "SymbolTable.h"
14 #include "Writer.h"
15 
16 #include "llvm/ADT/DenseMap.h"
17 #include "llvm/MC/StringTableBuilder.h"
18 #include "llvm/Support/FileOutputBuffer.h"
19 
20 using namespace llvm;
21 using namespace llvm::ELF;
22 using namespace llvm::object;
23 
24 using namespace lld;
25 using namespace lld::elf2;
26 
27 static const int PageSize = 4096;
28 
29 namespace {
30 // OutputSection represents a section in an output file. It's a
31 // container of chunks. OutputSection and Chunk are 1:N relationship.
32 // Chunks cannot belong to more than one OutputSections. The writer
33 // creates multiple OutputSections and assign them unique,
34 // non-overlapping file offsets and VAs.
35 template <class ELFT> class OutputSection {
36 public:
37   typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
38   typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
39 
40   OutputSection(StringRef Name) : Name(Name) {
41     memset(&Header, 0, sizeof(Elf_Shdr));
42   }
43   void setVA(uintX_t);
44   void setFileOffset(uintX_t);
45   void addSectionChunk(SectionChunk<ELFT> *C);
46   std::vector<Chunk *> &getChunks() { return Chunks; }
47   void writeHeaderTo(Elf_Shdr *SHdr);
48   StringRef getName() { return Name; }
49   void setNameOffset(uintX_t Offset) { Header.sh_name = Offset; }
50 
51   // Returns the size of the section in the output file.
52   uintX_t getSize() { return Header.sh_size; }
53   uintX_t getFlags() { return Header.sh_flags; }
54   uintX_t getOffset() { return Header.sh_offset; }
55 
56 private:
57   StringRef Name;
58   Elf_Shdr Header;
59   std::vector<Chunk *> Chunks;
60 };
61 
62 // The writer writes a SymbolTable result to a file.
63 template <class ELFT> class Writer {
64 public:
65   typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
66   typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
67   Writer(SymbolTable *T) : Symtab(T) {}
68   void run();
69 
70 private:
71   void createSections();
72   void assignAddresses();
73   void openFile(StringRef OutputPath);
74   void writeHeader();
75   void writeSections();
76 
77   SymbolTable *Symtab;
78   std::unique_ptr<llvm::FileOutputBuffer> Buffer;
79   llvm::SpecificBumpPtrAllocator<OutputSection<ELFT>> CAlloc;
80   std::vector<OutputSection<ELFT> *> OutputSections;
81 
82   uintX_t FileSize;
83   uintX_t SizeOfHeaders;
84   uintX_t SectionHeaderOff;
85   uintX_t StringTableOff;
86   unsigned StringTableIndex;
87   StringTableBuilder StrTabBuilder;
88   unsigned NumSections;
89 
90   std::vector<std::unique_ptr<Chunk>> Chunks;
91 };
92 } // anonymous namespace
93 
94 namespace lld {
95 namespace elf2 {
96 
97 template <class ELFT>
98 void writeResult(SymbolTable *Symtab) { Writer<ELFT>(Symtab).run(); }
99 
100 template void writeResult<ELF32LE>(SymbolTable *);
101 template void writeResult<ELF32BE>(SymbolTable *);
102 template void writeResult<ELF64LE>(SymbolTable *);
103 template void writeResult<ELF64BE>(SymbolTable *);
104 
105 } // namespace elf2
106 } // namespace lld
107 
108 // The main function of the writer.
109 template <class ELFT> void Writer<ELFT>::run() {
110   createSections();
111   assignAddresses();
112   openFile(Config->OutputFile);
113   writeHeader();
114   writeSections();
115   error(Buffer->commit());
116 }
117 
118 template <class ELFT> void OutputSection<ELFT>::setVA(uintX_t VA) {
119   Header.sh_addr = VA;
120 }
121 
122 template <class ELFT> void OutputSection<ELFT>::setFileOffset(uintX_t Off) {
123   if (Header.sh_size == 0)
124     return;
125   Header.sh_offset = Off;
126 }
127 
128 template <class ELFT>
129 void OutputSection<ELFT>::addSectionChunk(SectionChunk<ELFT> *C) {
130   Chunks.push_back(C);
131   uintX_t Off = Header.sh_size;
132   Off = RoundUpToAlignment(Off, C->getAlign());
133   C->setOutputSectionOff(Off);
134   Off += C->getSize();
135   Header.sh_size = Off;
136   Header.sh_type = C->getSectionHdr()->sh_type;
137   Header.sh_flags |= C->getSectionHdr()->sh_flags;
138 }
139 
140 template <class ELFT> void OutputSection<ELFT>::writeHeaderTo(Elf_Shdr *SHdr) {
141   *SHdr = Header;
142 }
143 
144 namespace {
145 template <bool Is64Bits> struct SectionKey {
146   typedef typename std::conditional<Is64Bits, uint64_t, uint32_t>::type uintX_t;
147   StringRef Name;
148   uint32_t sh_type;
149   uintX_t sh_flags;
150 };
151 }
152 namespace llvm {
153 template <bool Is64Bits> struct DenseMapInfo<SectionKey<Is64Bits>> {
154   static SectionKey<Is64Bits> getEmptyKey() {
155     return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0};
156   }
157   static SectionKey<Is64Bits> getTombstoneKey() {
158     return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getTombstoneKey(), 0,
159                                 0};
160   }
161   static unsigned getHashValue(const SectionKey<Is64Bits> &Val) {
162     return hash_combine(Val.Name, Val.sh_type, Val.sh_flags);
163   }
164   static bool isEqual(const SectionKey<Is64Bits> &LHS,
165                       const SectionKey<Is64Bits> &RHS) {
166     return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name) &&
167            LHS.sh_type == RHS.sh_type && LHS.sh_flags == RHS.sh_flags;
168   }
169 };
170 }
171 
172 // Create output section objects and add them to OutputSections.
173 template <class ELFT> void Writer<ELFT>::createSections() {
174   SmallDenseMap<SectionKey<ELFT::Is64Bits>, OutputSection<ELFT> *> Map;
175   for (std::unique_ptr<ObjectFileBase> &FileB : Symtab->ObjectFiles) {
176     auto &File = cast<ObjectFile<ELFT>>(*FileB);
177     for (SectionChunk<ELFT> *C : File.getChunks()) {
178       const Elf_Shdr *H = C->getSectionHdr();
179       SectionKey<ELFT::Is64Bits> Key{C->getSectionName(), H->sh_type,
180                                      H->sh_flags};
181       OutputSection<ELFT> *&Sec = Map[Key];
182       if (!Sec) {
183         Sec = new (CAlloc.Allocate()) OutputSection<ELFT>(C->getSectionName());
184         OutputSections.push_back(Sec);
185       }
186       Sec->addSectionChunk(C);
187     }
188   }
189 }
190 
191 template <class ELFT>
192 static bool compSec(OutputSection<ELFT> *A, OutputSection<ELFT> *B) {
193   // Place SHF_ALLOC sections first.
194   return (A->getFlags() & SHF_ALLOC) && !(B->getFlags() & SHF_ALLOC);
195 }
196 
197 // Visits all sections to assign incremental, non-overlapping RVAs and
198 // file offsets.
199 template <class ELFT> void Writer<ELFT>::assignAddresses() {
200   SizeOfHeaders = RoundUpToAlignment(sizeof(Elf_Ehdr_Impl<ELFT>), PageSize);
201   uintX_t VA = 0x1000; // The first page is kept unmapped.
202   uintX_t FileOff = SizeOfHeaders;
203 
204   std::stable_sort(OutputSections.begin(), OutputSections.end(), compSec<ELFT>);
205 
206   for (OutputSection<ELFT> *Sec : OutputSections) {
207     if (Sec->getFlags() & SHF_ALLOC) {
208       Sec->setVA(VA);
209       VA += RoundUpToAlignment(Sec->getSize(), PageSize);
210     }
211     Sec->setFileOffset(FileOff);
212     FileOff += RoundUpToAlignment(Sec->getSize(), 8);
213     StrTabBuilder.add(Sec->getName());
214   }
215 
216   // Regular sections.
217   NumSections = OutputSections.size();
218 
219   // First dummy section.
220   NumSections++;
221 
222   // String table.
223   StrTabBuilder.add(".strtab");
224   StringTableIndex = NumSections;
225   StringTableOff = FileOff;
226   StrTabBuilder.finalize(StringTableBuilder::ELF);
227   FileOff += StrTabBuilder.data().size();
228   NumSections++;
229 
230   FileOff += OffsetToAlignment(FileOff, ELFT::Is64Bits ? 8 : 4);
231 
232   // Add space for section headers.
233   SectionHeaderOff = FileOff;
234   FileOff += NumSections * sizeof(Elf_Shdr_Impl<ELFT>);
235   FileSize = SizeOfHeaders + RoundUpToAlignment(FileOff - SizeOfHeaders, 8);
236 }
237 
238 template <class ELFT> void Writer<ELFT>::writeHeader() {
239   uint8_t *Buf = Buffer->getBufferStart();
240   auto *EHdr = reinterpret_cast<Elf_Ehdr_Impl<ELFT> *>(Buf);
241   EHdr->e_ident[EI_MAG0] = 0x7F;
242   EHdr->e_ident[EI_MAG1] = 0x45;
243   EHdr->e_ident[EI_MAG2] = 0x4C;
244   EHdr->e_ident[EI_MAG3] = 0x46;
245   EHdr->e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
246   EHdr->e_ident[EI_DATA] = ELFT::TargetEndianness == llvm::support::little
247                                ? ELFDATA2LSB
248                                : ELFDATA2MSB;
249   EHdr->e_ident[EI_VERSION] = EV_CURRENT;
250   EHdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
251 
252   EHdr->e_type = ET_EXEC;
253   auto &FirstObj = cast<ObjectFile<ELFT>>(*Symtab->ObjectFiles[0]);
254   EHdr->e_machine = FirstObj.getObj()->getHeader()->e_machine;
255   EHdr->e_version = EV_CURRENT;
256   EHdr->e_entry = 0x401000;
257   EHdr->e_phoff = sizeof(Elf_Ehdr_Impl<ELFT>);
258   EHdr->e_shoff = SectionHeaderOff;
259   EHdr->e_ehsize = sizeof(Elf_Ehdr_Impl<ELFT>);
260   EHdr->e_phentsize = sizeof(Elf_Phdr_Impl<ELFT>);
261   EHdr->e_phnum = 1;
262   EHdr->e_shentsize = sizeof(Elf_Shdr_Impl<ELFT>);
263   EHdr->e_shnum = NumSections;
264   EHdr->e_shstrndx = StringTableIndex;
265 
266   auto PHdrs = reinterpret_cast<Elf_Phdr_Impl<ELFT> *>(Buf + EHdr->e_phoff);
267   PHdrs->p_type = PT_LOAD;
268   PHdrs->p_flags = PF_R | PF_X;
269   PHdrs->p_offset = 0x0000;
270   PHdrs->p_vaddr = 0x400000;
271   PHdrs->p_paddr = PHdrs->p_vaddr;
272   PHdrs->p_filesz = FileSize;
273   PHdrs->p_memsz = FileSize;
274   PHdrs->p_align = 0x4000;
275 
276   auto SHdrs = reinterpret_cast<Elf_Shdr_Impl<ELFT> *>(Buf + EHdr->e_shoff);
277   // First entry is null.
278   ++SHdrs;
279   for (OutputSection<ELFT> *Sec : OutputSections) {
280     Sec->setNameOffset(StrTabBuilder.getOffset(Sec->getName()));
281     Sec->writeHeaderTo(SHdrs++);
282   }
283 
284   // String table.
285   SHdrs->sh_name = StrTabBuilder.getOffset(".strtab");
286   SHdrs->sh_type = SHT_STRTAB;
287   SHdrs->sh_flags = 0;
288   SHdrs->sh_addr = 0;
289   SHdrs->sh_offset = StringTableOff;
290   SHdrs->sh_size = StrTabBuilder.data().size();
291   SHdrs->sh_link = 0;
292   SHdrs->sh_info = 0;
293   SHdrs->sh_addralign = 1;
294   SHdrs->sh_entsize = 0;
295 }
296 
297 template <class ELFT> void Writer<ELFT>::openFile(StringRef Path) {
298   ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
299       FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable);
300   error(BufferOrErr, Twine("failed to open ") + Path);
301   Buffer = std::move(*BufferOrErr);
302 }
303 
304 // Write section contents to a mmap'ed file.
305 template <class ELFT> void Writer<ELFT>::writeSections() {
306   uint8_t *Buf = Buffer->getBufferStart();
307   for (OutputSection<ELFT> *Sec : OutputSections) {
308     uint8_t *SecBuf = Buf + Sec->getOffset();
309     for (Chunk *C : Sec->getChunks())
310       C->writeTo(SecBuf);
311   }
312 
313   // String table.
314   StringRef Data = StrTabBuilder.data();
315   memcpy(Buf + StringTableOff, Data.data(), Data.size());
316 }
317