diff options
-rw-r--r-- | include/llvm/MC/MCStreamer.h | 2 | ||||
-rw-r--r-- | lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 84 | ||||
-rw-r--r-- | lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp | 26 | ||||
-rw-r--r-- | lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.h | 6 | ||||
-rw-r--r-- | test/MC/ARM/eh-directive-unwind_raw-diagnostics.s | 73 | ||||
-rw-r--r-- | test/MC/ARM/eh-directive-unwind_raw.s | 113 |
6 files changed, 304 insertions, 0 deletions
diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index 946baf1b7c4..eb0eb7f19f2 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -92,6 +92,8 @@ public: virtual void emitPad(int64_t Offset) = 0; virtual void emitRegSave(const SmallVectorImpl<unsigned> &RegList, bool isVector) = 0; + virtual void emitUnwindRaw(int64_t StackOffset, + const SmallVectorImpl<uint8_t> &Opcodes) = 0; virtual void switchVendor(StringRef Vendor) = 0; virtual void emitAttribute(unsigned Attribute, unsigned Value) = 0; diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 0a1ba9105a7..dc9a308bb95 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -295,6 +295,7 @@ class ARMAsmParser : public MCTargetAsmParser { bool parseDirectiveLtorg(SMLoc L); bool parseDirectiveEven(SMLoc L); bool parseDirectivePersonalityIndex(SMLoc L); + bool parseDirectiveUnwindRaw(SMLoc L); StringRef splitMnemonic(StringRef Mnemonic, unsigned &PredicationCode, bool &CarrySetting, unsigned &ProcessorIMod, @@ -8081,6 +8082,8 @@ bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) { return parseDirectiveEven(DirectiveID.getLoc()); else if (IDVal == ".personalityindex") return parseDirectivePersonalityIndex(DirectiveID.getLoc()); + else if (IDVal == ".unwind_raw") + return parseDirectiveUnwindRaw(DirectiveID.getLoc()); return true; } @@ -8915,6 +8918,87 @@ bool ARMAsmParser::parseDirectivePersonalityIndex(SMLoc L) { return false; } +/// parseDirectiveUnwindRaw +/// ::= .unwind_raw offset, opcode [, opcode...] +bool ARMAsmParser::parseDirectiveUnwindRaw(SMLoc L) { + if (!UC.hasFnStart()) { + Parser.eatToEndOfStatement(); + Error(L, ".fnstart must precede .unwind_raw directives"); + return false; + } + + int64_t StackOffset; + + const MCExpr *OffsetExpr; + SMLoc OffsetLoc = getLexer().getLoc(); + if (getLexer().is(AsmToken::EndOfStatement) || + getParser().parseExpression(OffsetExpr)) { + Error(OffsetLoc, "expected expression"); + Parser.eatToEndOfStatement(); + return false; + } + + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(OffsetExpr); + if (!CE) { + Error(OffsetLoc, "offset must be a constant"); + Parser.eatToEndOfStatement(); + return false; + } + + StackOffset = CE->getValue(); + + if (getLexer().isNot(AsmToken::Comma)) { + Error(getLexer().getLoc(), "expected comma"); + Parser.eatToEndOfStatement(); + return false; + } + Parser.Lex(); + + SmallVector<uint8_t, 16> Opcodes; + for (;;) { + const MCExpr *OE; + + SMLoc OpcodeLoc = getLexer().getLoc(); + if (getLexer().is(AsmToken::EndOfStatement) || Parser.parseExpression(OE)) { + Error(OpcodeLoc, "expected opcode expression"); + Parser.eatToEndOfStatement(); + return false; + } + + const MCConstantExpr *OC = dyn_cast<MCConstantExpr>(OE); + if (!OC) { + Error(OpcodeLoc, "opcode value must be a constant"); + Parser.eatToEndOfStatement(); + return false; + } + + const int64_t Opcode = OC->getValue(); + if (Opcode & ~0xff) { + Error(OpcodeLoc, "invalid opcode"); + Parser.eatToEndOfStatement(); + return false; + } + + Opcodes.push_back(uint8_t(Opcode)); + + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + if (getLexer().isNot(AsmToken::Comma)) { + Error(getLexer().getLoc(), "unexpected token in directive"); + Parser.eatToEndOfStatement(); + return false; + } + + Parser.Lex(); + } + + getTargetStreamer().emitUnwindRaw(StackOffset, Opcodes); + + Parser.Lex(); + return false; +} + /// Force static initialization. extern "C" void LLVMInitializeARMAsmParser() { RegisterMCAsmParser<ARMAsmParser> X(TheARMTarget); diff --git a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp index 82543a45f24..79d5619b764 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp @@ -123,6 +123,8 @@ class ARMTargetAsmStreamer : public ARMTargetStreamer { virtual void emitPad(int64_t Offset); virtual void emitRegSave(const SmallVectorImpl<unsigned> &RegList, bool isVector); + virtual void emitUnwindRaw(int64_t Offset, + const SmallVectorImpl<uint8_t> &Opcodes); virtual void switchVendor(StringRef Vendor); virtual void emitAttribute(unsigned Attribute, unsigned Value); @@ -242,6 +244,16 @@ void ARMTargetAsmStreamer::emitInst(uint32_t Inst, char Suffix) { OS << "\t0x" << utohexstr(Inst) << "\n"; } +void ARMTargetAsmStreamer::emitUnwindRaw(int64_t Offset, + const SmallVectorImpl<uint8_t> &Opcodes) { + OS << "\t.unwind_raw " << Offset; + for (SmallVectorImpl<uint8_t>::const_iterator OCI = Opcodes.begin(), + OCE = Opcodes.end(); + OCI != OCE; ++OCI) + OS << ", 0x" << utohexstr(*OCI); + OS << '\n'; +} + class ARMTargetELFStreamer : public ARMTargetStreamer { private: // This structure holds all attributes, accounting for @@ -367,6 +379,8 @@ private: virtual void emitPad(int64_t Offset); virtual void emitRegSave(const SmallVectorImpl<unsigned> &RegList, bool isVector); + virtual void emitUnwindRaw(int64_t Offset, + const SmallVectorImpl<uint8_t> &Opcodes); virtual void switchVendor(StringRef Vendor); virtual void emitAttribute(unsigned Attribute, unsigned Value); @@ -425,6 +439,7 @@ public: void emitSetFP(unsigned NewFpReg, unsigned NewSpReg, int64_t Offset = 0); void emitPad(int64_t Offset); void emitRegSave(const SmallVectorImpl<unsigned> &RegList, bool isVector); + void emitUnwindRaw(int64_t Offset, const SmallVectorImpl<uint8_t> &Opcodes); virtual void ChangeSection(const MCSection *Section, const MCExpr *Subsection) { @@ -637,6 +652,10 @@ void ARMTargetELFStreamer::emitRegSave(const SmallVectorImpl<unsigned> &RegList, bool isVector) { getStreamer().emitRegSave(RegList, isVector); } +void ARMTargetELFStreamer::emitUnwindRaw(int64_t Offset, + const SmallVectorImpl<uint8_t> &Opcodes) { + getStreamer().emitUnwindRaw(Offset, Opcodes); +} void ARMTargetELFStreamer::switchVendor(StringRef Vendor) { assert(!Vendor.empty() && "Vendor cannot be empty."); @@ -1202,6 +1221,13 @@ void ARMELFStreamer::emitRegSave(const SmallVectorImpl<unsigned> &RegList, UnwindOpAsm.EmitRegSave(Mask); } +void ARMELFStreamer::emitUnwindRaw(int64_t Offset, + const SmallVectorImpl<uint8_t> &Opcodes) { + FlushPendingOffset(); + SPOffset = SPOffset - Offset; + UnwindOpAsm.EmitRaw(Opcodes); +} + namespace llvm { MCStreamer *createMCAsmStreamer(MCContext &Ctx, formatted_raw_ostream &OS, diff --git a/lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.h b/lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.h index b7937535761..e2c44008144 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.h +++ b/lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.h @@ -61,6 +61,12 @@ public: /// Emit unwind opcodes to add $sp with an offset. void EmitSPOffset(int64_t Offset); + /// Emit unwind raw opcodes + void EmitRaw(const SmallVectorImpl<uint8_t> &Opcodes) { + Ops.insert(Ops.end(), Opcodes.begin(), Opcodes.end()); + OpBegins.push_back(OpBegins.back() + Opcodes.size()); + } + /// Finalize the unwind opcode sequence for EmitBytes() void Finalize(unsigned &PersonalityIndex, SmallVectorImpl<uint8_t> &Result); diff --git a/test/MC/ARM/eh-directive-unwind_raw-diagnostics.s b/test/MC/ARM/eh-directive-unwind_raw-diagnostics.s new file mode 100644 index 00000000000..72a208ed83d --- /dev/null +++ b/test/MC/ARM/eh-directive-unwind_raw-diagnostics.s @@ -0,0 +1,73 @@ +@ RUN: not llvm-mc -triple armv7-linux-eabi -filetype asm -o /dev/null 2>&1 %s \ +@ RUN: | FileCheck %s + + .syntax unified + + .type require_fnstart,%function +require_fnstart: + .unwind_raw 0, 0 + +@ CHECK: error: .fnstart must precede .unwind_raw directive +@ CHECK: .unwind_raw 0, 0 +@ CHECK: ^ + + .type check_arguments,%function +check_arguments: + .fnstart + .unwind_raw + .fnend + +@ CHECK: error: expected expression +@ CHECK: .unwind_raw +@ CHECK: ^ + + .type check_stack_offset,%function +check_stack_offset: + .fnstart + .unwind_raw ., 0 + .fnend + +@ CHECK: error: offset must be a constant +@ CHECK: .unwind_raw ., 0 +@ CHECK: ^ + + .type comma_check,%function +comma_check: + .fnstart + .unwind_raw 0 + .fnend + +@ CHECK: error: expected comma +@ CHECK: .unwind_raw 0 +@ CHECK: ^ + + .type require_opcode,%function +require_opcode: + .fnstart + .unwind_raw 0, + .fnend + +@ CHECK: error: expected opcode expression +@ CHECK: .unwind_raw 0, +@ CHECK: ^ + + .type require_opcode_constant,%function +require_opcode_constant: + .fnstart + .unwind_raw 0, . + .fnend + +@ CHECK: error: opcode value must be a constant +@ CHECK: .unwind_raw 0, . +@ CHECK: ^ + + .type check_opcode_range,%function +check_opcode_range: + .fnstart + .unwind_raw 0, 0x100 + .fnend + +@ CHECK: error: invalid opcode +@ CHECK: .unwind_raw 0, 0x100 +@ CHECK: ^ + diff --git a/test/MC/ARM/eh-directive-unwind_raw.s b/test/MC/ARM/eh-directive-unwind_raw.s new file mode 100644 index 00000000000..ab826d58e63 --- /dev/null +++ b/test/MC/ARM/eh-directive-unwind_raw.s @@ -0,0 +1,113 @@ +@ RUN: llvm-mc -triple armv7-linux-eabi -filetype obj -o - %s | llvm-readobj -u \ +@ RUN: | FileCheck %s + + .syntax unified + + .type save,%function + .thumb_func +save: + .fnstart + .unwind_raw 4, 0xb1, 0x01 + push {r0} + pop {r0} + bx lr + .fnend + + .type empty,%function + .thumb_func +empty: + .fnstart + .unwind_raw 0, 0xb0 + bx lr + .fnend + + .type extended,%function + .thumb_func +extended: + .fnstart + .unwind_raw 12, 0x9b, 0x40, 0x84, 0x80, 0xb0, 0xb0 + @ .save {fp, lr} + stmfd sp!, {fp, lr} + @ .setfp fp, sp, #4 + add fp, sp, #4 + @ .pad #8 + sub sp, sp, #8 + add sp, sp, #8 + sub fp, sp, #4 + ldmfd sp!, {fp, lr} + bx lr + .fnend + + .type refuse,%function + .thumb_func +refuse: + .fnstart + .unwind_raw 0, 0x80, 0x00 + bx lr + .fnend + + .type stack_adjust,%function + .thumb_func +stack_adjust: + .fnstart + .setfp fp, sp, #32 + .unwind_raw 24, 0xc2 + .fnend + +@ CHECK: UnwindInformation { +@ CHECK: UnwindIndexTable { +@ CHECK: SectionName: .ARM.exidx +@ CHECK: Entries [ +@ CHECK: Entry { +@ CHECK: Model: Compact (Inline) +@ CHECK: PersonalityIndex: 0 +@ CHECK: Opcodes [ +@ CHECK: Opcode: 0xB1 +@ CHECK: Opcode: 0x1 +@ CHECK: Opcode: 0xB0 +@ CHECK: ] +@ CHECK: } +@ CHECK: Entry { +@ CHECK: Model: Compact (Inline) +@ CHECK: PersonalityIndex: 0 +@ CHECK: Opcodes [ +@ CHECK: Opcode: 0xB0 +@ CHECK: Opcode: 0xB0 +@ CHECK: Opcode: 0xB0 +@ CHECK: ] +@ CHECK: } +@ CHECK: Entry { +@ CHECK: ExceptionHandlingTable: .ARM.extab +@ CHECK: Model: Compact +@ CHECK: PersonalityIndex: 1 +@ CHECK: Opcodes [ +@ CHECK: Opcode: 0x9B +@ CHECK: Opcode: 0x40 +@ CHECK: Opcode: 0x84 +@ CHECK: Opcode: 0x80 +@ CHECK: Opcode: 0xB0 +@ CHECK: Opcode: 0xB0 +@ CHECK: ] +@ CHECK: } +@ CHECK: Entry { +@ CHECK: Model: Compact (Inline) +@ CHECK: PersonalityIndex: 0 +@ CHECK: Opcodes [ +@ CHECK: Opcode: 0x80 +@ CHECK: Opcode: 0x0 +@ CHECK: Opcode: 0xB0 +@ CHECK: ] +@ CHECK: } +@ CHECK: Entry { +@ CHECK: Model: Compact (Inline) +@ CHECK: PersonalityIndex: 0 +@ CHECK: Opcodes [ +@ CHECK: Opcode: 0x9B +@ CHECK: Opcode: 0x4D +@ CHECK: Opcode: 0xC2 +@ CHECK: ] +@ CHECK: } +@ CHECK: ] +@ CHECK: } +@ CHECK: } + |