InputFiles.h 13 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
//===- InputFiles.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_ELF_INPUT_FILES_H
#define LLD_ELF_INPUT_FILES_H

#include "Config.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/LLVM.h"
#include "lld/Common/Reproduce.h"
#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/Comdat.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ELF.h"
#include "llvm/Object/IRObjectFile.h"
#include "llvm/Support/Threading.h"
#include <map>

namespace llvm {
struct DILineInfo;
class TarWriter;
namespace lto {
class InputFile;
}
} // namespace llvm

namespace lld {
class DWARFCache;

// Returns "<internal>", "foo.a(bar.o)" or "baz.o".
std::string toString(const elf::InputFile *f);

namespace elf {

using llvm::object::Archive;

class Symbol;

// If -reproduce option is given, all input files are written
// to this tar archive.
extern std::unique_ptr<llvm::TarWriter> tar;

// Opens a given file.
llvm::Optional<MemoryBufferRef> readFile(StringRef path);

// Add symbols in File to the symbol table.
void parseFile(InputFile *file);

// The root class of input files.
class InputFile {
public:
  enum Kind {
    ObjKind,
    SharedKind,
    LazyObjKind,
    ArchiveKind,
    BitcodeKind,
    BinaryKind,
  };

  Kind kind() const { return fileKind; }

  bool isElf() const {
    Kind k = kind();
    return k == ObjKind || k == SharedKind;
  }

  StringRef getName() const { return mb.getBufferIdentifier(); }
  MemoryBufferRef mb;

  // Returns sections. It is a runtime error to call this function
  // on files that don't have the notion of sections.
  ArrayRef<InputSectionBase *> getSections() const {
    assert(fileKind == ObjKind || fileKind == BinaryKind);
    return sections;
  }

  // Returns object file symbols. It is a runtime error to call this
  // function on files of other types.
  ArrayRef<Symbol *> getSymbols() { return getMutableSymbols(); }

  MutableArrayRef<Symbol *> getMutableSymbols() {
    assert(fileKind == BinaryKind || fileKind == ObjKind ||
           fileKind == BitcodeKind);
    return symbols;
  }

  // Get filename to use for linker script processing.
  StringRef getNameForScript() const;

  // Filename of .a which contained this file. If this file was
  // not in an archive file, it is the empty string. We use this
  // string for creating error messages.
  std::string archiveName;

  // If this is an architecture-specific file, the following members
  // have ELF type (i.e. ELF{32,64}{LE,BE}) and target machine type.
  ELFKind ekind = ELFNoneKind;
  uint16_t emachine = llvm::ELF::EM_NONE;
  uint8_t osabi = 0;
  uint8_t abiVersion = 0;

  // Cache for toString(). Only toString() should use this member.
  mutable std::string toStringCache;

  std::string getSrcMsg(const Symbol &sym, InputSectionBase &sec,
                        uint64_t offset);

  // True if this is an argument for --just-symbols. Usually false.
  bool justSymbols = false;

  // outSecOff of .got2 in the current file. This is used by PPC32 -fPIC/-fPIE
  // to compute offsets in PLT call stubs.
  uint32_t ppc32Got2OutSecOff = 0;

  // On PPC64 we need to keep track of which files contain small code model
  // relocations that access the .toc section. To minimize the chance of a
  // relocation overflow, files that do contain said relocations should have
  // their .toc sections sorted closer to the .got section than files that do
  // not contain any small code model relocations. Thats because the toc-pointer
  // is defined to point at .got + 0x8000 and the instructions used with small
  // code model relocations support immediates in the range [-0x8000, 0x7FFC],
  // making the addressable range relative to the toc pointer
  // [.got, .got + 0xFFFC].
  bool ppc64SmallCodeModelTocRelocs = false;

  // groupId is used for --warn-backrefs which is an optional error
  // checking feature. All files within the same --{start,end}-group or
  // --{start,end}-lib get the same group ID. Otherwise, each file gets a new
  // group ID. For more info, see checkDependency() in SymbolTable.cpp.
  uint32_t groupId;
  static bool isInGroup;
  static uint32_t nextGroupId;

  // Index of MIPS GOT built for this file.
  llvm::Optional<size_t> mipsGotIndex;

  std::vector<Symbol *> symbols;

protected:
  InputFile(Kind k, MemoryBufferRef m);
  std::vector<InputSectionBase *> sections;

private:
  const Kind fileKind;

  // Cache for getNameForScript().
  mutable std::string nameForScriptCache;
};

class ELFFileBase : public InputFile {
public:
  ELFFileBase(Kind k, MemoryBufferRef m);
  static bool classof(const InputFile *f) { return f->isElf(); }

  template <typename ELFT> llvm::object::ELFFile<ELFT> getObj() const {
    return check(llvm::object::ELFFile<ELFT>::create(mb.getBuffer()));
  }

  StringRef getStringTable() const { return stringTable; }

  template <typename ELFT> typename ELFT::SymRange getELFSyms() const {
    return typename ELFT::SymRange(
        reinterpret_cast<const typename ELFT::Sym *>(elfSyms), numELFSyms);
  }
  template <typename ELFT> typename ELFT::SymRange getGlobalELFSyms() const {
    return getELFSyms<ELFT>().slice(firstGlobal);
  }

protected:
  // Initializes this class's member variables.
  template <typename ELFT> void init();

  const void *elfSyms = nullptr;
  size_t numELFSyms = 0;
  uint32_t firstGlobal = 0;
  StringRef stringTable;
};

// .o file.
template <class ELFT> class ObjFile : public ELFFileBase {
  using Elf_Rel = typename ELFT::Rel;
  using Elf_Rela = typename ELFT::Rela;
  using Elf_Sym = typename ELFT::Sym;
  using Elf_Shdr = typename ELFT::Shdr;
  using Elf_Word = typename ELFT::Word;
  using Elf_CGProfile = typename ELFT::CGProfile;

public:
  static bool classof(const InputFile *f) { return f->kind() == ObjKind; }

  llvm::object::ELFFile<ELFT> getObj() const {
    return this->ELFFileBase::getObj<ELFT>();
  }

  ArrayRef<Symbol *> getLocalSymbols();
  ArrayRef<Symbol *> getGlobalSymbols();

  ObjFile(MemoryBufferRef m, StringRef archiveName) : ELFFileBase(ObjKind, m) {
    this->archiveName = std::string(archiveName);
  }

  void parse(bool ignoreComdats = false);

  StringRef getShtGroupSignature(ArrayRef<Elf_Shdr> sections,
                                 const Elf_Shdr &sec);

  Symbol &getSymbol(uint32_t symbolIndex) const {
    if (symbolIndex >= this->symbols.size())
      fatal(toString(this) + ": invalid symbol index");
    return *this->symbols[symbolIndex];
  }

  uint32_t getSectionIndex(const Elf_Sym &sym) const;

  template <typename RelT> Symbol &getRelocTargetSym(const RelT &rel) const {
    uint32_t symIndex = rel.getSymbol(config->isMips64EL);
    return getSymbol(symIndex);
  }

  llvm::Optional<llvm::DILineInfo> getDILineInfo(InputSectionBase *, uint64_t);
  llvm::Optional<std::pair<std::string, unsigned>> getVariableLoc(StringRef name);

  // MIPS GP0 value defined by this file. This value represents the gp value
  // used to create the relocatable object and required to support
  // R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations.
  uint32_t mipsGp0 = 0;

  uint32_t andFeatures = 0;

  // Name of source file obtained from STT_FILE symbol value,
  // or empty string if there is no such symbol in object file
  // symbol table.
  StringRef sourceFile;

  // True if the file defines functions compiled with
  // -fsplit-stack. Usually false.
  bool splitStack = false;

  // True if the file defines functions compiled with -fsplit-stack,
  // but had one or more functions with the no_split_stack attribute.
  bool someNoSplitStack = false;

  // Pointer to this input file's .llvm_addrsig section, if it has one.
  const Elf_Shdr *addrsigSec = nullptr;

  // SHT_LLVM_CALL_GRAPH_PROFILE table
  ArrayRef<Elf_CGProfile> cgProfile;

  // Get cached DWARF information.
  DWARFCache *getDwarf();

private:
  void initializeSections(bool ignoreComdats);
  void initializeSymbols();
  void initializeJustSymbols();

  InputSectionBase *getRelocTarget(const Elf_Shdr &sec);
  InputSectionBase *createInputSection(const Elf_Shdr &sec);
  StringRef getSectionName(const Elf_Shdr &sec);

  bool shouldMerge(const Elf_Shdr &sec, StringRef name);

  // Each ELF symbol contains a section index which the symbol belongs to.
  // However, because the number of bits dedicated for that is limited, a
  // symbol can directly point to a section only when the section index is
  // equal to or smaller than 65280.
  //
  // If an object file contains more than 65280 sections, the file must
  // contain .symtab_shndx section. The section contains an array of
  // 32-bit integers whose size is the same as the number of symbols.
  // Nth symbol's section index is in the Nth entry of .symtab_shndx.
  //
  // The following variable contains the contents of .symtab_shndx.
  // If the section does not exist (which is common), the array is empty.
  ArrayRef<Elf_Word> shndxTable;

  // .shstrtab contents.
  StringRef sectionStringTable;

  // Debugging information to retrieve source file and line for error
  // reporting. Linker may find reasonable number of errors in a
  // single object file, so we cache debugging information in order to
  // parse it only once for each object file we link.
  std::unique_ptr<DWARFCache> dwarf;
  llvm::once_flag initDwarf;
};

// LazyObjFile is analogous to ArchiveFile in the sense that
// the file contains lazy symbols. The difference is that
// LazyObjFile wraps a single file instead of multiple files.
//
// This class is used for --start-lib and --end-lib options which
// instruct the linker to link object files between them with the
// archive file semantics.
class LazyObjFile : public InputFile {
public:
  LazyObjFile(MemoryBufferRef m, StringRef archiveName,
              uint64_t offsetInArchive)
      : InputFile(LazyObjKind, m), offsetInArchive(offsetInArchive) {
    this->archiveName = std::string(archiveName);
  }

  static bool classof(const InputFile *f) { return f->kind() == LazyObjKind; }

  template <class ELFT> void parse();
  void fetch();

  bool fetched = false;

private:
  uint64_t offsetInArchive;
};

// An ArchiveFile object represents a .a file.
class ArchiveFile : public InputFile {
public:
  explicit ArchiveFile(std::unique_ptr<Archive> &&file);
  static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; }
  void parse();

  // Pulls out an object file that contains a definition for Sym and
  // returns it. If the same file was instantiated before, this
  // function does nothing (so we don't instantiate the same file
  // more than once.)
  void fetch(const Archive::Symbol &sym);

  size_t getMemberCount() const;
  size_t getFetchedMemberCount() const { return seen.size(); }

  bool parsed = false;

private:
  std::unique_ptr<Archive> file;
  llvm::DenseSet<uint64_t> seen;
};

class BitcodeFile : public InputFile {
public:
  BitcodeFile(MemoryBufferRef m, StringRef archiveName,
              uint64_t offsetInArchive);
  static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
  template <class ELFT> void parse();
  std::unique_ptr<llvm::lto::InputFile> obj;
};

// .so file.
class SharedFile : public ELFFileBase {
public:
  SharedFile(MemoryBufferRef m, StringRef defaultSoName)
      : ELFFileBase(SharedKind, m), soName(std::string(defaultSoName)),
        isNeeded(!config->asNeeded) {}

  // This is actually a vector of Elf_Verdef pointers.
  std::vector<const void *> verdefs;

  // If the output file needs Elf_Verneed data structures for this file, this is
  // a vector of Elf_Vernaux version identifiers that map onto the entries in
  // Verdefs, otherwise it is empty.
  std::vector<unsigned> vernauxs;

  static unsigned vernauxNum;

  std::vector<StringRef> dtNeeded;
  std::string soName;

  static bool classof(const InputFile *f) { return f->kind() == SharedKind; }

  template <typename ELFT> void parse();

  // Used for --no-allow-shlib-undefined.
  bool allNeededIsKnown;

  // Used for --as-needed
  bool isNeeded;

private:
  template <typename ELFT>
  std::vector<uint32_t> parseVerneed(const llvm::object::ELFFile<ELFT> &obj,
                                     const typename ELFT::Shdr *sec);
};

class BinaryFile : public InputFile {
public:
  explicit BinaryFile(MemoryBufferRef m) : InputFile(BinaryKind, m) {}
  static bool classof(const InputFile *f) { return f->kind() == BinaryKind; }
  void parse();
};

InputFile *createObjectFile(MemoryBufferRef mb, StringRef archiveName = "",
                            uint64_t offsetInArchive = 0);

inline bool isBitcode(MemoryBufferRef mb) {
  return identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode;
}

std::string replaceThinLTOSuffix(StringRef path);

extern std::vector<ArchiveFile *> archiveFiles;
extern std::vector<BinaryFile *> binaryFiles;
extern std::vector<BitcodeFile *> bitcodeFiles;
extern std::vector<LazyObjFile *> lazyObjFiles;
extern std::vector<InputFile *> objectFiles;
extern std::vector<SharedFile *> sharedFiles;

} // namespace elf
} // namespace lld

#endif