1fe6060f1SDimitry Andric //===- ConcatOutputSection.h ------------------------------------*- C++ -*-===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric 9*81ad6265SDimitry Andric #ifndef LLD_MACHO_CONCAT_OUTPUT_SECTION_H 10*81ad6265SDimitry Andric #define LLD_MACHO_CONCAT_OUTPUT_SECTION_H 11fe6060f1SDimitry Andric 12fe6060f1SDimitry Andric #include "InputSection.h" 13fe6060f1SDimitry Andric #include "OutputSection.h" 14fe6060f1SDimitry Andric #include "lld/Common/LLVM.h" 15fe6060f1SDimitry Andric #include "llvm/ADT/DenseMap.h" 16fe6060f1SDimitry Andric #include "llvm/ADT/MapVector.h" 17fe6060f1SDimitry Andric 18fe6060f1SDimitry Andric namespace lld { 19fe6060f1SDimitry Andric namespace macho { 20fe6060f1SDimitry Andric 21fe6060f1SDimitry Andric class Defined; 22fe6060f1SDimitry Andric 23fe6060f1SDimitry Andric // Linking multiple files will inevitably mean resolving sections in different 24fe6060f1SDimitry Andric // files that are labeled with the same segment and section name. This class 25fe6060f1SDimitry Andric // contains all such sections and writes the data from each section sequentially 26fe6060f1SDimitry Andric // in the final binary. 27*81ad6265SDimitry Andric class ConcatOutputSection : public OutputSection { 28fe6060f1SDimitry Andric public: 29fe6060f1SDimitry Andric explicit ConcatOutputSection(StringRef name) 30fe6060f1SDimitry Andric : OutputSection(ConcatKind, name) {} 31fe6060f1SDimitry Andric 32fe6060f1SDimitry Andric const ConcatInputSection *firstSection() const { return inputs.front(); } 33fe6060f1SDimitry Andric const ConcatInputSection *lastSection() const { return inputs.back(); } 34fe6060f1SDimitry Andric bool isNeeded() const override { return !inputs.empty(); } 35fe6060f1SDimitry Andric 36fe6060f1SDimitry Andric // These accessors will only be valid after finalizing the section 37fe6060f1SDimitry Andric uint64_t getSize() const override { return size; } 38fe6060f1SDimitry Andric uint64_t getFileSize() const override { return fileSize; } 39fe6060f1SDimitry Andric 40*81ad6265SDimitry Andric // Assign values to InputSection::outSecOff. In contrast to TextOutputSection, 41*81ad6265SDimitry Andric // which does this in its implementation of `finalize()`, we can do this 42*81ad6265SDimitry Andric // without `finalize()`'s sequential guarantees detailed in the block comment 43*81ad6265SDimitry Andric // of `OutputSection::finalize()`. 44*81ad6265SDimitry Andric virtual void finalizeContents(); 45*81ad6265SDimitry Andric 46fe6060f1SDimitry Andric void addInput(ConcatInputSection *input); 47fe6060f1SDimitry Andric void writeTo(uint8_t *buf) const override; 48fe6060f1SDimitry Andric 49fe6060f1SDimitry Andric static bool classof(const OutputSection *sec) { 50fe6060f1SDimitry Andric return sec->kind() == ConcatKind; 51fe6060f1SDimitry Andric } 52fe6060f1SDimitry Andric 53fe6060f1SDimitry Andric static ConcatOutputSection *getOrCreateForInput(const InputSection *); 54fe6060f1SDimitry Andric 55*81ad6265SDimitry Andric std::vector<ConcatInputSection *> inputs; 56fe6060f1SDimitry Andric 57*81ad6265SDimitry Andric protected: 58fe6060f1SDimitry Andric size_t size = 0; 59fe6060f1SDimitry Andric uint64_t fileSize = 0; 60*81ad6265SDimitry Andric void finalizeOne(ConcatInputSection *); 61*81ad6265SDimitry Andric 62*81ad6265SDimitry Andric private: 63*81ad6265SDimitry Andric void finalizeFlags(InputSection *input); 64*81ad6265SDimitry Andric }; 65*81ad6265SDimitry Andric 66*81ad6265SDimitry Andric // ConcatOutputSections that contain code (text) require special handling to 67*81ad6265SDimitry Andric // support thunk insertion. 68*81ad6265SDimitry Andric class TextOutputSection : public ConcatOutputSection { 69*81ad6265SDimitry Andric public: 70*81ad6265SDimitry Andric explicit TextOutputSection(StringRef name) : ConcatOutputSection(name) {} 71*81ad6265SDimitry Andric void finalizeContents() override {} 72*81ad6265SDimitry Andric void finalize() override; 73*81ad6265SDimitry Andric bool needsThunks() const; 74*81ad6265SDimitry Andric void writeTo(uint8_t *buf) const override; 75*81ad6265SDimitry Andric 76*81ad6265SDimitry Andric private: 77*81ad6265SDimitry Andric uint64_t estimateStubsInRangeVA(size_t callIdx) const; 78*81ad6265SDimitry Andric 79*81ad6265SDimitry Andric std::vector<ConcatInputSection *> thunks; 80fe6060f1SDimitry Andric }; 81fe6060f1SDimitry Andric 82fe6060f1SDimitry Andric // We maintain one ThunkInfo per real function. 83fe6060f1SDimitry Andric // 84fe6060f1SDimitry Andric // The "active thunk" is represented by the sym/isec pair that 85fe6060f1SDimitry Andric // turns-over during finalize(): as the call-site address advances, 86fe6060f1SDimitry Andric // the active thunk goes out of branch-range, and we create a new 87fe6060f1SDimitry Andric // thunk to take its place. 88fe6060f1SDimitry Andric // 89fe6060f1SDimitry Andric // The remaining members -- bools and counters -- apply to the 90fe6060f1SDimitry Andric // collection of thunks associated with the real function. 91fe6060f1SDimitry Andric 92fe6060f1SDimitry Andric struct ThunkInfo { 93fe6060f1SDimitry Andric // These denote the active thunk: 94fe6060f1SDimitry Andric Defined *sym = nullptr; // private-extern symbol for active thunk 95fe6060f1SDimitry Andric ConcatInputSection *isec = nullptr; // input section for active thunk 96fe6060f1SDimitry Andric 97fe6060f1SDimitry Andric // The following values are cumulative across all thunks on this function 98fe6060f1SDimitry Andric uint32_t callSiteCount = 0; // how many calls to the real function? 99fe6060f1SDimitry Andric uint32_t callSitesUsed = 0; // how many call sites processed so-far? 100fe6060f1SDimitry Andric uint32_t thunkCallCount = 0; // how many call sites went to thunk? 101fe6060f1SDimitry Andric uint8_t sequence = 0; // how many thunks created so-far? 102fe6060f1SDimitry Andric }; 103fe6060f1SDimitry Andric 104fe6060f1SDimitry Andric NamePair maybeRenameSection(NamePair key); 105fe6060f1SDimitry Andric 106fe6060f1SDimitry Andric // Output sections are added to output segments in iteration order 107fe6060f1SDimitry Andric // of ConcatOutputSection, so must have deterministic iteration order. 108fe6060f1SDimitry Andric extern llvm::MapVector<NamePair, ConcatOutputSection *> concatOutputSections; 109fe6060f1SDimitry Andric 110fe6060f1SDimitry Andric extern llvm::DenseMap<Symbol *, ThunkInfo> thunkMap; 111fe6060f1SDimitry Andric 112fe6060f1SDimitry Andric } // namespace macho 113fe6060f1SDimitry Andric } // namespace lld 114fe6060f1SDimitry Andric 115fe6060f1SDimitry Andric #endif 116