diff --git a/lld/MachO/CMakeLists.txt b/lld/MachO/CMakeLists.txt --- a/lld/MachO/CMakeLists.txt +++ b/lld/MachO/CMakeLists.txt @@ -7,6 +7,7 @@ Driver.cpp InputFiles.cpp InputSection.cpp + OutputSection.cpp OutputSegment.cpp SymbolTable.cpp Symbols.cpp diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -10,6 +10,7 @@ #include "Config.h" #include "InputFiles.h" #include "OutputSegment.h" +#include "OutputSection.h" #include "SymbolTable.h" #include "Symbols.h" #include "Target.h" diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -43,7 +43,7 @@ #include "InputFiles.h" #include "InputSection.h" -#include "OutputSegment.h" +#include "OutputSection.h" #include "SymbolTable.h" #include "Symbols.h" #include "Target.h" diff --git a/lld/MachO/InputSection.h b/lld/MachO/InputSection.h --- a/lld/MachO/InputSection.h +++ b/lld/MachO/InputSection.h @@ -19,7 +19,7 @@ class InputFile; class InputSection; -class OutputSegment; +class OutputSection; class Symbol; struct Reloc { @@ -42,19 +42,15 @@ virtual void writeTo(uint8_t *buf); InputFile *file = nullptr; - OutputSegment *parent = nullptr; + OutputSection *parent = nullptr; StringRef name; StringRef segname; - ArrayRef data; - - // TODO these properties ought to live in an OutputSection class. - // Move them once available. uint64_t addr = 0; uint32_t align = 1; - uint32_t sectionIndex = 0; uint32_t flags = 0; + ArrayRef data; std::vector relocs; }; diff --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp --- a/lld/MachO/InputSection.cpp +++ b/lld/MachO/InputSection.cpp @@ -22,7 +22,7 @@ std::vector macho::inputSections; uint64_t InputSection::getFileOffset() const { - return parent->fileOff + addr - parent->firstSection()->addr; + return parent->getFileOffset() + addr - parent->firstSection()->addr; } void InputSection::writeTo(uint8_t *buf) { diff --git a/lld/MachO/OutputSection.h b/lld/MachO/OutputSection.h new file mode 100644 --- /dev/null +++ b/lld/MachO/OutputSection.h @@ -0,0 +1,56 @@ +//===- OutputSection.h ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_MACHO_OUTPUT_SECTION_H +#define LLD_MACHO_OUTPUT_SECTION_H + +#include "InputSection.h" +#include "lld/Common/LLVM.h" +#include "llvm/ADT/MapVector.h" + +namespace lld { +namespace macho { + +class InputSection; +class OutputSegment; + +class OutputSection { +public: + const InputSection *firstSection() const { return inputs.front(); } + const InputSection *lastSection() const { return inputs.back(); } + + size_t getSize() const { return size; } + size_t getFileSize() const { return file_size; } + uint64_t getFileOffset() const { return inputs[0]->getFileOffset(); } + bool isHidden() const { return inputs.size() == 0 || inputs[0]->isHidden(); } + + void addInput(InputSection *input); + void finalize(); + + void writeTo(uint8_t *buf) const; + + StringRef name; + OutputSegment *parent = nullptr; + std::vector inputs; + + uint32_t index = 0; + + uint32_t numNonHiddenSections = 0; + uint64_t addr = 0; + uint32_t align = 1; + uint32_t flags = 0; + +private: + size_t size = 0; + size_t file_size = 0; +}; + +} // namespace macho +} // namespace lld + +#endif diff --git a/lld/MachO/OutputSection.cpp b/lld/MachO/OutputSection.cpp new file mode 100644 --- /dev/null +++ b/lld/MachO/OutputSection.cpp @@ -0,0 +1,55 @@ +//===- OutputSection.cpp --------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "OutputSection.h" +#include "lld/Common/Memory.h" +#include "llvm/BinaryFormat/MachO.h" + +using namespace llvm; +using namespace llvm::MachO; +using namespace lld; +using namespace lld::macho; + +void OutputSection::addInput(InputSection *input) { + if (this->inputs.empty()) { + this->align = input->align; + this->flags = input->flags; + } else { + //CHECK(input->flags == this->flags, "Cannot add merge section with inconsistent flags"); + this->align = std::max(this->align, input->align); + } + + if (!input->isHidden()) { + ++this->numNonHiddenSections; + } + this->inputs.push_back(input); + input->parent = this; +} + +void OutputSection::finalize() { + uint64_t addr = this->addr; + for (InputSection *i : inputs) { + if (i->isHidden()) { + continue; + } + i->addr = alignTo(addr, i->align); + addr += i->getSize(); + this->file_size += i->getFileSize(); + } + this->size = addr - this->addr; +} + +void OutputSection::writeTo(uint8_t *buf) const { + for (InputSection *i : inputs) { + if (i->isHidden()) { + continue; + } + i->writeTo(buf); + buf += i->getSize(); + } +} diff --git a/lld/MachO/OutputSegment.h b/lld/MachO/OutputSegment.h --- a/lld/MachO/OutputSegment.h +++ b/lld/MachO/OutputSegment.h @@ -9,6 +9,7 @@ #ifndef LLD_MACHO_OUTPUT_SEGMENT_H #define LLD_MACHO_OUTPUT_SEGMENT_H +#include "OutputSection.h" #include "lld/Common/LLVM.h" #include "llvm/ADT/MapVector.h" @@ -23,13 +24,16 @@ } // namespace segment_names +class OutputSection; class InputSection; class OutputSegment { public: - InputSection *firstSection() const { return sections.front().second.at(0); } + typedef llvm::MapVector SectionMap; - InputSection *lastSection() const { return sections.back().second.back(); } + const OutputSection *firstSection() const { return sections.front().second; } + + const OutputSection *lastSection() const { return sections.back().second; } bool isNeeded() const { return !sections.empty() || name == segment_names::linkEdit; @@ -37,20 +41,17 @@ void addSection(InputSection *); - const llvm::MapVector> & - getSections() const { + const SectionMap &getSections() const { return sections; } + uint32_t numNonHiddenSections = 0; uint64_t fileOff = 0; StringRef name; - uint32_t numNonHiddenSections = 0; uint32_t maxProt = 0; uint32_t initProt = 0; uint8_t index; - -private: - llvm::MapVector> sections; + SectionMap sections; }; extern std::vector outputSegments; diff --git a/lld/MachO/OutputSegment.cpp b/lld/MachO/OutputSegment.cpp --- a/lld/MachO/OutputSegment.cpp +++ b/lld/MachO/OutputSegment.cpp @@ -33,13 +33,24 @@ return VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; } -void OutputSegment::addSection(InputSection *isec) { - isec->parent = this; - std::vector &vec = sections[isec->name]; - if (vec.empty() && !isec->isHidden()) { - ++numNonHiddenSections; +void OutputSegment::addSection(InputSection *input) { + OutputSegment::SectionMap::iterator i = this->sections.find(input->name); + if (i != this->sections.end()) { + auto os = i->second; + os->addInput(input); + return; + } + + auto *os = make(); + os->name = input->name; + os->parent = this; + os->addInput(input); + this->sections[os->name] = os; + + // While creating the output section + if (os->isHidden()) { + this->numNonHiddenSections++; } - vec.push_back(isec); } static llvm::DenseMap nameToOutputSegment; diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -193,7 +193,7 @@ if (auto defined = dyn_cast(entry.sym)) { nList->n_strx = entry.strx; nList->n_type = N_EXT | N_SECT; - nList->n_sect = defined->isec->sectionIndex; + nList->n_sect = defined->isec->parent->index; // For the N_SECT symbol type, n_value is the address of the symbol nList->n_value = defined->value + defined->isec->addr; } diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -38,7 +38,7 @@ void scanRelocations(); void createHiddenSections(); - void sortSections(); + void createOutputSections(); void createLoadCommands(); void assignAddresses(OutputSegment *); void createSymtabContents(); @@ -125,10 +125,9 @@ for (auto &p : seg->getSections()) { StringRef s = p.first; - ArrayRef sections = p.second; - for (InputSection *isec : sections) - c->filesize += isec->getFileSize(); - if (sections[0]->isHidden()) + OutputSection *section = p.second; + c->filesize += section->getFileSize(); + if (section->isHidden()) continue; auto *sectHdr = reinterpret_cast(buf); @@ -137,16 +136,11 @@ memcpy(sectHdr->sectname, s.data(), s.size()); memcpy(sectHdr->segname, name.data(), name.size()); - sectHdr->addr = sections[0]->addr; - sectHdr->offset = sections[0]->getFileOffset(); - sectHdr->align = sections[0]->align; - uint32_t maxAlign = 0; - for (const InputSection *section : sections) - maxAlign = std::max(maxAlign, section->align); - sectHdr->align = Log2_32(maxAlign); - sectHdr->flags = sections[0]->flags; - sectHdr->size = sections.back()->addr + sections.back()->getSize() - - sections[0]->addr; + sectHdr->addr = section->addr; + sectHdr->offset = section->getFileOffset(); + sectHdr->align = Log2_32(section->align); + sectHdr->flags = section->flags; + sectHdr->size = section->getSize(); } } @@ -376,20 +370,25 @@ } } -void Writer::sortSections() { +void Writer::createOutputSections() { llvm::stable_sort(inputSections, SectionComparator()); - // TODO This is wrong; input sections ought to be grouped into - // output sections, which are then organized like this. - uint32_t sectionIndex = 0; - // Add input sections to output segments. + // Add input sections to output sections/segments. for (InputSection *isec : inputSections) { if (isec->isNeeded()) { - if (!isec->isHidden()) - isec->sectionIndex = ++sectionIndex; getOrCreateOutputSegment(isec->segname)->addSection(isec); } } + + // Now that the input sections are sorted, assign the final + // output section indices. + uint32_t sectionIndex = 0; + for (OutputSegment *seg : outputSegments) { + for (auto &p : seg->sections) { + OutputSection *section = p.second; + section->index = ++sectionIndex; + } + } } void Writer::assignAddresses(OutputSegment *seg) { @@ -398,13 +397,13 @@ seg->fileOff = fileOff; for (auto &p : seg->getSections()) { - ArrayRef sections = p.second; - for (InputSection *isec : sections) { - addr = alignTo(addr, isec->align); - isec->addr = addr; - addr += isec->getSize(); - fileOff += isec->getFileSize(); - } + OutputSection *section = p.second; + addr = alignTo(addr, section->align); + section->addr = addr; + section->finalize(); + + addr += section->getSize(); + fileOff += section->getFileSize(); } } @@ -424,11 +423,10 @@ uint8_t *buf = buffer->getBufferStart(); for (OutputSegment *seg : outputSegments) { uint64_t fileOff = seg->fileOff; - for (auto § : seg->getSections()) { - for (InputSection *isec : sect.second) { - isec->writeTo(buf + fileOff); - fileOff += isec->getFileSize(); - } + for (auto &p : seg->getSections()) { + OutputSection *section = p.second; + section->writeTo(buf + fileOff); + fileOff += section->getFileSize(); } } } @@ -438,7 +436,7 @@ createHiddenSections(); // Sort and assign sections to their respective segments. No more sections can // be created after this method runs. - sortSections(); + createOutputSections(); // dyld requires __LINKEDIT segment to always exist (even if empty). getOrCreateOutputSegment(segment_names::linkEdit); // No more segments can be created after this method runs. @@ -460,7 +458,7 @@ // Now that __LINKEDIT is filled out, do a proper calculation of its // addresses and offsets. We don't have to recalculate the other segments - // since sortSections() ensures that __LINKEDIT is the last segment. + // since createOutputSections() ensures that __LINKEDIT is the last segment. assignAddresses(getOutputSegment(segment_names::linkEdit)); openFile();