1 //===-- Hexagon.cpp -------------------------------------------------------===// 2 // 3 // The LLVM Linker 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "InputFiles.h" 11 #include "Symbols.h" 12 #include "SyntheticSections.h" 13 #include "Target.h" 14 #include "lld/Common/ErrorHandler.h" 15 #include "llvm/BinaryFormat/ELF.h" 16 #include "llvm/Object/ELF.h" 17 #include "llvm/Support/Endian.h" 18 19 using namespace llvm; 20 using namespace llvm::object; 21 using namespace llvm::support::endian; 22 using namespace llvm::ELF; 23 using namespace lld; 24 using namespace lld::elf; 25 26 namespace { 27 class Hexagon final : public TargetInfo { 28 public: 29 Hexagon(); 30 uint32_t calcEFlags() const override; 31 RelExpr getRelExpr(RelType Type, const Symbol &S, 32 const uint8_t *Loc) const override; 33 void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; 34 void writePltHeader(uint8_t *Buf) const override; 35 void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, 36 int32_t Index, unsigned RelOff) const override; 37 }; 38 } // namespace 39 40 Hexagon::Hexagon() { 41 PltRel = R_HEX_JMP_SLOT; 42 RelativeRel = R_HEX_RELATIVE; 43 GotRel = R_HEX_GLOB_DAT; 44 GotEntrySize = 4; 45 // The zero'th GOT entry is reserved for the address of _DYNAMIC. The 46 // next 3 are reserved for the dynamic loader. 47 GotPltHeaderEntriesNum = 4; 48 GotPltEntrySize = 4; 49 50 PltEntrySize = 16; 51 PltHeaderSize = 32; 52 53 // Hexagon Linux uses 64K pages by default. 54 DefaultMaxPageSize = 0x10000; 55 NoneRel = R_HEX_NONE; 56 } 57 58 uint32_t Hexagon::calcEFlags() const { 59 assert(!ObjectFiles.empty()); 60 61 // The architecture revision must always be equal to or greater than 62 // greatest revision in the list of inputs. 63 uint32_t Ret = 0; 64 for (InputFile *F : ObjectFiles) { 65 uint32_t EFlags = cast<ObjFile<ELF32LE>>(F)->getObj().getHeader()->e_flags; 66 if (EFlags > Ret) 67 Ret = EFlags; 68 } 69 return Ret; 70 } 71 72 static uint32_t applyMask(uint32_t Mask, uint32_t Data) { 73 uint32_t Result = 0; 74 size_t Off = 0; 75 76 for (size_t Bit = 0; Bit != 32; ++Bit) { 77 uint32_t ValBit = (Data >> Off) & 1; 78 uint32_t MaskBit = (Mask >> Bit) & 1; 79 if (MaskBit) { 80 Result |= (ValBit << Bit); 81 ++Off; 82 } 83 } 84 return Result; 85 } 86 87 RelExpr Hexagon::getRelExpr(RelType Type, const Symbol &S, 88 const uint8_t *Loc) const { 89 switch (Type) { 90 case R_HEX_B9_PCREL: 91 case R_HEX_B9_PCREL_X: 92 case R_HEX_B13_PCREL: 93 case R_HEX_B15_PCREL: 94 case R_HEX_B15_PCREL_X: 95 case R_HEX_6_PCREL_X: 96 case R_HEX_32_PCREL: 97 return R_PC; 98 case R_HEX_B22_PCREL: 99 case R_HEX_PLT_B22_PCREL: 100 case R_HEX_B22_PCREL_X: 101 case R_HEX_B32_PCREL_X: 102 return R_PLT_PC; 103 case R_HEX_GOT_11_X: 104 case R_HEX_GOT_16_X: 105 case R_HEX_GOT_32_6_X: 106 return R_HEXAGON_GOT; 107 default: 108 return R_ABS; 109 } 110 } 111 112 static uint32_t findMaskR6(uint32_t Insn) { 113 // There are (arguably too) many relocation masks for the DSP's 114 // R_HEX_6_X type. The table below is used to select the correct mask 115 // for the given instruction. 116 struct InstructionMask { 117 uint32_t CmpMask; 118 uint32_t RelocMask; 119 }; 120 121 static const InstructionMask R6[] = { 122 {0x38000000, 0x0000201f}, {0x39000000, 0x0000201f}, 123 {0x3e000000, 0x00001f80}, {0x3f000000, 0x00001f80}, 124 {0x40000000, 0x000020f8}, {0x41000000, 0x000007e0}, 125 {0x42000000, 0x000020f8}, {0x43000000, 0x000007e0}, 126 {0x44000000, 0x000020f8}, {0x45000000, 0x000007e0}, 127 {0x46000000, 0x000020f8}, {0x47000000, 0x000007e0}, 128 {0x6a000000, 0x00001f80}, {0x7c000000, 0x001f2000}, 129 {0x9a000000, 0x00000f60}, {0x9b000000, 0x00000f60}, 130 {0x9c000000, 0x00000f60}, {0x9d000000, 0x00000f60}, 131 {0x9f000000, 0x001f0100}, {0xab000000, 0x0000003f}, 132 {0xad000000, 0x0000003f}, {0xaf000000, 0x00030078}, 133 {0xd7000000, 0x006020e0}, {0xd8000000, 0x006020e0}, 134 {0xdb000000, 0x006020e0}, {0xdf000000, 0x006020e0}}; 135 136 // Duplex forms have a fixed mask and parse bits 15:14 are always 137 // zero. Non-duplex insns will always have at least one bit set in the 138 // parse field. 139 if ((0xC000 & Insn) == 0x0) 140 return 0x03f00000; 141 142 for (InstructionMask I : R6) 143 if ((0xff000000 & Insn) == I.CmpMask) 144 return I.RelocMask; 145 146 error("unrecognized instruction for R_HEX_6 relocation: 0x" + 147 utohexstr(Insn)); 148 return 0; 149 } 150 151 static uint32_t findMaskR8(uint32_t Insn) { 152 if ((0xff000000 & Insn) == 0xde000000) 153 return 0x00e020e8; 154 if ((0xff000000 & Insn) == 0x3c000000) 155 return 0x0000207f; 156 return 0x00001fe0; 157 } 158 159 static uint32_t findMaskR11(uint32_t Insn) { 160 if ((0xff000000 & Insn) == 0xa1000000) 161 return 0x060020ff; 162 return 0x06003fe0; 163 } 164 165 static uint32_t findMaskR16(uint32_t Insn) { 166 if ((0xff000000 & Insn) == 0x48000000) 167 return 0x061f20ff; 168 if ((0xff000000 & Insn) == 0x49000000) 169 return 0x061f3fe0; 170 if ((0xff000000 & Insn) == 0x78000000) 171 return 0x00df3fe0; 172 if ((0xff000000 & Insn) == 0xb0000000) 173 return 0x0fe03fe0; 174 175 error("unrecognized instruction for R_HEX_16_X relocation: 0x" + 176 utohexstr(Insn)); 177 return 0; 178 } 179 180 static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); } 181 182 void Hexagon::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { 183 switch (Type) { 184 case R_HEX_NONE: 185 break; 186 case R_HEX_6_PCREL_X: 187 case R_HEX_6_X: 188 or32le(Loc, applyMask(findMaskR6(read32le(Loc)), Val)); 189 break; 190 case R_HEX_8_X: 191 or32le(Loc, applyMask(findMaskR8(read32le(Loc)), Val)); 192 break; 193 case R_HEX_9_X: 194 or32le(Loc, applyMask(0x00003fe0, Val & 0x3f)); 195 break; 196 case R_HEX_10_X: 197 or32le(Loc, applyMask(0x00203fe0, Val & 0x3f)); 198 break; 199 case R_HEX_11_X: 200 case R_HEX_GOT_11_X: 201 or32le(Loc, applyMask(findMaskR11(read32le(Loc)), Val & 0x3f)); 202 break; 203 case R_HEX_12_X: 204 or32le(Loc, applyMask(0x000007e0, Val)); 205 break; 206 case R_HEX_16_X: // These relocs only have 6 effective bits. 207 case R_HEX_GOT_16_X: 208 or32le(Loc, applyMask(findMaskR16(read32le(Loc)), Val & 0x3f)); 209 break; 210 case R_HEX_32: 211 case R_HEX_32_PCREL: 212 or32le(Loc, Val); 213 break; 214 case R_HEX_32_6_X: 215 case R_HEX_GOT_32_6_X: 216 or32le(Loc, applyMask(0x0fff3fff, Val >> 6)); 217 break; 218 case R_HEX_B9_PCREL: 219 or32le(Loc, applyMask(0x003000fe, Val >> 2)); 220 break; 221 case R_HEX_B9_PCREL_X: 222 or32le(Loc, applyMask(0x003000fe, Val & 0x3f)); 223 break; 224 case R_HEX_B13_PCREL: 225 or32le(Loc, applyMask(0x00202ffe, Val >> 2)); 226 break; 227 case R_HEX_B15_PCREL: 228 or32le(Loc, applyMask(0x00df20fe, Val >> 2)); 229 break; 230 case R_HEX_B15_PCREL_X: 231 or32le(Loc, applyMask(0x00df20fe, Val & 0x3f)); 232 break; 233 case R_HEX_B22_PCREL: 234 case R_HEX_PLT_B22_PCREL: 235 or32le(Loc, applyMask(0x1ff3ffe, Val >> 2)); 236 break; 237 case R_HEX_B22_PCREL_X: 238 or32le(Loc, applyMask(0x1ff3ffe, Val & 0x3f)); 239 break; 240 case R_HEX_B32_PCREL_X: 241 or32le(Loc, applyMask(0x0fff3fff, Val >> 6)); 242 break; 243 case R_HEX_HI16: 244 or32le(Loc, applyMask(0x00c03fff, Val >> 16)); 245 break; 246 case R_HEX_LO16: 247 or32le(Loc, applyMask(0x00c03fff, Val)); 248 break; 249 default: 250 error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type)); 251 break; 252 } 253 } 254 255 void Hexagon::writePltHeader(uint8_t *Buf) const { 256 const uint8_t PltData[] = { 257 0x00, 0x40, 0x00, 0x00, // { immext (#0) 258 0x1c, 0xc0, 0x49, 0x6a, // r28 = add (pc, ##GOT0@PCREL) } # @GOT0 259 0x0e, 0x42, 0x9c, 0xe2, // { r14 -= add (r28, #16) # offset of GOTn 260 0x4f, 0x40, 0x9c, 0x91, // r15 = memw (r28 + #8) # object ID at GOT2 261 0x3c, 0xc0, 0x9c, 0x91, // r28 = memw (r28 + #4) }# dynamic link at GOT1 262 0x0e, 0x42, 0x0e, 0x8c, // { r14 = asr (r14, #2) # index of PLTn 263 0x00, 0xc0, 0x9c, 0x52, // jumpr r28 } # call dynamic linker 264 0x0c, 0xdb, 0x00, 0x54, // trap0(#0xdb) # bring plt0 into 16byte alignment 265 }; 266 memcpy(Buf, PltData, sizeof(PltData)); 267 268 // Offset from PLT0 to the GOT. 269 uint64_t Off = In.GotPlt->getVA() - In.Plt->getVA(); 270 relocateOne(Buf, R_HEX_B32_PCREL_X, Off); 271 relocateOne(Buf + 4, R_HEX_6_PCREL_X, Off); 272 } 273 274 void Hexagon::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, 275 uint64_t PltEntryAddr, int32_t Index, 276 unsigned RelOff) const { 277 const uint8_t Inst[] = { 278 0x00, 0x40, 0x00, 0x00, // { immext (#0) 279 0x0e, 0xc0, 0x49, 0x6a, // r14 = add (pc, ##GOTn@PCREL) } 280 0x1c, 0xc0, 0x8e, 0x91, // r28 = memw (r14) 281 0x00, 0xc0, 0x9c, 0x52, // jumpr r28 282 }; 283 memcpy(Buf, Inst, sizeof(Inst)); 284 285 relocateOne(Buf, R_HEX_B32_PCREL_X, GotPltEntryAddr - PltEntryAddr); 286 relocateOne(Buf + 4, R_HEX_6_PCREL_X, GotPltEntryAddr - PltEntryAddr); 287 } 288 289 TargetInfo *elf::getHexagonTargetInfo() { 290 static Hexagon Target; 291 return &Target; 292 } 293