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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }