Index: include/llvm/MC/MCELFStreamer.h =================================================================== --- include/llvm/MC/MCELFStreamer.h +++ include/llvm/MC/MCELFStreamer.h @@ -0,0 +1,109 @@ +//===- MCELFStreamer.h - MCStreamer ELF Object File Interface ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCELFSTREAMER_H +#define LLVM_MC_MCELFSTREAMER_H + +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/MC/MCDirectives.h" +#include "llvm/MC/MCObjectStreamer.h" +#include "llvm/MC/SectionKind.h" + +#include + +#include + +namespace llvm { +class MCAsmBackend; +class MCAssembler; +class MCCodeEmitter; +class MCExpr; +class MCInst; +class MCSymbol; +class MCSymbolData; +class raw_ostream; + +class MCELFStreamer : public MCObjectStreamer { +public: + MCELFStreamer(MCContext &Context, MCAsmBackend &TAB, + raw_ostream &OS, MCCodeEmitter *Emitter) + : MCObjectStreamer(Context, TAB, OS, Emitter) {} + + MCELFStreamer(MCContext &Context, MCAsmBackend &TAB, + raw_ostream &OS, MCCodeEmitter *Emitter, + MCAssembler *Assembler) + : MCObjectStreamer(Context, TAB, OS, Emitter, Assembler) {} + + virtual ~MCELFStreamer(); + + /// @name MCStreamer Interface + /// @{ + + virtual void InitSections(); + virtual void ChangeSection(const MCSection *Section); + virtual void EmitLabel(MCSymbol *Symbol); + virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); + virtual void EmitThumbFunc(MCSymbol *Func); + virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol); + virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); + virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue); + virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment); + virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol); + virtual void EmitCOFFSymbolStorageClass(int StorageClass); + virtual void EmitCOFFSymbolType(int Type); + virtual void EndCOFFSymbolDef(); + + virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value); + + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment); + + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, + uint64_t Size = 0, unsigned ByteAlignment = 0); + virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment = 0); + virtual void EmitValueImpl(const MCExpr *Value, unsigned Size, + unsigned AddrSpace); + + virtual void EmitFileDirective(StringRef Filename); + + virtual void EmitTCEntry(const MCSymbol &S); + + virtual void FinishImpl(); + /// @} + +private: + virtual void EmitInstToFragment(const MCInst &Inst); + virtual void EmitInstToData(const MCInst &Inst); + + void fixSymbolsInTLSFixups(const MCExpr *expr); + + struct LocalCommon { + MCSymbolData *SD; + uint64_t Size; + unsigned ByteAlignment; + }; + + std::vector LocalCommons; + + SmallPtrSet BindingExplicitlySet; + + + void SetSection(StringRef Section, unsigned Type, unsigned Flags, + SectionKind Kind); + void SetSectionData(); + void SetSectionText(); + void SetSectionBss(); +}; + +} // end namespace llvm + +#endif Index: include/llvm/MC/MCExpr.h =================================================================== --- include/llvm/MC/MCExpr.h +++ include/llvm/MC/MCExpr.h @@ -160,6 +160,7 @@ VK_TLVP, // Mach-O thread local variable relocation VK_SECREL, // FIXME: We'd really like to use the generic Kinds listed above for these. + VK_ARM_NONE, VK_ARM_PLT, // ARM-style PLT references. i.e., (PLT) instead of @PLT VK_ARM_TLSGD, // ditto for TLSGD, GOT, GOTOFF, TPOFF and GOTTPOFF VK_ARM_GOT, @@ -168,6 +169,7 @@ VK_ARM_GOTTPOFF, VK_ARM_TARGET1, VK_ARM_TARGET2, + VK_ARM_PREL31, VK_PPC_TOC, // TOC base VK_PPC_TOC_ENTRY, // TOC entry Index: include/llvm/MC/MCStreamer.h =================================================================== --- include/llvm/MC/MCStreamer.h +++ include/llvm/MC/MCStreamer.h @@ -619,6 +619,12 @@ raw_ostream &OS, MCCodeEmitter *CE, bool RelaxAll, bool NoExecStack); + /// createARMELFStreamer - Create a machine code streamer which will generate + /// ARM-specific ELF format object files. + MCStreamer *createARMELFStreamer(MCContext &Ctx, MCAsmBackend &TAB, + raw_ostream &OS, MCCodeEmitter *CE, + bool RelaxAll, bool NoExecStack); + /// createPureStreamer - Create a machine code streamer which will generate /// "pure" MC object files, for use with MC-JIT and testing tools. /// Index: lib/MC/ELFObjectWriter.cpp =================================================================== --- lib/MC/ELFObjectWriter.cpp +++ lib/MC/ELFObjectWriter.cpp @@ -1333,6 +1333,24 @@ break; } + if (TargetObjectWriter->getEMachine() == ELF::EM_ARM && + Section.getType() == ELF::SHT_ARM_EXIDX) { + StringRef SecName(Section.getSectionName()); + if (SecName == ".ARM.exidx") { + sh_link = SectionIndexMap.lookup( + Asm.getContext().getELFSection(".text", + ELF::SHT_PROGBITS, + ELF::SHF_EXECINSTR | ELF::SHF_ALLOC, + SectionKind::getText())); + } else if (SecName.startswith(".ARM.exidx")) { + sh_link = SectionIndexMap.lookup( + Asm.getContext().getELFSection(SecName.substr(sizeof(".ARM.exidx") - 1), + ELF::SHT_PROGBITS, + ELF::SHF_EXECINSTR | ELF::SHF_ALLOC, + SectionKind::getText())); + } + } + WriteSecHdrEntry(SectionStringTableIndex[&Section], Section.getType(), Section.getFlags(), 0, Offset, Size, sh_link, sh_info, Alignment, Section.getEntrySize()); Index: lib/MC/MCELFStreamer.cpp =================================================================== --- lib/MC/MCELFStreamer.cpp +++ lib/MC/MCELFStreamer.cpp @@ -11,6 +11,8 @@ // //===----------------------------------------------------------------------===// +#include "llvm/MC/MCELFStreamer.h" + #include "MCELF.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringExtras.h" @@ -35,117 +37,37 @@ using namespace llvm; -namespace { -class MCELFStreamer : public MCObjectStreamer { -public: - MCELFStreamer(MCContext &Context, MCAsmBackend &TAB, - raw_ostream &OS, MCCodeEmitter *Emitter) - : MCObjectStreamer(Context, TAB, OS, Emitter) {} - MCELFStreamer(MCContext &Context, MCAsmBackend &TAB, - raw_ostream &OS, MCCodeEmitter *Emitter, - MCAssembler *Assembler) - : MCObjectStreamer(Context, TAB, OS, Emitter, Assembler) {} +inline void MCELFStreamer::SetSection(StringRef Section, unsigned Type, + unsigned Flags, SectionKind Kind) { + SwitchSection(getContext().getELFSection(Section, Type, Flags, Kind)); +} +inline void MCELFStreamer::SetSectionData() { + SetSection(".data", + ELF::SHT_PROGBITS, + ELF::SHF_WRITE | ELF::SHF_ALLOC, + SectionKind::getDataRel()); + EmitCodeAlignment(4, 0); +} - ~MCELFStreamer() {} +inline void MCELFStreamer::SetSectionText() { + SetSection(".text", + ELF::SHT_PROGBITS, + ELF::SHF_EXECINSTR | ELF::SHF_ALLOC, + SectionKind::getText()); + EmitCodeAlignment(4, 0); +} - /// @name MCStreamer Interface - /// @{ +inline void MCELFStreamer::SetSectionBss() { + SetSection(".bss", + ELF::SHT_NOBITS, + ELF::SHF_WRITE | ELF::SHF_ALLOC, + SectionKind::getBSS()); + EmitCodeAlignment(4, 0); +} - virtual void InitSections(); - virtual void ChangeSection(const MCSection *Section); - virtual void EmitLabel(MCSymbol *Symbol); - virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); - virtual void EmitThumbFunc(MCSymbol *Func); - virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); - virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol); - virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); - virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { - llvm_unreachable("ELF doesn't support this directive"); - } - virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, - unsigned ByteAlignment); - virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol) { - llvm_unreachable("ELF doesn't support this directive"); - } - - virtual void EmitCOFFSymbolStorageClass(int StorageClass) { - llvm_unreachable("ELF doesn't support this directive"); - } - - virtual void EmitCOFFSymbolType(int Type) { - llvm_unreachable("ELF doesn't support this directive"); - } - - virtual void EndCOFFSymbolDef() { - llvm_unreachable("ELF doesn't support this directive"); - } - - virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { - MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); - SD.setSize(Value); - } - - virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, - unsigned ByteAlignment); - - virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, - uint64_t Size = 0, unsigned ByteAlignment = 0) { - llvm_unreachable("ELF doesn't support this directive"); - } - virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, - uint64_t Size, unsigned ByteAlignment = 0) { - llvm_unreachable("ELF doesn't support this directive"); - } - virtual void EmitValueImpl(const MCExpr *Value, unsigned Size, - unsigned AddrSpace); - - virtual void EmitFileDirective(StringRef Filename); - - virtual void EmitTCEntry(const MCSymbol &S); - - virtual void FinishImpl(); - -private: - virtual void EmitInstToFragment(const MCInst &Inst); - virtual void EmitInstToData(const MCInst &Inst); - - void fixSymbolsInTLSFixups(const MCExpr *expr); - - struct LocalCommon { - MCSymbolData *SD; - uint64_t Size; - unsigned ByteAlignment; - }; - std::vector LocalCommons; - - SmallPtrSet BindingExplicitlySet; - /// @} - void SetSection(StringRef Section, unsigned Type, unsigned Flags, - SectionKind Kind) { - SwitchSection(getContext().getELFSection(Section, Type, Flags, Kind)); - } - - void SetSectionData() { - SetSection(".data", ELF::SHT_PROGBITS, - ELF::SHF_WRITE |ELF::SHF_ALLOC, - SectionKind::getDataRel()); - EmitCodeAlignment(4, 0); - } - void SetSectionText() { - SetSection(".text", ELF::SHT_PROGBITS, - ELF::SHF_EXECINSTR | - ELF::SHF_ALLOC, SectionKind::getText()); - EmitCodeAlignment(4, 0); - } - void SetSectionBss() { - SetSection(".bss", ELF::SHT_NOBITS, - ELF::SHF_WRITE | - ELF::SHF_ALLOC, SectionKind::getBSS()); - EmitCodeAlignment(4, 0); - } -}; +MCELFStreamer::~MCELFStreamer() { } void MCELFStreamer::InitSections() { @@ -341,6 +263,11 @@ SD.setSize(MCConstantExpr::Create(Size, getContext())); } +void MCELFStreamer::EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + SD.setSize(Value); +} + void MCELFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { // FIXME: Should this be caught and done earlier? @@ -487,3 +414,33 @@ S->getAssembler().setNoExecStack(true); return S; } + +void MCELFStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { + llvm_unreachable("ELF doesn't support this directive"); +} + +void MCELFStreamer::BeginCOFFSymbolDef(const MCSymbol *Symbol) { + llvm_unreachable("ELF doesn't support this directive"); +} + +void MCELFStreamer::EmitCOFFSymbolStorageClass(int StorageClass) { + llvm_unreachable("ELF doesn't support this directive"); +} + +void MCELFStreamer::EmitCOFFSymbolType(int Type) { + llvm_unreachable("ELF doesn't support this directive"); +} + +void MCELFStreamer::EndCOFFSymbolDef() { + llvm_unreachable("ELF doesn't support this directive"); +} + +void MCELFStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment) { + llvm_unreachable("ELF doesn't support this directive"); +} + +void MCELFStreamer::EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment) { + llvm_unreachable("ELF doesn't support this directive"); +} Index: lib/MC/MCExpr.cpp =================================================================== --- lib/MC/MCExpr.cpp +++ lib/MC/MCExpr.cpp @@ -54,14 +54,16 @@ else OS << Sym; - if (SRE.getKind() == MCSymbolRefExpr::VK_ARM_PLT || + if (SRE.getKind() == MCSymbolRefExpr::VK_ARM_NONE || + SRE.getKind() == MCSymbolRefExpr::VK_ARM_PLT || SRE.getKind() == MCSymbolRefExpr::VK_ARM_TLSGD || SRE.getKind() == MCSymbolRefExpr::VK_ARM_GOT || SRE.getKind() == MCSymbolRefExpr::VK_ARM_GOTOFF || SRE.getKind() == MCSymbolRefExpr::VK_ARM_TPOFF || SRE.getKind() == MCSymbolRefExpr::VK_ARM_GOTTPOFF || SRE.getKind() == MCSymbolRefExpr::VK_ARM_TARGET1 || - SRE.getKind() == MCSymbolRefExpr::VK_ARM_TARGET2) + SRE.getKind() == MCSymbolRefExpr::VK_ARM_TARGET2 || + SRE.getKind() == MCSymbolRefExpr::VK_ARM_PREL31) OS << MCSymbolRefExpr::getVariantKindName(SRE.getKind()); else if (SRE.getKind() != MCSymbolRefExpr::VK_None && SRE.getKind() != MCSymbolRefExpr::VK_PPC_DARWIN_HA16 && @@ -193,6 +195,7 @@ case VK_DTPOFF: return "DTPOFF"; case VK_TLVP: return "TLVP"; case VK_SECREL: return "SECREL"; + case VK_ARM_NONE: return "(NONE)"; case VK_ARM_PLT: return "(PLT)"; case VK_ARM_GOT: return "(GOT)"; case VK_ARM_GOTOFF: return "(GOTOFF)"; @@ -201,6 +204,7 @@ case VK_ARM_TLSGD: return "(tlsgd)"; case VK_ARM_TARGET1: return "(target1)"; case VK_ARM_TARGET2: return "(target2)"; + case VK_ARM_PREL31: return "(prel31)"; case VK_PPC_TOC: return "tocbase"; case VK_PPC_TOC_ENTRY: return "toc"; case VK_PPC_DARWIN_HA16: return "ha16"; Index: lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp +++ lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp @@ -119,6 +119,9 @@ .Default(true); EmitThisSym = false; break; + case ELF::R_ARM_PREL31: + EmitThisSym = false; + break; } } else { NonPCRelCount++; @@ -133,6 +136,7 @@ switch (RelocType) { default: EmitThisSym = true; break; case ELF::R_ARM_ABS32: EmitThisSym = false; break; + case ELF::R_ARM_PREL31: EmitThisSym = false; break; } } @@ -225,6 +229,9 @@ case FK_Data_4: switch (Modifier) { default: llvm_unreachable("Unsupported Modifier"); + case MCSymbolRefExpr::VK_ARM_NONE: + Type = ELF::R_ARM_NONE; + break; case MCSymbolRefExpr::VK_ARM_GOT: Type = ELF::R_ARM_GOT_BREL; break; @@ -249,6 +256,9 @@ case MCSymbolRefExpr::VK_ARM_TARGET2: Type = ELF::R_ARM_TARGET2; break; + case MCSymbolRefExpr::VK_ARM_PREL31: + Type = ELF::R_ARM_PREL31; + break; } break; case ARM::fixup_arm_ldst_pcrel_12: Index: lib/Target/ARM/MCTargetDesc/ARMMCELFStreamer.cpp =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMMCELFStreamer.cpp +++ lib/Target/ARM/MCTargetDesc/ARMMCELFStreamer.cpp @@ -0,0 +1,597 @@ +//===- lib/Target/ARM/MCTargetDesc/ARMMCELFStreamer.cpp -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// ARMMCELFStreamer is an ELF object file streamer. It implements several +// ARM specific pseudo-instructions, such as fnstart, setfp, save, vsave, +// pad, personality, handlerdata, and fnend. These pseudo-instruction are +// essential to generate zero-cost exception table for ARM. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCELFStreamer.h" + +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCELFSymbolFlags.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCObjectStreamer.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCValue.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ELF.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/LEB128.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +namespace { + +// The stack pointer register encoding value +const uint16_t ARM_SP = 13u; // MRI.getEncodingValue(llvm::ARM::SP) + +class UnwindOpcodeAssembler { +private: + size_t Offset; + SmallVector Ops; + +public: + UnwindOpcodeAssembler(): Offset(2) { + // Note: These are placeholders for possible additional prefix for unwind + // opcodes. Read Finalize() for more details. + Ops.push_back(0x00); + Ops.push_back(0x00); + } + + /// Reset the unwind opcode assembler. + void Reset() { + Ops.resize(0); + + // Note: These are placeholders for possible additional prefix for unwind + // opcodes. Read Finalize() for more details. + Ops.push_back(0x00); + Ops.push_back(0x00); + Offset = 2; + } + + /// Get the size of the opcodes in bytes. + size_t getOpcodeSize() const { + return Ops.size() - 2; + } + + /// Get the size of the payload (including the size byte) + size_t size() const { + return Ops.size() - Offset; + } + + /// Get the beginning of the payload + const uint8_t *begin() const { + return Ops.begin() + Offset; + } + + /// Get the payload + StringRef data() const { + return StringRef(reinterpret_cast(begin()), size()); + } + + /// Emit unwind opcodes for .save directives + void EmitRegSave(uint32_t RegSave); + + /// Emit unwind opcodes for .vsave directives + void EmitVFPRegSave(uint32_t VFPRegSave); + + /// Emit unwind opcodes for .setfp directives + void EmitSetFP(uint16_t FpReg); + + /// Emit unwind opcodes to update stack pointer + void EmitSPOffset(int64_t Offset); + + /// Finalize the unwind opcode sequence for EmitBytes() + void Finalize(int PersonalityIndex); + +private: + /// Add the length prefix to the payload + void AddOpcodeSizePrefix(size_t Pos); + + /// Add personality index prefix in some compact format + void AddPersonalityIndexPrefix(size_t Pos, int PersonalityIndex); + + /// Fill the words with finish opcode if it is not aligned + void EmitFinishOpcodes(); +}; + +class ARMMCELFStreamer : public MCELFStreamer { +private: + // ARM Exception Handling Frame Information + MCSymbol *ExTab; + MCSymbol *FnStart; + const MCSymbol *Personality; + uint32_t VFPRegSave; // Register mask for {d31-d0} + uint32_t RegSave; // Register mask for {r15-r0} + int64_t SPOffset; + uint16_t FpReg; + bool UsedFP; + bool CantUnwind; + + UnwindOpcodeAssembler UnwindOpAsm; + +public: + ARMMCELFStreamer(MCContext &Context, MCAsmBackend &TAB, + raw_ostream &OS, MCCodeEmitter *Emitter) + : MCELFStreamer(Context, TAB, OS, Emitter), ExTab(0), FnStart(0), + Personality(0), VFPRegSave(0), RegSave(0), SPOffset(0), FpReg(ARM_SP), + UsedFP(false), CantUnwind(false) { + } + + ARMMCELFStreamer(MCContext &Context, MCAsmBackend &TAB, + raw_ostream &OS, MCCodeEmitter *Emitter, + MCAssembler *Assembler) + : MCELFStreamer(Context, TAB, OS, Emitter, Assembler), ExTab(0), FnStart(0), + Personality(0), VFPRegSave(0), RegSave(0), SPOffset(0), FpReg(ARM_SP), + UsedFP(false), CantUnwind(false) { + } + + ~ARMMCELFStreamer(); + + virtual void EmitFnStart(); + virtual void EmitFnEnd(); + virtual void EmitCantUnwind(); + virtual void EmitPersonality(const MCSymbol *Per); + virtual void EmitHandlerData(); + virtual void EmitSetFP(unsigned NewFpReg, + unsigned NewSpReg, + int64_t Offset = 0); + virtual void EmitPad(int64_t Offset); + virtual void EmitRegSave(const SmallVectorImpl &RegList, + bool isVector); + +private: + void Reset(); + + void EmitPersonalityFixup(StringRef Name); + + void CollectUnwindOpcodes(); + + void SetSectionARMEH(const char *Prefix, unsigned Type, unsigned Flags, + SectionKind Kind, const MCSymbol &Fn) { + const MCSectionELF &FnSection = + static_cast(Fn.getSection()); + + // Create the name for new section + StringRef FnSecName(FnSection.getSectionName()); + SmallString<128> EHSecName(Prefix); + if (FnSecName != ".text") { + EHSecName += FnSecName; + } + + // Get .ARM.extab or .ARM.exidx section + const MCSectionELF *EHSection = NULL; + if (const MCSymbol *Group = FnSection.getGroup()) { + EHSection = getContext().getELFSection( + EHSecName, Type, Flags | ELF::SHF_GROUP, Kind, + FnSection.getEntrySize(), Group->getName()); + } else { + EHSection = getContext().getELFSection(EHSecName, Type, Flags, Kind); + } + + // Switch to .ARM.extab or .ARM.exidx section + SwitchSection(EHSection); + EmitCodeAlignment(4, 0); + } + + void SetSectionARMExTab(const MCSymbol &FnStart) { + SetSectionARMEH(".ARM.extab", + ELF::SHT_PROGBITS, + ELF::SHF_ALLOC, + SectionKind::getDataRel(), + FnStart); + } + + void SetSectionARMExIdx(const MCSymbol &FnStart) { + SetSectionARMEH(".ARM.exidx", + ELF::SHT_ARM_EXIDX, + ELF::SHF_ALLOC | ELF::SHF_LINK_ORDER, + SectionKind::getDataRel(), + FnStart); + } +}; + +} // end anonymous namespace + +void UnwindOpcodeAssembler::EmitRegSave(uint32_t RegSave) { + if (RegSave == 0u) { + return; + } + + // One bytes opcode to save register r14 and r11-r4 + if (RegSave & 0x0010u) { + uint32_t Range = 0; + uint32_t Mask = 0x0010; + for (uint32_t Bit = (1u << 5); Bit < (1u << 12); Bit <<= 1) { + if (RegSave & Bit) { + ++Range; + Mask |= Bit; + } else { + break; + } + } + + if (RegSave & 0x4000u) { + if (((RegSave & 0xbff0u) & (~Mask)) == 0u) { + // Pop r[14] + r[4 : (4 + n)] + Ops.push_back(0xa8u | Range); + RegSave &= 0x000fu; + } + } else { + if (((RegSave & 0xfff0u) & (~Mask)) == 0u) { + // Pop r[4 : (4 + n)] + Ops.push_back(0xa0u | Range); + RegSave &= 0x000fu; + } + } + } + + // Two bytes opcode to save register r15-r4 + if ((RegSave & 0xfff0u) != 0) { + uint32_t Op = 0x8000u | (RegSave >> 4); + Ops.push_back(static_cast(Op >> 8)); + Ops.push_back(static_cast(Op & 0xff)); + } + + // Opcode to save register r3-r0 + if ((RegSave & 0x000fu) != 0) { + uint32_t Op = 0xb100u | (RegSave & 0x000fu); + Ops.push_back(static_cast(Op >> 8)); + Ops.push_back(static_cast(Op & 0xff)); + } +} + +/// Emit unwind opcodes for .vsave directives +void UnwindOpcodeAssembler::EmitVFPRegSave(uint32_t VFPRegSave) { + size_t i = 32; + + while (i > 16) { + uint32_t Bit = 1u << (i - 1); + if ((VFPRegSave & Bit) == 0u) { + --i; + continue; + } + + uint32_t Range = 0; + + --i; + Bit >>= 1; + + while (i > 16 && (VFPRegSave & Bit)) { + --i; + ++Range; + Bit >>= 1; + } + + Ops.push_back(0xc8u); + Ops.push_back(((i - 16) << 4) | Range); + } + + while (i > 0) { + uint32_t Bit = 1u << (i - 1); + if ((VFPRegSave & Bit) == 0u) { + --i; + continue; + } + + uint32_t Range = 0; + + --i; + Bit >>= 1; + + while (i > 0 && (VFPRegSave & Bit)) { + --i; + ++Range; + Bit >>= 1; + } + + Ops.push_back(0xc9u); + Ops.push_back((i << 4) | Range); + } +} + +/// Emit unwind opcodes for .setfp directives +void UnwindOpcodeAssembler::EmitSetFP(uint16_t FpReg) { + Ops.push_back(0x90u | FpReg); +} + +/// Emit unwind opcodes to update stack pointer +void UnwindOpcodeAssembler::EmitSPOffset(int64_t Offset) { + // NOTE: + // 0xb2u is the prefix for vSP = vSP + (val << 2) + 0x204. + // 0x00u is the prefix for vSP = vSP + (val << 2) + 0x4. + // 0x40u is the prefix for vSP = vSP - (val << 2) - 0x4. + + // REMARK: + // 0x3fu is the opcode for vSP = vSP + 0x100. + // 0x7fu is the opcode for vSP = vSP - 0x100. + + if (Offset > 0x200) { + uint8_t Buff[10]; + size_t Size = encodeULEB128((Offset - 0x204) >> 2, Buff); + Ops.push_back(0xb2u); // ULEB128 format + Ops.append(Buff, Buff + Size); + } else if (Offset > 0) { + if (Offset > 0x100) { + Ops.push_back(0x3fu); + Offset -= 0x100; + } + Ops.push_back(static_cast((Offset - 4) >> 2)); + } else if (Offset < 0) { + while (Offset < -0x100) { + Ops.push_back(0x7fu); + Offset += 0x100; + } + Ops.push_back(0x40u | static_cast(((-Offset) - 4) >> 2)); + } +} + +void UnwindOpcodeAssembler::AddOpcodeSizePrefix(size_t Pos) { + size_t SizeInWords = (size() + 3) / 4; + if (SizeInWords > 0x100u) { + report_fatal_error("Too many unwind opcodes"); + } else { + Ops[Pos] = static_cast(SizeInWords - 1); + } +} + +void UnwindOpcodeAssembler::AddPersonalityIndexPrefix(size_t Pos, + int PersonalityIndex) { + Ops[Pos] = 0x80u | PersonalityIndex; +} + +void UnwindOpcodeAssembler::EmitFinishOpcodes() { + for (size_t i = (0x4u - (size() & 0x3u)) & 0x3u; i > 0; --i) { + Ops.push_back(0xb0); // Finish opcode + } +} + +void UnwindOpcodeAssembler::Finalize(int PersonalityIndex) { + // Add the prefix properly + if (PersonalityIndex == 0) { + // __aeabi_unwind_cpp_pr0: [ 0x80 , OP1 , OP2 , OP3 ] + if (getOpcodeSize() > 3) { + report_fatal_error("too many opcodes for __aeabi_unwind_cpp_pr0"); + } + + Offset = 1; + AddPersonalityIndexPrefix(1, PersonalityIndex); + + } else if (PersonalityIndex == 1) { + // __aeabi_unwind_cpp_pr1: [ 0x81 , SIZE , OP1 , OP2 , ... ] + Offset = 0; + AddPersonalityIndexPrefix(0, PersonalityIndex); + AddOpcodeSizePrefix(1); + + } else if (PersonalityIndex == -1) { + // Personality specified by .personality directive + Offset = 1; + AddOpcodeSizePrefix(1); + } + + // Emit the padding finish opcodes if the size() is not multiple of 4. + EmitFinishOpcodes(); + + // Swap the byte order + uint8_t *Ptr = Ops.begin() + Offset; + assert(size() % 4 == 0); + for (size_t i = 0, n = size(); i < n; i += 4) { + std::swap(Ptr[i], Ptr[i + 3]); + std::swap(Ptr[i + 1], Ptr[i + 2]); + } +} + +ARMMCELFStreamer::~ARMMCELFStreamer() { +} + +void ARMMCELFStreamer::Reset() { + ExTab = NULL; + FnStart = NULL; + Personality = NULL; + VFPRegSave = 0; + RegSave = 0; + FpReg = ARM_SP; + SPOffset = 0; + UsedFP = false; + CantUnwind = false; + + UnwindOpAsm.Reset(); +} + +void ARMMCELFStreamer::EmitPersonalityFixup(StringRef Name) { + const MCSymbol *PersonalitySym = getContext().GetOrCreateSymbol(Name); + + const MCSymbolRefExpr *PersonalityRef = + MCSymbolRefExpr::Create(PersonalitySym, + MCSymbolRefExpr::VK_ARM_NONE, + getContext()); + + // Add the R_ARM_NONE fixup at the same position + AddValueSymbols(PersonalityRef); + MCDataFragment *DF = getOrCreateDataFragment(); + DF->addFixup(MCFixup::Create(DF->getContents().size(), + PersonalityRef, + MCFixup::getKindForSize(4, false))); +} + +void ARMMCELFStreamer::CollectUnwindOpcodes() { + UnwindOpAsm.EmitSPOffset(SPOffset); + if (UsedFP) { + UnwindOpAsm.EmitSetFP(FpReg); + } + UnwindOpAsm.EmitVFPRegSave(VFPRegSave); + UnwindOpAsm.EmitRegSave(RegSave); +} + +void ARMMCELFStreamer::EmitFnStart() { + assert(FnStart == 0); + FnStart = getContext().CreateTempSymbol(); + EmitLabel(FnStart); +} + +void ARMMCELFStreamer::EmitFnEnd() { + // Emit unwind opcodes if there is no .handlerdata directive + int PersonalityIndex = -1; + if (!ExTab && !CantUnwind) { + CollectUnwindOpcodes(); + + if (UnwindOpAsm.getOpcodeSize() <= 3) { + PersonalityIndex = 0; + UnwindOpAsm.Finalize(PersonalityIndex); + } else { + PersonalityIndex = 1; + UnwindOpAsm.Finalize(PersonalityIndex); + + // For __aeabi_unwind_cpp_pr1, we have to emit opcodes in .ARM.extab. + SetSectionARMExTab(*FnStart); + + // Create temporary label for reference + ExTab = getContext().CreateTempSymbol(); + EmitLabel(ExTab); + EmitBytes(UnwindOpAsm.data(), 0); + } + } + + // Emit the exception index table entry + assert(FnStart && ".fnstart must preceeds .fnend"); + + SetSectionARMExIdx(*FnStart); + + if (PersonalityIndex == 0) { + EmitPersonalityFixup("__aeabi_unwind_cpp_pr0"); + } else if (PersonalityIndex == 1) { + EmitPersonalityFixup("__aeabi_unwind_cpp_pr1"); + } + + const MCSymbolRefExpr *FnStartRef = + MCSymbolRefExpr::Create(FnStart, + MCSymbolRefExpr::VK_ARM_PREL31, + getContext()); + + EmitValue(FnStartRef, 4, 0); + + if (CantUnwind) { + EmitIntValue(0x00000001U, 4, 0); + } else if (ExTab) { + const MCSymbolRefExpr *ExTabEntryRef = + MCSymbolRefExpr::Create(ExTab, + MCSymbolRefExpr::VK_ARM_PREL31, + getContext()); + EmitValue(ExTabEntryRef, 4, 0); + } else { + assert(UnwindOpAsm.size() == 4u); + EmitBytes(UnwindOpAsm.data(), 0); + } + + // Clean exception handling frame information + Reset(); +} + +void ARMMCELFStreamer::EmitCantUnwind() { + CantUnwind = true; +} + +void ARMMCELFStreamer::EmitHandlerData() { + SetSectionARMExTab(*FnStart); + + // Create .ARM.extab label for offset in .ARM.exidx + ExTab = getContext().CreateTempSymbol(); + EmitLabel(ExTab); + + // Emit Personality + if (!Personality) { + report_fatal_error(".personality directive must preceed .handlerdata"); + } + + const MCSymbolRefExpr *PersonalityRef = + MCSymbolRefExpr::Create(Personality, + MCSymbolRefExpr::VK_ARM_PREL31, + getContext()); + + EmitValue(PersonalityRef, 4, 0); + + // Emit unwind opcodes + CollectUnwindOpcodes(); + UnwindOpAsm.Finalize(-1); + + EmitBytes(UnwindOpAsm.data(), 0); +} + +void ARMMCELFStreamer::EmitPersonality(const MCSymbol *Per) { + Personality = Per; +} + +void ARMMCELFStreamer::EmitSetFP(unsigned NewFpReg, + unsigned NewSpReg, + int64_t Offset) { + const MCRegisterInfo &MRI = getContext().getRegisterInfo(); + + uint16_t NewFpRegEncVal = MRI.getEncodingValue(NewFpReg); + uint16_t NewSpRegEncVal = MRI.getEncodingValue(NewSpReg); + + if (NewSpRegEncVal != ARM_SP && NewSpRegEncVal != FpReg) { + report_fatal_error("the 2nd operand of .setfp directive should be " + "either sp or fp."); + } + + UsedFP = true; + FpReg = NewFpRegEncVal; + + assert(Offset == 0 && "not implemented"); +} + +void ARMMCELFStreamer::EmitPad(int64_t Offset) { + SPOffset += Offset; +} + +void ARMMCELFStreamer::EmitRegSave(const SmallVectorImpl &RegList, + bool IsVector) { + const MCRegisterInfo &MRI = getContext().getRegisterInfo(); + + unsigned Max = IsVector ? 32 : 16; + uint32_t &RegMask = IsVector ? VFPRegSave : RegSave; + + for (size_t i = 0; i < RegList.size(); ++i) { + unsigned Reg = MRI.getEncodingValue(RegList[i]); + if (Reg < Max) { + RegMask |= 1u << Reg; + } else { + report_fatal_error("Unexpected register " + + StringRef(MRI.getName(RegList[i])) + + " in .save/.vsave directive"); + } + } +} + +MCStreamer *llvm::createARMELFStreamer(MCContext &Context, MCAsmBackend &MAB, + raw_ostream &OS, MCCodeEmitter *CE, + bool RelaxAll, bool NoExecStack) { + ARMMCELFStreamer *S = new ARMMCELFStreamer(Context, MAB, OS, CE); + if (RelaxAll) + S->getAssembler().setRelaxAll(true); + if (NoExecStack) + S->getAssembler().setNoExecStack(true); + return S; +} Index: lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp +++ lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp @@ -186,7 +186,7 @@ llvm_unreachable("ARM does not support Windows COFF format"); } - return createELFStreamer(Ctx, MAB, OS, Emitter, false, NoExecStack); + return createARMELFStreamer(Ctx, MAB, OS, Emitter, false, NoExecStack); } static MCInstPrinter *createARMMCInstPrinter(const Target &T, Index: lib/Target/ARM/MCTargetDesc/CMakeLists.txt =================================================================== --- lib/Target/ARM/MCTargetDesc/CMakeLists.txt +++ lib/Target/ARM/MCTargetDesc/CMakeLists.txt @@ -3,6 +3,7 @@ ARMELFObjectWriter.cpp ARMMCAsmInfo.cpp ARMMCCodeEmitter.cpp + ARMMCELFStreamer.cpp ARMMCExpr.cpp ARMMCTargetDesc.cpp ARMMachObjectWriter.cpp