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;
#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"
Locs FnStartLocs;
Locs CantUnwindLocs;
Locs PersonalityLocs;
+ Locs PersonalityIndexLocs;
Locs HandlerDataLocs;
int FPReg;
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; }
}
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() {
CantUnwindLocs = Locs();
PersonalityLocs = Locs();
HandlerDataLocs = Locs();
+ PersonalityIndexLocs = Locs();
FPReg = -1;
}
};
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,
return parseDirectiveLtorg(DirectiveID.getLoc());
else if (IDVal == ".even")
return parseDirectiveEven(DirectiveID.getLoc());
+ else if (IDVal == ".personalityindex")
+ return parseDirectivePersonalityIndex(DirectiveID.getLoc());
return true;
}
return false;
}
+ // Reset the unwind directives parser state
+ UC.reset();
+
getTargetStreamer().emitFnStart();
UC.recordFnStart(L);
/// parseDirectivePersonality
/// ::= .personality name
bool ARMAsmParser::parseDirectivePersonality(SMLoc L) {
+ bool HasExistingPersonality = UC.hasPersonality();
+
UC.recordPersonality(L);
// Check the ordering of unwind directives
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)) {
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<MCConstantExpr>(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<ARMAsmParser> X(TheARMTarget);
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);
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) {
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);
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);
void ARMTargetELFStreamer::emitPersonality(const MCSymbol *Personality) {
getStreamer().emitPersonality(Personality);
}
+void ARMTargetELFStreamer::emitPersonalityIndex(unsigned Index) {
+ getStreamer().emitPersonalityIndex(Index);
+}
void ARMTargetELFStreamer::emitHandlerData() {
getStreamer().emitHandlerData();
}
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) &&
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);
--- /dev/null
+@ 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 <expression>
+ .fnend
+
+@ CHECK: error: unknown token in expression
+@ CHECK: .personalityindex <expression>
+@ 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: ^
+
--- /dev/null
+@ 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: }
+