<commit_before>//===- Relocations.cpp ----------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains platform-independent functions to process relocations.
// I'll describe the overview of this file here.
//
// Simple relocations are easy to handle for the linker. For example,
// for R_X86_64_PC64 relocs, the linker just has to fix up locations
// with the relative offsets to the target symbols. It would just be
// reading records from relocation sections and applying them to output.
//
// But not all relocations are that easy to handle. For example, for
// R_386_GOTOFF relocs, the linker has to create new GOT entries for
// symbols if they don't exist, and fix up locations with GOT entry
// offsets from the beginning of GOT section. So there is more than
// fixing addresses in relocation processing.
//
// ELF defines a large number of complex relocations.
//
// The functions in this file analyze relocations and do whatever needs
// to be done. It includes, but not limited to, the following.
//
//  - create GOT/PLT entries
//  - create new relocations in .dynsym to let the dynamic linker resolve
//    them at runtime (since ELF supports dynamic linking, not all
//    relocations can be resolved at link-time)
//  - create COPY relocs and reserve space in .bss
//  - replace expensive relocs (in terms of runtime cost) with cheap ones
//  - error out infeasible combinations such as PIC and non-relative relocs
//
// Note that the functions in this file don't actually apply relocations
// because it doesn't know about the output file nor the output file buffer.
// It instead stores Relocation objects to InputSection's Relocations
// vector to let it apply later in InputSection::writeTo.
//
//===----------------------------------------------------------------------===//

#include "Relocations.h"
#include "Config.h"
#include "Memory.h"
#include "OutputSections.h"
#include "Strings.h"
#include "SymbolTable.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "Thunks.h"

#include "llvm/Support/Endian.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>

using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace llvm::support::endian;

using namespace lld;
using namespace lld::elf;

// Construct a message in the following format.
//
// >>> defined in /home/alice/src/foo.o
// >>> referenced by bar.c:12 (/home/alice/src/bar.c:12)
// >>>               /home/alice/src/bar.o:(.text+0x1)
template <class ELFT>
static std::string getLocation(InputSectionBase &S, const SymbolBody &Sym,
                               uint64_t Off) {
  std::string Msg =
      "\n>>> defined in " + toString(Sym.File) + "\n>>> referenced by ";
  std::string Src = S.getSrcMsg<ELFT>(Off);
  if (!Src.empty())
    Msg += Src + "\n>>>               ";
  return Msg + S.getObjMsg<ELFT>(Off);
}

static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
  // In case of MIPS GP-relative relocations always resolve to a definition
  // in a regular input file, ignoring the one-definition rule. So we,
  // for example, should not attempt to create a dynamic relocation even
  // if the target symbol is preemptible. There are two two MIPS GP-relative
  // relocations R_MIPS_GPREL16 and R_MIPS_GPREL32. But only R_MIPS_GPREL16
  // can be against a preemptible symbol.
  // To get MIPS relocation type we apply 0xff mask. In case of O32 ABI all
  // relocation types occupy eight bit. In case of N64 ABI we extract first
  // relocation from 3-in-1 packet because only the first relocation can
  // be against a real symbol.
  if (Config->EMachine == EM_MIPS && (Type & 0xff) == R_MIPS_GPREL16)
    return false;
  return Body.isPreemptible();
}

// This function is similar to the `handleTlsRelocation`. ARM and MIPS do not
// support any relaxations for TLS relocations so by factoring out ARM and MIPS
// handling in to the separate function we can simplify the code and do not
// pollute `handleTlsRelocation` by ARM and MIPS `ifs` statements.
template <class ELFT, class GOT>
static unsigned handleNoRelaxTlsRelocation(GOT *Got, uint32_t Type,
                                           SymbolBody &Body,
                                           InputSectionBase &C, uint64_t Offset,
                                           int64_t Addend, RelExpr Expr) {
  auto addModuleReloc = [&](uint64_t Off, bool LD) {
    // The Dynamic TLS Module Index Relocation can be statically resolved to 1
    // if we know that we are linking an executable. For ARM we resolve the
    // relocation when writing the Got. MIPS has a custom Got implementation
    // that writes the Module index in directly.
    if (!Body.isPreemptible() && !Config->Pic && Config->EMachine == EM_ARM)
      Got->Relocations.push_back(
          {R_ABS, Target->TlsModuleIndexRel, Off, 0, &Body});
    else {
      SymbolBody *Dest = LD ? nullptr : &Body;
      In<ELFT>::RelaDyn->addReloc(
          {Target->TlsModuleIndexRel, Got, Off, false, Dest, 0});
    }
  };

  if (isRelExprOneOf<R_MIPS_TLSLD, R_TLSLD_PC>(Expr)) {
    if (Got->addTlsIndex() && (Config->Pic || Config->EMachine == EM_ARM))
      addModuleReloc(Got->getTlsIndexOff(), true);
    C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
    return 1;
  }

  if (isRelExprOneOf<R_TLSGD, R_TLSGD_PC, R_MIPS_TLSGD>(Expr)) {
    if (Got->addDynTlsEntry(Body) &&
        (Body.isPreemptible() || Config->EMachine == EM_ARM)) {
      uint64_t Off = Got->getGlobalDynOffset(Body);
      addModuleReloc(Off, false);
      if (Body.isPreemptible())
        In<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Got,
                                     Off + Config->Wordsize, false, &Body, 0});
    }
    C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
    return 1;
  }

  return 0;
}

// Returns the number of relocations processed.
template <class ELFT>
static unsigned
handleTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase &C,
                    typename ELFT::uint Offset, int64_t Addend, RelExpr Expr) {
  if (!(C.Flags & SHF_ALLOC))
    return 0;

  if (!Body.isTls())
    return 0;

  if (Config->EMachine == EM_ARM)
    return handleNoRelaxTlsRelocation<ELFT>(In<ELFT>::Got, Type, Body, C,
                                            Offset, Addend, Expr);
  if (Config->EMachine == EM_MIPS)
    return handleNoRelaxTlsRelocation<ELFT>(In<ELFT>::MipsGot, Type, Body, C,
                                            Offset, Addend, Expr);

  bool IsPreemptible = isPreemptible(Body, Type);
  if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) &&
      Config->Shared) {
    if (In<ELFT>::Got->addDynTlsEntry(Body)) {
      uint64_t Off = In<ELFT>::Got->getGlobalDynOffset(Body);
      In<ELFT>::RelaDyn->addReloc({Target->TlsDescRel, In<ELFT>::Got, Off,
                                   !IsPreemptible, &Body, 0});
    }
    if (Expr != R_TLSDESC_CALL)
      C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
    return 1;
  }

  if (isRelExprOneOf<R_TLSLD_PC, R_TLSLD>(Expr)) {
    // Local-Dynamic relocs can be relaxed to Local-Exec.
    if (!Config->Shared) {
      C.Relocations.push_back(
          {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body});
      return 2;
    }<commit_msg>[ELF] Split handleNoRelaxTlsRelocation into ARM and Mips specific impls      The handleNoRelaxTlsRelocation handled both ARM and Mips as at a high-level the actions of what to do when encountering a local dynamic or global dynamic TLS relocation are the same. However due to Mips using a custom GOT the differences of the implementation are enough that the function became difficult to understand.      This change replaces handleNotRelaxTlsRelocation into handleARMTlsRelocation() and handleMipsTlsRelocation() so that the ARM and Mips specific code is isolated.<commit_after>//===- Relocations.cpp ----------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains platform-independent functions to process relocations.
// I'll describe the overview of this file here.
//
// Simple relocations are easy to handle for the linker. For example,
// for R_X86_64_PC64 relocs, the linker just has to fix up locations
// with the relative offsets to the target symbols. It would just be
// reading records from relocation sections and applying them to output.
//
// But not all relocations are that easy to handle. For example, for
// R_386_GOTOFF relocs, the linker has to create new GOT entries for
// symbols if they don't exist, and fix up locations with GOT entry
// offsets from the beginning of GOT section. So there is more than
// fixing addresses in relocation processing.
//
// ELF defines a large number of complex relocations.
//
// The functions in this file analyze relocations and do whatever needs
// to be done. It includes, but not limited to, the following.
//
//  - create GOT/PLT entries
//  - create new relocations in .dynsym to let the dynamic linker resolve
//    them at runtime (since ELF supports dynamic linking, not all
//    relocations can be resolved at link-time)
//  - create COPY relocs and reserve space in .bss
//  - replace expensive relocs (in terms of runtime cost) with cheap ones
//  - error out infeasible combinations such as PIC and non-relative relocs
//
// Note that the functions in this file don't actually apply relocations
// because it doesn't know about the output file nor the output file buffer.
// It instead stores Relocation objects to InputSection's Relocations
// vector to let it apply later in InputSection::writeTo.
//
//===----------------------------------------------------------------------===//

#include "Relocations.h"
#include "Config.h"
#include "Memory.h"
#include "OutputSections.h"
#include "Strings.h"
#include "SymbolTable.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "Thunks.h"

#include "llvm/Support/Endian.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>

using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace llvm::support::endian;

using namespace lld;
using namespace lld::elf;

// Construct a message in the following format.
//
// >>> defined in /home/alice/src/foo.o
// >>> referenced by bar.c:12 (/home/alice/src/bar.c:12)
// >>>               /home/alice/src/bar.o:(.text+0x1)
template <class ELFT>
static std::string getLocation(InputSectionBase &S, const SymbolBody &Sym,
                               uint64_t Off) {
  std::string Msg =
      "\n>>> defined in " + toString(Sym.File) + "\n>>> referenced by ";
  std::string Src = S.getSrcMsg<ELFT>(Off);
  if (!Src.empty())
    Msg += Src + "\n>>>               ";
  return Msg + S.getObjMsg<ELFT>(Off);
}

static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
  // In case of MIPS GP-relative relocations always resolve to a definition
  // in a regular input file, ignoring the one-definition rule. So we,
  // for example, should not attempt to create a dynamic relocation even
  // if the target symbol is preemptible. There are two two MIPS GP-relative
  // relocations R_MIPS_GPREL16 and R_MIPS_GPREL32. But only R_MIPS_GPREL16
  // can be against a preemptible symbol.
  // To get MIPS relocation type we apply 0xff mask. In case of O32 ABI all
  // relocation types occupy eight bit. In case of N64 ABI we extract first
  // relocation from 3-in-1 packet because only the first relocation can
  // be against a real symbol.
  if (Config->EMachine == EM_MIPS && (Type & 0xff) == R_MIPS_GPREL16)
    return false;
  return Body.isPreemptible();
}

// This function is similar to the `handleTlsRelocation`. MIPS does not
// support any relaxations for TLS relocations so by factoring out MIPS
// handling in to the separate function we can simplify the code and do not
// pollute other `handleTlsRelocation` by MIPS `ifs` statements.
// Mips has a custom MipsGotSection that handles the writing of GOT entries
// without dynamic relocations.
template <class ELFT>
static unsigned handleMipsTlsRelocation(MipsGotSection *Got, uint32_t Type,
                                        SymbolBody &Body, InputSectionBase &C,
                                        uint64_t Offset, int64_t Addend,
                                        RelExpr Expr) {
  if (Expr == R_MIPS_TLSLD) {
    if (Got->addTlsIndex() && Config->Pic)
      In<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Got,
                                   Got->getTlsIndexOff(), false, nullptr, 0});
    C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
    return 1;
  }

  if (Expr == R_MIPS_TLSGD) {
    if (Got->addDynTlsEntry(Body) && Body.isPreemptible()) {
      uint64_t Off = Got->getGlobalDynOffset(Body);
      In<ELFT>::RelaDyn->addReloc(
          {Target->TlsModuleIndexRel, Got, Off, false, &Body, 0});
      if (Body.isPreemptible())
        In<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Got,
                                     Off + Config->Wordsize, false, &Body, 0});
    }
    C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
    return 1;
  }
  return 0;
}

// This function is similar to the `handleMipsTlsRelocation`. ARM also does not
// support any relaxations for TLS relocations. ARM is logically similar to Mips
// in how it handles TLS, but Mips uses its own custom GOT which handles some
// of the cases that ARM uses GOT relocations for.
//
// We look for TLS global dynamic and local dynamic relocations, these may
// require the generation of a pair of GOT entries that have associated
// dynamic relocations. When the results of the dynamic relocations can be
// resolved at static link time we do so. This is necessary for static linking
// as there will be no dynamic loader to resolve them at load-time.
//
// The pair of GOT entries created are of the form
// GOT[e0] Module Index (Used to find pointer to TLS block at run-time)
// GOT[e1] Offset of symbol in TLS block
template <class ELFT>
static unsigned handleARMTlsRelocation(GotSection<ELFT> *Got, uint32_t Type,
                                       SymbolBody &Body, InputSectionBase &C,
                                       uint64_t Offset, int64_t Addend,
                                       RelExpr Expr) {
  auto addModuleReloc = [&](uint64_t Off, bool LD) {
    // The Dynamic TLS Module Index Relocation can be statically resolved to 1
    // if we know that the TLS Symbol is in an executable.
    if (!Body.isPreemptible() && !Config->Pic)
      Got->Relocations.push_back(
          {R_ABS, Target->TlsModuleIndexRel, Off, 0, &Body});
    else {
      SymbolBody *Dest = LD ? nullptr : &Body;
      In<ELFT>::RelaDyn->addReloc(
          {Target->TlsModuleIndexRel, Got, Off, false, Dest, 0});
    }
  };

  // Local Dynamic is for access to module local TLS variables, while still
  // being suitable for being dynamically loaded via dlopen.
  // GOT[e0] is the module index, with a special value of 0 for the current
  // module. GOT[e1] is unused. There only needs to be one module index entry.
  if (Expr == R_TLSLD_PC && Got->addTlsIndex()) {
    addModuleReloc(Got->getTlsIndexOff(), true);
    C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
    return 1;
  }

  // Global Dynamic is the most general purpose access model. When we know
  // the module index and offset of symbol in TLS block we can fill these in
  // using static GOT relocations.
  if (Expr == R_TLSGD_PC) {
    if (Got->addDynTlsEntry(Body)) {
      uint64_t Off = Got->getGlobalDynOffset(Body);
      addModuleReloc(Off, false);
      if (Body.isPreemptible())
        In<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Got,
                                     Off + Config->Wordsize, false, &Body, 0});
    }
    C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
    return 1;
  }
  return 0;
}

// Returns the number of relocations processed.
template <class ELFT>
static unsigned
handleTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase &C,
                    typename ELFT::uint Offset, int64_t Addend, RelExpr Expr) {
  if (!(C.Flags & SHF_ALLOC))
    return 0;

  if (!Body.isTls())
    return 0;

  if (Config->EMachine == EM_ARM)
    return handleARMTlsRelocation<ELFT>(In<ELFT>::Got, Type, Body, C, Offset,
                                        Addend, Expr);
  if (Config->EMachine == EM_MIPS)
    return handleMipsTlsRelocation<ELFT>(In<ELFT>::MipsGot, Type, Body, C,
                                         Offset, Addend, Expr);

  bool IsPreemptible = isPreemptible(Body, Type);
  if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) &&
      Config->Shared) {
    if (In<ELFT>::Got->addDynTlsEntry(Body)) {
      uint64_t Off = In<ELFT>::Got->getGlobalDynOffset(Body);
      In<ELFT>::RelaDyn->addReloc({Target->TlsDescRel, In<ELFT>::Got, Off,
                                   !IsPreemptible, &Body, 0});
    }
    if (Expr != R_TLSDESC_CALL)
      C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
    return 1;
  }

  if (isRelExprOneOf<R_TLSLD_PC, R_TLSLD>(Expr)) {
    // Local-Dynamic relocs can be relaxed to Local-Exec.
    if (!Config->Shared) {
      C.Relocations.push_back(
          {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body});
      return 2;
    }
{'fraction_non_alphanumeric': 0.1253373819163293, 'fraction_numerical': 0.008153396311291049, 'mean_word_length': 2.65420176700226, 'pattern_counts': {'":': 0, '<': 46, '<?xml version=': 0, '>': 140, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 30, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2533425', 'n_tokens_mistral': 5509, 'n_tokens_neox': 5187, 'n_words': 1872}