Path: blob/main/contrib/llvm-project/lld/ELF/Arch/Hexagon.cpp
34878 views
//===-- Hexagon.cpp -------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "InputFiles.h"9#include "Symbols.h"10#include "SyntheticSections.h"11#include "Target.h"12#include "lld/Common/ErrorHandler.h"13#include "llvm/BinaryFormat/ELF.h"14#include "llvm/Support/Endian.h"1516using namespace llvm;17using namespace llvm::object;18using namespace llvm::support::endian;19using namespace llvm::ELF;20using namespace lld;21using namespace lld::elf;2223namespace {24class Hexagon final : public TargetInfo {25public:26Hexagon();27uint32_t calcEFlags() const override;28RelExpr getRelExpr(RelType type, const Symbol &s,29const uint8_t *loc) const override;30RelType getDynRel(RelType type) const override;31int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;32void relocate(uint8_t *loc, const Relocation &rel,33uint64_t val) const override;34void writePltHeader(uint8_t *buf) const override;35void writePlt(uint8_t *buf, const Symbol &sym,36uint64_t pltEntryAddr) const override;37};38} // namespace3940Hexagon::Hexagon() {41pltRel = R_HEX_JMP_SLOT;42relativeRel = R_HEX_RELATIVE;43gotRel = R_HEX_GLOB_DAT;44symbolicRel = R_HEX_32;4546gotBaseSymInGotPlt = true;47// The zero'th GOT entry is reserved for the address of _DYNAMIC. The48// next 3 are reserved for the dynamic loader.49gotPltHeaderEntriesNum = 4;5051pltEntrySize = 16;52pltHeaderSize = 32;5354// Hexagon Linux uses 64K pages by default.55defaultMaxPageSize = 0x10000;56tlsGotRel = R_HEX_TPREL_32;57tlsModuleIndexRel = R_HEX_DTPMOD_32;58tlsOffsetRel = R_HEX_DTPREL_32;59}6061uint32_t Hexagon::calcEFlags() const {62// The architecture revision must always be equal to or greater than63// greatest revision in the list of inputs.64std::optional<uint32_t> ret;65for (InputFile *f : ctx.objectFiles) {66uint32_t eflags = cast<ObjFile<ELF32LE>>(f)->getObj().getHeader().e_flags;67if (!ret || eflags > *ret)68ret = eflags;69}70return ret.value_or(/* Default Arch Rev: */ 0x60);71}7273static uint32_t applyMask(uint32_t mask, uint32_t data) {74uint32_t result = 0;75size_t off = 0;7677for (size_t bit = 0; bit != 32; ++bit) {78uint32_t valBit = (data >> off) & 1;79uint32_t maskBit = (mask >> bit) & 1;80if (maskBit) {81result |= (valBit << bit);82++off;83}84}85return result;86}8788RelExpr Hexagon::getRelExpr(RelType type, const Symbol &s,89const uint8_t *loc) const {90switch (type) {91case R_HEX_NONE:92return R_NONE;93case R_HEX_6_X:94case R_HEX_8_X:95case R_HEX_9_X:96case R_HEX_10_X:97case R_HEX_11_X:98case R_HEX_12_X:99case R_HEX_16_X:100case R_HEX_32:101case R_HEX_32_6_X:102case R_HEX_HI16:103case R_HEX_LO16:104case R_HEX_DTPREL_32:105return R_ABS;106case R_HEX_B9_PCREL:107case R_HEX_B13_PCREL:108case R_HEX_B15_PCREL:109case R_HEX_6_PCREL_X:110case R_HEX_32_PCREL:111return R_PC;112case R_HEX_B9_PCREL_X:113case R_HEX_B15_PCREL_X:114case R_HEX_B22_PCREL:115case R_HEX_PLT_B22_PCREL:116case R_HEX_B22_PCREL_X:117case R_HEX_B32_PCREL_X:118case R_HEX_GD_PLT_B22_PCREL:119case R_HEX_GD_PLT_B22_PCREL_X:120case R_HEX_GD_PLT_B32_PCREL_X:121return R_PLT_PC;122case R_HEX_IE_32_6_X:123case R_HEX_IE_16_X:124case R_HEX_IE_HI16:125case R_HEX_IE_LO16:126return R_GOT;127case R_HEX_GD_GOT_11_X:128case R_HEX_GD_GOT_16_X:129case R_HEX_GD_GOT_32_6_X:130return R_TLSGD_GOTPLT;131case R_HEX_GOTREL_11_X:132case R_HEX_GOTREL_16_X:133case R_HEX_GOTREL_32_6_X:134case R_HEX_GOTREL_HI16:135case R_HEX_GOTREL_LO16:136return R_GOTPLTREL;137case R_HEX_GOT_11_X:138case R_HEX_GOT_16_X:139case R_HEX_GOT_32_6_X:140return R_GOTPLT;141case R_HEX_IE_GOT_11_X:142case R_HEX_IE_GOT_16_X:143case R_HEX_IE_GOT_32_6_X:144case R_HEX_IE_GOT_HI16:145case R_HEX_IE_GOT_LO16:146return R_GOTPLT;147case R_HEX_TPREL_11_X:148case R_HEX_TPREL_16:149case R_HEX_TPREL_16_X:150case R_HEX_TPREL_32_6_X:151case R_HEX_TPREL_HI16:152case R_HEX_TPREL_LO16:153return R_TPREL;154default:155error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +156") against symbol " + toString(s));157return R_NONE;158}159}160161// There are (arguably too) many relocation masks for the DSP's162// R_HEX_6_X type. The table below is used to select the correct mask163// for the given instruction.164struct InstructionMask {165uint32_t cmpMask;166uint32_t relocMask;167};168static const InstructionMask r6[] = {169{0x38000000, 0x0000201f}, {0x39000000, 0x0000201f},170{0x3e000000, 0x00001f80}, {0x3f000000, 0x00001f80},171{0x40000000, 0x000020f8}, {0x41000000, 0x000007e0},172{0x42000000, 0x000020f8}, {0x43000000, 0x000007e0},173{0x44000000, 0x000020f8}, {0x45000000, 0x000007e0},174{0x46000000, 0x000020f8}, {0x47000000, 0x000007e0},175{0x6a000000, 0x00001f80}, {0x7c000000, 0x001f2000},176{0x9a000000, 0x00000f60}, {0x9b000000, 0x00000f60},177{0x9c000000, 0x00000f60}, {0x9d000000, 0x00000f60},178{0x9f000000, 0x001f0100}, {0xab000000, 0x0000003f},179{0xad000000, 0x0000003f}, {0xaf000000, 0x00030078},180{0xd7000000, 0x006020e0}, {0xd8000000, 0x006020e0},181{0xdb000000, 0x006020e0}, {0xdf000000, 0x006020e0}};182183constexpr uint32_t instParsePacketEnd = 0x0000c000;184185static bool isDuplex(uint32_t insn) {186// Duplex forms have a fixed mask and parse bits 15:14 are always187// zero. Non-duplex insns will always have at least one bit set in the188// parse field.189return (instParsePacketEnd & insn) == 0;190}191192static uint32_t findMaskR6(uint32_t insn) {193if (isDuplex(insn))194return 0x03f00000;195196for (InstructionMask i : r6)197if ((0xff000000 & insn) == i.cmpMask)198return i.relocMask;199200error("unrecognized instruction for 6_X relocation: 0x" +201utohexstr(insn));202return 0;203}204205static uint32_t findMaskR8(uint32_t insn) {206if ((0xff000000 & insn) == 0xde000000)207return 0x00e020e8;208if ((0xff000000 & insn) == 0x3c000000)209return 0x0000207f;210return 0x00001fe0;211}212213static uint32_t findMaskR11(uint32_t insn) {214if ((0xff000000 & insn) == 0xa1000000)215return 0x060020ff;216return 0x06003fe0;217}218219static uint32_t findMaskR16(uint32_t insn) {220if (isDuplex(insn))221return 0x03f00000;222223// Clear the end-packet-parse bits:224insn = insn & ~instParsePacketEnd;225226if ((0xff000000 & insn) == 0x48000000)227return 0x061f20ff;228if ((0xff000000 & insn) == 0x49000000)229return 0x061f3fe0;230if ((0xff000000 & insn) == 0x78000000)231return 0x00df3fe0;232if ((0xff000000 & insn) == 0xb0000000)233return 0x0fe03fe0;234235if ((0xff802000 & insn) == 0x74000000)236return 0x00001fe0;237if ((0xff802000 & insn) == 0x74002000)238return 0x00001fe0;239if ((0xff802000 & insn) == 0x74800000)240return 0x00001fe0;241if ((0xff802000 & insn) == 0x74802000)242return 0x00001fe0;243244for (InstructionMask i : r6)245if ((0xff000000 & insn) == i.cmpMask)246return i.relocMask;247248error("unrecognized instruction for 16_X type: 0x" +249utohexstr(insn));250return 0;251}252253static void or32le(uint8_t *p, int32_t v) { write32le(p, read32le(p) | v); }254255void Hexagon::relocate(uint8_t *loc, const Relocation &rel,256uint64_t val) const {257switch (rel.type) {258case R_HEX_NONE:259break;260case R_HEX_6_PCREL_X:261case R_HEX_6_X:262or32le(loc, applyMask(findMaskR6(read32le(loc)), val));263break;264case R_HEX_8_X:265or32le(loc, applyMask(findMaskR8(read32le(loc)), val));266break;267case R_HEX_9_X:268or32le(loc, applyMask(0x00003fe0, val & 0x3f));269break;270case R_HEX_10_X:271or32le(loc, applyMask(0x00203fe0, val & 0x3f));272break;273case R_HEX_11_X:274case R_HEX_GD_GOT_11_X:275case R_HEX_IE_GOT_11_X:276case R_HEX_GOT_11_X:277case R_HEX_GOTREL_11_X:278case R_HEX_TPREL_11_X:279or32le(loc, applyMask(findMaskR11(read32le(loc)), val & 0x3f));280break;281case R_HEX_12_X:282or32le(loc, applyMask(0x000007e0, val));283break;284case R_HEX_16_X: // These relocs only have 6 effective bits.285case R_HEX_IE_16_X:286case R_HEX_IE_GOT_16_X:287case R_HEX_GD_GOT_16_X:288case R_HEX_GOT_16_X:289case R_HEX_GOTREL_16_X:290case R_HEX_TPREL_16_X:291or32le(loc, applyMask(findMaskR16(read32le(loc)), val & 0x3f));292break;293case R_HEX_TPREL_16:294or32le(loc, applyMask(findMaskR16(read32le(loc)), val & 0xffff));295break;296case R_HEX_32:297case R_HEX_32_PCREL:298case R_HEX_DTPREL_32:299or32le(loc, val);300break;301case R_HEX_32_6_X:302case R_HEX_GD_GOT_32_6_X:303case R_HEX_GOT_32_6_X:304case R_HEX_GOTREL_32_6_X:305case R_HEX_IE_GOT_32_6_X:306case R_HEX_IE_32_6_X:307case R_HEX_TPREL_32_6_X:308or32le(loc, applyMask(0x0fff3fff, val >> 6));309break;310case R_HEX_B9_PCREL:311checkInt(loc, val, 11, rel);312or32le(loc, applyMask(0x003000fe, val >> 2));313break;314case R_HEX_B9_PCREL_X:315or32le(loc, applyMask(0x003000fe, val & 0x3f));316break;317case R_HEX_B13_PCREL:318checkInt(loc, val, 15, rel);319or32le(loc, applyMask(0x00202ffe, val >> 2));320break;321case R_HEX_B15_PCREL:322checkInt(loc, val, 17, rel);323or32le(loc, applyMask(0x00df20fe, val >> 2));324break;325case R_HEX_B15_PCREL_X:326or32le(loc, applyMask(0x00df20fe, val & 0x3f));327break;328case R_HEX_B22_PCREL:329case R_HEX_GD_PLT_B22_PCREL:330case R_HEX_PLT_B22_PCREL:331checkInt(loc, val, 24, rel);332or32le(loc, applyMask(0x1ff3ffe, val >> 2));333break;334case R_HEX_B22_PCREL_X:335case R_HEX_GD_PLT_B22_PCREL_X:336or32le(loc, applyMask(0x1ff3ffe, val & 0x3f));337break;338case R_HEX_B32_PCREL_X:339case R_HEX_GD_PLT_B32_PCREL_X:340or32le(loc, applyMask(0x0fff3fff, val >> 6));341break;342case R_HEX_GOTREL_HI16:343case R_HEX_HI16:344case R_HEX_IE_GOT_HI16:345case R_HEX_IE_HI16:346case R_HEX_TPREL_HI16:347or32le(loc, applyMask(0x00c03fff, val >> 16));348break;349case R_HEX_GOTREL_LO16:350case R_HEX_LO16:351case R_HEX_IE_GOT_LO16:352case R_HEX_IE_LO16:353case R_HEX_TPREL_LO16:354or32le(loc, applyMask(0x00c03fff, val));355break;356default:357llvm_unreachable("unknown relocation");358}359}360361void Hexagon::writePltHeader(uint8_t *buf) const {362const uint8_t pltData[] = {3630x00, 0x40, 0x00, 0x00, // { immext (#0)3640x1c, 0xc0, 0x49, 0x6a, // r28 = add (pc, ##GOT0@PCREL) } # @GOT03650x0e, 0x42, 0x9c, 0xe2, // { r14 -= add (r28, #16) # offset of GOTn3660x4f, 0x40, 0x9c, 0x91, // r15 = memw (r28 + #8) # object ID at GOT23670x3c, 0xc0, 0x9c, 0x91, // r28 = memw (r28 + #4) }# dynamic link at GOT13680x0e, 0x42, 0x0e, 0x8c, // { r14 = asr (r14, #2) # index of PLTn3690x00, 0xc0, 0x9c, 0x52, // jumpr r28 } # call dynamic linker3700x0c, 0xdb, 0x00, 0x54, // trap0(#0xdb) # bring plt0 into 16byte alignment371};372memcpy(buf, pltData, sizeof(pltData));373374// Offset from PLT0 to the GOT.375uint64_t off = in.gotPlt->getVA() - in.plt->getVA();376relocateNoSym(buf, R_HEX_B32_PCREL_X, off);377relocateNoSym(buf + 4, R_HEX_6_PCREL_X, off);378}379380void Hexagon::writePlt(uint8_t *buf, const Symbol &sym,381uint64_t pltEntryAddr) const {382const uint8_t inst[] = {3830x00, 0x40, 0x00, 0x00, // { immext (#0)3840x0e, 0xc0, 0x49, 0x6a, // r14 = add (pc, ##GOTn@PCREL) }3850x1c, 0xc0, 0x8e, 0x91, // r28 = memw (r14)3860x00, 0xc0, 0x9c, 0x52, // jumpr r28387};388memcpy(buf, inst, sizeof(inst));389390uint64_t gotPltEntryAddr = sym.getGotPltVA();391relocateNoSym(buf, R_HEX_B32_PCREL_X, gotPltEntryAddr - pltEntryAddr);392relocateNoSym(buf + 4, R_HEX_6_PCREL_X, gotPltEntryAddr - pltEntryAddr);393}394395RelType Hexagon::getDynRel(RelType type) const {396if (type == R_HEX_32)397return type;398return R_HEX_NONE;399}400401int64_t Hexagon::getImplicitAddend(const uint8_t *buf, RelType type) const {402switch (type) {403case R_HEX_NONE:404case R_HEX_GLOB_DAT:405case R_HEX_JMP_SLOT:406return 0;407case R_HEX_32:408case R_HEX_RELATIVE:409case R_HEX_DTPMOD_32:410case R_HEX_DTPREL_32:411case R_HEX_TPREL_32:412return SignExtend64<32>(read32(buf));413default:414internalLinkerError(getErrorLocation(buf),415"cannot read addend for relocation " + toString(type));416return 0;417}418}419420TargetInfo *elf::getHexagonTargetInfo() {421static Hexagon target;422return ⌖423}424425426