From 070b5add699add385384c5a17835cc614cbb62b9 Mon Sep 17 00:00:00 2001
From: Nguyen Anh Quynh <aquynh@gmail.com>
Date: Tue, 31 May 2016 15:08:32 +0800
Subject: [PATCH] x86: fix
 crash-21-x64-llvm-error-expected-absolute-expression.c

---
 bindings/go/keystone/keystone_const.go        |  1 +
 bindings/nodejs/consts/keystone.js            |  1 +
 bindings/python/keystone/keystone_const.py    |  1 +
 .../lib/keystone/keystone_const.rb            |  1 +
 bindings/rust/src/keystone_const.rs           |  1 +
 include/keystone/keystone.h                   |  1 +
 llvm/include/llvm/MC/MCAssembler.h            |  5 +-
 llvm/keystone/ks.cpp                          |  2 +
 llvm/lib/MC/ELFObjectWriter.cpp               |  2 +
 llvm/lib/MC/MCAssembler.cpp                   | 57 ++++++++++++++-----
 llvm/lib/MC/MCFragment.cpp                    |  3 +-
 11 files changed, 59 insertions(+), 16 deletions(-)

diff --git a/bindings/go/keystone/keystone_const.go b/bindings/go/keystone/keystone_const.go
index 0c232a2..1b89932 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 e8d33bf..d08941b 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 853e0f7..b19e620 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 bdcc354..d21c7a8 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 b138756..ba04139 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 ad8bff1..515e7ab 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 1e504fd..93542b6 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 1602c79..65c836c 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 8f17f7d..10f3228 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 7a8407c..dac547f 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 3113b60..444009a 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 {
-- 
GitLab