521 lines · cpp
1//===-- PPCELFObjectWriter.cpp - PPC ELF Writer ---------------------------===//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 "MCTargetDesc/PPCFixupKinds.h"10#include "MCTargetDesc/PPCMCAsmInfo.h"11#include "MCTargetDesc/PPCMCTargetDesc.h"12#include "llvm/MC/MCContext.h"13#include "llvm/MC/MCELFObjectWriter.h"14#include "llvm/MC/MCExpr.h"15#include "llvm/MC/MCObjectWriter.h"16#include "llvm/MC/MCSymbolELF.h"17#include "llvm/MC/MCValue.h"18#include "llvm/Support/ErrorHandling.h"19 20using namespace llvm;21 22namespace {23 class PPCELFObjectWriter : public MCELFObjectTargetWriter {24 public:25 PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI);26 27 protected:28 unsigned getRelocType(const MCFixup &Fixup, const MCValue &Target,29 bool IsPCRel) const override;30 31 bool needsRelocateWithSymbol(const MCValue &, unsigned Type) const override;32 };33}34 35PPCELFObjectWriter::PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI)36 : MCELFObjectTargetWriter(Is64Bit, OSABI,37 Is64Bit ? ELF::EM_PPC64 : ELF::EM_PPC,38 /*HasRelocationAddend*/ true) {}39 40unsigned PPCELFObjectWriter::getRelocType(const MCFixup &Fixup,41 const MCValue &Target,42 bool IsPCRel) const {43 SMLoc Loc = Fixup.getValue()->getLoc();44 auto Spec = static_cast<PPCMCExpr::Specifier>(Target.getSpecifier());45 switch (Spec) {46 case PPC::S_DTPMOD:47 case PPC::S_DTPREL:48 case PPC::S_DTPREL_HA:49 case PPC::S_DTPREL_HI:50 case PPC::S_DTPREL_HIGH:51 case PPC::S_DTPREL_HIGHA:52 case PPC::S_DTPREL_HIGHER:53 case PPC::S_DTPREL_HIGHERA:54 case PPC::S_DTPREL_HIGHEST:55 case PPC::S_DTPREL_HIGHESTA:56 case PPC::S_DTPREL_LO:57 case PPC::S_GOT_DTPREL:58 case PPC::S_GOT_DTPREL_HA:59 case PPC::S_GOT_DTPREL_HI:60 case PPC::S_GOT_DTPREL_LO:61 case PPC::S_GOT_TLSGD:62 case PPC::S_GOT_TLSGD_HA:63 case PPC::S_GOT_TLSGD_HI:64 case PPC::S_GOT_TLSGD_LO:65 case PPC::S_GOT_TLSGD_PCREL:66 case PPC::S_GOT_TLSLD:67 case PPC::S_GOT_TLSLD_HA:68 case PPC::S_GOT_TLSLD_HI:69 case PPC::S_GOT_TLSLD_LO:70 case PPC::S_GOT_TPREL:71 case PPC::S_GOT_TPREL_HA:72 case PPC::S_GOT_TPREL_HI:73 case PPC::S_GOT_TPREL_LO:74 case PPC::S_GOT_TPREL_PCREL:75 case PPC::S_TLS:76 case PPC::S_TLSGD:77 case PPC::S_TLSLD:78 case PPC::S_TLS_PCREL:79 case PPC::S_TPREL:80 case PPC::S_TPREL_HA:81 case PPC::S_TPREL_HI:82 case PPC::S_TPREL_HIGH:83 case PPC::S_TPREL_HIGHA:84 case PPC::S_TPREL_HIGHER:85 case PPC::S_TPREL_HIGHERA:86 case PPC::S_TPREL_HIGHEST:87 case PPC::S_TPREL_HIGHESTA:88 case PPC::S_TPREL_LO:89 if (auto *SA = const_cast<MCSymbol *>(Target.getAddSym()))90 static_cast<MCSymbolELF *>(SA)->setType(ELF::STT_TLS);91 break;92 default:93 break;94 }95 96 // determine the type of the relocation97 unsigned Type = 0;98 if (IsPCRel) {99 switch (Fixup.getKind()) {100 default:101 llvm_unreachable("Unimplemented");102 case PPC::fixup_ppc_br24:103 case PPC::fixup_ppc_br24abs:104 case PPC::fixup_ppc_br24_notoc:105 switch (Spec) {106 default:107 reportError(Loc, "unsupported relocation type");108 break;109 case PPC::S_None:110 Type = ELF::R_PPC_REL24;111 break;112 case PPC::S_PLT:113 Type = ELF::R_PPC_PLTREL24;114 break;115 case PPC::S_LOCAL:116 Type = ELF::R_PPC_LOCAL24PC;117 break;118 case PPC::S_NOTOC:119 Type = ELF::R_PPC64_REL24_NOTOC;120 break;121 }122 break;123 case PPC::fixup_ppc_brcond14:124 case PPC::fixup_ppc_brcond14abs:125 Type = ELF::R_PPC_REL14;126 break;127 case PPC::fixup_ppc_half16:128 switch (Spec) {129 default:130 reportError(Loc, "unsupported relocation type");131 return ELF::R_PPC_NONE;132 case PPC::S_None:133 return ELF::R_PPC_REL16;134 case PPC::S_LO:135 return ELF::R_PPC_REL16_LO;136 case PPC::S_HI:137 return ELF::R_PPC_REL16_HI;138 case PPC::S_HA:139 return ELF::R_PPC_REL16_HA;140 }141 break;142 case PPC::fixup_ppc_half16ds:143 case PPC::fixup_ppc_half16dq:144 reportError(Loc, "unsupported relocation type");145 break;146 case PPC::fixup_ppc_pcrel34:147 switch (Spec) {148 default:149 reportError(Loc, "unsupported relocation type");150 break;151 case PPC::S_PCREL:152 Type = ELF::R_PPC64_PCREL34;153 break;154 case PPC::S_GOT_PCREL:155 Type = ELF::R_PPC64_GOT_PCREL34;156 break;157 case PPC::S_GOT_TLSGD_PCREL:158 Type = ELF::R_PPC64_GOT_TLSGD_PCREL34;159 break;160 case PPC::S_GOT_TLSLD_PCREL:161 Type = ELF::R_PPC64_GOT_TLSLD_PCREL34;162 break;163 case PPC::S_GOT_TPREL_PCREL:164 Type = ELF::R_PPC64_GOT_TPREL_PCREL34;165 break;166 }167 break;168 case FK_Data_4:169 Type = ELF::R_PPC_REL32;170 break;171 case FK_Data_8:172 Type = ELF::R_PPC64_REL64;173 break;174 }175 } else {176 switch (Fixup.getKind()) {177 default:178 llvm_unreachable("invalid fixup kind!");179 case PPC::fixup_ppc_br24abs:180 Type = ELF::R_PPC_ADDR24;181 break;182 case PPC::fixup_ppc_brcond14abs:183 Type = ELF::R_PPC_ADDR14; // XXX: or BRNTAKEN?_184 break;185 case PPC::fixup_ppc_half16:186 switch (Spec) {187 default:188 reportError(Loc, "unsupported relocation type");189 break;190 case PPC::S_LO:191 return ELF::R_PPC_ADDR16_LO;192 case PPC::S_HI:193 return ELF::R_PPC_ADDR16_HI;194 case PPC::S_HA:195 return ELF::R_PPC_ADDR16_HA;196 case PPC::S_HIGH:197 return ELF::R_PPC64_ADDR16_HIGH;198 case PPC::S_HIGHA:199 return ELF::R_PPC64_ADDR16_HIGHA;200 case PPC::S_HIGHER:201 return ELF::R_PPC64_ADDR16_HIGHER;202 case PPC::S_HIGHERA:203 return ELF::R_PPC64_ADDR16_HIGHERA;204 case PPC::S_HIGHEST:205 return ELF::R_PPC64_ADDR16_HIGHEST;206 case PPC::S_HIGHESTA:207 return ELF::R_PPC64_ADDR16_HIGHESTA;208 209 case PPC::S_None:210 Type = ELF::R_PPC_ADDR16;211 break;212 case PPC::S_GOT:213 Type = ELF::R_PPC_GOT16;214 break;215 case PPC::S_GOT_LO:216 Type = ELF::R_PPC_GOT16_LO;217 break;218 case PPC::S_GOT_HI:219 Type = ELF::R_PPC_GOT16_HI;220 break;221 case PPC::S_GOT_HA:222 Type = ELF::R_PPC_GOT16_HA;223 break;224 case PPC::S_TOC:225 Type = ELF::R_PPC64_TOC16;226 break;227 case PPC::S_TOC_LO:228 Type = ELF::R_PPC64_TOC16_LO;229 break;230 case PPC::S_TOC_HI:231 Type = ELF::R_PPC64_TOC16_HI;232 break;233 case PPC::S_TOC_HA:234 Type = ELF::R_PPC64_TOC16_HA;235 break;236 case PPC::S_TPREL:237 Type = ELF::R_PPC_TPREL16;238 break;239 case PPC::S_TPREL_LO:240 Type = ELF::R_PPC_TPREL16_LO;241 break;242 case PPC::S_TPREL_HI:243 Type = ELF::R_PPC_TPREL16_HI;244 break;245 case PPC::S_TPREL_HA:246 Type = ELF::R_PPC_TPREL16_HA;247 break;248 case PPC::S_TPREL_HIGH:249 Type = ELF::R_PPC64_TPREL16_HIGH;250 break;251 case PPC::S_TPREL_HIGHA:252 Type = ELF::R_PPC64_TPREL16_HIGHA;253 break;254 case PPC::S_TPREL_HIGHER:255 Type = ELF::R_PPC64_TPREL16_HIGHER;256 break;257 case PPC::S_TPREL_HIGHERA:258 Type = ELF::R_PPC64_TPREL16_HIGHERA;259 break;260 case PPC::S_TPREL_HIGHEST:261 Type = ELF::R_PPC64_TPREL16_HIGHEST;262 break;263 case PPC::S_TPREL_HIGHESTA:264 Type = ELF::R_PPC64_TPREL16_HIGHESTA;265 break;266 case PPC::S_DTPREL:267 Type = ELF::R_PPC64_DTPREL16;268 break;269 case PPC::S_DTPREL_LO:270 Type = ELF::R_PPC64_DTPREL16_LO;271 break;272 case PPC::S_DTPREL_HI:273 Type = ELF::R_PPC64_DTPREL16_HI;274 break;275 case PPC::S_DTPREL_HA:276 Type = ELF::R_PPC64_DTPREL16_HA;277 break;278 case PPC::S_DTPREL_HIGH:279 Type = ELF::R_PPC64_DTPREL16_HIGH;280 break;281 case PPC::S_DTPREL_HIGHA:282 Type = ELF::R_PPC64_DTPREL16_HIGHA;283 break;284 case PPC::S_DTPREL_HIGHER:285 Type = ELF::R_PPC64_DTPREL16_HIGHER;286 break;287 case PPC::S_DTPREL_HIGHERA:288 Type = ELF::R_PPC64_DTPREL16_HIGHERA;289 break;290 case PPC::S_DTPREL_HIGHEST:291 Type = ELF::R_PPC64_DTPREL16_HIGHEST;292 break;293 case PPC::S_DTPREL_HIGHESTA:294 Type = ELF::R_PPC64_DTPREL16_HIGHESTA;295 break;296 case PPC::S_GOT_TLSGD:297 if (is64Bit())298 Type = ELF::R_PPC64_GOT_TLSGD16;299 else300 Type = ELF::R_PPC_GOT_TLSGD16;301 break;302 case PPC::S_GOT_TLSGD_LO:303 Type = ELF::R_PPC64_GOT_TLSGD16_LO;304 break;305 case PPC::S_GOT_TLSGD_HI:306 Type = ELF::R_PPC64_GOT_TLSGD16_HI;307 break;308 case PPC::S_GOT_TLSGD_HA:309 Type = ELF::R_PPC64_GOT_TLSGD16_HA;310 break;311 case PPC::S_GOT_TLSLD:312 if (is64Bit())313 Type = ELF::R_PPC64_GOT_TLSLD16;314 else315 Type = ELF::R_PPC_GOT_TLSLD16;316 break;317 case PPC::S_GOT_TLSLD_LO:318 Type = ELF::R_PPC64_GOT_TLSLD16_LO;319 break;320 case PPC::S_GOT_TLSLD_HI:321 Type = ELF::R_PPC64_GOT_TLSLD16_HI;322 break;323 case PPC::S_GOT_TLSLD_HA:324 Type = ELF::R_PPC64_GOT_TLSLD16_HA;325 break;326 case PPC::S_GOT_TPREL:327 /* We don't have R_PPC64_GOT_TPREL16, but since GOT offsets328 are always 4-aligned, we can use R_PPC64_GOT_TPREL16_DS. */329 Type = ELF::R_PPC64_GOT_TPREL16_DS;330 break;331 case PPC::S_GOT_TPREL_LO:332 /* We don't have R_PPC64_GOT_TPREL16_LO, but since GOT offsets333 are always 4-aligned, we can use R_PPC64_GOT_TPREL16_LO_DS. */334 Type = ELF::R_PPC64_GOT_TPREL16_LO_DS;335 break;336 case PPC::S_GOT_TPREL_HI:337 Type = ELF::R_PPC64_GOT_TPREL16_HI;338 break;339 case PPC::S_GOT_DTPREL:340 /* We don't have R_PPC64_GOT_DTPREL16, but since GOT offsets341 are always 4-aligned, we can use R_PPC64_GOT_DTPREL16_DS. */342 Type = ELF::R_PPC64_GOT_DTPREL16_DS;343 break;344 case PPC::S_GOT_DTPREL_LO:345 /* We don't have R_PPC64_GOT_DTPREL16_LO, but since GOT offsets346 are always 4-aligned, we can use R_PPC64_GOT_DTPREL16_LO_DS. */347 Type = ELF::R_PPC64_GOT_DTPREL16_LO_DS;348 break;349 case PPC::S_GOT_TPREL_HA:350 Type = ELF::R_PPC64_GOT_TPREL16_HA;351 break;352 case PPC::S_GOT_DTPREL_HI:353 Type = ELF::R_PPC64_GOT_DTPREL16_HI;354 break;355 case PPC::S_GOT_DTPREL_HA:356 Type = ELF::R_PPC64_GOT_DTPREL16_HA;357 break;358 }359 break;360 case PPC::fixup_ppc_half16ds:361 case PPC::fixup_ppc_half16dq:362 switch (Spec) {363 default:364 reportError(Loc, "unsupported relocation type");365 break;366 case PPC::S_LO:367 return ELF::R_PPC64_ADDR16_LO_DS;368 case PPC::S_None:369 Type = ELF::R_PPC64_ADDR16_DS;370 break;371 case PPC::S_GOT:372 Type = ELF::R_PPC64_GOT16_DS;373 break;374 case PPC::S_GOT_LO:375 Type = ELF::R_PPC64_GOT16_LO_DS;376 break;377 case PPC::S_TOC:378 Type = ELF::R_PPC64_TOC16_DS;379 break;380 case PPC::S_TOC_LO:381 Type = ELF::R_PPC64_TOC16_LO_DS;382 break;383 case PPC::S_TPREL:384 Type = ELF::R_PPC64_TPREL16_DS;385 break;386 case PPC::S_TPREL_LO:387 Type = ELF::R_PPC64_TPREL16_LO_DS;388 break;389 case PPC::S_DTPREL:390 Type = ELF::R_PPC64_DTPREL16_DS;391 break;392 case PPC::S_DTPREL_LO:393 Type = ELF::R_PPC64_DTPREL16_LO_DS;394 break;395 case PPC::S_GOT_TPREL:396 Type = ELF::R_PPC64_GOT_TPREL16_DS;397 break;398 case PPC::S_GOT_TPREL_LO:399 Type = ELF::R_PPC64_GOT_TPREL16_LO_DS;400 break;401 case PPC::S_GOT_DTPREL:402 Type = ELF::R_PPC64_GOT_DTPREL16_DS;403 break;404 case PPC::S_GOT_DTPREL_LO:405 Type = ELF::R_PPC64_GOT_DTPREL16_LO_DS;406 break;407 }408 break;409 case PPC::fixup_ppc_nofixup:410 switch (Spec) {411 default:412 reportError(Loc, "unsupported relocation type");413 break;414 case PPC::S_TLSGD:415 if (is64Bit())416 Type = ELF::R_PPC64_TLSGD;417 else418 Type = ELF::R_PPC_TLSGD;419 break;420 case PPC::S_TLSLD:421 if (is64Bit())422 Type = ELF::R_PPC64_TLSLD;423 else424 Type = ELF::R_PPC_TLSLD;425 break;426 case PPC::S_TLS:427 if (is64Bit())428 Type = ELF::R_PPC64_TLS;429 else430 Type = ELF::R_PPC_TLS;431 break;432 case PPC::S_TLS_PCREL:433 Type = ELF::R_PPC64_TLS;434 break;435 }436 break;437 case PPC::fixup_ppc_imm34:438 switch (Spec) {439 default:440 reportError(Loc, "unsupported relocation type");441 break;442 case PPC::S_DTPREL:443 Type = ELF::R_PPC64_DTPREL34;444 break;445 case PPC::S_TPREL:446 Type = ELF::R_PPC64_TPREL34;447 break;448 }449 break;450 case FK_Data_8:451 switch (Spec) {452 default:453 reportError(Loc, "unsupported relocation type");454 break;455 case PPC::S_TOCBASE:456 Type = ELF::R_PPC64_TOC;457 break;458 case PPC::S_None:459 Type = ELF::R_PPC64_ADDR64;460 break;461 case PPC::S_DTPMOD:462 Type = ELF::R_PPC64_DTPMOD64;463 break;464 case PPC::S_TPREL:465 Type = ELF::R_PPC64_TPREL64;466 break;467 case PPC::S_DTPREL:468 Type = ELF::R_PPC64_DTPREL64;469 break;470 }471 break;472 case FK_Data_4:473 switch (Spec) {474 case PPC::S_DTPREL:475 Type = ELF::R_PPC_DTPREL32;476 break;477 default:478 Type = ELF::R_PPC_ADDR32;479 }480 break;481 case FK_Data_2:482 Type = ELF::R_PPC_ADDR16;483 break;484 }485 }486 return Type;487}488 489bool PPCELFObjectWriter::needsRelocateWithSymbol(const MCValue &V,490 unsigned Type) const {491 switch (Type) {492 default:493 return false;494 495 case ELF::R_PPC_REL24:496 case ELF::R_PPC64_REL24_NOTOC: {497 // If the target symbol has a local entry point, we must keep the498 // target symbol to preserve that information for the linker.499 // The "other" values are stored in the last 6 bits of the second byte.500 // The traditional defines for STO values assume the full byte and thus501 // the shift to pack it.502 unsigned Other =503 static_cast<const MCSymbolELF *>(V.getAddSym())->getOther() << 2;504 return (Other & ELF::STO_PPC64_LOCAL_MASK) != 0;505 }506 507 case ELF::R_PPC64_GOT16:508 case ELF::R_PPC64_GOT16_DS:509 case ELF::R_PPC64_GOT16_LO:510 case ELF::R_PPC64_GOT16_LO_DS:511 case ELF::R_PPC64_GOT16_HI:512 case ELF::R_PPC64_GOT16_HA:513 return true;514 }515}516 517std::unique_ptr<MCObjectTargetWriter>518llvm::createPPCELFObjectWriter(bool Is64Bit, uint8_t OSABI) {519 return std::make_unique<PPCELFObjectWriter>(Is64Bit, OSABI);520}521