diff options
Diffstat (limited to 'ELF/OutputSections.cpp')
| -rw-r--r-- | ELF/OutputSections.cpp | 114 | 
1 files changed, 97 insertions, 17 deletions
diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index a89bd509bc96d..ea7c96eb676a3 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -27,9 +27,8 @@ using namespace llvm::object;  using namespace llvm::support::endian;  using namespace llvm::ELF; -using namespace lld; -using namespace lld::elf; - +namespace lld { +namespace elf {  uint8_t *Out::bufferStart;  uint8_t Out::first;  PhdrEntry *Out::tlsPhdr; @@ -39,7 +38,7 @@ OutputSection *Out::preinitArray;  OutputSection *Out::initArray;  OutputSection *Out::finiArray; -std::vector<OutputSection *> elf::outputSections; +std::vector<OutputSection *> outputSections;  uint32_t OutputSection::getPhdrFlags() const {    uint32_t ret = 0; @@ -83,12 +82,32 @@ static bool canMergeToProgbits(unsigned type) {           type == SHT_NOTE;  } -void OutputSection::addSection(InputSection *isec) { +// Record that isec will be placed in the OutputSection. isec does not become +// permanent until finalizeInputSections() is called. The function should not be +// used after finalizeInputSections() is called. If you need to add an +// InputSection post finalizeInputSections(), then you must do the following: +// +// 1. Find or create an InputSectionDescription to hold InputSection. +// 2. Add the InputSection to the InputSectionDesciption::sections. +// 3. Call commitSection(isec). +void OutputSection::recordSection(InputSectionBase *isec) { +  partition = isec->partition; +  isec->parent = this; +  if (sectionCommands.empty() || +      !isa<InputSectionDescription>(sectionCommands.back())) +    sectionCommands.push_back(make<InputSectionDescription>("")); +  auto *isd = cast<InputSectionDescription>(sectionCommands.back()); +  isd->sectionBases.push_back(isec); +} + +// Update fields (type, flags, alignment, etc) according to the InputSection +// isec. Also check whether the InputSection flags and type are consistent with +// other InputSections. +void OutputSection::commitSection(InputSection *isec) {    if (!hasInputSections) {      // If IS is the first section to be added to this section, -    // initialize Partition, Type, Entsize and flags from IS. +    // initialize type, entsize and flags from isec.      hasInputSections = true; -    partition = isec->partition;      type = isec->type;      entsize = isec->entsize;      flags = isec->flags; @@ -110,6 +129,8 @@ void OutputSection::addSection(InputSection *isec) {        type = SHT_PROGBITS;      }    } +  if (noload) +    type = SHT_NOBITS;    isec->parent = this;    uint64_t andMask = @@ -118,6 +139,8 @@ void OutputSection::addSection(InputSection *isec) {    uint64_t andFlags = (flags & isec->flags) & andMask;    uint64_t orFlags = (flags | isec->flags) & orMask;    flags = andFlags | orFlags; +  if (nonAlloc) +    flags &= ~(uint64_t)SHF_ALLOC;    alignment = std::max(alignment, isec->alignment); @@ -126,15 +149,69 @@ void OutputSection::addSection(InputSection *isec) {    // set sh_entsize to 0.    if (entsize != isec->entsize)      entsize = 0; +} -  if (!isec->assigned) { -    isec->assigned = true; -    if (sectionCommands.empty() || -        !isa<InputSectionDescription>(sectionCommands.back())) -      sectionCommands.push_back(make<InputSectionDescription>("")); -    auto *isd = cast<InputSectionDescription>(sectionCommands.back()); -    isd->sections.push_back(isec); +// This function scans over the InputSectionBase list sectionBases to create +// InputSectionDescription::sections. +// +// It removes MergeInputSections from the input section array and adds +// new synthetic sections at the location of the first input section +// that it replaces. It then finalizes each synthetic section in order +// to compute an output offset for each piece of each input section. +void OutputSection::finalizeInputSections() { +  std::vector<MergeSyntheticSection *> mergeSections; +  for (BaseCommand *base : sectionCommands) { +    auto *cmd = dyn_cast<InputSectionDescription>(base); +    if (!cmd) +      continue; +    cmd->sections.reserve(cmd->sectionBases.size()); +    for (InputSectionBase *s : cmd->sectionBases) { +      MergeInputSection *ms = dyn_cast<MergeInputSection>(s); +      if (!ms) { +        cmd->sections.push_back(cast<InputSection>(s)); +        continue; +      } + +      // We do not want to handle sections that are not alive, so just remove +      // them instead of trying to merge. +      if (!ms->isLive()) +        continue; + +      auto i = llvm::find_if(mergeSections, [=](MergeSyntheticSection *sec) { +        // While we could create a single synthetic section for two different +        // values of Entsize, it is better to take Entsize into consideration. +        // +        // With a single synthetic section no two pieces with different Entsize +        // could be equal, so we may as well have two sections. +        // +        // Using Entsize in here also allows us to propagate it to the synthetic +        // section. +        // +        // SHF_STRINGS section with different alignments should not be merged. +        return sec->flags == ms->flags && sec->entsize == ms->entsize && +               (sec->alignment == ms->alignment || !(sec->flags & SHF_STRINGS)); +      }); +      if (i == mergeSections.end()) { +        MergeSyntheticSection *syn = +            createMergeSynthetic(name, ms->type, ms->flags, ms->alignment); +        mergeSections.push_back(syn); +        i = std::prev(mergeSections.end()); +        syn->entsize = ms->entsize; +        cmd->sections.push_back(syn); +      } +      (*i)->addSection(ms); +    } + +    // sectionBases should not be used from this point onwards. Clear it to +    // catch misuses. +    cmd->sectionBases.clear(); + +    // Some input sections may be removed from the list after ICF. +    for (InputSection *s : cmd->sections) +      commitSection(s);    } +  for (auto *ms : mergeSections) +    ms->finalizeContents();  }  static void sortByOrder(MutableArrayRef<InputSection *> in, @@ -148,7 +225,7 @@ static void sortByOrder(MutableArrayRef<InputSection *> in,      in[i] = v[i].second;  } -uint64_t elf::getHeaderSize() { +uint64_t getHeaderSize() {    if (config->oFormatBinary)      return 0;    return Out::elfHeader->size + Out::programHeaders->size; @@ -368,7 +445,7 @@ void OutputSection::sortCtorsDtors() {  // If an input string is in the form of "foo.N" where N is a number,  // return N. Otherwise, returns 65536, which is one greater than the  // lowest priority. -int elf::getPriority(StringRef s) { +int getPriority(StringRef s) {    size_t pos = s.rfind('.');    if (pos == StringRef::npos)      return 65536; @@ -378,7 +455,7 @@ int elf::getPriority(StringRef s) {    return v;  } -std::vector<InputSection *> elf::getInputSections(OutputSection *os) { +std::vector<InputSection *> getInputSections(OutputSection *os) {    std::vector<InputSection *> ret;    for (BaseCommand *base : os->sectionCommands)      if (auto *isd = dyn_cast<InputSectionDescription>(base)) @@ -419,3 +496,6 @@ template void OutputSection::maybeCompress<ELF32LE>();  template void OutputSection::maybeCompress<ELF32BE>();  template void OutputSection::maybeCompress<ELF64LE>();  template void OutputSection::maybeCompress<ELF64BE>(); + +} // namespace elf +} // namespace lld  | 
