15805c4f5SRafael Espindola //===- OutputSections.cpp -------------------------------------------------===//
25805c4f5SRafael Espindola //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65805c4f5SRafael Espindola //
75805c4f5SRafael Espindola //===----------------------------------------------------------------------===//
85805c4f5SRafael Espindola
95805c4f5SRafael Espindola #include "OutputSections.h"
105805c4f5SRafael Espindola #include "Config.h"
11b01430a0SFangrui Song #include "InputFiles.h"
1295642b95SRui Ueyama #include "LinkerScript.h"
1327bb7990SFangrui Song #include "Symbols.h"
14e8a6102fSRui Ueyama #include "SyntheticSections.h"
1501205f79SRafael Espindola #include "Target.h"
16fcd8817dSFangrui Song #include "lld/Common/Arrays.h"
172017d52bSRui Ueyama #include "lld/Common/Memory.h"
18264b5d9eSZachary Turner #include "llvm/BinaryFormat/Dwarf.h"
19e8bff9aeSMariusz Ceier #include "llvm/Config/llvm-config.h" // LLVM_ENABLE_ZLIB
20932f0276SReid Kleckner #include "llvm/Support/Parallel.h"
2127bb7990SFangrui Song #include "llvm/Support/Path.h"
22439341b9SJames Henderson #include "llvm/Support/TimeProfiler.h"
234cdc4416SFangrui Song #if LLVM_ENABLE_ZLIB
244cdc4416SFangrui Song #include <zlib.h>
254cdc4416SFangrui Song #endif
265805c4f5SRafael Espindola
275805c4f5SRafael Espindola using namespace llvm;
28dbcfedb3SRui Ueyama using namespace llvm::dwarf;
295805c4f5SRafael Espindola using namespace llvm::object;
30b0486051SSimon Atanasyan using namespace llvm::support::endian;
315805c4f5SRafael Espindola using namespace llvm::ELF;
3207837b8fSFangrui Song using namespace lld;
3307837b8fSFangrui Song using namespace lld::elf;
345805c4f5SRafael Espindola
353837f427SRui Ueyama uint8_t *Out::bufferStart;
363837f427SRui Ueyama PhdrEntry *Out::tlsPhdr;
373837f427SRui Ueyama OutputSection *Out::elfHeader;
383837f427SRui Ueyama OutputSection *Out::programHeaders;
393837f427SRui Ueyama OutputSection *Out::preinitArray;
403837f427SRui Ueyama OutputSection *Out::initArray;
413837f427SRui Ueyama OutputSection *Out::finiArray;
429d1bacb1SRui Ueyama
43ba948c5aSFangrui Song SmallVector<OutputSection *, 0> elf::outputSections;
44f51c8055SRafael Espindola
getPhdrFlags() const4524e6f363SRafael Espindola uint32_t OutputSection::getPhdrFlags() const {
463837f427SRui Ueyama uint32_t ret = 0;
473837f427SRui Ueyama if (config->emachine != EM_ARM || !(flags & SHF_ARM_PURECODE))
483837f427SRui Ueyama ret |= PF_R;
493837f427SRui Ueyama if (flags & SHF_WRITE)
503837f427SRui Ueyama ret |= PF_W;
513837f427SRui Ueyama if (flags & SHF_EXECINSTR)
523837f427SRui Ueyama ret |= PF_X;
533837f427SRui Ueyama return ret;
540b113671SRafael Espindola }
550b113671SRafael Espindola
5635c6af3cSRafael Espindola template <class ELFT>
writeHeaderTo(typename ELFT::Shdr * shdr)573837f427SRui Ueyama void OutputSection::writeHeaderTo(typename ELFT::Shdr *shdr) {
583837f427SRui Ueyama shdr->sh_entsize = entsize;
593837f427SRui Ueyama shdr->sh_addralign = alignment;
603837f427SRui Ueyama shdr->sh_type = type;
613837f427SRui Ueyama shdr->sh_offset = offset;
623837f427SRui Ueyama shdr->sh_flags = flags;
633837f427SRui Ueyama shdr->sh_info = info;
643837f427SRui Ueyama shdr->sh_link = link;
653837f427SRui Ueyama shdr->sh_addr = addr;
663837f427SRui Ueyama shdr->sh_size = size;
673837f427SRui Ueyama shdr->sh_name = shName;
68c63c1dbdSRui Ueyama }
69c63c1dbdSRui Ueyama
OutputSection(StringRef name,uint32_t type,uint64_t flags)703837f427SRui Ueyama OutputSection::OutputSection(StringRef name, uint32_t type, uint64_t flags)
716c814931SFangrui Song : SectionBase(Output, name, flags, /*Entsize*/ 0, /*Alignment*/ 1, type,
72b5a307faSPeter Collingbourne /*Info*/ 0, /*Link*/ 0) {}
7358941ee1SGeorge Rimar
740e2bfb1eSRui Ueyama // We allow sections of types listed below to merged into a
750e2bfb1eSRui Ueyama // single progbits section. This is typically done by linker
760e2bfb1eSRui Ueyama // scripts. Merging nobits and progbits will force disk space
770e2bfb1eSRui Ueyama // to be allocated for nobits sections. Other ones don't require
780e2bfb1eSRui Ueyama // any special treatment on top of progbits, so there doesn't
790e2bfb1eSRui Ueyama // seem to be a harm in merging them.
8088498f44SFangrui Song //
8188498f44SFangrui Song // NOTE: clang since rL252300 emits SHT_X86_64_UNWIND .eh_frame sections. Allow
8288498f44SFangrui Song // them to be merged into SHT_PROGBITS .eh_frame (GNU as .cfi_*).
canMergeToProgbits(unsigned type)833837f427SRui Ueyama static bool canMergeToProgbits(unsigned type) {
843837f427SRui Ueyama return type == SHT_NOBITS || type == SHT_PROGBITS || type == SHT_INIT_ARRAY ||
853837f427SRui Ueyama type == SHT_PREINIT_ARRAY || type == SHT_FINI_ARRAY ||
8688498f44SFangrui Song type == SHT_NOTE ||
8788498f44SFangrui Song (type == SHT_X86_64_UNWIND && config->emachine == EM_X86_64);
880e2bfb1eSRui Ueyama }
890e2bfb1eSRui Ueyama
90e47bbd28SFangrui Song // Record that isec will be placed in the OutputSection. isec does not become
91e47bbd28SFangrui Song // permanent until finalizeInputSections() is called. The function should not be
92e47bbd28SFangrui Song // used after finalizeInputSections() is called. If you need to add an
93e47bbd28SFangrui Song // InputSection post finalizeInputSections(), then you must do the following:
94e47bbd28SFangrui Song //
95e47bbd28SFangrui Song // 1. Find or create an InputSectionDescription to hold InputSection.
967ae3d335SKazuaki Ishizaki // 2. Add the InputSection to the InputSectionDescription::sections.
97e47bbd28SFangrui Song // 3. Call commitSection(isec).
recordSection(InputSectionBase * isec)98e47bbd28SFangrui Song void OutputSection::recordSection(InputSectionBase *isec) {
99e47bbd28SFangrui Song partition = isec->partition;
100e47bbd28SFangrui Song isec->parent = this;
1016188fd49SFangrui Song if (commands.empty() || !isa<InputSectionDescription>(commands.back()))
1026188fd49SFangrui Song commands.push_back(make<InputSectionDescription>(""));
1036188fd49SFangrui Song auto *isd = cast<InputSectionDescription>(commands.back());
104e47bbd28SFangrui Song isd->sectionBases.push_back(isec);
105e47bbd28SFangrui Song }
106e47bbd28SFangrui Song
107e47bbd28SFangrui Song // Update fields (type, flags, alignment, etc) according to the InputSection
108e47bbd28SFangrui Song // isec. Also check whether the InputSection flags and type are consistent with
109e47bbd28SFangrui Song // other InputSections.
commitSection(InputSection * isec)110e47bbd28SFangrui Song void OutputSection::commitSection(InputSection *isec) {
11166f8ac8dSFangrui Song if (LLVM_UNLIKELY(type != isec->type)) {
11266f8ac8dSFangrui Song if (hasInputSections || typeIsSet) {
11366f8ac8dSFangrui Song if (typeIsSet || !canMergeToProgbits(type) ||
11466f8ac8dSFangrui Song !canMergeToProgbits(isec->type)) {
115cb0a4bb5SFangrui Song // Changing the type of a (NOLOAD) section is fishy, but some projects
116cb0a4bb5SFangrui Song // (e.g. https://github.com/ClangBuiltLinux/linux/issues/1597)
117cb0a4bb5SFangrui Song // traditionally rely on the behavior. Issue a warning to not break
118cb0a4bb5SFangrui Song // them. Other types get an error.
119cb0a4bb5SFangrui Song auto diagnose = type == SHT_NOBITS ? warn : errorOrWarn;
120cb0a4bb5SFangrui Song diagnose("section type mismatch for " + isec->name + "\n>>> " +
12166f8ac8dSFangrui Song toString(isec) + ": " +
12266f8ac8dSFangrui Song getELFSectionTypeName(config->emachine, isec->type) +
12366f8ac8dSFangrui Song "\n>>> output section " + name + ": " +
12466f8ac8dSFangrui Song getELFSectionTypeName(config->emachine, type));
12566f8ac8dSFangrui Song }
126b3d5bb3bSFangrui Song if (!typeIsSet)
12766f8ac8dSFangrui Song type = SHT_PROGBITS;
12866f8ac8dSFangrui Song } else {
12966f8ac8dSFangrui Song type = isec->type;
13066f8ac8dSFangrui Song }
13166f8ac8dSFangrui Song }
1323837f427SRui Ueyama if (!hasInputSections) {
133c8e0f79bSRui Ueyama // If IS is the first section to be added to this section,
134e47bbd28SFangrui Song // initialize type, entsize and flags from isec.
1353837f427SRui Ueyama hasInputSections = true;
1363837f427SRui Ueyama entsize = isec->entsize;
1373837f427SRui Ueyama flags = isec->flags;
138c8e0f79bSRui Ueyama } else {
139c8e0f79bSRui Ueyama // Otherwise, check if new type or flags are compatible with existing ones.
140673e81eeSFangrui Song if ((flags ^ isec->flags) & SHF_TLS)
14166f8ac8dSFangrui Song error("incompatible section flags for " + name + "\n>>> " +
14266f8ac8dSFangrui Song toString(isec) + ": 0x" + utohexstr(isec->flags) +
14366f8ac8dSFangrui Song "\n>>> output section " + name + ": 0x" + utohexstr(flags));
1440e2bfb1eSRui Ueyama }
1450e2bfb1eSRui Ueyama
1463837f427SRui Ueyama isec->parent = this;
1473837f427SRui Ueyama uint64_t andMask =
1483837f427SRui Ueyama config->emachine == EM_ARM ? (uint64_t)SHF_ARM_PURECODE : 0;
1493837f427SRui Ueyama uint64_t orMask = ~andMask;
1503837f427SRui Ueyama uint64_t andFlags = (flags & isec->flags) & andMask;
1513837f427SRui Ueyama uint64_t orFlags = (flags | isec->flags) & orMask;
1523837f427SRui Ueyama flags = andFlags | orFlags;
153e47bbd28SFangrui Song if (nonAlloc)
154e47bbd28SFangrui Song flags &= ~(uint64_t)SHF_ALLOC;
1553bfa8f01SRafael Espindola
1563837f427SRui Ueyama alignment = std::max(alignment, isec->alignment);
157d86a4e50SGeorge Rimar
1582787664dSRui Ueyama // If this section contains a table of fixed-size entries, sh_entsize
1598bc2a19eSRafael Espindola // holds the element size. If it contains elements of different size we
1608bc2a19eSRafael Espindola // set sh_entsize to 0.
1613837f427SRui Ueyama if (entsize != isec->entsize)
1623837f427SRui Ueyama entsize = 0;
1638c022ca7SRafael Espindola }
164e47bbd28SFangrui Song
createMergeSynthetic(StringRef name,uint32_t type,uint64_t flags,uint32_t alignment)16593558e57SFangrui Song static MergeSyntheticSection *createMergeSynthetic(StringRef name,
16693558e57SFangrui Song uint32_t type,
16793558e57SFangrui Song uint64_t flags,
16893558e57SFangrui Song uint32_t alignment) {
16993558e57SFangrui Song if ((flags & SHF_STRINGS) && config->optimize >= 2)
17093558e57SFangrui Song return make<MergeTailSection>(name, type, flags, alignment);
17193558e57SFangrui Song return make<MergeNoTailSection>(name, type, flags, alignment);
17293558e57SFangrui Song }
17393558e57SFangrui Song
174e47bbd28SFangrui Song // This function scans over the InputSectionBase list sectionBases to create
175e47bbd28SFangrui Song // InputSectionDescription::sections.
176e47bbd28SFangrui Song //
177e47bbd28SFangrui Song // It removes MergeInputSections from the input section array and adds
178e47bbd28SFangrui Song // new synthetic sections at the location of the first input section
179e47bbd28SFangrui Song // that it replaces. It then finalizes each synthetic section in order
180e47bbd28SFangrui Song // to compute an output offset for each piece of each input section.
finalizeInputSections()181e47bbd28SFangrui Song void OutputSection::finalizeInputSections() {
182e47bbd28SFangrui Song std::vector<MergeSyntheticSection *> mergeSections;
1837051aeefSFangrui Song for (SectionCommand *cmd : commands) {
1847051aeefSFangrui Song auto *isd = dyn_cast<InputSectionDescription>(cmd);
1857051aeefSFangrui Song if (!isd)
186e47bbd28SFangrui Song continue;
1877051aeefSFangrui Song isd->sections.reserve(isd->sectionBases.size());
1887051aeefSFangrui Song for (InputSectionBase *s : isd->sectionBases) {
189e47bbd28SFangrui Song MergeInputSection *ms = dyn_cast<MergeInputSection>(s);
190e47bbd28SFangrui Song if (!ms) {
1917051aeefSFangrui Song isd->sections.push_back(cast<InputSection>(s));
192e47bbd28SFangrui Song continue;
193e47bbd28SFangrui Song }
194e47bbd28SFangrui Song
195e47bbd28SFangrui Song // We do not want to handle sections that are not alive, so just remove
196e47bbd28SFangrui Song // them instead of trying to merge.
197e47bbd28SFangrui Song if (!ms->isLive())
198e47bbd28SFangrui Song continue;
199e47bbd28SFangrui Song
200e47bbd28SFangrui Song auto i = llvm::find_if(mergeSections, [=](MergeSyntheticSection *sec) {
201e47bbd28SFangrui Song // While we could create a single synthetic section for two different
202e47bbd28SFangrui Song // values of Entsize, it is better to take Entsize into consideration.
203e47bbd28SFangrui Song //
204e47bbd28SFangrui Song // With a single synthetic section no two pieces with different Entsize
205e47bbd28SFangrui Song // could be equal, so we may as well have two sections.
206e47bbd28SFangrui Song //
207e47bbd28SFangrui Song // Using Entsize in here also allows us to propagate it to the synthetic
208e47bbd28SFangrui Song // section.
209e47bbd28SFangrui Song //
210e47bbd28SFangrui Song // SHF_STRINGS section with different alignments should not be merged.
211e47bbd28SFangrui Song return sec->flags == ms->flags && sec->entsize == ms->entsize &&
212e47bbd28SFangrui Song (sec->alignment == ms->alignment || !(sec->flags & SHF_STRINGS));
213e47bbd28SFangrui Song });
214e47bbd28SFangrui Song if (i == mergeSections.end()) {
215e47bbd28SFangrui Song MergeSyntheticSection *syn =
216e47bbd28SFangrui Song createMergeSynthetic(name, ms->type, ms->flags, ms->alignment);
217e47bbd28SFangrui Song mergeSections.push_back(syn);
218e47bbd28SFangrui Song i = std::prev(mergeSections.end());
219e47bbd28SFangrui Song syn->entsize = ms->entsize;
2207051aeefSFangrui Song isd->sections.push_back(syn);
221e47bbd28SFangrui Song }
222e47bbd28SFangrui Song (*i)->addSection(ms);
223e47bbd28SFangrui Song }
224e47bbd28SFangrui Song
225e47bbd28SFangrui Song // sectionBases should not be used from this point onwards. Clear it to
226e47bbd28SFangrui Song // catch misuses.
2277051aeefSFangrui Song isd->sectionBases.clear();
228e47bbd28SFangrui Song
229e47bbd28SFangrui Song // Some input sections may be removed from the list after ICF.
2307051aeefSFangrui Song for (InputSection *s : isd->sections)
231e47bbd28SFangrui Song commitSection(s);
232e47bbd28SFangrui Song }
233e47bbd28SFangrui Song for (auto *ms : mergeSections)
234e47bbd28SFangrui Song ms->finalizeContents();
2355805c4f5SRafael Espindola }
2365805c4f5SRafael Espindola
sortByOrder(MutableArrayRef<InputSection * > in,llvm::function_ref<int (InputSectionBase * s)> order)2373837f427SRui Ueyama static void sortByOrder(MutableArrayRef<InputSection *> in,
2383837f427SRui Ueyama llvm::function_ref<int(InputSectionBase *s)> order) {
2393837f427SRui Ueyama std::vector<std::pair<int, InputSection *>> v;
2403837f427SRui Ueyama for (InputSection *s : in)
2413837f427SRui Ueyama v.push_back({order(s), s});
2423837f427SRui Ueyama llvm::stable_sort(v, less_first());
243d6bcde38SGeorge Rimar
2443837f427SRui Ueyama for (size_t i = 0; i < v.size(); ++i)
2453837f427SRui Ueyama in[i] = v[i].second;
246d6bcde38SGeorge Rimar }
247d6bcde38SGeorge Rimar
getHeaderSize()24807837b8fSFangrui Song uint64_t elf::getHeaderSize() {
2493837f427SRui Ueyama if (config->oFormatBinary)
25078aa2700SGeorge Rimar return 0;
2513837f427SRui Ueyama return Out::elfHeader->size + Out::programHeaders->size;
25278aa2700SGeorge Rimar }
25378aa2700SGeorge Rimar
sort(llvm::function_ref<int (InputSectionBase * s)> order)2543837f427SRui Ueyama void OutputSection::sort(llvm::function_ref<int(InputSectionBase *s)> order) {
255ba2816beSPeter Collingbourne assert(isLive());
2567051aeefSFangrui Song for (SectionCommand *b : commands)
2573837f427SRui Ueyama if (auto *isd = dyn_cast<InputSectionDescription>(b))
2583837f427SRui Ueyama sortByOrder(isd->sections, order);
2598c022ca7SRafael Espindola }
2608c022ca7SRafael Espindola
nopInstrFill(uint8_t * buf,size_t size)26194317878SSriraman Tallam static void nopInstrFill(uint8_t *buf, size_t size) {
26294317878SSriraman Tallam if (size == 0)
26394317878SSriraman Tallam return;
26494317878SSriraman Tallam unsigned i = 0;
26594317878SSriraman Tallam if (size == 0)
26694317878SSriraman Tallam return;
26794317878SSriraman Tallam std::vector<std::vector<uint8_t>> nopFiller = *target->nopInstrs;
26894317878SSriraman Tallam unsigned num = size / nopFiller.back().size();
26994317878SSriraman Tallam for (unsigned c = 0; c < num; ++c) {
27094317878SSriraman Tallam memcpy(buf + i, nopFiller.back().data(), nopFiller.back().size());
27194317878SSriraman Tallam i += nopFiller.back().size();
27294317878SSriraman Tallam }
27394317878SSriraman Tallam unsigned remaining = size - i;
27494317878SSriraman Tallam if (!remaining)
27594317878SSriraman Tallam return;
27694317878SSriraman Tallam assert(nopFiller[remaining - 1].size() == remaining);
27794317878SSriraman Tallam memcpy(buf + i, nopFiller[remaining - 1].data(), remaining);
27894317878SSriraman Tallam }
27994317878SSriraman Tallam
2808c022ca7SRafael Espindola // Fill [Buf, Buf + Size) with Filler.
2818c022ca7SRafael Espindola // This is used for linker script "=fillexp" command.
fill(uint8_t * buf,size_t size,const std::array<uint8_t,4> & filler)2823837f427SRui Ueyama static void fill(uint8_t *buf, size_t size,
2833837f427SRui Ueyama const std::array<uint8_t, 4> &filler) {
2843837f427SRui Ueyama size_t i = 0;
2853837f427SRui Ueyama for (; i + 4 < size; i += 4)
2863837f427SRui Ueyama memcpy(buf + i, filler.data(), 4);
2873837f427SRui Ueyama memcpy(buf + i, filler.data(), size - i);
2888c022ca7SRafael Espindola }
2898c022ca7SRafael Espindola
2904cdc4416SFangrui Song #if LLVM_ENABLE_ZLIB
deflateShard(ArrayRef<uint8_t> in,int level,int flush)2914cdc4416SFangrui Song static SmallVector<uint8_t, 0> deflateShard(ArrayRef<uint8_t> in, int level,
2924cdc4416SFangrui Song int flush) {
2934cdc4416SFangrui Song // 15 and 8 are default. windowBits=-15 is negative to generate raw deflate
2944cdc4416SFangrui Song // data with no zlib header or trailer.
2954cdc4416SFangrui Song z_stream s = {};
2964cdc4416SFangrui Song deflateInit2(&s, level, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
2974cdc4416SFangrui Song s.next_in = const_cast<uint8_t *>(in.data());
2984cdc4416SFangrui Song s.avail_in = in.size();
2994cdc4416SFangrui Song
3004cdc4416SFangrui Song // Allocate a buffer of half of the input size, and grow it by 1.5x if
3014cdc4416SFangrui Song // insufficient.
3024cdc4416SFangrui Song SmallVector<uint8_t, 0> out;
3034cdc4416SFangrui Song size_t pos = 0;
3044cdc4416SFangrui Song out.resize_for_overwrite(std::max<size_t>(in.size() / 2, 64));
3054cdc4416SFangrui Song do {
3064cdc4416SFangrui Song if (pos == out.size())
3074cdc4416SFangrui Song out.resize_for_overwrite(out.size() * 3 / 2);
3084cdc4416SFangrui Song s.next_out = out.data() + pos;
3094cdc4416SFangrui Song s.avail_out = out.size() - pos;
3104cdc4416SFangrui Song (void)deflate(&s, flush);
3114cdc4416SFangrui Song pos = s.next_out - out.data();
3124cdc4416SFangrui Song } while (s.avail_out == 0);
3134cdc4416SFangrui Song assert(s.avail_in == 0);
3144cdc4416SFangrui Song
3154cdc4416SFangrui Song out.truncate(pos);
3164cdc4416SFangrui Song deflateEnd(&s);
3174cdc4416SFangrui Song return out;
3184cdc4416SFangrui Song }
3194cdc4416SFangrui Song #endif
3204cdc4416SFangrui Song
3218c022ca7SRafael Espindola // Compress section contents if this section contains debug info.
maybeCompress()3228c022ca7SRafael Espindola template <class ELFT> void OutputSection::maybeCompress() {
3234cdc4416SFangrui Song #if LLVM_ENABLE_ZLIB
32468b9f45fSRui Ueyama using Elf_Chdr = typename ELFT::Chdr;
3258c022ca7SRafael Espindola
3268c022ca7SRafael Espindola // Compress only DWARF debug sections.
3273837f427SRui Ueyama if (!config->compressDebugSections || (flags & SHF_ALLOC) ||
3284cdc4416SFangrui Song !name.startswith(".debug_") || size == 0)
3298c022ca7SRafael Espindola return;
3308c022ca7SRafael Espindola
331439341b9SJames Henderson llvm::TimeTraceScope timeScope("Compress debug sections");
332439341b9SJames Henderson
333223f9deaSFangrui Song // Write uncompressed data to a temporary zero-initialized buffer.
334223f9deaSFangrui Song auto buf = std::make_unique<uint8_t[]>(size);
335223f9deaSFangrui Song writeTo<ELFT>(buf.get());
3362a80c3dbSFangrui Song // We chose 1 (Z_BEST_SPEED) as the default compression level because it is
3372a80c3dbSFangrui Song // the fastest. If -O2 is given, we use level 6 to compress debug info more by
3382a80c3dbSFangrui Song // ~15%. We found that level 7 to 9 doesn't make much difference (~1% more
3392a80c3dbSFangrui Song // compression) while they take significant amount of time (~2x), so level 6
3402a80c3dbSFangrui Song // seems enough.
3414cdc4416SFangrui Song const int level = config->optimize >= 2 ? 6 : Z_BEST_SPEED;
3428c022ca7SRafael Espindola
3434cdc4416SFangrui Song // Split input into 1-MiB shards.
3444cdc4416SFangrui Song constexpr size_t shardSize = 1 << 20;
345fcd8817dSFangrui Song auto shardsIn = split(makeArrayRef<uint8_t>(buf.get(), size), shardSize);
346fcd8817dSFangrui Song const size_t numShards = shardsIn.size();
3474cdc4416SFangrui Song
3484cdc4416SFangrui Song // Compress shards and compute Alder-32 checksums. Use Z_SYNC_FLUSH for all
3494cdc4416SFangrui Song // shards but the last to flush the output to a byte boundary to be
3504cdc4416SFangrui Song // concatenated with the next shard.
3514cdc4416SFangrui Song auto shardsOut = std::make_unique<SmallVector<uint8_t, 0>[]>(numShards);
3524cdc4416SFangrui Song auto shardsAdler = std::make_unique<uint32_t[]>(numShards);
3537effcbdaSNico Weber parallelFor(0, numShards, [&](size_t i) {
3544cdc4416SFangrui Song shardsOut[i] = deflateShard(shardsIn[i], level,
3554cdc4416SFangrui Song i != numShards - 1 ? Z_SYNC_FLUSH : Z_FINISH);
3564cdc4416SFangrui Song shardsAdler[i] = adler32(1, shardsIn[i].data(), shardsIn[i].size());
3574cdc4416SFangrui Song });
3584cdc4416SFangrui Song
3594cdc4416SFangrui Song // Update section size and combine Alder-32 checksums.
3604cdc4416SFangrui Song uint32_t checksum = 1; // Initial Adler-32 value
361913914f0SFangrui Song compressed.uncompressedSize = size;
3624cdc4416SFangrui Song size = sizeof(Elf_Chdr) + 2; // Elf_Chdir and zlib header
3634cdc4416SFangrui Song for (size_t i = 0; i != numShards; ++i) {
3644cdc4416SFangrui Song size += shardsOut[i].size();
3654cdc4416SFangrui Song checksum = adler32_combine(checksum, shardsAdler[i], shardsIn[i].size());
3664cdc4416SFangrui Song }
3674cdc4416SFangrui Song size += 4; // checksum
3684cdc4416SFangrui Song
3694cdc4416SFangrui Song compressed.shards = std::move(shardsOut);
3704cdc4416SFangrui Song compressed.numShards = numShards;
3714cdc4416SFangrui Song compressed.checksum = checksum;
3723837f427SRui Ueyama flags |= SHF_COMPRESSED;
3734cdc4416SFangrui Song #endif
3748c022ca7SRafael Espindola }
3758c022ca7SRafael Espindola
writeInt(uint8_t * buf,uint64_t data,uint64_t size)3763837f427SRui Ueyama static void writeInt(uint8_t *buf, uint64_t data, uint64_t size) {
3773837f427SRui Ueyama if (size == 1)
3783837f427SRui Ueyama *buf = data;
3793837f427SRui Ueyama else if (size == 2)
3803837f427SRui Ueyama write16(buf, data);
3813837f427SRui Ueyama else if (size == 4)
3823837f427SRui Ueyama write32(buf, data);
3833837f427SRui Ueyama else if (size == 8)
3843837f427SRui Ueyama write64(buf, data);
3858c022ca7SRafael Espindola else
3868c022ca7SRafael Espindola llvm_unreachable("unsupported Size argument");
3878c022ca7SRafael Espindola }
3888c022ca7SRafael Espindola
writeTo(uint8_t * buf)3893837f427SRui Ueyama template <class ELFT> void OutputSection::writeTo(uint8_t *buf) {
3908825ffdbSFangrui Song llvm::TimeTraceScope timeScope("Write sections", name);
3913837f427SRui Ueyama if (type == SHT_NOBITS)
3928c022ca7SRafael Espindola return;
3938c022ca7SRafael Espindola
394bf6e259bSFangrui Song // If --compress-debug-section is specified and if this is a debug section,
3958c022ca7SRafael Espindola // we've already compressed section contents. If that's the case,
3968c022ca7SRafael Espindola // just write it down.
3974cdc4416SFangrui Song if (compressed.shards) {
398913914f0SFangrui Song auto *chdr = reinterpret_cast<typename ELFT::Chdr *>(buf);
399913914f0SFangrui Song chdr->ch_type = ELFCOMPRESS_ZLIB;
400913914f0SFangrui Song chdr->ch_size = compressed.uncompressedSize;
401913914f0SFangrui Song chdr->ch_addralign = alignment;
402913914f0SFangrui Song buf += sizeof(*chdr);
4034cdc4416SFangrui Song
4044cdc4416SFangrui Song // Compute shard offsets.
4054cdc4416SFangrui Song auto offsets = std::make_unique<size_t[]>(compressed.numShards);
4064cdc4416SFangrui Song offsets[0] = 2; // zlib header
4074cdc4416SFangrui Song for (size_t i = 1; i != compressed.numShards; ++i)
4084cdc4416SFangrui Song offsets[i] = offsets[i - 1] + compressed.shards[i - 1].size();
4094cdc4416SFangrui Song
4104cdc4416SFangrui Song buf[0] = 0x78; // CMF
4114cdc4416SFangrui Song buf[1] = 0x01; // FLG: best speed
4127effcbdaSNico Weber parallelFor(0, compressed.numShards, [&](size_t i) {
4134cdc4416SFangrui Song memcpy(buf + offsets[i], compressed.shards[i].data(),
4144cdc4416SFangrui Song compressed.shards[i].size());
4154cdc4416SFangrui Song });
4164cdc4416SFangrui Song
417913914f0SFangrui Song write32be(buf + (size - sizeof(*chdr) - 4), compressed.checksum);
4188c022ca7SRafael Espindola return;
4198c022ca7SRafael Espindola }
4208c022ca7SRafael Espindola
4218c022ca7SRafael Espindola // Write leading padding.
422*e0612c91SFangrui Song SmallVector<InputSection *, 0> storage;
423*e0612c91SFangrui Song ArrayRef<InputSection *> sections = getInputSections(*this, storage);
4243837f427SRui Ueyama std::array<uint8_t, 4> filler = getFiller();
4253837f427SRui Ueyama bool nonZeroFiller = read32(filler.data()) != 0;
4263837f427SRui Ueyama if (nonZeroFiller)
4273837f427SRui Ueyama fill(buf, sections.empty() ? size : sections[0]->outSecOff, filler);
4288c022ca7SRafael Espindola
4297effcbdaSNico Weber parallelFor(0, sections.size(), [&](size_t i) {
4303837f427SRui Ueyama InputSection *isec = sections[i];
4314976d1feSFangrui Song if (auto *s = dyn_cast<SyntheticSection>(isec))
4324976d1feSFangrui Song s->writeTo(buf + isec->outSecOff);
4334976d1feSFangrui Song else
434bf7f3dd7SFangrui Song isec->writeTo<ELFT>(buf + isec->outSecOff);
4358c022ca7SRafael Espindola
4368c022ca7SRafael Espindola // Fill gaps between sections.
4373837f427SRui Ueyama if (nonZeroFiller) {
4383837f427SRui Ueyama uint8_t *start = buf + isec->outSecOff + isec->getSize();
4393837f427SRui Ueyama uint8_t *end;
4403837f427SRui Ueyama if (i + 1 == sections.size())
4413837f427SRui Ueyama end = buf + size;
4428c022ca7SRafael Espindola else
4433837f427SRui Ueyama end = buf + sections[i + 1]->outSecOff;
44494317878SSriraman Tallam if (isec->nopFiller) {
44594317878SSriraman Tallam assert(target->nopInstrs);
44694317878SSriraman Tallam nopInstrFill(start, end - start);
44794317878SSriraman Tallam } else
4483837f427SRui Ueyama fill(start, end - start, filler);
4498c022ca7SRafael Espindola }
4508c022ca7SRafael Espindola });
4518c022ca7SRafael Espindola
4528c022ca7SRafael Espindola // Linker scripts may have BYTE()-family commands with which you
4538c022ca7SRafael Espindola // can write arbitrary bytes to the output. Process them if any.
4547051aeefSFangrui Song for (SectionCommand *cmd : commands)
4557051aeefSFangrui Song if (auto *data = dyn_cast<ByteCommand>(cmd))
4563837f427SRui Ueyama writeInt(buf + data->offset, data->expression().getValue(), data->size);
4578c022ca7SRafael Espindola }
4588c022ca7SRafael Espindola
finalizeShtGroup(OutputSection * os,InputSection * section)45966f8ac8dSFangrui Song static void finalizeShtGroup(OutputSection *os, InputSection *section) {
4608c022ca7SRafael Espindola // sh_link field for SHT_GROUP sections should contain the section index of
4618c022ca7SRafael Espindola // the symbol table.
4623837f427SRui Ueyama os->link = in.symTab->getParent()->sectionIndex;
4638c022ca7SRafael Espindola
46466f8ac8dSFangrui Song if (!section)
46566f8ac8dSFangrui Song return;
46666f8ac8dSFangrui Song
4678c022ca7SRafael Espindola // sh_info then contain index of an entry in symbol table section which
4688c022ca7SRafael Espindola // provides signature of the section group.
4693837f427SRui Ueyama ArrayRef<Symbol *> symbols = section->file->getSymbols();
4703837f427SRui Ueyama os->info = in.symTab->getSymbolIndex(symbols[section->info]);
47186ab98b0SFangrui Song
47286ab98b0SFangrui Song // Some group members may be combined or discarded, so we need to compute the
47386ab98b0SFangrui Song // new size. The content will be rewritten in InputSection::copyShtGroup.
4745a2020d0SFangrui Song DenseSet<uint32_t> seen;
47586ab98b0SFangrui Song ArrayRef<InputSectionBase *> sections = section->file->getSections();
47686ab98b0SFangrui Song for (const uint32_t &idx : section->getDataAs<uint32_t>().slice(1))
47786ab98b0SFangrui Song if (OutputSection *osec = sections[read32(&idx)]->getOutputSection())
47886ab98b0SFangrui Song seen.insert(osec->sectionIndex);
47986ab98b0SFangrui Song os->size = (1 + seen.size()) * sizeof(uint32_t);
4808c022ca7SRafael Espindola }
4818c022ca7SRafael Espindola
finalize()4825ee9abd4SPeter Collingbourne void OutputSection::finalize() {
4834e8116f4SAndrew Ng InputSection *first = getFirstInputSection(this);
4848c022ca7SRafael Espindola
4853837f427SRui Ueyama if (flags & SHF_LINK_ORDER) {
4868c022ca7SRafael Espindola // We must preserve the link order dependency of sections with the
4878c022ca7SRafael Espindola // SHF_LINK_ORDER flag. The dependency is indicated by the sh_link field. We
4888c022ca7SRafael Espindola // need to translate the InputSection sh_link to the OutputSection sh_link,
4898c022ca7SRafael Espindola // all InputSections in the OutputSection have the same dependency.
4903837f427SRui Ueyama if (auto *ex = dyn_cast<ARMExidxSyntheticSection>(first))
4913837f427SRui Ueyama link = ex->getLinkOrderDep()->getParent()->sectionIndex;
492673e81eeSFangrui Song else if (first->flags & SHF_LINK_ORDER)
493673e81eeSFangrui Song if (auto *d = first->getLinkOrderDep())
4943837f427SRui Ueyama link = d->getParent()->sectionIndex;
4958c022ca7SRafael Espindola }
4968c022ca7SRafael Espindola
4973837f427SRui Ueyama if (type == SHT_GROUP) {
4983837f427SRui Ueyama finalizeShtGroup(this, first);
4998c022ca7SRafael Espindola return;
5008c022ca7SRafael Espindola }
5018c022ca7SRafael Espindola
5023837f427SRui Ueyama if (!config->copyRelocs || (type != SHT_RELA && type != SHT_REL))
5038c022ca7SRafael Espindola return;
5048c022ca7SRafael Espindola
50516cb7910SFangrui Song // Skip if 'first' is synthetic, i.e. not a section created by --emit-relocs.
50616cb7910SFangrui Song // Normally 'type' was changed by 'first' so 'first' should be non-null.
50716cb7910SFangrui Song // However, if the output section is .rela.dyn, 'type' can be set by the empty
50816cb7910SFangrui Song // synthetic .rela.plt and first can be null.
50916cb7910SFangrui Song if (!first || isa<SyntheticSection>(first))
5108c022ca7SRafael Espindola return;
5118c022ca7SRafael Espindola
5123837f427SRui Ueyama link = in.symTab->getParent()->sectionIndex;
5138c022ca7SRafael Espindola // sh_info for SHT_REL[A] sections should contain the section header index of
5148c022ca7SRafael Espindola // the section to which the relocation applies.
5153837f427SRui Ueyama InputSectionBase *s = first->getRelocatedSection();
5163837f427SRui Ueyama info = s->getOutputSection()->sectionIndex;
5173837f427SRui Ueyama flags |= SHF_INFO_LINK;
5188c022ca7SRafael Espindola }
5198c022ca7SRafael Espindola
520118ceea5SSterling Augustine // Returns true if S is in one of the many forms the compiler driver may pass
521118ceea5SSterling Augustine // crtbegin files.
522118ceea5SSterling Augustine //
523118ceea5SSterling Augustine // Gcc uses any of crtbegin[<empty>|S|T].o.
524f318fd9bSFangrui Song // Clang uses Gcc's plus clang_rt.crtbegin[-<arch>|<empty>].o.
525118ceea5SSterling Augustine
isCrt(StringRef s,StringRef beginEnd)526f318fd9bSFangrui Song static bool isCrt(StringRef s, StringRef beginEnd) {
527118ceea5SSterling Augustine s = sys::path::filename(s);
528f318fd9bSFangrui Song if (!s.consume_back(".o"))
529f318fd9bSFangrui Song return false;
530f318fd9bSFangrui Song if (s.consume_front("clang_rt."))
531f318fd9bSFangrui Song return s.consume_front(beginEnd);
532f318fd9bSFangrui Song return s.consume_front(beginEnd) && s.size() <= 1;
533118ceea5SSterling Augustine }
5348c022ca7SRafael Espindola
53540a42f9fSFangrui Song // .ctors and .dtors are sorted by this order:
5368c022ca7SRafael Espindola //
53740a42f9fSFangrui Song // 1. .ctors/.dtors in crtbegin (which contains a sentinel value -1).
53840a42f9fSFangrui Song // 2. The section is named ".ctors" or ".dtors" (priority: 65536).
53940a42f9fSFangrui Song // 3. The section has an optional priority value in the form of ".ctors.N" or
54040a42f9fSFangrui Song // ".dtors.N" where N is a number in the form of %05u (priority: 65535-N).
54140a42f9fSFangrui Song // 4. .ctors/.dtors in crtend (which contains a sentinel value 0).
5428c022ca7SRafael Espindola //
54340a42f9fSFangrui Song // For 2 and 3, the sections are sorted by priority from high to low, e.g.
54440a42f9fSFangrui Song // .ctors (65536), .ctors.00100 (65436), .ctors.00200 (65336). In GNU ld's
54540a42f9fSFangrui Song // internal linker scripts, the sorting is by string comparison which can
54640a42f9fSFangrui Song // achieve the same goal given the optional priority values are of the same
54740a42f9fSFangrui Song // length.
5488c022ca7SRafael Espindola //
5498c022ca7SRafael Espindola // In an ideal world, we don't need this function because .init_array and
5508c022ca7SRafael Espindola // .ctors are duplicate features (and .init_array is newer.) However, there
5518c022ca7SRafael Espindola // are too many real-world use cases of .ctors, so we had no choice to
5528c022ca7SRafael Espindola // support that with this rather ad-hoc semantics.
compCtors(const InputSection * a,const InputSection * b)5533837f427SRui Ueyama static bool compCtors(const InputSection *a, const InputSection *b) {
554f318fd9bSFangrui Song bool beginA = isCrt(a->file->getName(), "crtbegin");
555f318fd9bSFangrui Song bool beginB = isCrt(b->file->getName(), "crtbegin");
5563837f427SRui Ueyama if (beginA != beginB)
5573837f427SRui Ueyama return beginA;
558f318fd9bSFangrui Song bool endA = isCrt(a->file->getName(), "crtend");
559f318fd9bSFangrui Song bool endB = isCrt(b->file->getName(), "crtend");
5603837f427SRui Ueyama if (endA != endB)
5613837f427SRui Ueyama return endB;
56240a42f9fSFangrui Song return getPriority(a->name) > getPriority(b->name);
5638c022ca7SRafael Espindola }
5648c022ca7SRafael Espindola
5658c022ca7SRafael Espindola // Sorts input sections by the special rules for .ctors and .dtors.
5668c022ca7SRafael Espindola // Unfortunately, the rules are different from the one for .{init,fini}_array.
5678c022ca7SRafael Espindola // Read the comment above.
sortCtorsDtors()5688c022ca7SRafael Espindola void OutputSection::sortCtorsDtors() {
5696188fd49SFangrui Song assert(commands.size() == 1);
5706188fd49SFangrui Song auto *isd = cast<InputSectionDescription>(commands[0]);
5713837f427SRui Ueyama llvm::stable_sort(isd->sections, compCtors);
5728c022ca7SRafael Espindola }
5738c022ca7SRafael Espindola
57440a42f9fSFangrui Song // If an input string is in the form of "foo.N" where N is a number, return N
57540a42f9fSFangrui Song // (65535-N if .ctors.N or .dtors.N). Otherwise, returns 65536, which is one
57640a42f9fSFangrui Song // greater than the lowest priority.
getPriority(StringRef s)57707837b8fSFangrui Song int elf::getPriority(StringRef s) {
5783837f427SRui Ueyama size_t pos = s.rfind('.');
5793837f427SRui Ueyama if (pos == StringRef::npos)
5808c022ca7SRafael Espindola return 65536;
58140a42f9fSFangrui Song int v = 65536;
58240a42f9fSFangrui Song if (to_integer(s.substr(pos + 1), v, 10) &&
58340a42f9fSFangrui Song (pos == 6 && (s.startswith(".ctors") || s.startswith(".dtors"))))
58440a42f9fSFangrui Song v = 65535 - v;
5853837f427SRui Ueyama return v;
5868c022ca7SRafael Espindola }
5878c022ca7SRafael Espindola
getFirstInputSection(const OutputSection * os)58807837b8fSFangrui Song InputSection *elf::getFirstInputSection(const OutputSection *os) {
5897051aeefSFangrui Song for (SectionCommand *cmd : os->commands)
5907051aeefSFangrui Song if (auto *isd = dyn_cast<InputSectionDescription>(cmd))
5914e8116f4SAndrew Ng if (!isd->sections.empty())
5924e8116f4SAndrew Ng return isd->sections[0];
5934e8116f4SAndrew Ng return nullptr;
5944e8116f4SAndrew Ng }
5954e8116f4SAndrew Ng
596*e0612c91SFangrui Song ArrayRef<InputSection *>
getInputSections(const OutputSection & os,SmallVector<InputSection *,0> & storage)597*e0612c91SFangrui Song elf::getInputSections(const OutputSection &os,
598*e0612c91SFangrui Song SmallVector<InputSection *, 0> &storage) {
599*e0612c91SFangrui Song ArrayRef<InputSection *> ret;
600*e0612c91SFangrui Song storage.clear();
601*e0612c91SFangrui Song for (SectionCommand *cmd : os.commands) {
602*e0612c91SFangrui Song auto *isd = dyn_cast<InputSectionDescription>(cmd);
603*e0612c91SFangrui Song if (!isd)
604*e0612c91SFangrui Song continue;
605*e0612c91SFangrui Song if (ret.empty()) {
606*e0612c91SFangrui Song ret = isd->sections;
607*e0612c91SFangrui Song } else {
608*e0612c91SFangrui Song if (storage.empty())
609*e0612c91SFangrui Song storage.assign(ret.begin(), ret.end());
610*e0612c91SFangrui Song storage.insert(storage.end(), isd->sections.begin(), isd->sections.end());
611*e0612c91SFangrui Song }
612*e0612c91SFangrui Song }
613*e0612c91SFangrui Song return storage.empty() ? ret : makeArrayRef(storage);
614563e4f2fSGeorge Rimar }
615563e4f2fSGeorge Rimar
6168c022ca7SRafael Espindola // Sorts input sections by section name suffixes, so that .foo.N comes
6178c022ca7SRafael Espindola // before .foo.M if N < M. Used to sort .{init,fini}_array.N sections.
6188c022ca7SRafael Espindola // We want to keep the original order if the priorities are the same
6198c022ca7SRafael Espindola // because the compiler keeps the original initialization order in a
6208c022ca7SRafael Espindola // translation unit and we need to respect that.
6218c022ca7SRafael Espindola // For more detail, read the section of the GCC's manual about init_priority.
sortInitFini()6228c022ca7SRafael Espindola void OutputSection::sortInitFini() {
6238c022ca7SRafael Espindola // Sort sections by priority.
6243837f427SRui Ueyama sort([](InputSectionBase *s) { return getPriority(s->name); });
6258c022ca7SRafael Espindola }
6268c022ca7SRafael Espindola
getFiller()627b0486051SSimon Atanasyan std::array<uint8_t, 4> OutputSection::getFiller() {
6283837f427SRui Ueyama if (filler)
6293837f427SRui Ueyama return *filler;
6303837f427SRui Ueyama if (flags & SHF_EXECINSTR)
6313837f427SRui Ueyama return target->trapInstr;
632b0486051SSimon Atanasyan return {0, 0, 0, 0};
6338c022ca7SRafael Espindola }
6348c022ca7SRafael Espindola
checkDynRelAddends(const uint8_t * bufStart)63535c5e564SAlex Richardson void OutputSection::checkDynRelAddends(const uint8_t *bufStart) {
63635c5e564SAlex Richardson assert(config->writeAddends && config->checkDynamicRelocs);
63735c5e564SAlex Richardson assert(type == SHT_REL || type == SHT_RELA);
638*e0612c91SFangrui Song SmallVector<InputSection *, 0> storage;
639*e0612c91SFangrui Song ArrayRef<InputSection *> sections = getInputSections(*this, storage);
6407effcbdaSNico Weber parallelFor(0, sections.size(), [&](size_t i) {
64135c5e564SAlex Richardson // When linking with -r or --emit-relocs we might also call this function
64235c5e564SAlex Richardson // for input .rel[a].<sec> sections which we simply pass through to the
64335c5e564SAlex Richardson // output. We skip over those and only look at the synthetic relocation
64435c5e564SAlex Richardson // sections created during linking.
64535c5e564SAlex Richardson const auto *sec = dyn_cast<RelocationBaseSection>(sections[i]);
64635c5e564SAlex Richardson if (!sec)
64735c5e564SAlex Richardson return;
64835c5e564SAlex Richardson for (const DynamicReloc &rel : sec->relocs) {
6496683099aSFangrui Song int64_t addend = rel.addend;
65035c5e564SAlex Richardson const OutputSection *relOsec = rel.inputSec->getOutputSection();
65135c5e564SAlex Richardson assert(relOsec != nullptr && "missing output section for relocation");
65235c5e564SAlex Richardson const uint8_t *relocTarget =
65335c5e564SAlex Richardson bufStart + relOsec->offset + rel.inputSec->getOffset(rel.offsetInSec);
65435c5e564SAlex Richardson // For SHT_NOBITS the written addend is always zero.
65535c5e564SAlex Richardson int64_t writtenAddend =
65635c5e564SAlex Richardson relOsec->type == SHT_NOBITS
65735c5e564SAlex Richardson ? 0
65835c5e564SAlex Richardson : target->getImplicitAddend(relocTarget, rel.type);
65935c5e564SAlex Richardson if (addend != writtenAddend)
66035c5e564SAlex Richardson internalLinkerError(
66135c5e564SAlex Richardson getErrorLocation(relocTarget),
66235c5e564SAlex Richardson "wrote incorrect addend value 0x" + utohexstr(writtenAddend) +
66335c5e564SAlex Richardson " instead of 0x" + utohexstr(addend) +
66435c5e564SAlex Richardson " for dynamic relocation " + toString(rel.type) +
66535c5e564SAlex Richardson " at offset 0x" + utohexstr(rel.getOffset()) +
66635c5e564SAlex Richardson (rel.sym ? " against symbol " + toString(*rel.sym) : ""));
66735c5e564SAlex Richardson }
66835c5e564SAlex Richardson });
66935c5e564SAlex Richardson }
67035c5e564SAlex Richardson
67124e6f363SRafael Espindola template void OutputSection::writeHeaderTo<ELF32LE>(ELF32LE::Shdr *Shdr);
67224e6f363SRafael Espindola template void OutputSection::writeHeaderTo<ELF32BE>(ELF32BE::Shdr *Shdr);
67324e6f363SRafael Espindola template void OutputSection::writeHeaderTo<ELF64LE>(ELF64LE::Shdr *Shdr);
67424e6f363SRafael Espindola template void OutputSection::writeHeaderTo<ELF64BE>(ELF64BE::Shdr *Shdr);
6758c022ca7SRafael Espindola
6768c022ca7SRafael Espindola template void OutputSection::writeTo<ELF32LE>(uint8_t *Buf);
6778c022ca7SRafael Espindola template void OutputSection::writeTo<ELF32BE>(uint8_t *Buf);
6788c022ca7SRafael Espindola template void OutputSection::writeTo<ELF64LE>(uint8_t *Buf);
6798c022ca7SRafael Espindola template void OutputSection::writeTo<ELF64BE>(uint8_t *Buf);
6808c022ca7SRafael Espindola
6818c022ca7SRafael Espindola template void OutputSection::maybeCompress<ELF32LE>();
6828c022ca7SRafael Espindola template void OutputSection::maybeCompress<ELF32BE>();
6838c022ca7SRafael Espindola template void OutputSection::maybeCompress<ELF64LE>();
6848c022ca7SRafael Espindola template void OutputSection::maybeCompress<ELF64BE>();
685