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/OutputSection.h b/lld/MachO/OutputSection.h new file mode 100644 --- /dev/null +++ b/lld/MachO/OutputSection.h @@ -0,0 +1,49 @@ +//===- 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; + + void addInput(InputSection *input); + void assignAddresses(uint64_t addr); + + 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; +}; + +} // 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,65 @@ +//===- 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; + + +size_t OutputSection::getSize() const { + size_t size = 0; + for (InputSection *i : inputs) { + if (i->isHidden()) { + continue; + } + size += i->getSize(); + } + return size; +} + +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::assignAddresses() { + uint64_t addr = this->addr; + for (InputSection *i : inputs) { + if (i->isHidden()) { + continue; + } + i->addr = alignTo(addr, i->align); + addr += i->getSize(); + } +} + +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; @@ -44,13 +48,10 @@ 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 @@ -62,3 +62,20 @@ outputSegments.push_back(segRef); return segRef; } + +OutputSection *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 os; + } + + auto *os = make(); + os->name = input->name; + os->parent = this; + os->addInput(input); + + this->sections[os->name] = os; + return os; +} diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -125,11 +125,7 @@ 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()) - continue; + OutputSection *section = p.second; auto *sectHdr = reinterpret_cast(buf); buf += sizeof(section_64); @@ -137,16 +133,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->addr - ImageBase; + sectHdr->align = Log2_32(section->align); + sectHdr->flags = section->flags; + sectHdr->size = section->getSize(); } } @@ -304,6 +295,7 @@ SectionType *createInputSection(ArgT &&... args) { auto *section = make(std::forward(args)...); inputSections.push_back(section); + OutputSegment::getOrCreateOutputSegment(Section->segname)->insertOutputSection(section); return section; } @@ -379,17 +371,24 @@ void Writer::sortSections() { 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); } } + + // Fix up the output addresses of the output sections. + uint64_t sectionIndex = 0; + for (OutputSegment *seg : outputSegments) { + addr = alignTo(addr, PageSize); + for (auto &p : seg->sections) { + OutputSection *section = p.second; + section->addr = addr; + addr += section->getSize(); + section->index = ++sectionIndex; + } + } } void Writer::assignAddresses(OutputSegment *seg) { @@ -398,13 +397,12 @@ 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->assignAddresses(); + addr += section->getSize(); + fileOff += section->getFileSize(); } } @@ -425,10 +423,8 @@ 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(); - } + sect->writeTo(buf + fileOff); + fileOff += sect->getFileSize(); } } }