brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.8 KiB · 28b4fc0 Raw
180 lines · cpp
1//===- bolt/Target/AArch64/AArch64MCSymbolizer.cpp ------------------------===//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#include "AArch64MCSymbolizer.h"10#include "bolt/Core/BinaryContext.h"11#include "bolt/Core/BinaryFunction.h"12#include "bolt/Core/MCPlusBuilder.h"13#include "bolt/Core/Relocation.h"14#include "llvm/MC/MCInst.h"15#include "llvm/Support/Debug.h"16 17#define DEBUG_TYPE "bolt-symbolizer"18 19namespace llvm {20namespace bolt {21 22AArch64MCSymbolizer::~AArch64MCSymbolizer() {}23 24bool AArch64MCSymbolizer::tryAddingSymbolicOperand(25    MCInst &Inst, raw_ostream &CStream, int64_t Value, uint64_t InstAddress,26    bool IsBranch, uint64_t ImmOffset, uint64_t ImmSize, uint64_t InstSize) {27  BinaryContext &BC = Function.getBinaryContext();28  MCContext *Ctx = BC.Ctx.get();29 30  // NOTE: the callee may incorrectly set IsBranch.31  if (BC.MIB->isBranch(Inst) || BC.MIB->isCall(Inst))32    return false;33 34  const uint64_t InstOffset = InstAddress - Function.getAddress();35  const Relocation *Relocation = Function.getRelocationAt(InstOffset);36 37  /// Add symbolic operand to the instruction with an optional addend.38  auto addOperand = [&](const MCSymbol *Symbol, uint64_t Addend,39                        uint64_t RelType) {40    const MCExpr *Expr = MCSymbolRefExpr::create(Symbol, *Ctx);41    if (Addend)42      Expr = MCBinaryExpr::createAdd(Expr, MCConstantExpr::create(Addend, *Ctx),43                                     *Ctx);44    Inst.addOperand(MCOperand::createExpr(45        BC.MIB->getTargetExprFor(Inst, Expr, *Ctx, RelType)));46  };47 48  if (Relocation) {49    auto AdjustedRel = adjustRelocation(*Relocation, Inst);50    if (AdjustedRel) {51      addOperand(AdjustedRel->Symbol, AdjustedRel->Addend, AdjustedRel->Type);52      return true;53    }54 55    LLVM_DEBUG(dbgs() << "BOLT-DEBUG: ignoring relocation at 0x"56                      << Twine::utohexstr(InstAddress) << '\n');57  }58 59  if (!BC.MIB->hasPCRelOperand(Inst))60    return false;61 62  Value += InstAddress;63  const MCSymbol *TargetSymbol;64  uint64_t TargetOffset;65  if (!CreateNewSymbols) {66    if (BinaryData *BD = BC.getBinaryDataContainingAddress(Value)) {67      TargetSymbol = BD->getSymbol();68      TargetOffset = Value - BD->getAddress();69    } else {70      return false;71    }72  } else {73    std::tie(TargetSymbol, TargetOffset) =74        BC.handleAddressRef(Value, Function, /*IsPCRel*/ true);75  }76 77  addOperand(TargetSymbol, TargetOffset, 0);78 79  return true;80}81 82std::optional<Relocation>83AArch64MCSymbolizer::adjustRelocation(const Relocation &Rel,84                                      const MCInst &Inst) const {85  BinaryContext &BC = Function.getBinaryContext();86 87  // The linker can convert ADRP+ADD and ADRP+LDR instruction sequences into88  // NOP+ADR. After the conversion, the linker might keep the relocations and89  // if we try to symbolize ADR's operand using outdated relocations, we might90  // get unexpected results. Hence, we check for the conversion/relaxation, and91  // ignore the relocation. The symbolization is done based on the PC-relative92  // value of the operand instead.93  if (BC.MIB->isADR(Inst) && (Rel.Type == ELF::R_AARCH64_ADD_ABS_LO12_NC ||94                              Rel.Type == ELF::R_AARCH64_LD64_GOT_LO12_NC))95    return std::nullopt;96 97  // The linker might perform TLS relocations relaxations, such as changed TLS98  // access model (e.g. changed global dynamic model to initial exec), thus99  // changing the instructions. The static relocations might be invalid at this100  // point and we don't have to process these relocations anymore. More101  // information could be found by searching elfNN_aarch64_tls_relax in bfd.102  if (BC.MIB->isMOVW(Inst)) {103    switch (Rel.Type) {104    default:105      break;106    case ELF::R_AARCH64_TLSDESC_LD64_LO12:107    case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:108    case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:109    case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:110      return std::nullopt;111    }112  }113 114  if (!Relocation::isGOT(Rel.Type))115    return Rel;116 117  Relocation AdjustedRel = Rel;118  if (Rel.Type == ELF::R_AARCH64_LD64_GOT_LO12_NC && BC.MIB->isAddXri(Inst)) {119    // The ADRP+LDR sequence was converted into ADRP+ADD. We are looking at the120    // second instruction and have to use the relocation type for ADD.121    AdjustedRel.Type = ELF::R_AARCH64_ADD_ABS_LO12_NC;122    return AdjustedRel;123  }124 125  // ADRP is a special case since the linker can leave the instruction opcode126  // intact and modify only the operand. We are doing our best to detect when127  // such conversion has happened without looking at the next instruction.128  //129  // If we detect that a page referenced by the ADRP cannot belong to GOT, and130  // that it matches the symbol from the relocation, then we can be certain131  // that the linker converted the GOT reference into the local one. Otherwise,132  // we leave the disambiguation resolution to FixRelaxationPass.133  //134  // Note that ADRP relaxation described above cannot happen for TLS relocation.135  // Since TLS relocations may not even have a valid symbol (not supported by136  // BOLT), we explicitly exclude them from the check.137  if (BC.MIB->isADRP(Inst) && Rel.Addend == 0 && !Relocation::isTLS(Rel.Type)) {138    ErrorOr<uint64_t> SymbolValue = BC.getSymbolValue(*Rel.Symbol);139    assert(SymbolValue && "Symbol value should be set");140    const uint64_t SymbolPageAddr = *SymbolValue & ~0xfffULL;141 142    if (SymbolPageAddr == Rel.Value &&143        !isPageAddressValidForGOT(SymbolPageAddr)) {144      AdjustedRel.Type = ELF::R_AARCH64_ADR_PREL_PG_HI21;145      return AdjustedRel;146    }147  }148 149  // For instructions that reference GOT, ignore the referenced symbol and150  // use value at the relocation site. FixRelaxationPass will look at151  // instruction pairs and will perform necessary adjustments.152  AdjustedRel.Symbol = BC.registerNameAtAddress("__BOLT_got_zero", 0, 0, 0);153  AdjustedRel.Addend = Rel.Value;154 155  return AdjustedRel;156}157 158bool AArch64MCSymbolizer::isPageAddressValidForGOT(uint64_t PageAddress) const {159  assert(!(PageAddress & 0xfffULL) && "Page address not aligned at 4KB");160 161  ErrorOr<BinarySection &> GOT =162      Function.getBinaryContext().getUniqueSectionByName(".got");163  if (!GOT || !GOT->getSize())164    return false;165 166  const uint64_t GOTFirstPageAddress = GOT->getAddress() & ~0xfffULL;167  const uint64_t GOTLastPageAddress =168      (GOT->getAddress() + GOT->getSize() - 1) & ~0xfffULL;169 170  return PageAddress >= GOTFirstPageAddress &&171         PageAddress <= GOTLastPageAddress;172}173 174void AArch64MCSymbolizer::tryAddingPcLoadReferenceComment(raw_ostream &CStream,175                                                          int64_t Value,176                                                          uint64_t Address) {}177 178} // namespace bolt179} // namespace llvm180