brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.5 KiB · 068fbed Raw
497 lines · c
1//===- SyntheticSection.h ---------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Synthetic sections represent chunks of linker-created data. If you10// need to create a chunk of data that to be included in some section11// in the result, you probably want to create that as a synthetic section.12//13//===----------------------------------------------------------------------===//14 15#ifndef LLD_WASM_SYNTHETIC_SECTIONS_H16#define LLD_WASM_SYNTHETIC_SECTIONS_H17 18#include "OutputSections.h"19 20#include "llvm/ADT/SmallSet.h"21#include "llvm/ADT/StringMap.h"22#include "llvm/BinaryFormat/WasmTraits.h"23#include <optional>24 25#define DEBUG_TYPE "lld"26 27namespace lld::wasm {28 29// An init entry to be written to either the synthetic init func or the30// linking metadata.31struct WasmInitEntry {32  const FunctionSymbol *sym;33  uint32_t priority;34};35 36class SyntheticSection : public OutputSection {37public:38  SyntheticSection(uint32_t type, std::string name = "")39      : OutputSection(type, name), bodyOutputStream(body) {40    if (!name.empty())41      writeStr(bodyOutputStream, name, "section name");42  }43 44  void writeTo(uint8_t *buf) override {45    assert(offset);46    log("writing " + toString(*this));47    memcpy(buf + offset, header.data(), header.size());48    memcpy(buf + offset + header.size(), body.data(), body.size());49  }50 51  size_t getSize() const override { return header.size() + body.size(); }52 53  virtual void writeBody() {}54 55  virtual void assignIndexes() {}56 57  void finalizeContents() override {58    writeBody();59    createHeader(body.size());60  }61 62  raw_ostream &getStream() { return bodyOutputStream; }63 64  std::string body;65 66protected:67  llvm::raw_string_ostream bodyOutputStream;68};69 70// Create the custom "dylink" section containing information for the dynamic71// linker.72// See73// https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md74class DylinkSection : public SyntheticSection {75public:76  DylinkSection() : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "dylink.0") {}77  bool isNeeded() const override;78  void writeBody() override;79 80  uint32_t memAlign = 0;81  uint32_t memSize = 0;82};83 84class TypeSection : public SyntheticSection {85public:86  TypeSection() : SyntheticSection(llvm::wasm::WASM_SEC_TYPE) {}87 88  bool isNeeded() const override { return types.size() > 0; };89  void writeBody() override;90  uint32_t registerType(const WasmSignature &sig);91  uint32_t lookupType(const WasmSignature &sig);92 93protected:94  std::vector<const WasmSignature *> types;95  llvm::DenseMap<WasmSignature, int32_t> typeIndices;96};97 98/**99 * A key for some kind of imported entity of type `T`.100 *101 * Used when de-duplicating imports.102 */103template <typename T> struct ImportKey {104public:105  enum class State { Plain, Empty, Tombstone };106 107public:108  T type;109  std::optional<StringRef> importModule;110  std::optional<StringRef> importName;111  State state;112 113public:114  ImportKey(T type) : type(type), state(State::Plain) {}115  ImportKey(T type, State state) : type(type), state(state) {}116  ImportKey(T type, std::optional<StringRef> importModule,117            std::optional<StringRef> importName)118      : type(type), importModule(importModule), importName(importName),119        state(State::Plain) {}120};121 122template <typename T>123inline bool operator==(const ImportKey<T> &lhs, const ImportKey<T> &rhs) {124  return lhs.state == rhs.state && lhs.importModule == rhs.importModule &&125         lhs.importName == rhs.importName && lhs.type == rhs.type;126}127 128} // namespace wasm::lld129 130// `ImportKey<T>` can be used as a key in a `DenseMap` if `T` can be used as a131// key in a `DenseMap`.132namespace llvm {133template <typename T> struct DenseMapInfo<lld::wasm::ImportKey<T>> {134  static lld::wasm::ImportKey<T> getEmptyKey() {135    typename lld::wasm::ImportKey<T> key(llvm::DenseMapInfo<T>::getEmptyKey());136    key.state = lld::wasm::ImportKey<T>::State::Empty;137    return key;138  }139  static lld::wasm::ImportKey<T> getTombstoneKey() {140    typename lld::wasm::ImportKey<T> key(llvm::DenseMapInfo<T>::getEmptyKey());141    key.state = lld::wasm::ImportKey<T>::State::Tombstone;142    return key;143  }144  static unsigned getHashValue(const lld::wasm::ImportKey<T> &key) {145    uintptr_t hash = hash_value(key.importModule);146    hash = hash_combine(hash, key.importName);147    hash = hash_combine(hash, llvm::DenseMapInfo<T>::getHashValue(key.type));148    hash = hash_combine(hash, key.state);149    return hash;150  }151  static bool isEqual(const lld::wasm::ImportKey<T> &lhs,152                      const lld::wasm::ImportKey<T> &rhs) {153    return lhs == rhs;154  }155};156} // end namespace llvm157 158namespace lld {159namespace wasm {160 161class ImportSection : public SyntheticSection {162public:163  ImportSection() : SyntheticSection(llvm::wasm::WASM_SEC_IMPORT) {}164  bool isNeeded() const override { return getNumImports() > 0; }165  void writeBody() override;166  void addImport(Symbol *sym);167  void addGOTEntry(Symbol *sym);168  void seal() { isSealed = true; }169  uint32_t getNumImports() const;170  uint32_t getNumImportedGlobals() const {171    assert(isSealed);172    return numImportedGlobals;173  }174  uint32_t getNumImportedFunctions() const {175    assert(isSealed);176    return numImportedFunctions;177  }178  uint32_t getNumImportedTags() const {179    assert(isSealed);180    return numImportedTags;181  }182  uint32_t getNumImportedTables() const {183    assert(isSealed);184    return numImportedTables;185  }186 187  std::vector<const Symbol *> importedSymbols;188  std::vector<const Symbol *> gotSymbols;189 190protected:191  bool isSealed = false;192  unsigned numImportedGlobals = 0;193  unsigned numImportedFunctions = 0;194  unsigned numImportedTags = 0;195  unsigned numImportedTables = 0;196  llvm::DenseMap<ImportKey<WasmGlobalType>, uint32_t> importedGlobals;197  llvm::DenseMap<ImportKey<WasmSignature>, uint32_t> importedFunctions;198  llvm::DenseMap<ImportKey<WasmTableType>, uint32_t> importedTables;199  llvm::DenseMap<ImportKey<WasmSignature>, uint32_t> importedTags;200};201 202class FunctionSection : public SyntheticSection {203public:204  FunctionSection() : SyntheticSection(llvm::wasm::WASM_SEC_FUNCTION) {}205 206  bool isNeeded() const override { return inputFunctions.size() > 0; };207  void writeBody() override;208  void addFunction(InputFunction *func);209 210  std::vector<InputFunction *> inputFunctions;211 212protected:213};214 215class TableSection : public SyntheticSection {216public:217  TableSection() : SyntheticSection(llvm::wasm::WASM_SEC_TABLE) {}218 219  bool isNeeded() const override { return inputTables.size() > 0; };220  void assignIndexes() override;221  void writeBody() override;222  void addTable(InputTable *table);223 224  std::vector<InputTable *> inputTables;225};226 227class MemorySection : public SyntheticSection {228public:229  MemorySection() : SyntheticSection(llvm::wasm::WASM_SEC_MEMORY) {}230 231  bool isNeeded() const override { return !ctx.arg.memoryImport.has_value(); }232  void writeBody() override;233 234  uint64_t numMemoryPages = 0;235  uint64_t maxMemoryPages = 0;236};237 238// The tag section contains a list of declared wasm tags associated with the239// module. Currently the only supported tag kind is exceptions. All C++240// exceptions are represented by a single tag. A tag entry in this section241// contains information on what kind of tag it is (e.g. exception) and the type242// of values associated with the tag. (In Wasm, a tag can contain multiple243// values of primitive types. But for C++ exceptions, we just throw a pointer244// which is an i32 value (for wasm32 architecture), so the signature of C++245// exception is (i32)->(void), because all exception tag types are assumed to246// have void return type to share WasmSignature with functions.)247class TagSection : public SyntheticSection {248public:249  TagSection() : SyntheticSection(llvm::wasm::WASM_SEC_TAG) {}250  void writeBody() override;251  bool isNeeded() const override { return inputTags.size() > 0; }252  void addTag(InputTag *tag);253 254  std::vector<InputTag *> inputTags;255};256 257class GlobalSection : public SyntheticSection {258public:259  GlobalSection() : SyntheticSection(llvm::wasm::WASM_SEC_GLOBAL) {}260 261  static bool classof(const OutputSection *sec) {262    return sec->type == llvm::wasm::WASM_SEC_GLOBAL;263  }264 265  uint32_t numGlobals() const {266    assert(isSealed);267    return inputGlobals.size() + dataAddressGlobals.size() +268           internalGotSymbols.size();269  }270  bool isNeeded() const override { return numGlobals() > 0; }271  void assignIndexes() override;272  void writeBody() override;273  void addGlobal(InputGlobal *global);274 275  // Add an internal GOT entry global that corresponds to the given symbol.276  // Normally GOT entries are imported and assigned by the external dynamic277  // linker.  However, when linking PIC code statically or when linking with278  // -Bsymbolic we can internalize GOT entries by declaring globals the hold279  // symbol addresses.280  //281  // For the static linking case these internal globals can be completely282  // eliminated by a post-link optimizer such as wasm-opt.283  //284  // TODO(sbc): Another approach to optimizing these away could be to use285  // specific relocation types combined with linker relaxation which could286  // transform a `global.get` to an `i32.const`.287  void addInternalGOTEntry(Symbol *sym);288  bool needsRelocations() {289    if (ctx.arg.extendedConst)290      return false;291    return llvm::any_of(internalGotSymbols,292                        [=](Symbol *sym) { return !sym->isTLS(); });293  }294  bool needsTLSRelocations() {295    return llvm::any_of(internalGotSymbols,296                        [=](Symbol *sym) { return sym->isTLS(); });297  }298  void generateRelocationCode(raw_ostream &os, bool TLS) const;299 300  std::vector<DefinedData *> dataAddressGlobals;301  std::vector<InputGlobal *> inputGlobals;302  std::vector<Symbol *> internalGotSymbols;303 304protected:305  bool isSealed = false;306};307 308class ExportSection : public SyntheticSection {309public:310  ExportSection() : SyntheticSection(llvm::wasm::WASM_SEC_EXPORT) {}311  bool isNeeded() const override { return exports.size() > 0; }312  void writeBody() override;313 314  std::vector<llvm::wasm::WasmExport> exports;315  std::vector<const Symbol *> exportedSymbols;316};317 318class StartSection : public SyntheticSection {319public:320  StartSection() : SyntheticSection(llvm::wasm::WASM_SEC_START) {}321  bool isNeeded() const override;322  void writeBody() override;323};324 325class ElemSection : public SyntheticSection {326public:327  ElemSection()328      : SyntheticSection(llvm::wasm::WASM_SEC_ELEM) {}329  bool isNeeded() const override { return indirectFunctions.size() > 0; };330  void writeBody() override;331  void addEntry(FunctionSymbol *sym);332  uint32_t numEntries() const { return indirectFunctions.size(); }333 334protected:335  std::vector<const FunctionSymbol *> indirectFunctions;336};337 338class DataCountSection : public SyntheticSection {339public:340  DataCountSection(ArrayRef<OutputSegment *> segments);341  bool isNeeded() const override;342  void writeBody() override;343 344protected:345  uint32_t numSegments;346};347 348// Create the custom "linking" section containing linker metadata.349// This is only created when relocatable output is requested.350class LinkingSection : public SyntheticSection {351public:352  LinkingSection(const std::vector<WasmInitEntry> &initFunctions,353                 const std::vector<OutputSegment *> &dataSegments)354      : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "linking"),355        initFunctions(initFunctions), dataSegments(dataSegments) {}356  bool isNeeded() const override {357    return ctx.arg.relocatable || ctx.arg.emitRelocs;358  }359  void writeBody() override;360  void addToSymtab(Symbol *sym);361 362protected:363  std::vector<const Symbol *> symtabEntries;364  llvm::StringMap<uint32_t> sectionSymbolIndices;365  const std::vector<WasmInitEntry> &initFunctions;366  const std::vector<OutputSegment *> &dataSegments;367};368 369// Create the custom "name" section containing debug symbol names.370class NameSection : public SyntheticSection {371public:372  NameSection(ArrayRef<OutputSegment *> segments)373      : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "name"),374        segments(segments) {}375  bool isNeeded() const override {376    if (ctx.arg.stripAll && !ctx.arg.keepSections.count(name))377      return false;378    return numNames() > 0;379  }380  void writeBody() override;381  unsigned numNames() const {382    // We always write at least one name which is the name of the383    // module itself.384    return 1 + numNamedGlobals() + numNamedFunctions();385  }386  unsigned numNamedGlobals() const;387  unsigned numNamedFunctions() const;388  unsigned numNamedDataSegments() const;389 390protected:391  ArrayRef<OutputSegment *> segments;392};393 394class ProducersSection : public SyntheticSection {395public:396  ProducersSection()397      : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "producers") {}398  bool isNeeded() const override {399    if (ctx.arg.stripAll && !ctx.arg.keepSections.count(name))400      return false;401    return fieldCount() > 0;402  }403  void writeBody() override;404  void addInfo(const llvm::wasm::WasmProducerInfo &info);405 406protected:407  int fieldCount() const {408    return int(!languages.empty()) + int(!tools.empty()) + int(!sDKs.empty());409  }410  SmallVector<std::pair<std::string, std::string>, 8> languages;411  SmallVector<std::pair<std::string, std::string>, 8> tools;412  SmallVector<std::pair<std::string, std::string>, 8> sDKs;413};414 415class TargetFeaturesSection : public SyntheticSection {416public:417  TargetFeaturesSection()418      : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "target_features") {}419  bool isNeeded() const override {420    if (ctx.arg.stripAll && !ctx.arg.keepSections.count(name))421      return false;422    return features.size() > 0;423  }424  void writeBody() override;425 426  llvm::SmallSet<std::string, 8> features;427};428 429class RelocSection : public SyntheticSection {430public:431  RelocSection(StringRef name, OutputSection *sec)432      : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, std::string(name)),433        sec(sec) {}434  void writeBody() override;435  bool isNeeded() const override { return sec->getNumRelocations() > 0; };436 437protected:438  OutputSection *sec;439};440 441class BuildIdSection : public SyntheticSection {442public:443  BuildIdSection();444  void writeBody() override;445  bool isNeeded() const override {446    return ctx.arg.buildId != BuildIdKind::None;447  }448  void writeBuildId(llvm::ArrayRef<uint8_t> buf);449  void writeTo(uint8_t *buf) override {450    LLVM_DEBUG(llvm::dbgs()451               << "BuildId writeto buf " << buf << " offset " << offset452               << " headersize " << header.size() << '\n');453    // The actual build ID is derived from a hash of all of the output454    // sections, so it can't be calculated until they are written. Here455    // we write the section leaving zeros in place of the hash.456    SyntheticSection::writeTo(buf);457    // Calculate and store the location where the hash will be written.458    hashPlaceholderPtr = buf + offset + header.size() +459                         +sizeof(buildIdSectionName) /*name string*/ +460                         1 /* hash size */;461  }462 463  const uint32_t hashSize;464 465private:466  static constexpr char buildIdSectionName[] = "build_id";467  uint8_t *hashPlaceholderPtr = nullptr;468};469 470// Linker generated output sections471struct OutStruct {472  DylinkSection *dylinkSec;473  TypeSection *typeSec;474  FunctionSection *functionSec;475  ImportSection *importSec;476  TableSection *tableSec;477  MemorySection *memorySec;478  GlobalSection *globalSec;479  TagSection *tagSec;480  ExportSection *exportSec;481  StartSection *startSec;482  ElemSection *elemSec;483  DataCountSection *dataCountSec;484  LinkingSection *linkingSec;485  NameSection *nameSec;486  ProducersSection *producersSec;487  TargetFeaturesSection *targetFeaturesSec;488  BuildIdSection *buildIdSec;489};490 491extern OutStruct out;492 493} // namespace wasm494} // namespace lld495 496#endif497