123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490 |
- //===-- PPCELFObjectWriter.cpp - PPC ELF Writer ---------------------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "MCTargetDesc/PPCFixupKinds.h"
- #include "MCTargetDesc/PPCMCExpr.h"
- #include "MCTargetDesc/PPCMCTargetDesc.h"
- #include "llvm/ADT/STLExtras.h"
- #include "llvm/MC/MCELFObjectWriter.h"
- #include "llvm/MC/MCExpr.h"
- #include "llvm/MC/MCObjectWriter.h"
- #include "llvm/MC/MCSymbolELF.h"
- #include "llvm/MC/MCValue.h"
- #include "llvm/Support/ErrorHandling.h"
- using namespace llvm;
- namespace {
- class PPCELFObjectWriter : public MCELFObjectTargetWriter {
- public:
- PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI);
- protected:
- unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
- const MCFixup &Fixup, bool IsPCRel) const override;
- bool needsRelocateWithSymbol(const MCSymbol &Sym,
- unsigned Type) const override;
- };
- }
- PPCELFObjectWriter::PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI)
- : MCELFObjectTargetWriter(Is64Bit, OSABI,
- Is64Bit ? ELF::EM_PPC64 : ELF::EM_PPC,
- /*HasRelocationAddend*/ true) {}
- static MCSymbolRefExpr::VariantKind getAccessVariant(const MCValue &Target,
- const MCFixup &Fixup) {
- const MCExpr *Expr = Fixup.getValue();
- if (Expr->getKind() != MCExpr::Target)
- return Target.getAccessVariant();
- switch (cast<PPCMCExpr>(Expr)->getKind()) {
- case PPCMCExpr::VK_PPC_None:
- return MCSymbolRefExpr::VK_None;
- case PPCMCExpr::VK_PPC_LO:
- return MCSymbolRefExpr::VK_PPC_LO;
- case PPCMCExpr::VK_PPC_HI:
- return MCSymbolRefExpr::VK_PPC_HI;
- case PPCMCExpr::VK_PPC_HA:
- return MCSymbolRefExpr::VK_PPC_HA;
- case PPCMCExpr::VK_PPC_HIGH:
- return MCSymbolRefExpr::VK_PPC_HIGH;
- case PPCMCExpr::VK_PPC_HIGHA:
- return MCSymbolRefExpr::VK_PPC_HIGHA;
- case PPCMCExpr::VK_PPC_HIGHERA:
- return MCSymbolRefExpr::VK_PPC_HIGHERA;
- case PPCMCExpr::VK_PPC_HIGHER:
- return MCSymbolRefExpr::VK_PPC_HIGHER;
- case PPCMCExpr::VK_PPC_HIGHEST:
- return MCSymbolRefExpr::VK_PPC_HIGHEST;
- case PPCMCExpr::VK_PPC_HIGHESTA:
- return MCSymbolRefExpr::VK_PPC_HIGHESTA;
- }
- llvm_unreachable("unknown PPCMCExpr kind");
- }
- unsigned PPCELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
- const MCFixup &Fixup,
- bool IsPCRel) const {
- MCFixupKind Kind = Fixup.getKind();
- if (Kind >= FirstLiteralRelocationKind)
- return Kind - FirstLiteralRelocationKind;
- MCSymbolRefExpr::VariantKind Modifier = getAccessVariant(Target, Fixup);
- // determine the type of the relocation
- unsigned Type;
- if (IsPCRel) {
- switch (Fixup.getTargetKind()) {
- default:
- llvm_unreachable("Unimplemented");
- case PPC::fixup_ppc_br24:
- case PPC::fixup_ppc_br24abs:
- case PPC::fixup_ppc_br24_notoc:
- switch (Modifier) {
- default: llvm_unreachable("Unsupported Modifier");
- case MCSymbolRefExpr::VK_None:
- Type = ELF::R_PPC_REL24;
- break;
- case MCSymbolRefExpr::VK_PLT:
- Type = ELF::R_PPC_PLTREL24;
- break;
- case MCSymbolRefExpr::VK_PPC_LOCAL:
- Type = ELF::R_PPC_LOCAL24PC;
- break;
- case MCSymbolRefExpr::VK_PPC_NOTOC:
- Type = ELF::R_PPC64_REL24_NOTOC;
- break;
- }
- break;
- case PPC::fixup_ppc_brcond14:
- case PPC::fixup_ppc_brcond14abs:
- Type = ELF::R_PPC_REL14;
- break;
- case PPC::fixup_ppc_half16:
- switch (Modifier) {
- default: llvm_unreachable("Unsupported Modifier");
- case MCSymbolRefExpr::VK_None:
- Type = ELF::R_PPC_REL16;
- break;
- case MCSymbolRefExpr::VK_PPC_LO:
- Type = ELF::R_PPC_REL16_LO;
- break;
- case MCSymbolRefExpr::VK_PPC_HI:
- Type = ELF::R_PPC_REL16_HI;
- break;
- case MCSymbolRefExpr::VK_PPC_HA:
- Type = ELF::R_PPC_REL16_HA;
- break;
- }
- break;
- case PPC::fixup_ppc_half16ds:
- case PPC::fixup_ppc_half16dq:
- Target.print(errs());
- errs() << '\n';
- report_fatal_error("Invalid PC-relative half16ds relocation");
- case PPC::fixup_ppc_pcrel34:
- switch (Modifier) {
- default:
- llvm_unreachable("Unsupported Modifier for fixup_ppc_pcrel34");
- case MCSymbolRefExpr::VK_PCREL:
- Type = ELF::R_PPC64_PCREL34;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_PCREL:
- Type = ELF::R_PPC64_GOT_PCREL34;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_PCREL:
- Type = ELF::R_PPC64_GOT_TLSGD_PCREL34;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_PCREL:
- Type = ELF::R_PPC64_GOT_TLSLD_PCREL34;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_TPREL_PCREL:
- Type = ELF::R_PPC64_GOT_TPREL_PCREL34;
- break;
- }
- break;
- case FK_Data_4:
- case FK_PCRel_4:
- Type = ELF::R_PPC_REL32;
- break;
- case FK_Data_8:
- case FK_PCRel_8:
- Type = ELF::R_PPC64_REL64;
- break;
- }
- } else {
- switch (Fixup.getTargetKind()) {
- default: llvm_unreachable("invalid fixup kind!");
- case PPC::fixup_ppc_br24abs:
- Type = ELF::R_PPC_ADDR24;
- break;
- case PPC::fixup_ppc_brcond14abs:
- Type = ELF::R_PPC_ADDR14; // XXX: or BRNTAKEN?_
- break;
- case PPC::fixup_ppc_half16:
- switch (Modifier) {
- default: llvm_unreachable("Unsupported Modifier");
- case MCSymbolRefExpr::VK_None:
- Type = ELF::R_PPC_ADDR16;
- break;
- case MCSymbolRefExpr::VK_PPC_LO:
- Type = ELF::R_PPC_ADDR16_LO;
- break;
- case MCSymbolRefExpr::VK_PPC_HI:
- Type = ELF::R_PPC_ADDR16_HI;
- break;
- case MCSymbolRefExpr::VK_PPC_HA:
- Type = ELF::R_PPC_ADDR16_HA;
- break;
- case MCSymbolRefExpr::VK_PPC_HIGH:
- Type = ELF::R_PPC64_ADDR16_HIGH;
- break;
- case MCSymbolRefExpr::VK_PPC_HIGHA:
- Type = ELF::R_PPC64_ADDR16_HIGHA;
- break;
- case MCSymbolRefExpr::VK_PPC_HIGHER:
- Type = ELF::R_PPC64_ADDR16_HIGHER;
- break;
- case MCSymbolRefExpr::VK_PPC_HIGHERA:
- Type = ELF::R_PPC64_ADDR16_HIGHERA;
- break;
- case MCSymbolRefExpr::VK_PPC_HIGHEST:
- Type = ELF::R_PPC64_ADDR16_HIGHEST;
- break;
- case MCSymbolRefExpr::VK_PPC_HIGHESTA:
- Type = ELF::R_PPC64_ADDR16_HIGHESTA;
- break;
- case MCSymbolRefExpr::VK_GOT:
- Type = ELF::R_PPC_GOT16;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_LO:
- Type = ELF::R_PPC_GOT16_LO;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_HI:
- Type = ELF::R_PPC_GOT16_HI;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_HA:
- Type = ELF::R_PPC_GOT16_HA;
- break;
- case MCSymbolRefExpr::VK_PPC_TOC:
- Type = ELF::R_PPC64_TOC16;
- break;
- case MCSymbolRefExpr::VK_PPC_TOC_LO:
- Type = ELF::R_PPC64_TOC16_LO;
- break;
- case MCSymbolRefExpr::VK_PPC_TOC_HI:
- Type = ELF::R_PPC64_TOC16_HI;
- break;
- case MCSymbolRefExpr::VK_PPC_TOC_HA:
- Type = ELF::R_PPC64_TOC16_HA;
- break;
- case MCSymbolRefExpr::VK_TPREL:
- Type = ELF::R_PPC_TPREL16;
- break;
- case MCSymbolRefExpr::VK_PPC_TPREL_LO:
- Type = ELF::R_PPC_TPREL16_LO;
- break;
- case MCSymbolRefExpr::VK_PPC_TPREL_HI:
- Type = ELF::R_PPC_TPREL16_HI;
- break;
- case MCSymbolRefExpr::VK_PPC_TPREL_HA:
- Type = ELF::R_PPC_TPREL16_HA;
- break;
- case MCSymbolRefExpr::VK_PPC_TPREL_HIGH:
- Type = ELF::R_PPC64_TPREL16_HIGH;
- break;
- case MCSymbolRefExpr::VK_PPC_TPREL_HIGHA:
- Type = ELF::R_PPC64_TPREL16_HIGHA;
- break;
- case MCSymbolRefExpr::VK_PPC_TPREL_HIGHER:
- Type = ELF::R_PPC64_TPREL16_HIGHER;
- break;
- case MCSymbolRefExpr::VK_PPC_TPREL_HIGHERA:
- Type = ELF::R_PPC64_TPREL16_HIGHERA;
- break;
- case MCSymbolRefExpr::VK_PPC_TPREL_HIGHEST:
- Type = ELF::R_PPC64_TPREL16_HIGHEST;
- break;
- case MCSymbolRefExpr::VK_PPC_TPREL_HIGHESTA:
- Type = ELF::R_PPC64_TPREL16_HIGHESTA;
- break;
- case MCSymbolRefExpr::VK_DTPREL:
- Type = ELF::R_PPC64_DTPREL16;
- break;
- case MCSymbolRefExpr::VK_PPC_DTPREL_LO:
- Type = ELF::R_PPC64_DTPREL16_LO;
- break;
- case MCSymbolRefExpr::VK_PPC_DTPREL_HI:
- Type = ELF::R_PPC64_DTPREL16_HI;
- break;
- case MCSymbolRefExpr::VK_PPC_DTPREL_HA:
- Type = ELF::R_PPC64_DTPREL16_HA;
- break;
- case MCSymbolRefExpr::VK_PPC_DTPREL_HIGH:
- Type = ELF::R_PPC64_DTPREL16_HIGH;
- break;
- case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHA:
- Type = ELF::R_PPC64_DTPREL16_HIGHA;
- break;
- case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHER:
- Type = ELF::R_PPC64_DTPREL16_HIGHER;
- break;
- case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHERA:
- Type = ELF::R_PPC64_DTPREL16_HIGHERA;
- break;
- case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHEST:
- Type = ELF::R_PPC64_DTPREL16_HIGHEST;
- break;
- case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHESTA:
- Type = ELF::R_PPC64_DTPREL16_HIGHESTA;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_TLSGD:
- if (is64Bit())
- Type = ELF::R_PPC64_GOT_TLSGD16;
- else
- Type = ELF::R_PPC_GOT_TLSGD16;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_LO:
- Type = ELF::R_PPC64_GOT_TLSGD16_LO;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_HI:
- Type = ELF::R_PPC64_GOT_TLSGD16_HI;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_HA:
- Type = ELF::R_PPC64_GOT_TLSGD16_HA;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_TLSLD:
- if (is64Bit())
- Type = ELF::R_PPC64_GOT_TLSLD16;
- else
- Type = ELF::R_PPC_GOT_TLSLD16;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_LO:
- Type = ELF::R_PPC64_GOT_TLSLD16_LO;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_HI:
- Type = ELF::R_PPC64_GOT_TLSLD16_HI;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_HA:
- Type = ELF::R_PPC64_GOT_TLSLD16_HA;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_TPREL:
- /* We don't have R_PPC64_GOT_TPREL16, but since GOT offsets
- are always 4-aligned, we can use R_PPC64_GOT_TPREL16_DS. */
- Type = ELF::R_PPC64_GOT_TPREL16_DS;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_TPREL_LO:
- /* We don't have R_PPC64_GOT_TPREL16_LO, but since GOT offsets
- are always 4-aligned, we can use R_PPC64_GOT_TPREL16_LO_DS. */
- Type = ELF::R_PPC64_GOT_TPREL16_LO_DS;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_TPREL_HI:
- Type = ELF::R_PPC64_GOT_TPREL16_HI;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_DTPREL:
- /* We don't have R_PPC64_GOT_DTPREL16, but since GOT offsets
- are always 4-aligned, we can use R_PPC64_GOT_DTPREL16_DS. */
- Type = ELF::R_PPC64_GOT_DTPREL16_DS;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_LO:
- /* We don't have R_PPC64_GOT_DTPREL16_LO, but since GOT offsets
- are always 4-aligned, we can use R_PPC64_GOT_DTPREL16_LO_DS. */
- Type = ELF::R_PPC64_GOT_DTPREL16_LO_DS;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_TPREL_HA:
- Type = ELF::R_PPC64_GOT_TPREL16_HA;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_HI:
- Type = ELF::R_PPC64_GOT_DTPREL16_HI;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_HA:
- Type = ELF::R_PPC64_GOT_DTPREL16_HA;
- break;
- }
- break;
- case PPC::fixup_ppc_half16ds:
- case PPC::fixup_ppc_half16dq:
- switch (Modifier) {
- default: llvm_unreachable("Unsupported Modifier");
- case MCSymbolRefExpr::VK_None:
- Type = ELF::R_PPC64_ADDR16_DS;
- break;
- case MCSymbolRefExpr::VK_PPC_LO:
- Type = ELF::R_PPC64_ADDR16_LO_DS;
- break;
- case MCSymbolRefExpr::VK_GOT:
- Type = ELF::R_PPC64_GOT16_DS;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_LO:
- Type = ELF::R_PPC64_GOT16_LO_DS;
- break;
- case MCSymbolRefExpr::VK_PPC_TOC:
- Type = ELF::R_PPC64_TOC16_DS;
- break;
- case MCSymbolRefExpr::VK_PPC_TOC_LO:
- Type = ELF::R_PPC64_TOC16_LO_DS;
- break;
- case MCSymbolRefExpr::VK_TPREL:
- Type = ELF::R_PPC64_TPREL16_DS;
- break;
- case MCSymbolRefExpr::VK_PPC_TPREL_LO:
- Type = ELF::R_PPC64_TPREL16_LO_DS;
- break;
- case MCSymbolRefExpr::VK_DTPREL:
- Type = ELF::R_PPC64_DTPREL16_DS;
- break;
- case MCSymbolRefExpr::VK_PPC_DTPREL_LO:
- Type = ELF::R_PPC64_DTPREL16_LO_DS;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_TPREL:
- Type = ELF::R_PPC64_GOT_TPREL16_DS;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_TPREL_LO:
- Type = ELF::R_PPC64_GOT_TPREL16_LO_DS;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_DTPREL:
- Type = ELF::R_PPC64_GOT_DTPREL16_DS;
- break;
- case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_LO:
- Type = ELF::R_PPC64_GOT_DTPREL16_LO_DS;
- break;
- }
- break;
- case PPC::fixup_ppc_nofixup:
- switch (Modifier) {
- default: llvm_unreachable("Unsupported Modifier");
- case MCSymbolRefExpr::VK_PPC_TLSGD:
- if (is64Bit())
- Type = ELF::R_PPC64_TLSGD;
- else
- Type = ELF::R_PPC_TLSGD;
- break;
- case MCSymbolRefExpr::VK_PPC_TLSLD:
- if (is64Bit())
- Type = ELF::R_PPC64_TLSLD;
- else
- Type = ELF::R_PPC_TLSLD;
- break;
- case MCSymbolRefExpr::VK_PPC_TLS:
- if (is64Bit())
- Type = ELF::R_PPC64_TLS;
- else
- Type = ELF::R_PPC_TLS;
- break;
- case MCSymbolRefExpr::VK_PPC_TLS_PCREL:
- Type = ELF::R_PPC64_TLS;
- break;
- }
- break;
- case PPC::fixup_ppc_imm34:
- switch (Modifier) {
- default:
- report_fatal_error("Unsupported Modifier for fixup_ppc_imm34.");
- case MCSymbolRefExpr::VK_DTPREL:
- Type = ELF::R_PPC64_DTPREL34;
- break;
- case MCSymbolRefExpr::VK_TPREL:
- Type = ELF::R_PPC64_TPREL34;
- break;
- }
- break;
- case FK_Data_8:
- switch (Modifier) {
- default: llvm_unreachable("Unsupported Modifier");
- case MCSymbolRefExpr::VK_PPC_TOCBASE:
- Type = ELF::R_PPC64_TOC;
- break;
- case MCSymbolRefExpr::VK_None:
- Type = ELF::R_PPC64_ADDR64;
- break;
- case MCSymbolRefExpr::VK_PPC_DTPMOD:
- Type = ELF::R_PPC64_DTPMOD64;
- break;
- case MCSymbolRefExpr::VK_TPREL:
- Type = ELF::R_PPC64_TPREL64;
- break;
- case MCSymbolRefExpr::VK_DTPREL:
- Type = ELF::R_PPC64_DTPREL64;
- break;
- }
- break;
- case FK_Data_4:
- Type = ELF::R_PPC_ADDR32;
- break;
- case FK_Data_2:
- Type = ELF::R_PPC_ADDR16;
- break;
- }
- }
- return Type;
- }
- bool PPCELFObjectWriter::needsRelocateWithSymbol(const MCSymbol &Sym,
- unsigned Type) const {
- switch (Type) {
- default:
- return false;
- case ELF::R_PPC_REL24:
- case ELF::R_PPC64_REL24_NOTOC:
- // If the target symbol has a local entry point, we must keep the
- // target symbol to preserve that information for the linker.
- // The "other" values are stored in the last 6 bits of the second byte.
- // The traditional defines for STO values assume the full byte and thus
- // the shift to pack it.
- unsigned Other = cast<MCSymbolELF>(Sym).getOther() << 2;
- return (Other & ELF::STO_PPC64_LOCAL_MASK) != 0;
- }
- }
- std::unique_ptr<MCObjectTargetWriter>
- llvm::createPPCELFObjectWriter(bool Is64Bit, uint8_t OSABI) {
- return std::make_unique<PPCELFObjectWriter>(Is64Bit, OSABI);
- }
|