1//===- InputFiles.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-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLD_WASM_INPUT_FILES_H
10#define LLD_WASM_INPUT_FILES_H
11
12#include "Symbols.h"
13#include "lld/Common/LLVM.h"
14#include "llvm/ADT/DenseMap.h"
15#include "llvm/ADT/DenseSet.h"
16#include "llvm/ADT/Triple.h"
17#include "llvm/LTO/LTO.h"
18#include "llvm/Object/Archive.h"
19#include "llvm/Object/Wasm.h"
20#include "llvm/Support/MemoryBuffer.h"
21#include <optional>
22#include <vector>
23
24namespace llvm {
25class TarWriter;
26}
27
28namespace lld {
29namespace wasm {
30
31class InputChunk;
32class InputFunction;
33class InputSegment;
34class InputGlobal;
35class InputTag;
36class InputTable;
37class InputSection;
38
39// If --reproduce option is given, all input files are written
40// to this tar archive.
41extern std::unique_ptr<llvm::TarWriter> tar;
42
43class InputFile {
44public:
45  enum Kind {
46    ObjectKind,
47    SharedKind,
48    ArchiveKind,
49    BitcodeKind,
50    StubKind,
51  };
52
53  virtual ~InputFile() {}
54
55  // Returns the filename.
56  StringRef getName() const { return mb.getBufferIdentifier(); }
57
58  Kind kind() const { return fileKind; }
59
60  // An archive file name if this file is created from an archive.
61  std::string archiveName;
62
63  ArrayRef<Symbol *> getSymbols() const { return symbols; }
64
65  MutableArrayRef<Symbol *> getMutableSymbols() { return symbols; }
66
67  // An InputFile is considered live if any of the symbols defined by it
68  // are live.
69  void markLive() { live = true; }
70  bool isLive() const { return live; }
71
72protected:
73  InputFile(Kind k, MemoryBufferRef m)
74      : mb(m), fileKind(k), live(!config->gcSections) {}
75
76  void checkArch(llvm::Triple::ArchType arch) const;
77
78  MemoryBufferRef mb;
79
80  // List of all symbols referenced or defined by this file.
81  std::vector<Symbol *> symbols;
82
83private:
84  const Kind fileKind;
85  bool live;
86};
87
88// .a file (ar archive)
89class ArchiveFile : public InputFile {
90public:
91  explicit ArchiveFile(MemoryBufferRef m) : InputFile(ArchiveKind, m) {}
92  static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; }
93
94  void addMember(const llvm::object::Archive::Symbol *sym);
95
96  void parse();
97
98private:
99  std::unique_ptr<llvm::object::Archive> file;
100  llvm::DenseSet<uint64_t> seen;
101};
102
103// .o file (wasm object file)
104class ObjFile : public InputFile {
105public:
106  explicit ObjFile(MemoryBufferRef m, StringRef archiveName)
107      : InputFile(ObjectKind, m) {
108    this->archiveName = std::string(archiveName);
109
110    // If this isn't part of an archive, it's eagerly linked, so mark it live.
111    if (archiveName.empty())
112      markLive();
113  }
114  static bool classof(const InputFile *f) { return f->kind() == ObjectKind; }
115
116  void parse(bool ignoreComdats = false);
117
118  // Returns the underlying wasm file.
119  const WasmObjectFile *getWasmObj() const { return wasmObj.get(); }
120
121  uint32_t calcNewIndex(const WasmRelocation &reloc) const;
122  uint64_t calcNewValue(const WasmRelocation &reloc, uint64_t tombstone,
123                        const InputChunk *chunk) const;
124  int64_t calcNewAddend(const WasmRelocation &reloc) const;
125  Symbol *getSymbol(const WasmRelocation &reloc) const {
126    return symbols[reloc.Index];
127  };
128
129  const WasmSection *codeSection = nullptr;
130  const WasmSection *dataSection = nullptr;
131
132  // Maps input type indices to output type indices
133  std::vector<uint32_t> typeMap;
134  std::vector<bool> typeIsUsed;
135  // Maps function indices to table indices
136  std::vector<uint32_t> tableEntries;
137  std::vector<uint32_t> tableEntriesRel;
138  std::vector<bool> keptComdats;
139  std::vector<InputChunk *> segments;
140  std::vector<InputFunction *> functions;
141  std::vector<InputGlobal *> globals;
142  std::vector<InputTag *> tags;
143  std::vector<InputTable *> tables;
144  std::vector<InputChunk *> customSections;
145  llvm::DenseMap<uint32_t, InputChunk *> customSectionsByIndex;
146
147  Symbol *getSymbol(uint32_t index) const { return symbols[index]; }
148  FunctionSymbol *getFunctionSymbol(uint32_t index) const;
149  DataSymbol *getDataSymbol(uint32_t index) const;
150  GlobalSymbol *getGlobalSymbol(uint32_t index) const;
151  SectionSymbol *getSectionSymbol(uint32_t index) const;
152  TagSymbol *getTagSymbol(uint32_t index) const;
153  TableSymbol *getTableSymbol(uint32_t index) const;
154
155private:
156  Symbol *createDefined(const WasmSymbol &sym);
157  Symbol *createUndefined(const WasmSymbol &sym, bool isCalledDirectly);
158
159  bool isExcludedByComdat(const InputChunk *chunk) const;
160  void addLegacyIndirectFunctionTableIfNeeded(uint32_t tableSymbolCount);
161
162  std::unique_ptr<WasmObjectFile> wasmObj;
163};
164
165// .so file.
166class SharedFile : public InputFile {
167public:
168  explicit SharedFile(MemoryBufferRef m) : InputFile(SharedKind, m) {}
169  static bool classof(const InputFile *f) { return f->kind() == SharedKind; }
170};
171
172// .bc file
173class BitcodeFile : public InputFile {
174public:
175  BitcodeFile(MemoryBufferRef m, StringRef archiveName,
176              uint64_t offsetInArchive);
177  static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
178
179  void parse();
180  std::unique_ptr<llvm::lto::InputFile> obj;
181
182  // Set to true once LTO is complete in order prevent further bitcode objects
183  // being added.
184  static bool doneLTO;
185};
186
187// Stub libray (See docs/WebAssembly.rst)
188class StubFile : public InputFile {
189public:
190  explicit StubFile(MemoryBufferRef m) : InputFile(StubKind, m) {}
191
192  static bool classof(const InputFile *f) { return f->kind() == StubKind; }
193
194  void parse();
195
196  llvm::DenseMap<StringRef, std::vector<StringRef>> symbolDependencies;
197};
198
199inline bool isBitcode(MemoryBufferRef mb) {
200  return identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode;
201}
202
203// Will report a fatal() error if the input buffer is not a valid bitcode
204// or wasm object file.
205InputFile *createObjectFile(MemoryBufferRef mb, StringRef archiveName = "",
206                            uint64_t offsetInArchive = 0);
207
208// Opens a given file.
209std::optional<MemoryBufferRef> readFile(StringRef path);
210
211} // namespace wasm
212
213std::string toString(const wasm::InputFile *file);
214
215} // namespace lld
216
217#endif
218