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;
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,
return parseDirectiveEven(DirectiveID.getLoc());
else if (IDVal == ".personalityindex")
return parseDirectivePersonalityIndex(DirectiveID.getLoc());
+ else if (IDVal == ".unwind_raw")
+ return parseDirectiveUnwindRaw(DirectiveID.getLoc());
return true;
}
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);
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);
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
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);
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) {
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.");
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,
/// 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);
--- /dev/null
+@ 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: ^
+
--- /dev/null
+@ 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: }
+