123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- //===-- ARMELFObjectWriter.cpp - ARM 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/ARMFixupKinds.h"
- #include "MCTargetDesc/ARMMCTargetDesc.h"
- #include "llvm/BinaryFormat/ELF.h"
- #include "llvm/MC/MCContext.h"
- #include "llvm/MC/MCELFObjectWriter.h"
- #include "llvm/MC/MCExpr.h"
- #include "llvm/MC/MCFixup.h"
- #include "llvm/MC/MCObjectFileInfo.h"
- #include "llvm/MC/MCObjectWriter.h"
- #include "llvm/MC/MCValue.h"
- #include "llvm/Support/ErrorHandling.h"
- #include "llvm/Support/raw_ostream.h"
- #include <cstdint>
- using namespace llvm;
- namespace {
- class ARMELFObjectWriter : public MCELFObjectTargetWriter {
- enum { DefaultEABIVersion = 0x05000000U };
- unsigned GetRelocTypeInner(const MCValue &Target, const MCFixup &Fixup,
- bool IsPCRel, MCContext &Ctx) const;
- public:
- ARMELFObjectWriter(uint8_t OSABI);
- ~ARMELFObjectWriter() override = default;
- unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
- const MCFixup &Fixup, bool IsPCRel) const override;
- bool needsRelocateWithSymbol(const MCSymbol &Sym,
- unsigned Type) const override;
- void addTargetSectionFlags(MCContext &Ctx, MCSectionELF &Sec) override;
- };
- } // end anonymous namespace
- ARMELFObjectWriter::ARMELFObjectWriter(uint8_t OSABI)
- : MCELFObjectTargetWriter(/*Is64Bit*/ false, OSABI,
- ELF::EM_ARM,
- /*HasRelocationAddend*/ false) {}
- bool ARMELFObjectWriter::needsRelocateWithSymbol(const MCSymbol &Sym,
- unsigned Type) const {
- // FIXME: This is extremely conservative. This really needs to use an
- // explicit list with a clear explanation for why each realocation needs to
- // point to the symbol, not to the section.
- switch (Type) {
- default:
- return true;
- case ELF::R_ARM_PREL31:
- case ELF::R_ARM_ABS32:
- return false;
- }
- }
- // Need to examine the Fixup when determining whether to
- // emit the relocation as an explicit symbol or as a section relative
- // offset
- unsigned ARMELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
- const MCFixup &Fixup,
- bool IsPCRel) const {
- return GetRelocTypeInner(Target, Fixup, IsPCRel, Ctx);
- }
- unsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target,
- const MCFixup &Fixup,
- bool IsPCRel,
- MCContext &Ctx) const {
- unsigned Kind = Fixup.getTargetKind();
- if (Kind >= FirstLiteralRelocationKind)
- return Kind - FirstLiteralRelocationKind;
- MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant();
- if (IsPCRel) {
- switch (Fixup.getTargetKind()) {
- default:
- Ctx.reportError(Fixup.getLoc(), "unsupported relocation on symbol");
- return ELF::R_ARM_NONE;
- case FK_Data_4:
- switch (Modifier) {
- default:
- Ctx.reportError(Fixup.getLoc(),
- "invalid fixup for 4-byte pc-relative data relocation");
- return ELF::R_ARM_NONE;
- case MCSymbolRefExpr::VK_None: {
- if (const MCSymbolRefExpr *SymRef = Target.getSymA()) {
- // For GNU AS compatibility expressions such as
- // _GLOBAL_OFFSET_TABLE_ - label emit a R_ARM_BASE_PREL relocation.
- if (SymRef->getSymbol().getName() == "_GLOBAL_OFFSET_TABLE_")
- return ELF::R_ARM_BASE_PREL;
- }
- return ELF::R_ARM_REL32;
- }
- case MCSymbolRefExpr::VK_GOTTPOFF:
- return ELF::R_ARM_TLS_IE32;
- case MCSymbolRefExpr::VK_ARM_GOT_PREL:
- return ELF::R_ARM_GOT_PREL;
- case MCSymbolRefExpr::VK_ARM_PREL31:
- return ELF::R_ARM_PREL31;
- }
- case ARM::fixup_arm_blx:
- case ARM::fixup_arm_uncondbl:
- switch (Modifier) {
- case MCSymbolRefExpr::VK_PLT:
- return ELF::R_ARM_CALL;
- case MCSymbolRefExpr::VK_TLSCALL:
- return ELF::R_ARM_TLS_CALL;
- default:
- return ELF::R_ARM_CALL;
- }
- case ARM::fixup_arm_condbl:
- case ARM::fixup_arm_condbranch:
- case ARM::fixup_arm_uncondbranch:
- return ELF::R_ARM_JUMP24;
- case ARM::fixup_t2_condbranch:
- return ELF::R_ARM_THM_JUMP19;
- case ARM::fixup_t2_uncondbranch:
- return ELF::R_ARM_THM_JUMP24;
- case ARM::fixup_arm_movt_hi16:
- return ELF::R_ARM_MOVT_PREL;
- case ARM::fixup_arm_movw_lo16:
- return ELF::R_ARM_MOVW_PREL_NC;
- case ARM::fixup_t2_movt_hi16:
- return ELF::R_ARM_THM_MOVT_PREL;
- case ARM::fixup_t2_movw_lo16:
- return ELF::R_ARM_THM_MOVW_PREL_NC;
- case ARM::fixup_arm_thumb_br:
- return ELF::R_ARM_THM_JUMP11;
- case ARM::fixup_arm_thumb_bcc:
- return ELF::R_ARM_THM_JUMP8;
- case ARM::fixup_arm_thumb_bl:
- case ARM::fixup_arm_thumb_blx:
- switch (Modifier) {
- case MCSymbolRefExpr::VK_TLSCALL:
- return ELF::R_ARM_THM_TLS_CALL;
- default:
- return ELF::R_ARM_THM_CALL;
- }
- case ARM::fixup_bf_target:
- return ELF::R_ARM_THM_BF16;
- case ARM::fixup_bfc_target:
- return ELF::R_ARM_THM_BF12;
- case ARM::fixup_bfl_target:
- return ELF::R_ARM_THM_BF18;
- }
- }
- switch (Kind) {
- default:
- Ctx.reportError(Fixup.getLoc(), "unsupported relocation on symbol");
- return ELF::R_ARM_NONE;
- case FK_Data_1:
- switch (Modifier) {
- default:
- Ctx.reportError(Fixup.getLoc(),
- "invalid fixup for 1-byte data relocation");
- return ELF::R_ARM_NONE;
- case MCSymbolRefExpr::VK_None:
- return ELF::R_ARM_ABS8;
- }
- case FK_Data_2:
- switch (Modifier) {
- default:
- Ctx.reportError(Fixup.getLoc(),
- "invalid fixup for 2-byte data relocation");
- return ELF::R_ARM_NONE;
- case MCSymbolRefExpr::VK_None:
- return ELF::R_ARM_ABS16;
- }
- case FK_Data_4:
- switch (Modifier) {
- default:
- Ctx.reportError(Fixup.getLoc(),
- "invalid fixup for 4-byte data relocation");
- return ELF::R_ARM_NONE;
- case MCSymbolRefExpr::VK_ARM_NONE:
- return ELF::R_ARM_NONE;
- case MCSymbolRefExpr::VK_GOT:
- return ELF::R_ARM_GOT_BREL;
- case MCSymbolRefExpr::VK_TLSGD:
- return ELF::R_ARM_TLS_GD32;
- case MCSymbolRefExpr::VK_TPOFF:
- return ELF::R_ARM_TLS_LE32;
- case MCSymbolRefExpr::VK_GOTTPOFF:
- return ELF::R_ARM_TLS_IE32;
- case MCSymbolRefExpr::VK_None:
- return ELF::R_ARM_ABS32;
- case MCSymbolRefExpr::VK_GOTOFF:
- return ELF::R_ARM_GOTOFF32;
- case MCSymbolRefExpr::VK_ARM_GOT_PREL:
- return ELF::R_ARM_GOT_PREL;
- case MCSymbolRefExpr::VK_ARM_TARGET1:
- return ELF::R_ARM_TARGET1;
- case MCSymbolRefExpr::VK_ARM_TARGET2:
- return ELF::R_ARM_TARGET2;
- case MCSymbolRefExpr::VK_ARM_PREL31:
- return ELF::R_ARM_PREL31;
- case MCSymbolRefExpr::VK_ARM_SBREL:
- return ELF::R_ARM_SBREL32;
- case MCSymbolRefExpr::VK_ARM_TLSLDO:
- return ELF::R_ARM_TLS_LDO32;
- case MCSymbolRefExpr::VK_TLSCALL:
- return ELF::R_ARM_TLS_CALL;
- case MCSymbolRefExpr::VK_TLSDESC:
- return ELF::R_ARM_TLS_GOTDESC;
- case MCSymbolRefExpr::VK_TLSLDM:
- return ELF::R_ARM_TLS_LDM32;
- case MCSymbolRefExpr::VK_ARM_TLSDESCSEQ:
- return ELF::R_ARM_TLS_DESCSEQ;
- }
- case ARM::fixup_arm_condbranch:
- case ARM::fixup_arm_uncondbranch:
- return ELF::R_ARM_JUMP24;
- case ARM::fixup_arm_movt_hi16:
- switch (Modifier) {
- default:
- Ctx.reportError(Fixup.getLoc(), "invalid fixup for ARM MOVT instruction");
- return ELF::R_ARM_NONE;
- case MCSymbolRefExpr::VK_None:
- return ELF::R_ARM_MOVT_ABS;
- case MCSymbolRefExpr::VK_ARM_SBREL:
- return ELF::R_ARM_MOVT_BREL;
- }
- case ARM::fixup_arm_movw_lo16:
- switch (Modifier) {
- default:
- Ctx.reportError(Fixup.getLoc(), "invalid fixup for ARM MOVW instruction");
- return ELF::R_ARM_NONE;
- case MCSymbolRefExpr::VK_None:
- return ELF::R_ARM_MOVW_ABS_NC;
- case MCSymbolRefExpr::VK_ARM_SBREL:
- return ELF::R_ARM_MOVW_BREL_NC;
- }
- case ARM::fixup_t2_movt_hi16:
- switch (Modifier) {
- default:
- Ctx.reportError(Fixup.getLoc(),
- "invalid fixup for Thumb MOVT instruction");
- return ELF::R_ARM_NONE;
- case MCSymbolRefExpr::VK_None:
- return ELF::R_ARM_THM_MOVT_ABS;
- case MCSymbolRefExpr::VK_ARM_SBREL:
- return ELF::R_ARM_THM_MOVT_BREL;
- }
- case ARM::fixup_t2_movw_lo16:
- switch (Modifier) {
- default:
- Ctx.reportError(Fixup.getLoc(),
- "invalid fixup for Thumb MOVW instruction");
- return ELF::R_ARM_NONE;
- case MCSymbolRefExpr::VK_None:
- return ELF::R_ARM_THM_MOVW_ABS_NC;
- case MCSymbolRefExpr::VK_ARM_SBREL:
- return ELF::R_ARM_THM_MOVW_BREL_NC;
- }
- }
- }
- void ARMELFObjectWriter::addTargetSectionFlags(MCContext &Ctx,
- MCSectionELF &Sec) {
- // The mix of execute-only and non-execute-only at link time is
- // non-execute-only. To avoid the empty implicitly created .text
- // section from making the whole .text section non-execute-only, we
- // mark it execute-only if it is empty and there is at least one
- // execute-only section in the object.
- MCSectionELF *TextSection =
- static_cast<MCSectionELF *>(Ctx.getObjectFileInfo()->getTextSection());
- if (Sec.getKind().isExecuteOnly() && !TextSection->hasInstructions()) {
- for (auto &F : TextSection->getFragmentList())
- if (auto *DF = dyn_cast<MCDataFragment>(&F))
- if (!DF->getContents().empty())
- return;
- TextSection->setFlags(TextSection->getFlags() | ELF::SHF_ARM_PURECODE);
- }
- }
- std::unique_ptr<MCObjectTargetWriter>
- llvm::createARMELFObjectWriter(uint8_t OSABI) {
- return std::make_unique<ARMELFObjectWriter>(OSABI);
- }
|