brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.4 KiB · 9b33e78 Raw
585 lines · cpp
1//===-- Hexagon.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 "InputFiles.h"10#include "OutputSections.h"11#include "Symbols.h"12#include "SyntheticSections.h"13#include "Target.h"14#include "Thunks.h"15#include "lld/Common/ErrorHandler.h"16#include "llvm/ADT/SmallVector.h"17#include "llvm/BinaryFormat/ELF.h"18#include "llvm/Support/ELFAttributes.h"19#include "llvm/Support/Endian.h"20#include "llvm/Support/HexagonAttributeParser.h"21#include "llvm/Support/HexagonAttributes.h"22#include "llvm/Support/LEB128.h"23 24using namespace llvm;25using namespace llvm::object;26using namespace llvm::support::endian;27using namespace llvm::ELF;28using namespace lld;29using namespace lld::elf;30 31namespace {32class Hexagon final : public TargetInfo {33public:34  Hexagon(Ctx &);35  uint32_t calcEFlags() const override;36  RelExpr getRelExpr(RelType type, const Symbol &s,37                     const uint8_t *loc) const override;38  RelType getDynRel(RelType type) const override;39  int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;40  bool needsThunk(RelExpr expr, RelType type, const InputFile *file,41                  uint64_t branchAddr, const Symbol &s,42                  int64_t a) const override;43  bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override;44  void relocate(uint8_t *loc, const Relocation &rel,45                uint64_t val) const override;46  void writePltHeader(uint8_t *buf) const override;47  void writePlt(uint8_t *buf, const Symbol &sym,48                uint64_t pltEntryAddr) const override;49};50} // namespace51 52Hexagon::Hexagon(Ctx &ctx) : TargetInfo(ctx) {53  pltRel = R_HEX_JMP_SLOT;54  relativeRel = R_HEX_RELATIVE;55  gotRel = R_HEX_GLOB_DAT;56  symbolicRel = R_HEX_32;57 58  gotBaseSymInGotPlt = true;59  // The zero'th GOT entry is reserved for the address of _DYNAMIC.  The60  // next 3 are reserved for the dynamic loader.61  gotPltHeaderEntriesNum = 4;62 63  pltEntrySize = 16;64  pltHeaderSize = 32;65 66  // Hexagon Linux uses 64K pages by default.67  defaultMaxPageSize = 0x10000;68  tlsGotRel = R_HEX_TPREL_32;69  tlsModuleIndexRel = R_HEX_DTPMOD_32;70  tlsOffsetRel = R_HEX_DTPREL_32;71 72  needsThunks = true;73}74 75uint32_t Hexagon::calcEFlags() const {76  // The architecture revision must always be equal to or greater than77  // greatest revision in the list of inputs.78  std::optional<uint32_t> ret;79  for (InputFile *f : ctx.objectFiles) {80    uint32_t eflags = cast<ObjFile<ELF32LE>>(f)->getObj().getHeader().e_flags;81    if (!ret || eflags > *ret)82      ret = eflags;83  }84  return ret.value_or(/* Default Arch Rev: */ EF_HEXAGON_MACH_V68);85}86 87static uint32_t applyMask(uint32_t mask, uint32_t data) {88  uint32_t result = 0;89  size_t off = 0;90 91  for (size_t bit = 0; bit != 32; ++bit) {92    uint32_t valBit = (data >> off) & 1;93    uint32_t maskBit = (mask >> bit) & 1;94    if (maskBit) {95      result |= (valBit << bit);96      ++off;97    }98  }99  return result;100}101 102RelExpr Hexagon::getRelExpr(RelType type, const Symbol &s,103                            const uint8_t *loc) const {104  switch (type) {105  case R_HEX_NONE:106    return R_NONE;107  case R_HEX_6_X:108  case R_HEX_8_X:109  case R_HEX_9_X:110  case R_HEX_10_X:111  case R_HEX_11_X:112  case R_HEX_12_X:113  case R_HEX_16_X:114  case R_HEX_32:115  case R_HEX_32_6_X:116  case R_HEX_HI16:117  case R_HEX_LO16:118  case R_HEX_DTPREL_32:119    return R_ABS;120  case R_HEX_B9_PCREL:121  case R_HEX_B13_PCREL:122  case R_HEX_B15_PCREL:123  case R_HEX_6_PCREL_X:124  case R_HEX_32_PCREL:125    return R_PC;126  case R_HEX_B9_PCREL_X:127  case R_HEX_B15_PCREL_X:128  case R_HEX_B22_PCREL:129  case R_HEX_PLT_B22_PCREL:130  case R_HEX_B22_PCREL_X:131  case R_HEX_B32_PCREL_X:132  case R_HEX_GD_PLT_B22_PCREL:133  case R_HEX_GD_PLT_B22_PCREL_X:134  case R_HEX_GD_PLT_B32_PCREL_X:135    return R_PLT_PC;136  case R_HEX_IE_32_6_X:137  case R_HEX_IE_16_X:138  case R_HEX_IE_HI16:139  case R_HEX_IE_LO16:140    return R_GOT;141  case R_HEX_GD_GOT_11_X:142  case R_HEX_GD_GOT_16_X:143  case R_HEX_GD_GOT_32_6_X:144    return R_TLSGD_GOTPLT;145  case R_HEX_GOTREL_11_X:146  case R_HEX_GOTREL_16_X:147  case R_HEX_GOTREL_32_6_X:148  case R_HEX_GOTREL_HI16:149  case R_HEX_GOTREL_LO16:150    return R_GOTPLTREL;151  case R_HEX_GOT_11_X:152  case R_HEX_GOT_16_X:153  case R_HEX_GOT_32_6_X:154    return R_GOTPLT;155  case R_HEX_IE_GOT_11_X:156  case R_HEX_IE_GOT_16_X:157  case R_HEX_IE_GOT_32_6_X:158  case R_HEX_IE_GOT_HI16:159  case R_HEX_IE_GOT_LO16:160    return R_GOTPLT;161  case R_HEX_TPREL_11_X:162  case R_HEX_TPREL_16:163  case R_HEX_TPREL_16_X:164  case R_HEX_TPREL_32_6_X:165  case R_HEX_TPREL_HI16:166  case R_HEX_TPREL_LO16:167    return R_TPREL;168  default:169    Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v170             << ") against symbol " << &s;171    return R_NONE;172  }173}174 175// There are (arguably too) many relocation masks for the DSP's176// R_HEX_6_X type.  The table below is used to select the correct mask177// for the given instruction.178struct InstructionMask {179  uint32_t cmpMask;180  uint32_t relocMask;181};182static const InstructionMask r6[] = {183    {0x38000000, 0x0000201f}, {0x39000000, 0x0000201f},184    {0x3e000000, 0x00001f80}, {0x3f000000, 0x00001f80},185    {0x40000000, 0x000020f8}, {0x41000000, 0x000007e0},186    {0x42000000, 0x000020f8}, {0x43000000, 0x000007e0},187    {0x44000000, 0x000020f8}, {0x45000000, 0x000007e0},188    {0x46000000, 0x000020f8}, {0x47000000, 0x000007e0},189    {0x6a000000, 0x00001f80}, {0x7c000000, 0x001f2000},190    {0x9a000000, 0x00000f60}, {0x9b000000, 0x00000f60},191    {0x9c000000, 0x00000f60}, {0x9d000000, 0x00000f60},192    {0x9f000000, 0x001f0100}, {0xab000000, 0x0000003f},193    {0xad000000, 0x0000003f}, {0xaf000000, 0x00030078},194    {0xd7000000, 0x006020e0}, {0xd8000000, 0x006020e0},195    {0xdb000000, 0x006020e0}, {0xdf000000, 0x006020e0}};196 197constexpr uint32_t instParsePacketEnd = 0x0000c000;198 199static bool isDuplex(uint32_t insn) {200  // Duplex forms have a fixed mask and parse bits 15:14 are always201  // zero.  Non-duplex insns will always have at least one bit set in the202  // parse field.203  return (instParsePacketEnd & insn) == 0;204}205 206static uint32_t findMaskR6(Ctx &ctx, uint32_t insn) {207  if (isDuplex(insn))208    return 0x03f00000;209 210  for (InstructionMask i : r6)211    if ((0xff000000 & insn) == i.cmpMask)212      return i.relocMask;213 214  Err(ctx) << "unrecognized instruction for 6_X relocation: 0x"215           << utohexstr(insn, true);216  return 0;217}218 219static uint32_t findMaskR8(uint32_t insn) {220  if ((0xff000000 & insn) == 0xde000000)221    return 0x00e020e8;222  if ((0xff000000 & insn) == 0x3c000000)223    return 0x0000207f;224  return 0x00001fe0;225}226 227static uint32_t findMaskR11(uint32_t insn) {228  if ((0xff000000 & insn) == 0xa1000000)229    return 0x060020ff;230  return 0x06003fe0;231}232 233static uint32_t findMaskR16(Ctx &ctx, uint32_t insn) {234  if (isDuplex(insn))235    return 0x03f00000;236 237  // Clear the end-packet-parse bits:238  insn = insn & ~instParsePacketEnd;239 240  if ((0xff000000 & insn) == 0x48000000)241    return 0x061f20ff;242  if ((0xff000000 & insn) == 0x49000000)243    return 0x061f3fe0;244  if ((0xff000000 & insn) == 0x78000000)245    return 0x00df3fe0;246  if ((0xff000000 & insn) == 0xb0000000)247    return 0x0fe03fe0;248 249  if ((0xff802000 & insn) == 0x74000000)250    return 0x00001fe0;251  if ((0xff802000 & insn) == 0x74002000)252    return 0x00001fe0;253  if ((0xff802000 & insn) == 0x74800000)254    return 0x00001fe0;255  if ((0xff802000 & insn) == 0x74802000)256    return 0x00001fe0;257 258  for (InstructionMask i : r6)259    if ((0xff000000 & insn) == i.cmpMask)260      return i.relocMask;261 262  Err(ctx) << "unrecognized instruction for 16_X type: 0x" << utohexstr(insn);263  return 0;264}265 266static void or32le(uint8_t *p, int32_t v) { write32le(p, read32le(p) | v); }267 268bool Hexagon::inBranchRange(RelType type, uint64_t src, uint64_t dst) const {269  int64_t offset = dst - src;270  switch (type) {271  case llvm::ELF::R_HEX_B22_PCREL:272  case llvm::ELF::R_HEX_PLT_B22_PCREL:273  case llvm::ELF::R_HEX_GD_PLT_B22_PCREL:274  case llvm::ELF::R_HEX_LD_PLT_B22_PCREL:275    return llvm::isInt<22>(offset >> 2);276  case llvm::ELF::R_HEX_B15_PCREL:277    return llvm::isInt<15>(offset >> 2);278    break;279  case llvm::ELF::R_HEX_B13_PCREL:280    return llvm::isInt<13>(offset >> 2);281    break;282  case llvm::ELF::R_HEX_B9_PCREL:283    return llvm::isInt<9>(offset >> 2);284  default:285    return true;286  }287  llvm_unreachable("unsupported relocation");288}289 290bool Hexagon::needsThunk(RelExpr expr, RelType type, const InputFile *file,291                         uint64_t branchAddr, const Symbol &s,292                         int64_t a) const {293  // Only check branch range for supported branch relocation types294  switch (type) {295  case R_HEX_B22_PCREL:296  case R_HEX_PLT_B22_PCREL:297  case R_HEX_GD_PLT_B22_PCREL:298  case R_HEX_LD_PLT_B22_PCREL:299  case R_HEX_B15_PCREL:300  case R_HEX_B13_PCREL:301  case R_HEX_B9_PCREL:302    return !ctx.target->inBranchRange(type, branchAddr, s.getVA(ctx, a));303  default:304    return false;305  }306}307 308void Hexagon::relocate(uint8_t *loc, const Relocation &rel,309                       uint64_t val) const {310  switch (rel.type) {311  case R_HEX_NONE:312    break;313  case R_HEX_6_PCREL_X:314  case R_HEX_6_X:315    or32le(loc, applyMask(findMaskR6(ctx, read32le(loc)), val));316    break;317  case R_HEX_8_X:318    or32le(loc, applyMask(findMaskR8(read32le(loc)), val));319    break;320  case R_HEX_9_X:321    or32le(loc, applyMask(0x00003fe0, val & 0x3f));322    break;323  case R_HEX_10_X:324    or32le(loc, applyMask(0x00203fe0, val & 0x3f));325    break;326  case R_HEX_11_X:327  case R_HEX_GD_GOT_11_X:328  case R_HEX_IE_GOT_11_X:329  case R_HEX_GOT_11_X:330  case R_HEX_GOTREL_11_X:331  case R_HEX_TPREL_11_X:332    or32le(loc, applyMask(findMaskR11(read32le(loc)), val & 0x3f));333    break;334  case R_HEX_12_X:335    or32le(loc, applyMask(0x000007e0, val));336    break;337  case R_HEX_16_X: // These relocs only have 6 effective bits.338  case R_HEX_IE_16_X:339  case R_HEX_IE_GOT_16_X:340  case R_HEX_GD_GOT_16_X:341  case R_HEX_GOT_16_X:342  case R_HEX_GOTREL_16_X:343  case R_HEX_TPREL_16_X:344    or32le(loc, applyMask(findMaskR16(ctx, read32le(loc)), val & 0x3f));345    break;346  case R_HEX_TPREL_16:347    or32le(loc, applyMask(findMaskR16(ctx, read32le(loc)), val & 0xffff));348    break;349  case R_HEX_32:350  case R_HEX_32_PCREL:351  case R_HEX_DTPREL_32:352    or32le(loc, val);353    break;354  case R_HEX_32_6_X:355  case R_HEX_GD_GOT_32_6_X:356  case R_HEX_GOT_32_6_X:357  case R_HEX_GOTREL_32_6_X:358  case R_HEX_IE_GOT_32_6_X:359  case R_HEX_IE_32_6_X:360  case R_HEX_TPREL_32_6_X:361    or32le(loc, applyMask(0x0fff3fff, val >> 6));362    break;363  case R_HEX_B9_PCREL:364    checkInt(ctx, loc, val, 11, rel);365    or32le(loc, applyMask(0x003000fe, val >> 2));366    break;367  case R_HEX_B9_PCREL_X:368    or32le(loc, applyMask(0x003000fe, val & 0x3f));369    break;370  case R_HEX_B13_PCREL:371    checkInt(ctx, loc, val, 15, rel);372    or32le(loc, applyMask(0x00202ffe, val >> 2));373    break;374  case R_HEX_B15_PCREL:375    checkInt(ctx, loc, val, 17, rel);376    or32le(loc, applyMask(0x00df20fe, val >> 2));377    break;378  case R_HEX_B15_PCREL_X:379    or32le(loc, applyMask(0x00df20fe, val & 0x3f));380    break;381  case R_HEX_B22_PCREL:382  case R_HEX_GD_PLT_B22_PCREL:383  case R_HEX_PLT_B22_PCREL:384    checkInt(ctx, loc, val, 24, rel);385    or32le(loc, applyMask(0x1ff3ffe, val >> 2));386    break;387  case R_HEX_B22_PCREL_X:388  case R_HEX_GD_PLT_B22_PCREL_X:389    or32le(loc, applyMask(0x1ff3ffe, val & 0x3f));390    break;391  case R_HEX_B32_PCREL_X:392  case R_HEX_GD_PLT_B32_PCREL_X:393    or32le(loc, applyMask(0x0fff3fff, val >> 6));394    break;395  case R_HEX_GOTREL_HI16:396  case R_HEX_HI16:397  case R_HEX_IE_GOT_HI16:398  case R_HEX_IE_HI16:399  case R_HEX_TPREL_HI16:400    or32le(loc, applyMask(0x00c03fff, val >> 16));401    break;402  case R_HEX_GOTREL_LO16:403  case R_HEX_LO16:404  case R_HEX_IE_GOT_LO16:405  case R_HEX_IE_LO16:406  case R_HEX_TPREL_LO16:407    or32le(loc, applyMask(0x00c03fff, val));408    break;409  default:410    llvm_unreachable("unknown relocation");411  }412}413 414void Hexagon::writePltHeader(uint8_t *buf) const {415  const uint8_t pltData[] = {416      0x00, 0x40, 0x00, 0x00, // { immext (#0)417      0x1c, 0xc0, 0x49, 0x6a, //   r28 = add (pc, ##GOT0@PCREL) } # @GOT0418      0x0e, 0x42, 0x9c, 0xe2, // { r14 -= add (r28, #16)  # offset of GOTn419      0x4f, 0x40, 0x9c, 0x91, //   r15 = memw (r28 + #8)  # object ID at GOT2420      0x3c, 0xc0, 0x9c, 0x91, //   r28 = memw (r28 + #4) }# dynamic link at GOT1421      0x0e, 0x42, 0x0e, 0x8c, // { r14 = asr (r14, #2)    # index of PLTn422      0x00, 0xc0, 0x9c, 0x52, //   jumpr r28 }            # call dynamic linker423      0x0c, 0xdb, 0x00, 0x54, // trap0(#0xdb) # bring plt0 into 16byte alignment424  };425  memcpy(buf, pltData, sizeof(pltData));426 427  // Offset from PLT0 to the GOT.428  uint64_t off = ctx.in.gotPlt->getVA() - ctx.in.plt->getVA();429  relocateNoSym(buf, R_HEX_B32_PCREL_X, off);430  relocateNoSym(buf + 4, R_HEX_6_PCREL_X, off);431}432 433void Hexagon::writePlt(uint8_t *buf, const Symbol &sym,434                       uint64_t pltEntryAddr) const {435  const uint8_t inst[] = {436      0x00, 0x40, 0x00, 0x00, // { immext (#0)437      0x0e, 0xc0, 0x49, 0x6a, //   r14 = add (pc, ##GOTn@PCREL) }438      0x1c, 0xc0, 0x8e, 0x91, // r28 = memw (r14)439      0x00, 0xc0, 0x9c, 0x52, // jumpr r28440  };441  memcpy(buf, inst, sizeof(inst));442 443  uint64_t gotPltEntryAddr = sym.getGotPltVA(ctx);444  relocateNoSym(buf, R_HEX_B32_PCREL_X, gotPltEntryAddr - pltEntryAddr);445  relocateNoSym(buf + 4, R_HEX_6_PCREL_X, gotPltEntryAddr - pltEntryAddr);446}447 448RelType Hexagon::getDynRel(RelType type) const {449  if (type == R_HEX_32)450    return type;451  return R_HEX_NONE;452}453 454int64_t Hexagon::getImplicitAddend(const uint8_t *buf, RelType type) const {455  switch (type) {456  case R_HEX_NONE:457  case R_HEX_GLOB_DAT:458  case R_HEX_JMP_SLOT:459    return 0;460  case R_HEX_32:461  case R_HEX_RELATIVE:462  case R_HEX_DTPMOD_32:463  case R_HEX_DTPREL_32:464  case R_HEX_TPREL_32:465    return SignExtend64<32>(read32(ctx, buf));466  default:467    InternalErr(ctx, buf) << "cannot read addend for relocation " << type;468    return 0;469  }470}471 472namespace {473class HexagonAttributesSection final : public SyntheticSection {474public:475  HexagonAttributesSection(Ctx &ctx)476      : SyntheticSection(ctx, ".hexagon.attributes", SHT_HEXAGON_ATTRIBUTES, 0,477                         1) {}478 479  size_t getSize() const override { return size; }480  void writeTo(uint8_t *buf) override;481 482  static constexpr StringRef vendor = "hexagon";483  DenseMap<unsigned, unsigned> intAttr;484  size_t size = 0;485};486} // namespace487 488static HexagonAttributesSection *489mergeAttributesSection(Ctx &ctx,490                       const SmallVector<InputSectionBase *, 0> &sections) {491  ctx.in.hexagonAttributes = std::make_unique<HexagonAttributesSection>(ctx);492  auto &merged =493      static_cast<HexagonAttributesSection &>(*ctx.in.hexagonAttributes);494 495  // Collect all tags values from attributes section.496  const auto &attributesTags = HexagonAttrs::getHexagonAttributeTags();497  for (const InputSectionBase *sec : sections) {498    HexagonAttributeParser parser;499    if (Error e = parser.parse(sec->content(), llvm::endianness::little))500      Warn(ctx) << sec << ": " << std::move(e);501    for (const auto &tag : attributesTags) {502      switch (HexagonAttrs::AttrType(tag.attr)) {503      case HexagonAttrs::ARCH:504      case HexagonAttrs::HVXARCH:505        if (auto i = parser.getAttributeValue(tag.attr)) {506          auto r = merged.intAttr.try_emplace(tag.attr, *i);507          if (!r.second)508            if (r.first->second < *i)509              r.first->second = *i;510        }511        continue;512 513      case HexagonAttrs::HVXIEEEFP:514      case HexagonAttrs::HVXQFLOAT:515      case HexagonAttrs::ZREG:516      case HexagonAttrs::AUDIO:517      case HexagonAttrs::CABAC:518        if (auto i = parser.getAttributeValue(tag.attr)) {519          auto r = merged.intAttr.try_emplace(tag.attr, *i);520          if (!r.second && r.first->second != *i) {521            r.first->second |= *i;522          }523        }524        continue;525      }526    }527  }528 529  // The total size of headers: format-version [ <section-length> "vendor-name"530  // [ <file-tag> <size>.531  size_t size = 5 + merged.vendor.size() + 1 + 5;532  for (auto &attr : merged.intAttr)533    if (attr.second != 0)534      size += getULEB128Size(attr.first) + getULEB128Size(attr.second);535  merged.size = size;536  return &merged;537}538 539void HexagonAttributesSection::writeTo(uint8_t *buf) {540  const size_t size = getSize();541  uint8_t *const end = buf + size;542  *buf = ELFAttrs::Format_Version;543  write32(ctx, buf + 1, size - 1);544  buf += 5;545 546  memcpy(buf, vendor.data(), vendor.size());547  buf += vendor.size() + 1;548 549  *buf = ELFAttrs::File;550  write32(ctx, buf + 1, end - buf);551  buf += 5;552 553  for (auto &attr : intAttr) {554    if (attr.second == 0)555      continue;556    buf += encodeULEB128(attr.first, buf);557    buf += encodeULEB128(attr.second, buf);558  }559}560 561void elf::mergeHexagonAttributesSections(Ctx &ctx) {562  // Find the first input SHT_HEXAGON_ATTRIBUTES; return if not found.563  size_t place =564      llvm::find_if(ctx.inputSections,565                    [](auto *s) { return s->type == SHT_HEXAGON_ATTRIBUTES; }) -566      ctx.inputSections.begin();567  if (place == ctx.inputSections.size())568    return;569 570  // Extract all SHT_HEXAGON_ATTRIBUTES sections into `sections`.571  SmallVector<InputSectionBase *, 0> sections;572  llvm::erase_if(ctx.inputSections, [&](InputSectionBase *s) {573    if (s->type != SHT_HEXAGON_ATTRIBUTES)574      return false;575    sections.push_back(s);576    return true;577  });578 579  // Add the merged section.580  ctx.inputSections.insert(ctx.inputSections.begin() + place,581                           mergeAttributesSection(ctx, sections));582}583 584void elf::setHexagonTargetInfo(Ctx &ctx) { ctx.target.reset(new Hexagon(ctx)); }585