diff --git a/bindings/go/keystone/keystone_const.go b/bindings/go/keystone/keystone_const.go index 0c232a28946223650320c8d7ddde5c2f5c279075..1b89932d345fe9b8dc91538a674f3e2ae86bb269 100644 --- a/bindings/go/keystone/keystone_const.go +++ b/bindings/go/keystone/keystone_const.go @@ -95,6 +95,7 @@ const ( ERR_ASM_INSN_UNSUPPORTED Error = 158 ERR_ASM_FIXUP_INVALID Error = 159 ERR_ASM_LABEL_INVALID Error = 160 + ERR_ASM_FRAGMENT_INVALID Error = 161 ERR_ASM_INVALIDOPERAND Error = 512 ERR_ASM_MISSINGFEATURE Error = 513 ERR_ASM_MNEMONICFAIL Error = 514 diff --git a/bindings/nodejs/consts/keystone.js b/bindings/nodejs/consts/keystone.js index e8d33bf2c1447d6d03ccdd1b42d622bb7f87773e..d08941b98dc2a28b73e709b1b0d1156026f8d106 100644 --- a/bindings/nodejs/consts/keystone.js +++ b/bindings/nodejs/consts/keystone.js @@ -71,6 +71,7 @@ module.exports.ERR_ASM_TOKEN_INVALID = 157 module.exports.ERR_ASM_INSN_UNSUPPORTED = 158 module.exports.ERR_ASM_FIXUP_INVALID = 159 module.exports.ERR_ASM_LABEL_INVALID = 160 +module.exports.ERR_ASM_FRAGMENT_INVALID = 161 module.exports.ERR_ASM_INVALIDOPERAND = 512 module.exports.ERR_ASM_MISSINGFEATURE = 513 module.exports.ERR_ASM_MNEMONICFAIL = 514 diff --git a/bindings/python/keystone/keystone_const.py b/bindings/python/keystone/keystone_const.py index 853e0f7dc18c2f9d0f6c943fcb3beb3e1f1e5895..b19e620e7c3dcc4e9e5447112854fc924b2357e4 100644 --- a/bindings/python/keystone/keystone_const.py +++ b/bindings/python/keystone/keystone_const.py @@ -71,6 +71,7 @@ KS_ERR_ASM_TOKEN_INVALID = 157 KS_ERR_ASM_INSN_UNSUPPORTED = 158 KS_ERR_ASM_FIXUP_INVALID = 159 KS_ERR_ASM_LABEL_INVALID = 160 +KS_ERR_ASM_FRAGMENT_INVALID = 161 KS_ERR_ASM_INVALIDOPERAND = 512 KS_ERR_ASM_MISSINGFEATURE = 513 KS_ERR_ASM_MNEMONICFAIL = 514 diff --git a/bindings/ruby/keystone_gem/lib/keystone/keystone_const.rb b/bindings/ruby/keystone_gem/lib/keystone/keystone_const.rb index bdcc3547a9966595ed60c6fd90587ebd4ff4ae05..d21c7a8d3e9023ca47eb2f88d945a8a18b55294d 100644 --- a/bindings/ruby/keystone_gem/lib/keystone/keystone_const.rb +++ b/bindings/ruby/keystone_gem/lib/keystone/keystone_const.rb @@ -73,6 +73,7 @@ module Keystone KS_ERR_ASM_INSN_UNSUPPORTED = 158 KS_ERR_ASM_FIXUP_INVALID = 159 KS_ERR_ASM_LABEL_INVALID = 160 + KS_ERR_ASM_FRAGMENT_INVALID = 161 KS_ERR_ASM_INVALIDOPERAND = 512 KS_ERR_ASM_MISSINGFEATURE = 513 KS_ERR_ASM_MNEMONICFAIL = 514 diff --git a/bindings/rust/src/keystone_const.rs b/bindings/rust/src/keystone_const.rs index b138756cfb655e8e3e09fe773c064839a49c093a..ba0413959ec19c2f4803af1979052195fd47d060 100644 --- a/bindings/rust/src/keystone_const.rs +++ b/bindings/rust/src/keystone_const.rs @@ -140,6 +140,7 @@ bitflags! { const ERR_ASM_INSN_UNSUPPORTED = 158, const ERR_ASM_FIXUP_INVALID = 159, const ERR_ASM_LABEL_INVALID = 160, + const ERR_ASM_FRAGMENT_INVALID = 161, const ERR_ASM_INVALIDOPERAND = 512, const ERR_ASM_MISSINGFEATURE = 513, const ERR_ASM_MNEMONICFAIL = 514, diff --git a/include/keystone/keystone.h b/include/keystone/keystone.h index ad8bff1d61d1153b98205cbcf7d0d04b4935f37e..515e7ab5104cf53fb3e70b5e5e10ac637aa5470f 100644 --- a/include/keystone/keystone.h +++ b/include/keystone/keystone.h @@ -130,6 +130,7 @@ typedef enum ks_err { KS_ERR_ASM_INSN_UNSUPPORTED, // this instruction is unsupported in this mode KS_ERR_ASM_FIXUP_INVALID, // invalid fixup KS_ERR_ASM_LABEL_INVALID, // invalid label + KS_ERR_ASM_FRAGMENT_INVALID, // invalid fragment // generic input assembly errors - architecture specific KS_ERR_ASM_INVALIDOPERAND = KS_ERR_ASM_ARCH, diff --git a/llvm/include/llvm/MC/MCAssembler.h b/llvm/include/llvm/MC/MCAssembler.h index 1e504fd5133d15e644ad5448c3d20fffb4e097e9..93542b62ae222870d20c838c959981b3fbe334b3 100644 --- a/llvm/include/llvm/MC/MCAssembler.h +++ b/llvm/include/llvm/MC/MCAssembler.h @@ -55,8 +55,11 @@ struct DataRegionData { class MCAssembler { friend class MCAsmLayout; + mutable unsigned KsError; public: + void setError(unsigned E) const { KsError = E; } + unsigned getError() const { return KsError; } typedef std::vector<MCSection *> SectionListType; typedef std::vector<const MCSymbol *> SymbolDataListType; @@ -200,7 +203,7 @@ public: /// Compute the effective fragment size assuming it is laid out at the given /// \p SectionAddress and \p FragmentOffset. uint64_t computeFragmentSize(const MCAsmLayout &Layout, - const MCFragment &F) const; + const MCFragment &F, bool &valid) const; /// Find the symbol which defines the atom containing the given symbol, or /// null if there is no such symbol. diff --git a/llvm/keystone/ks.cpp b/llvm/keystone/ks.cpp index 1602c79be8a01d91f8962a4fcefccec98c53e973..65c836c8f8189625a52114dae5240c7241994001 100644 --- a/llvm/keystone/ks.cpp +++ b/llvm/keystone/ks.cpp @@ -134,6 +134,8 @@ const char *ks_strerror(ks_err code) return "Invalid fixup (KS_ERR_ASM_FIXUP_INVALID)"; case KS_ERR_ASM_LABEL_INVALID: return "Invalid label (KS_ERR_ASM_LABEL_INVALID)"; + case KS_ERR_ASM_FRAGMENT_INVALID: + return "Invalid fragment (KS_ERR_ASM_FRAGMENT_INVALID)"; } } diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp index 8f17f7d6055bde7813511f0696cb5e61e4410ffb..10f3228002c5227695db219644a681dbfff07e18 100644 --- a/llvm/lib/MC/ELFObjectWriter.cpp +++ b/llvm/lib/MC/ELFObjectWriter.cpp @@ -1185,6 +1185,8 @@ void ELFObjectWriter::writeObject(MCAssembler &Asm, const MCSymbolELF *SignatureSymbol = Section.getGroup(); writeSectionData(Asm, Section, Layout); + if (Asm.getError()) + return; uint64_t SecEnd = getStream().tell(); SectionOffsets[&Section] = std::make_pair(SecStart, SecEnd); diff --git a/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp index 7a8407cd8aaf94f84cc40080fd999e9bc2300d83..dac547fd6f1ce83731fc34414eb5cc9df95ecbbf 100644 --- a/llvm/lib/MC/MCAssembler.cpp +++ b/llvm/lib/MC/MCAssembler.cpp @@ -230,7 +230,9 @@ bool MCAssembler::evaluateFixup(const MCAsmLayout &Layout, } uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout, - const MCFragment &F) const { + const MCFragment &F, bool &valid) const +{ + valid = true; switch (F.getKind()) { case MCFragment::FT_Data: return cast<MCDataFragment>(F).getContents().size(); @@ -265,22 +267,31 @@ uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout, case MCFragment::FT_Org: { const MCOrgFragment &OF = cast<MCOrgFragment>(F); MCValue Value; - if (!OF.getOffset().evaluateAsValue(Value, Layout)) - report_fatal_error("expected assembly-time absolute expression"); + if (!OF.getOffset().evaluateAsValue(Value, Layout)) { + //report_fatal_error("expected assembly-time absolute expression"); + valid = false; + return 0; + } // FIXME: We need a way to communicate this error. uint64_t FragmentOffset = Layout.getFragmentOffset(&OF); int64_t TargetLocation = Value.getConstant(); if (const MCSymbolRefExpr *A = Value.getSymA()) { uint64_t Val; - if (!Layout.getSymbolOffset(A->getSymbol(), Val)) - report_fatal_error("expected absolute expression"); + if (!Layout.getSymbolOffset(A->getSymbol(), Val)) { + //report_fatal_error("expected absolute expression"); + valid = false; + return 0; + } TargetLocation += Val; } int64_t Size = TargetLocation - FragmentOffset; - if (Size < 0 || Size >= 0x40000000) - report_fatal_error("invalid .org offset '" + Twine(TargetLocation) + - "' (at offset '" + Twine(FragmentOffset) + "')"); + if (Size < 0 || Size >= 0x40000000) { + //report_fatal_error("invalid .org offset '" + Twine(TargetLocation) + + // "' (at offset '" + Twine(FragmentOffset) + "')"); + valid = false; + return 0; + } return Size; } @@ -295,7 +306,8 @@ uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout, llvm_unreachable("invalid fragment kind"); } -void MCAsmLayout::layoutFragment(MCFragment *F) { +void MCAsmLayout::layoutFragment(MCFragment *F) +{ MCFragment *Prev = F->getPrevNode(); // We should never try to recompute something which is valid. @@ -305,11 +317,15 @@ void MCAsmLayout::layoutFragment(MCFragment *F) { assert((!Prev || isFragmentValid(Prev)) && "Attempt to compute fragment before its predecessor!"); + bool valid = true; // Compute fragment offset and size. if (Prev) - F->Offset = Prev->Offset + getAssembler().computeFragmentSize(*this, *Prev); + F->Offset = Prev->Offset + getAssembler().computeFragmentSize(*this, *Prev, valid); else F->Offset = getAssembler().getContext().getBaseAddress(); + if (!valid) { + return; + } LastValidFragment[F->getParent()] = F; // If bundling is enabled and this fragment has instructions in it, it has to @@ -342,7 +358,8 @@ void MCAsmLayout::layoutFragment(MCFragment *F) { if (Assembler.isBundlingEnabled() && F->hasInstructions()) { assert(isa<MCEncodedFragment>(F) && "Only MCEncodedFragment implementations have instructions"); - uint64_t FSize = Assembler.computeFragmentSize(*this, *F); + bool valid; + uint64_t FSize = Assembler.computeFragmentSize(*this, *F, valid); if (!Assembler.getRelaxAll() && FSize > Assembler.getBundleAlignSize()) report_fatal_error("Fragment can't be larger than a bundle size"); @@ -400,11 +417,20 @@ void MCAssembler::writeFragmentPadding(const MCFragment &F, uint64_t FSize, /// \brief Write the fragment \p F to the output file. static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout, - const MCFragment &F) { + const MCFragment &F) +{ + if (Asm.getError()) + return; + MCObjectWriter *OW = &Asm.getWriter(); + bool valid; // FIXME: Embed in fragments instead? - uint64_t FragmentSize = Asm.computeFragmentSize(Layout, F); + uint64_t FragmentSize = Asm.computeFragmentSize(Layout, F, valid); + if (!valid) { + Asm.setError(KS_ERR_ASM_FRAGMENT_INVALID); + return; + } Asm.writeFragmentPadding(F, FragmentSize, OW); @@ -524,7 +550,8 @@ static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout, } void MCAssembler::writeSectionData(const MCSection *Sec, - const MCAsmLayout &Layout) const { + const MCAsmLayout &Layout) const +{ // Ignore virtual sections. if (Sec->isVirtualSection()) { assert(Layout.getSectionFileSize(Sec) == 0 && "Invalid size for section!"); @@ -570,6 +597,7 @@ void MCAssembler::writeSectionData(const MCSection *Sec, uint64_t Start = getWriter().getStream().tell(); (void)Start; + setError(0); for (const MCFragment &F : *Sec) writeFragment(*this, Layout, F); @@ -695,6 +723,7 @@ void MCAssembler::Finish(unsigned int &KsError) { // Write the object file. if (!KsError) getWriter().writeObject(*this, Layout); + KsError = getError(); } bool MCAssembler::fixupNeedsRelaxation(const MCFixup &Fixup, diff --git a/llvm/lib/MC/MCFragment.cpp b/llvm/lib/MC/MCFragment.cpp index 3113b6051cc23b449102147024d16c4e3e0c174d..444009a750bb323c987a5fef71a6c102a10ce3f7 100644 --- a/llvm/lib/MC/MCFragment.cpp +++ b/llvm/lib/MC/MCFragment.cpp @@ -177,7 +177,8 @@ const MCSymbol *MCAsmLayout::getBaseSymbol(const MCSymbol &Symbol) const { uint64_t MCAsmLayout::getSectionAddressSize(const MCSection *Sec) const { // The size is the last fragment's end offset. const MCFragment &F = Sec->getFragmentList().back(); - return getFragmentOffset(&F) + getAssembler().computeFragmentSize(*this, F); + bool valid; + return getFragmentOffset(&F) + getAssembler().computeFragmentSize(*this, F, valid); } uint64_t MCAsmLayout::getSectionFileSize(const MCSection *Sec) const {