diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index 419e0068033..946baf1b7c4 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -85,6 +85,7 @@ public: virtual void emitFnEnd() = 0; virtual void emitCantUnwind() = 0; virtual void emitPersonality(const MCSymbol *Personality) = 0; + virtual void emitPersonalityIndex(unsigned Index) = 0; virtual void emitHandlerData() = 0; virtual void emitSetFP(unsigned FpReg, unsigned SpReg, int64_t Offset = 0) = 0; diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 1a3df51acd9..0a1ba9105a7 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -40,6 +40,7 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCTargetAsmParser.h" #include "llvm/Support/ARMBuildAttributes.h" +#include "llvm/Support/ARMEHABI.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ELF.h" #include "llvm/Support/MathExtras.h" @@ -121,6 +122,7 @@ class UnwindContext { Locs FnStartLocs; Locs CantUnwindLocs; Locs PersonalityLocs; + Locs PersonalityIndexLocs; Locs HandlerDataLocs; int FPReg; @@ -130,12 +132,15 @@ public: bool hasFnStart() const { return !FnStartLocs.empty(); } bool cantUnwind() const { return !CantUnwindLocs.empty(); } bool hasHandlerData() const { return !HandlerDataLocs.empty(); } - bool hasPersonality() const { return !PersonalityLocs.empty(); } + bool hasPersonality() const { + return !(PersonalityLocs.empty() && PersonalityIndexLocs.empty()); + } void recordFnStart(SMLoc L) { FnStartLocs.push_back(L); } void recordCantUnwind(SMLoc L) { CantUnwindLocs.push_back(L); } void recordPersonality(SMLoc L) { PersonalityLocs.push_back(L); } void recordHandlerData(SMLoc L) { HandlerDataLocs.push_back(L); } + void recordPersonalityIndex(SMLoc L) { PersonalityIndexLocs.push_back(L); } void saveFPReg(int Reg) { FPReg = Reg; } int getFPReg() const { return FPReg; } @@ -157,8 +162,18 @@ public: } void emitPersonalityLocNotes() const { for (Locs::const_iterator PI = PersonalityLocs.begin(), - PE = PersonalityLocs.end(); PI != PE; ++PI) - Parser.Note(*PI, ".personality was specified here"); + PE = PersonalityLocs.end(), + PII = PersonalityIndexLocs.begin(), + PIE = PersonalityIndexLocs.end(); + PI != PE || PII != PIE;) { + if (PI != PE && (PII == PIE || PI->getPointer() < PII->getPointer())) + Parser.Note(*PI++, ".personality was specified here"); + else if (PII != PIE && (PI == PE || PII->getPointer() < PI->getPointer())) + Parser.Note(*PII++, ".personalityindex was specified here"); + else + llvm_unreachable(".personality and .personalityindex cannot be " + "at the same location"); + } } void reset() { @@ -166,6 +181,7 @@ public: CantUnwindLocs = Locs(); PersonalityLocs = Locs(); HandlerDataLocs = Locs(); + PersonalityIndexLocs = Locs(); FPReg = -1; } }; @@ -278,6 +294,7 @@ class ARMAsmParser : public MCTargetAsmParser { bool parseDirectiveInst(SMLoc L, char Suffix = '\0'); bool parseDirectiveLtorg(SMLoc L); bool parseDirectiveEven(SMLoc L); + bool parseDirectivePersonalityIndex(SMLoc L); StringRef splitMnemonic(StringRef Mnemonic, unsigned &PredicationCode, bool &CarrySetting, unsigned &ProcessorIMod, @@ -8062,6 +8079,8 @@ bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) { return parseDirectiveLtorg(DirectiveID.getLoc()); else if (IDVal == ".even") return parseDirectiveEven(DirectiveID.getLoc()); + else if (IDVal == ".personalityindex") + return parseDirectivePersonalityIndex(DirectiveID.getLoc()); return true; } @@ -8454,6 +8473,9 @@ bool ARMAsmParser::parseDirectiveFnStart(SMLoc L) { return false; } + // Reset the unwind directives parser state + UC.reset(); + getTargetStreamer().emitFnStart(); UC.recordFnStart(L); @@ -8504,6 +8526,8 @@ bool ARMAsmParser::parseDirectiveCantUnwind(SMLoc L) { /// parseDirectivePersonality /// ::= .personality name bool ARMAsmParser::parseDirectivePersonality(SMLoc L) { + bool HasExistingPersonality = UC.hasPersonality(); + UC.recordPersonality(L); // Check the ordering of unwind directives @@ -8521,6 +8545,12 @@ bool ARMAsmParser::parseDirectivePersonality(SMLoc L) { UC.emitHandlerDataLocNotes(); return false; } + if (HasExistingPersonality) { + Parser.eatToEndOfStatement(); + Error(L, "multiple personality directives"); + UC.emitPersonalityLocNotes(); + return false; + } // Parse the name of the personality routine if (Parser.getTok().isNot(AsmToken::Identifier)) { @@ -8830,6 +8860,61 @@ bool ARMAsmParser::parseDirectiveEven(SMLoc L) { return false; } +/// parseDirectivePersonalityIndex +/// ::= .personalityindex index +bool ARMAsmParser::parseDirectivePersonalityIndex(SMLoc L) { + bool HasExistingPersonality = UC.hasPersonality(); + + UC.recordPersonalityIndex(L); + + if (!UC.hasFnStart()) { + Parser.eatToEndOfStatement(); + Error(L, ".fnstart must precede .personalityindex directive"); + return false; + } + if (UC.cantUnwind()) { + Parser.eatToEndOfStatement(); + Error(L, ".personalityindex cannot be used with .cantunwind"); + UC.emitCantUnwindLocNotes(); + return false; + } + if (UC.hasHandlerData()) { + Parser.eatToEndOfStatement(); + Error(L, ".personalityindex must precede .handlerdata directive"); + UC.emitHandlerDataLocNotes(); + return false; + } + if (HasExistingPersonality) { + Parser.eatToEndOfStatement(); + Error(L, "multiple personality directives"); + UC.emitPersonalityLocNotes(); + return false; + } + + const MCExpr *IndexExpression; + SMLoc IndexLoc = Parser.getTok().getLoc(); + if (Parser.parseExpression(IndexExpression)) { + Parser.eatToEndOfStatement(); + return false; + } + + const MCConstantExpr *CE = dyn_cast(IndexExpression); + if (!CE) { + Parser.eatToEndOfStatement(); + Error(IndexLoc, "index must be a constant number"); + return false; + } + if (CE->getValue() < 0 || + CE->getValue() >= ARM::EHABI::NUM_PERSONALITY_INDEX) { + Parser.eatToEndOfStatement(); + Error(IndexLoc, "personality routine index should be in range [0-3]"); + return false; + } + + getTargetStreamer().emitPersonalityIndex(CE->getValue()); + return false; +} + /// Force static initialization. extern "C" void LLVMInitializeARMAsmParser() { RegisterMCAsmParser X(TheARMTarget); diff --git a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp index 4c079262943..82543a45f24 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp @@ -117,6 +117,7 @@ class ARMTargetAsmStreamer : public ARMTargetStreamer { virtual void emitFnEnd(); virtual void emitCantUnwind(); virtual void emitPersonality(const MCSymbol *Personality); + virtual void emitPersonalityIndex(unsigned Index); virtual void emitHandlerData(); virtual void emitSetFP(unsigned FpReg, unsigned SpReg, int64_t Offset = 0); virtual void emitPad(int64_t Offset); @@ -148,6 +149,9 @@ void ARMTargetAsmStreamer::emitCantUnwind() { OS << "\t.cantunwind\n"; } void ARMTargetAsmStreamer::emitPersonality(const MCSymbol *Personality) { OS << "\t.personality " << Personality->getName() << '\n'; } +void ARMTargetAsmStreamer::emitPersonalityIndex(unsigned Index) { + OS << "\t.personalityindex " << Index << '\n'; +} void ARMTargetAsmStreamer::emitHandlerData() { OS << "\t.handlerdata\n"; } void ARMTargetAsmStreamer::emitSetFP(unsigned FpReg, unsigned SpReg, int64_t Offset) { @@ -357,6 +361,7 @@ private: virtual void emitFnEnd(); virtual void emitCantUnwind(); virtual void emitPersonality(const MCSymbol *Personality); + virtual void emitPersonalityIndex(unsigned Index); virtual void emitHandlerData(); virtual void emitSetFP(unsigned FpReg, unsigned SpReg, int64_t Offset = 0); virtual void emitPad(int64_t Offset); @@ -415,6 +420,7 @@ public: void emitFnEnd(); void emitCantUnwind(); void emitPersonality(const MCSymbol *Per); + void emitPersonalityIndex(unsigned index); void emitHandlerData(); void emitSetFP(unsigned NewFpReg, unsigned NewSpReg, int64_t Offset = 0); void emitPad(int64_t Offset); @@ -614,6 +620,9 @@ void ARMTargetELFStreamer::emitCantUnwind() { getStreamer().emitCantUnwind(); } void ARMTargetELFStreamer::emitPersonality(const MCSymbol *Personality) { getStreamer().emitPersonality(Personality); } +void ARMTargetELFStreamer::emitPersonalityIndex(unsigned Index) { + getStreamer().emitPersonalityIndex(Index); +} void ARMTargetELFStreamer::emitHandlerData() { getStreamer().emitHandlerData(); } @@ -1135,6 +1144,11 @@ void ARMELFStreamer::emitPersonality(const MCSymbol *Per) { UnwindOpAsm.setPersonality(Per); } +void ARMELFStreamer::emitPersonalityIndex(unsigned Index) { + assert(Index < ARM::EHABI::NUM_PERSONALITY_INDEX && "invalid index"); + PersonalityIndex = Index; +} + void ARMELFStreamer::emitSetFP(unsigned NewFPReg, unsigned NewSPReg, int64_t Offset) { assert((NewSPReg == ARM::SP || NewSPReg == FPReg) && diff --git a/lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.cpp b/lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.cpp index 8cba45acf30..593fe349b1d 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.cpp @@ -194,14 +194,17 @@ void UnwindOpcodeAssembler::Finalize(unsigned &PersonalityIndex, Result.resize(RoundUpSize); OpStreamer.EmitSize(RoundUpSize); } else { - if (Ops.size() <= 3) { + // If no personalityindex is specified, select ane + if (PersonalityIndex == ARM::EHABI::NUM_PERSONALITY_INDEX) + PersonalityIndex = (Ops.size() <= 3) ? ARM::EHABI::AEABI_UNWIND_CPP_PR0 + : ARM::EHABI::AEABI_UNWIND_CPP_PR1; + if (PersonalityIndex == ARM::EHABI::AEABI_UNWIND_CPP_PR0) { // __aeabi_unwind_cpp_pr0: [ 0x80 , OP1 , OP2 , OP3 ] - PersonalityIndex = ARM::EHABI::AEABI_UNWIND_CPP_PR0; + assert(Ops.size() <= 3 && "too many opcodes for __aeabi_unwind_cpp_pr0"); Result.resize(4); OpStreamer.EmitPersonalityIndex(PersonalityIndex); } else { - // __aeabi_unwind_cpp_pr1: [ 0x81 , SIZE , OP1 , OP2 , ... ] - PersonalityIndex = ARM::EHABI::AEABI_UNWIND_CPP_PR1; + // __aeabi_unwind_cpp_pr{1,2}: [ {0x81,0x82} , SIZE , OP1 , OP2 , ... ] size_t TotalSize = Ops.size() + 2; size_t RoundUpSize = (TotalSize + 3) / 4 * 4; Result.resize(RoundUpSize); diff --git a/test/MC/ARM/eh-directive-personalityindex-diagnostics.s b/test/MC/ARM/eh-directive-personalityindex-diagnostics.s new file mode 100644 index 00000000000..2dc2c8045a6 --- /dev/null +++ b/test/MC/ARM/eh-directive-personalityindex-diagnostics.s @@ -0,0 +1,122 @@ +@ RUN: not llvm-mc -triple armv7-linux-eabi -filetype asm -o /dev/null %s 2>&1 \ +@ RUN: | FileCheck %s + + .syntax unified + .thumb + + .global function + .type function,%function + .thumb_func +function: + .personalityindex 0 + +@ CHECK: error: .fnstart must precede .personalityindex directive +@ CHECK: .personalityindex 0 +@ CHECK: ^ + + .global ununwindable + .type ununwindable,%function + .thumb_func +ununwindable: + .fnstart + .cantunwind + .personalityindex 0 + .fnend + +@ CHECK: error: .personalityindex cannot be used with .cantunwind +@ CHECK: .personalityindex 0 +@ CHECK: ^ +@ CHECK: note: .cantunwind was specified here +@ CHECK: .cantunwind +@ CHECK: ^ + + .global nodata + .type nodata,%function + .thumb_func +nodata: + .fnstart + .handlerdata + .personalityindex 0 + .fnend + +@ CHECK: error: .personalityindex must precede .handlerdata directive +@ CHECK: .personalityindex 0 +@ CHECK: ^ +@ CHECK: note: .handlerdata was specified here +@ CHECK: .handlerdata +@ CHECK: ^ + + .global multiple_personality + .type multiple_personality,%function + .thumb_func +multiple_personality: + .fnstart + .personality __aeabi_personality_pr0 + .personalityindex 0 + .fnend + +@ CHECK: error: multiple personality directives +@ CHECK: .personalityindex 0 +@ CHECK: ^ +@ CHECK: note: .personality was specified here +@ CHECK: .personality __aeabi_personality_pr0 +@ CHECK: ^ +@ CHECK: note: .personalityindex was specified here +@ CHECK: .personalityindex 0 +@ CHECK: ^ + + .global multiple_personality_indicies + .type multiple_personality_indicies,%function + .thumb_func +multiple_personality_indicies: + .fnstart + .personalityindex 0 + .personalityindex 1 + .fnend + +@ CHECK: error: multiple personality directives +@ CHECK: .personalityindex 1 +@ CHECK: ^ +@ CHECK: note: .personalityindex was specified here +@ CHECK: .personalityindex 0 +@ CHECK: ^ +@ CHECK: note: .personalityindex was specified here +@ CHECK: .personalityindex 1 +@ CHECK: ^ + + .global invalid_expression + .type invalid_expression,%function + .thumb_func +invalid_expression: + .fnstart + .personalityindex + .fnend + +@ CHECK: error: unknown token in expression +@ CHECK: .personalityindex +@ CHECK: ^ + + .global nonconstant_expression + .type nonconstant_expression,%function + .thumb_func +nonconstant_expression: + .fnstart + .personalityindex nonconstant_expression + .fnend + +@ CHECK: error: index must be a constant number +@ CHECK: .personalityindex nonconstant_expression +@ CHECK: ^ + + .global bad_index + .type bad_index,%function + .thumb_func +bad_index: + .fnstart + .personalityindex 42 + .fnend + +@ CHECK: error: personality routine index should be in range [0-3] +@ CHECK: .personalityindex 42 +@ CHECK: ^ + diff --git a/test/MC/ARM/eh-directive-personalityindex.s b/test/MC/ARM/eh-directive-personalityindex.s new file mode 100644 index 00000000000..55172275093 --- /dev/null +++ b/test/MC/ARM/eh-directive-personalityindex.s @@ -0,0 +1,202 @@ +@ RUN: llvm-mc -triple armv7-linux-eabi -filetype obj -o - %s \ +@ RUN: | llvm-readobj -s -sd -sr | FileCheck %s + + .syntax unified + .thumb + + + .section .pr0 + + .global pr0 + .type pr0,%function + .thumb_func +pr0: + .fnstart + .personalityindex 0 + bx lr + .fnend + +@ CHECK: Section { +@ CHECK: Name: .ARM.exidx.pr0 +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B0B0B080 +@ CHECK: ) +@ CHECK: } + +@ CHECK: Section { +@ CHECK: Name: .rel.ARM.exidx.pr0 +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 .pr0 0x0 +@ CHECK: 0x0 R_ARM_NONE __aeabi_unwind_cpp_pr0 0x0 +@ CHECK: ] +@ CHECK: } + + .section .pr0.nontrivial + + .global pr0_nontrivial + .type pr0_nontrivial,%function + .thumb_func +pr0_nontrivial: + .fnstart + .personalityindex 0 + .pad #0x10 + sub sp, sp, #0x10 + add sp, sp, #0x10 + bx lr + .fnend + +@ CHECK: Section { +@ CHECK: Name: .ARM.exidx.pr0.nontrivial +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B0B00380 +@ CHECK: ) +@ CHECK: } + +@ CHECK: Section { +@ CHECK: Name: .rel.ARM.exidx.pr0.nontrivial +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 .pr0.nontrivial 0x0 +@ CHECK: 0x0 R_ARM_NONE __aeabi_unwind_cpp_pr0 0x0 +@ CHECK: ] +@ CHECK: } + + .section .pr1 + + .global pr1 + .type pr1,%function + .thumb_func +pr1: + .fnstart + .personalityindex 1 + bx lr + .fnend + +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.pr1 +@ CHECK: SectionData ( +@ CHECK: 0000: B0B00081 00000000 +@ CHECK: ) +@ CHECK: } + +@ CHECK: Section { +@ CHECK: Name: .ARM.exidx.pr1 +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 00000000 +@ CHECK: ) +@ CHECK: } + +@ CHECK: Section { +@ CHECK: Name: .rel.ARM.exidx.pr1 +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 .pr1 0x0 +@ CHECK: 0x0 R_ARM_NONE __aeabi_unwind_cpp_pr1 0x0 +@ CHECK: 0x4 R_ARM_PREL31 .ARM.extab.pr1 0x0 +@ CHECK: ] +@ CHECK: } + + .section .pr1.nontrivial + + .global pr1_nontrivial + .type pr1_nontrivial,%function + .thumb_func +pr1_nontrivial: + .fnstart + .personalityindex 1 + .pad #0x10 + sub sp, sp, #0x10 + add sp, sp, #0x10 + bx lr + .fnend + +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.pr1.nontrivial +@ CHECK: SectionData ( +@ CHECK: 0000: B0030081 00000000 +@ CHECK: ) +@ CHECK: } + +@ CHECK: Section { +@ CHECK: Name: .ARM.exidx.pr1.nontrivial +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 00000000 +@ CHECK: ) +@ CHECK: } + +@ CHECK: Section { +@ CHECK: Name: .rel.ARM.exidx.pr1.nontrivial +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 .pr1.nontrivial 0x0 +@ CHECK: 0x0 R_ARM_NONE __aeabi_unwind_cpp_pr1 0x0 +@ CHECK: 0x4 R_ARM_PREL31 .ARM.extab.pr1.nontrivial 0x0 +@ CHECK: ] +@ CHECK: } + + .section .pr2 + + .global pr2 + .type pr2,%function + .thumb_func +pr2: + .fnstart + .personalityindex 2 + bx lr + .fnend + +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.pr2 +@ CHECK: SectionData ( +@ CHECK: 0000: B0B00082 00000000 +@ CHECK: ) +@ CHECK: } + +@ CHECK: Section { +@ CHECK: Name: .ARM.exidx.pr2 +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 00000000 +@ CHECK: ) +@ CHECK: } + +@ CHECK: Section { +@ CHECK: Name: .rel.ARM.exidx.pr2 +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 .pr2 0x0 +@ CHECK: 0x0 R_ARM_NONE __aeabi_unwind_cpp_pr2 0x0 +@ CHECK: 0x4 R_ARM_PREL31 .ARM.extab.pr2 0x0 +@ CHECK: ] +@ CHECK: } + + .section .pr2.nontrivial + .type pr2_nontrivial,%function + .thumb_func +pr2_nontrivial: + .fnstart + .personalityindex 2 + .pad #0x10 + sub sp, sp, #0x10 + add sp, sp, #0x10 + bx lr + .fnend + +@ CHECK: Section { +@ CHECK: Name: .ARM.extab.pr2.nontrivial +@ CHECK: SectionData ( +@ CHECK: 0000: B0030082 00000000 +@ CHECK: ) +@ CHECK: } + +@ CHECK: Section { +@ CHECK: Name: .ARM.exidx.pr2.nontrivial +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 00000000 +@ CHECK: ) +@ CHECK: } + +@ CHECK: Section { +@ CHECK: Name: .rel.ARM.exidx.pr2.nontrivial +@ CHECK: Relocations [ +@ CHECK: 0x0 R_ARM_PREL31 .pr2.nontrivial 0x0 +@ CHECK: 0x0 R_ARM_NONE __aeabi_unwind_cpp_pr2 0x0 +@ CHECK: 0x4 R_ARM_PREL31 .ARM.extab.pr2.nontrivial 0x0 +@ CHECK: ] +@ CHECK: } +