Пример #1
0
bool CFWidget::generateBranch(CodeBuffer &buffer,
			    TargetInt *to,
			    Instruction::Ptr insn,
                            const RelocBlock *trace,
			    bool fallthrough) {
   assert(to);
   if (!to->necessary()) return true;

   // We can put in an unconditional branch as an ender for 
   // a block that doesn't have a real branch. So if we don't have
   // an instruction generate a "generic" branch

   // We can see a problem where we want to branch to (effectively) 
   // the next instruction. So if we ever see that (a branch of offset
   // == size) back up the codeGen and shrink us down.

   CFPatch *newPatch = new CFPatch(CFPatch::Jump, insn, to, trace->func(), addr_);

   if (fallthrough || trace->block() == NULL) {
      buffer.addPatch(newPatch, destTracker(to, trace));
   }
   else {
      buffer.addPatch(newPatch, tracker(trace));
   }
  
   return true;
}
Пример #2
0
bool PCWidget::PCtoReg(const codeGen &templ, const RelocBlock *t, CodeBuffer &buffer) {
  bool ignored;
  Register reg = convertRegID(a_.reg(), ignored);

  if(templ.addrSpace()->proc()) {
#if defined(arch_x86) || defined(arch_x86_64)
     std::vector<unsigned char> newInsn;
     newInsn.push_back(static_cast<unsigned char>(0xb8 + reg));
     // MOV family, destination of the register encoded by
     // 'reg', source is an Iv immediate
     
     Address EIP = addr_ + insn_->size();
     unsigned char *tmp = (unsigned char *) &EIP;
     newInsn.insert(newInsn.end(),
                    tmp,
                    tmp + sizeof(unsigned int));
     buffer.addPIC(newInsn, tracker(t));
#else
     // Move immediate to register?
     codeGen gen(16);
     insnCodeGen::loadImmIntoReg(gen, reg, addr_);
     buffer.addPIC(gen, tracker(t));
#endif
  }
  else {
    IPPatch *newPatch = new IPPatch(IPPatch::Reg, addr_, reg, thunkAddr_, insn_, t->block(), t->func());
    buffer.addPatch(newPatch, tracker(t));
  }
  return true;
}
Пример #3
0
bool InstWidget::generate(const codeGen &,
                    const RelocBlock *,
                    CodeBuffer &buffer) {
   // We should work baseTramp code generation into the CodeBuffer
   // system, but that's for future work...
   InstWidgetPatch *patch = new InstWidgetPatch(point_->tramp());
   buffer.addPatch(patch, tracker());
   return true;
}
Пример #4
0
bool PCWidget::PCtoReturnAddr(const codeGen &templ, const RelocBlock *t, CodeBuffer &buffer) {
  if(templ.addrSpace()->proc()) {
    std::vector<unsigned char> newInsn;
#if defined(arch_x86_64)
    codeGen gen(16);
    Address RIP = addr_ + insn_.size();
    insnCodeGen::generatePush64(gen, RIP);
    buffer.addPIC(gen, tracker(t));
#elif defined(arch_x86)
    newInsn.push_back(0x68); // push
    Address EIP = addr_ + insn_.size();
    unsigned char *tmp = (unsigned char *) &EIP;
    newInsn.insert(newInsn.end(),
		   tmp,
		   tmp+sizeof(unsigned int));
    buffer.addPIC(newInsn, tracker(t));
#else
    // We want to get a value into LR, which is the return address.
    // Fun for the whole family... we need a spare register. Argh!

    codeGen gen(16);
    gen.applyTemplate(templ);
    // Must be in LR
    instPoint *point = templ.point();
    // If we do not have a point then we have to invent one
    if (!point || 
	(point->type() != instPoint::PreInsn &&
	 point->insnAddr() != addr())) {
      point = instPoint::preInsn(t->func(), t->block(), addr(), insn_, true);
    }
    assert(point);
    
    registerSpace *rs = registerSpace::actualRegSpace(point);
    gen.setRegisterSpace(rs);
    int stackSize = 0;
    pdvector<Register> freeReg;
    pdvector<Register> excludeReg;
    
    Address origRet = addr() + insn_.size();
    Register scratch = gen.rs()->getScratchRegister(gen, true);
    if (scratch == REG_NULL) {
      stackSize = insnCodeGen::createStackFrame(gen, 1, freeReg, excludeReg);
      assert(stackSize == 1);
      scratch = freeReg[0];
    }
    insnCodeGen::loadImmIntoReg(gen, scratch, origRet);
    insnCodeGen::generateMoveToLR(gen, scratch);
    buffer.addPIC(gen, tracker(t));
#endif
  }
  else {
    IPPatch *newPatch = new IPPatch(IPPatch::Push, addr_, insn_, t->block(), t->func());
    buffer.addPatch(newPatch, tracker(t));
  }	
   
  return true;
}
Пример #5
0
bool CFWidget::generateConditionalBranch(CodeBuffer &buffer,
				       TargetInt *to,
                                       const RelocBlock *trace,
				       Instruction::Ptr insn) {
   assert(to);
   CFPatch *newPatch = new CFPatch(CFPatch::JCC, insn, to, trace->func(), addr_);

   buffer.addPatch(newPatch, tracker(trace));

   return true;
}
Пример #6
0
bool CFWidget::generateCall(CodeBuffer &buffer,
			  TargetInt *to,
                          const RelocBlock *trace,
			  Instruction::Ptr insn) {
   if (!to) {
      // This can mean an inter-module branch...
      return true;
   }

   CFPatch *newPatch = new CFPatch(CFPatch::Call, insn, to, trace->func(), addr_);

   buffer.addPatch(newPatch, tracker(trace));

   return true;
}
Пример #7
0
bool RelDataWidget::generate(const codeGen &,
                              const RelocBlock *t, 
                              CodeBuffer &buffer) {
  // We want to take the original instruction and emulate
  // it at whatever our new address is. 

  // Fortunately, we can reuse old code to handle the
  // translation

  // Find the original target of the instruction
   
  relocation_cerr << "  Generating a PC-relative data access (" << insn_.format()
		  << "," << std::hex << addr_ 
		  <<"," << target_ << std::dec << ")" << endl;

  RelDataPatch *newPatch = new RelDataPatch(insn_, target_, addr_);
  newPatch->setBlock(t->block());
  newPatch->setFunc(t->func());
  buffer.addPatch(newPatch, tracker(t));

  return true;
}
Пример #8
0
bool CFWidget::generate(const codeGen &templ,
                      const RelocBlock *trace,
                      CodeBuffer &buffer)
{
   // We need to create jumps to wherever our successors are
   // We can assume the addresses returned by our Targets
   // are valid, since we'll fixpoint until those stabilize. 
   //
   // There are the following cases:
   //
   // No explicit control flow/unconditional direct branch:
   //   1) One target
   //   2) Generate a branch unless it's unnecessary
   // Conditional branch:
   //   1) Two targets
   //   2) Use stored instruction to generate correct condition
   //   3) Generate a fallthrough "branch" if necessary
   // Call:
   //   1) Two targets (call and natural successor)
   //   2) As above, except make sure call bit is flipped on
   // Indirect branch:
   //   1) Just go for it... we have no control, really
   relocation_cerr << "CFWidget generation for " << trace->id() << endl;
   if (destMap_.empty() && !isIndirect_) {
      // No successors at all? Well, it happens if
      // we hit a halt...
      relocation_cerr << "CFWidget /w/ no successors, ret true" << endl;
      return true;
   }

   typedef enum {
      Illegal,
      Single,
      Taken_FT,
      Indirect } Options;
  
   Options opt = Illegal;

   if (isIndirect_) {
      opt = Indirect;
      relocation_cerr << "  generating CFWidget as indirect branch" << endl;
   }
   else if (isConditional_ || isCall_) {
      opt = Taken_FT;
      relocation_cerr << "  generating CFWidget as call or conditional branch" << endl;
   }
   else {
      opt = Single;
      relocation_cerr << "  generating CFWidget as direct branch" << endl;
   }

   switch (opt) {
      case Single: {

         assert(!isIndirect_);
         assert(!isConditional_);
         assert(!isCall_);

         // Check for a taken destination first.
         bool fallthrough = false;
         DestinationMap::iterator iter = destMap_.find(Taken);
         if (iter == destMap_.end()) {
            iter = destMap_.find(Fallthrough);
            fallthrough = true;
         }
         if (iter == destMap_.end()) {
            cerr << "Error in CFWidget from trace " << trace->id()
                 << ", could not find target for single control transfer" << endl;
            cerr << "\t DestMap dump:" << endl;
            for (DestinationMap::iterator d = destMap_.begin(); 
                 d != destMap_.end(); ++d) {
               cerr << "\t\t " << d->first << " : " << d->second->format() << endl;
            }
         }
            
         assert(iter != destMap_.end());

         TargetInt *target = iter->second;
         assert(target);

         if (target->necessary()) {
            if (!generateBranch(buffer,
                                target,
                                insn_,
                                trace,
                                fallthrough)) {
               return false;
            }
         }
         else {
            relocation_cerr << "    target reported unnecessary" << endl;
         }
         break;
      }
      case Taken_FT: {
         // This can be either a call (with an implicit fallthrough as shown by
         // the FUNLINK) or a conditional branch.
         if (isCall_) {
            // Well, that kinda explains things
            assert(!isConditional_);
            relocation_cerr << "  ... generating call" << endl;
            if (!generateCall(buffer,
                              destMap_[Taken],
                              trace,
                              insn_))
               return false;
         }
         else {
            assert(!isCall_);
            relocation_cerr << "  ... generating conditional branch" << endl;
            if (!generateConditionalBranch(buffer,
                                           destMap_[Taken],
                                           trace,
                                           insn_))
               return false;
         }

         // Not necessary by design - fallthroughs are always to the next generated
         // We can have calls that don't return and thus don't have funlink edges
    
         if (destMap_.find(Fallthrough) != destMap_.end()) {
            TargetInt *ft = destMap_[Fallthrough];
            if (ft->necessary()) {
               if (!generateBranch(buffer, 
                                   ft,
                                   insn_,
                                   trace,
                                   true)) {
                  return false;
               }
            }
         }
         break;
      }
      case Indirect: {
         Register reg = Null_Register; /* = originalRegister... */
         // Originally for use in helping with jump tables, I'm taking
         // this for the memory emulation effort. Huzzah!
         if (!generateAddressTranslator(buffer, templ, reg, trace))
            return false;
         if (isCall_) {
            if (!generateIndirectCall(buffer, 
                                      reg, 
                                      insn_, 
                                      trace,
                                      addr_)) 
               return false;
            // We may be putting another block in between this
            // one and its fallthrough due to edge instrumentation
            // So if there's the possibility for a return put in
            // a fallthrough branch
            if (destMap_.find(Fallthrough) != destMap_.end()) {
               if (!generateBranch(buffer,
                                   destMap_[Fallthrough],
                                   Instruction::Ptr(),
                                   trace,
                                   true)) 
                  return false;
            }
         }
         else {
            if (!generateIndirect(buffer, reg, trace, insn_))
               return false;
         }
         break;
      }
      default:
         assert(0);
   }
   if (gap_) {
      // We don't know what the callee does to the return addr,
      // so we'll catch it at runtime. 
      buffer.addPatch(new PaddingPatch(gap_, true, false, trace->block()), 
                      padTracker(addr_, gap_,
                                 trace));
   }
  
   return true;
}