Implement two new switch idioms closes #14
This commit is contained in:
parent
5c85c92d1a
commit
12ee08f87e
@ -1,258 +1,261 @@
|
||||
#pragma once
|
||||
#include <llvm/ADT/ilist.h>
|
||||
//#include <llvm/ADT/ilist_node.h>
|
||||
#include <bitset>
|
||||
#include <map>
|
||||
#include "BasicBlock.h"
|
||||
#include "locident.h"
|
||||
#include "state.h"
|
||||
#include "icode.h"
|
||||
#include "StackFrame.h"
|
||||
#include "CallConvention.h"
|
||||
/* PROCEDURE NODE */
|
||||
struct CALL_GRAPH;
|
||||
struct Expr;
|
||||
struct Disassembler;
|
||||
struct Function;
|
||||
struct CALL_GRAPH;
|
||||
struct PROG;
|
||||
|
||||
struct Function;
|
||||
|
||||
namespace llvm
|
||||
{
|
||||
// Traits for intrusive list of basic blocks...
|
||||
template<>
|
||||
struct ilist_traits<BB> : public ilist_default_traits<BB>
|
||||
{
|
||||
|
||||
// createSentinel is used to get hold of the node that marks the end of the
|
||||
// list... (same trick used here as in ilist_traits<Instruction>)
|
||||
BB *createSentinel() const {
|
||||
return static_cast<BB*>(&Sentinel);
|
||||
}
|
||||
static void destroySentinel(BB*) {}
|
||||
|
||||
BB *provideInitialHead() const { return createSentinel(); }
|
||||
BB *ensureHead(BB*) const { return createSentinel(); }
|
||||
static void noteHead(BB*, BB*) {}
|
||||
|
||||
//static ValueSymbolTable *getSymTab(Function *ItemParent);
|
||||
private:
|
||||
mutable ilist_half_node<BB> Sentinel;
|
||||
};
|
||||
}
|
||||
/* Procedure FLAGS */
|
||||
enum PROC_FLAGS
|
||||
{
|
||||
PROC_BADINST=0x00000100,/* Proc contains invalid or 386 instruction */
|
||||
PROC_IJMP =0x00000200,/* Proc incomplete due to indirect jmp */
|
||||
PROC_ICALL =0x00000400, /* Proc incomplete due to indirect call */
|
||||
PROC_HLL =0x00001000, /* Proc is likely to be from a HLL */
|
||||
// CALL_PASCAL =0x00002000, /* Proc uses Pascal calling convention */
|
||||
// CALL_C =0x00004000, /* Proc uses C calling convention */
|
||||
// CALL_UNKNOWN=0x00008000, /* Proc uses unknown calling convention */
|
||||
PROC_NEAR =0x00010000, /* Proc exits with near return */
|
||||
PROC_FAR =0x00020000, /* Proc exits with far return */
|
||||
GRAPH_IRRED =0x00100000, /* Proc generates an irreducible graph */
|
||||
SI_REGVAR =0x00200000, /* SI is used as a stack variable */
|
||||
DI_REGVAR =0x00400000, /* DI is used as a stack variable */
|
||||
PROC_IS_FUNC=0x00800000, /* Proc is a function */
|
||||
REG_ARGS =0x01000000, /* Proc has registers as arguments */
|
||||
// PROC_VARARG =0x02000000, /* Proc has variable arguments */
|
||||
PROC_OUTPUT =0x04000000, /* C for this proc has been output */
|
||||
PROC_RUNTIME=0x08000000, /* Proc is part of the runtime support */
|
||||
PROC_ISLIB =0x10000000, /* Proc is a library function */
|
||||
PROC_ASM =0x20000000, /* Proc is an intrinsic assembler routine */
|
||||
PROC_IS_HLL =0x40000000 /* Proc has HLL prolog code */
|
||||
//#define CALL_MASK 0xFFFF9FFF /* Masks off CALL_C and CALL_PASCAL */
|
||||
};
|
||||
|
||||
struct FunctionType
|
||||
{
|
||||
bool m_vararg=false;
|
||||
bool isVarArg() const {return m_vararg;}
|
||||
};
|
||||
struct Assignment
|
||||
{
|
||||
Expr *lhs;
|
||||
Expr *rhs;
|
||||
};
|
||||
struct JumpTable
|
||||
{
|
||||
uint32_t start;
|
||||
uint32_t finish;
|
||||
bool valid() {return start<finish;}
|
||||
size_t size() { return (finish-start)/2;}
|
||||
size_t entrySize() { return 2;}
|
||||
void pruneEntries(uint16_t cs);
|
||||
};
|
||||
class FunctionCfg
|
||||
{
|
||||
std::list<BB*> m_listBB; /* Ptr. to BB list/CFG */
|
||||
public:
|
||||
typedef std::list<BB*>::iterator iterator;
|
||||
iterator begin() {
|
||||
return m_listBB.begin();
|
||||
}
|
||||
iterator end() {
|
||||
return m_listBB.end();
|
||||
}
|
||||
BB * &front() { return m_listBB.front();}
|
||||
void nodeSplitting()
|
||||
{
|
||||
/* Converts the irreducible graph G into an equivalent reducible one, by
|
||||
* means of node splitting. */
|
||||
fprintf(stderr,"Attempt to perform node splitting: NOT IMPLEMENTED\n");
|
||||
}
|
||||
void push_back(BB *v) { m_listBB.push_back(v);}
|
||||
};
|
||||
struct Function : public llvm::ilist_node<Function>
|
||||
{
|
||||
typedef llvm::iplist<BB> BasicBlockListType;
|
||||
// BasicBlock iterators...
|
||||
typedef BasicBlockListType::iterator iterator;
|
||||
typedef BasicBlockListType::const_iterator const_iterator;
|
||||
protected:
|
||||
BasicBlockListType BasicBlocks; ///< The basic blocks
|
||||
Function(FunctionType */*ty*/) : procEntry(0),depth(0),flg(0),cbParam(0),m_dfsLast(0),numBBs(0),
|
||||
hasCase(false),liveAnal(0)
|
||||
{
|
||||
type = new FunctionType;
|
||||
callingConv(CConv::UNKNOWN);
|
||||
}
|
||||
|
||||
public:
|
||||
FunctionType * type;
|
||||
CConv * m_call_conv;
|
||||
uint32_t procEntry; /* label number */
|
||||
std::string name; /* Meaningful name for this proc */
|
||||
STATE state; /* Entry state */
|
||||
int depth; /* Depth at which we found it - for printing */
|
||||
uint32_t flg; /* Combination of Icode & Proc flags */
|
||||
int16_t cbParam; /* Probable no. of bytes of parameters */
|
||||
STKFRAME args; /* Array of arguments */
|
||||
LOCAL_ID localId; /* Local identifiers */
|
||||
ID retVal; /* Return value - identifier */
|
||||
|
||||
/* Icodes and control flow graph */
|
||||
CIcodeRec Icode; /* Object with ICODE records */
|
||||
FunctionCfg m_actual_cfg;
|
||||
std::vector<BB*> m_dfsLast;
|
||||
std::map<int,BB*> m_ip_to_bb;
|
||||
// * (reverse postorder) order */
|
||||
size_t numBBs; /* Number of BBs in the graph cfg */
|
||||
bool hasCase; /* Procedure has a case node */
|
||||
|
||||
/* For interprocedural live analysis */
|
||||
LivenessSet liveIn; /* Registers used before defined */
|
||||
LivenessSet liveOut; /* Registers that may be used in successors */
|
||||
bool liveAnal; /* Procedure has been analysed already */
|
||||
|
||||
virtual ~Function() {
|
||||
delete type;
|
||||
}
|
||||
public:
|
||||
static Function *Create(FunctionType *ty=0,int /*Linkage*/=0,const std::string &nm="",void */*module*/=0)
|
||||
{
|
||||
Function *r=new Function(ty);
|
||||
r->name = nm;
|
||||
return r;
|
||||
}
|
||||
FunctionType *getFunctionType() const {
|
||||
return type;
|
||||
}
|
||||
CConv *callingConv() const { return m_call_conv;}
|
||||
void callingConv(CConv::Type v);
|
||||
|
||||
// bool anyFlagsSet(uint32_t t) { return (flg&t)!=0;}
|
||||
bool hasRegArgs() const { return (flg & REG_ARGS)!=0;}
|
||||
bool isLibrary() const { return (flg & PROC_ISLIB)!=0;}
|
||||
void compoundCond();
|
||||
void writeProcComments();
|
||||
void lowLevelAnalysis();
|
||||
void bindIcodeOff();
|
||||
void dataFlow(LivenessSet &liveOut);
|
||||
void compressCFG();
|
||||
void highLevelGen();
|
||||
void structure(derSeq *derivedG);
|
||||
derSeq *checkReducibility();
|
||||
void createCFG();
|
||||
void markImpure();
|
||||
void findImmedDom();
|
||||
void FollowCtrl(CALL_GRAPH *pcallGraph, STATE *pstate);
|
||||
void process_operands(ICODE &pIcode, STATE *pstate);
|
||||
bool process_JMP(ICODE &pIcode, STATE *pstate, CALL_GRAPH *pcallGraph);
|
||||
bool process_CALL(ICODE &pIcode, CALL_GRAPH *pcallGraph, STATE *pstate);
|
||||
void freeCFG();
|
||||
void codeGen(std::ostream &fs);
|
||||
void mergeFallThrough(BB *pBB);
|
||||
void structIfs();
|
||||
void structLoops(derSeq *derivedG);
|
||||
void buildCFG(Disassembler &ds);
|
||||
void controlFlowAnalysis();
|
||||
void newRegArg(iICODE picode, iICODE ticode);
|
||||
void writeProcComments(std::ostream &ostr);
|
||||
|
||||
void displayCFG();
|
||||
void displayStats();
|
||||
void processHliCall(Expr *exp, iICODE picode);
|
||||
|
||||
void preprocessReturnDU(LivenessSet &_liveOut);
|
||||
Expr * adjustActArgType(Expr *_exp, hlType forType);
|
||||
std::string writeCall(Function *tproc, STKFRAME &args, int *numLoc);
|
||||
void processDosInt(STATE *pstate, PROG &prog, bool done);
|
||||
ICODE *translate_DIV(LLInst *ll, ICODE &_Icode);
|
||||
ICODE *translate_XCHG(LLInst *ll, ICODE &_Icode);
|
||||
protected:
|
||||
void extractJumpTableRange(ICODE& pIcode, STATE *pstate, JumpTable &table);
|
||||
bool followAllTableEntries(JumpTable &table, uint32_t cs, ICODE &pIcode, CALL_GRAPH *pcallGraph, STATE *pstate);
|
||||
bool removeInEdge_Flag_and_ProcessLatch(BB *pbb, BB *a, BB *b);
|
||||
bool Case_X_and_Y(BB* pbb, BB* thenBB, BB* elseBB);
|
||||
bool Case_X_or_Y(BB* pbb, BB* thenBB, BB* elseBB);
|
||||
bool Case_notX_or_Y(BB* pbb, BB* thenBB, BB* elseBB);
|
||||
bool Case_notX_and_Y(BB* pbb, BB* thenBB, BB* elseBB);
|
||||
void replaceInEdge(BB* where, BB* which, BB* with);
|
||||
void processExpPush(int &numHlIcodes, iICODE picode);
|
||||
|
||||
// TODO: replace those with friend visitor ?
|
||||
void propLongReg(int loc_ident_idx, const ID &pLocId);
|
||||
void propLongStk(int i, const ID &pLocId);
|
||||
void propLongGlb(int i, const ID &pLocId);
|
||||
void processTargetIcode(iICODE picode, int &numHlIcodes, iICODE ticode, bool isLong);
|
||||
|
||||
int findBackwarLongDefs(int loc_ident_idx, const ID &pLocId, iICODE iter);
|
||||
int findForwardLongUses(int loc_ident_idx, const ID &pLocId, iICODE beg);
|
||||
void structCases();
|
||||
void findExps();
|
||||
void genDU1();
|
||||
void elimCondCodes();
|
||||
void liveRegAnalysis(LivenessSet &in_liveOut);
|
||||
void findIdioms();
|
||||
void propLong();
|
||||
void genLiveKtes();
|
||||
bool findDerivedSeq(derSeq &derivedGi);
|
||||
bool nextOrderGraph(derSeq &derivedGi);
|
||||
};
|
||||
namespace llvm {
|
||||
template<> struct ilist_traits<typename ::Function>
|
||||
: public ilist_default_traits<typename ::Function> {
|
||||
|
||||
// createSentinel is used to get hold of the node that marks the end of the
|
||||
// list... (same trick used here as in ilist_traits<Instruction>)
|
||||
typename ::Function *createSentinel() const {
|
||||
return static_cast<typename ::Function*>(&Sentinel);
|
||||
}
|
||||
static void destroySentinel(typename ::Function*) {}
|
||||
|
||||
typename ::Function *provideInitialHead() const { return createSentinel(); }
|
||||
typename ::Function *ensureHead(::Function*) const { return createSentinel(); }
|
||||
static void noteHead(typename ::Function*, typename ::Function*) {}
|
||||
|
||||
private:
|
||||
mutable ilist_node<typename ::Function> Sentinel;
|
||||
};
|
||||
}
|
||||
typedef llvm::iplist<Function> FunctionListType;
|
||||
typedef FunctionListType lFunction;
|
||||
typedef lFunction::iterator ilFunction;
|
||||
#pragma once
|
||||
#include <llvm/ADT/ilist.h>
|
||||
//#include <llvm/ADT/ilist_node.h>
|
||||
#include <bitset>
|
||||
#include <map>
|
||||
#include "BasicBlock.h"
|
||||
#include "locident.h"
|
||||
#include "state.h"
|
||||
#include "icode.h"
|
||||
#include "StackFrame.h"
|
||||
#include "CallConvention.h"
|
||||
/* PROCEDURE NODE */
|
||||
struct CALL_GRAPH;
|
||||
struct Expr;
|
||||
struct Disassembler;
|
||||
struct Function;
|
||||
struct CALL_GRAPH;
|
||||
struct PROG;
|
||||
|
||||
struct Function;
|
||||
|
||||
namespace llvm
|
||||
{
|
||||
// Traits for intrusive list of basic blocks...
|
||||
template<>
|
||||
struct ilist_traits<BB> : public ilist_default_traits<BB>
|
||||
{
|
||||
|
||||
// createSentinel is used to get hold of the node that marks the end of the
|
||||
// list... (same trick used here as in ilist_traits<Instruction>)
|
||||
BB *createSentinel() const {
|
||||
return static_cast<BB*>(&Sentinel);
|
||||
}
|
||||
static void destroySentinel(BB*) {}
|
||||
|
||||
BB *provideInitialHead() const { return createSentinel(); }
|
||||
BB *ensureHead(BB*) const { return createSentinel(); }
|
||||
static void noteHead(BB*, BB*) {}
|
||||
|
||||
//static ValueSymbolTable *getSymTab(Function *ItemParent);
|
||||
private:
|
||||
mutable ilist_half_node<BB> Sentinel;
|
||||
};
|
||||
}
|
||||
/* Procedure FLAGS */
|
||||
enum PROC_FLAGS
|
||||
{
|
||||
PROC_BADINST=0x00000100,/* Proc contains invalid or 386 instruction */
|
||||
PROC_IJMP =0x00000200,/* Proc incomplete due to indirect jmp */
|
||||
PROC_ICALL =0x00000400, /* Proc incomplete due to indirect call */
|
||||
PROC_HLL =0x00001000, /* Proc is likely to be from a HLL */
|
||||
// CALL_PASCAL =0x00002000, /* Proc uses Pascal calling convention */
|
||||
// CALL_C =0x00004000, /* Proc uses C calling convention */
|
||||
// CALL_UNKNOWN=0x00008000, /* Proc uses unknown calling convention */
|
||||
PROC_NEAR =0x00010000, /* Proc exits with near return */
|
||||
PROC_FAR =0x00020000, /* Proc exits with far return */
|
||||
GRAPH_IRRED =0x00100000, /* Proc generates an irreducible graph */
|
||||
SI_REGVAR =0x00200000, /* SI is used as a stack variable */
|
||||
DI_REGVAR =0x00400000, /* DI is used as a stack variable */
|
||||
PROC_IS_FUNC=0x00800000, /* Proc is a function */
|
||||
REG_ARGS =0x01000000, /* Proc has registers as arguments */
|
||||
// PROC_VARARG =0x02000000, /* Proc has variable arguments */
|
||||
PROC_OUTPUT =0x04000000, /* C for this proc has been output */
|
||||
PROC_RUNTIME=0x08000000, /* Proc is part of the runtime support */
|
||||
PROC_ISLIB =0x10000000, /* Proc is a library function */
|
||||
PROC_ASM =0x20000000, /* Proc is an intrinsic assembler routine */
|
||||
PROC_IS_HLL =0x40000000 /* Proc has HLL prolog code */
|
||||
//#define CALL_MASK 0xFFFF9FFF /* Masks off CALL_C and CALL_PASCAL */
|
||||
};
|
||||
|
||||
struct FunctionType
|
||||
{
|
||||
bool m_vararg=false;
|
||||
bool isVarArg() const {return m_vararg;}
|
||||
};
|
||||
struct Assignment
|
||||
{
|
||||
Expr *lhs;
|
||||
Expr *rhs;
|
||||
};
|
||||
struct JumpTable
|
||||
{
|
||||
uint32_t start;
|
||||
uint32_t finish;
|
||||
bool valid() {return start<finish;}
|
||||
size_t size() { return (finish-start)/2;}
|
||||
size_t entrySize() { return 2;}
|
||||
void pruneEntries(uint16_t cs);
|
||||
};
|
||||
class FunctionCfg
|
||||
{
|
||||
std::list<BB*> m_listBB; /* Ptr. to BB list/CFG */
|
||||
public:
|
||||
typedef std::list<BB*>::iterator iterator;
|
||||
iterator begin() {
|
||||
return m_listBB.begin();
|
||||
}
|
||||
iterator end() {
|
||||
return m_listBB.end();
|
||||
}
|
||||
BB * &front() { return m_listBB.front();}
|
||||
void nodeSplitting()
|
||||
{
|
||||
/* Converts the irreducible graph G into an equivalent reducible one, by
|
||||
* means of node splitting. */
|
||||
fprintf(stderr,"Attempt to perform node splitting: NOT IMPLEMENTED\n");
|
||||
}
|
||||
void push_back(BB *v) { m_listBB.push_back(v);}
|
||||
};
|
||||
struct Function : public llvm::ilist_node<Function>
|
||||
{
|
||||
typedef llvm::iplist<BB> BasicBlockListType;
|
||||
// BasicBlock iterators...
|
||||
typedef BasicBlockListType::iterator iterator;
|
||||
typedef BasicBlockListType::const_iterator const_iterator;
|
||||
protected:
|
||||
BasicBlockListType BasicBlocks; ///< The basic blocks
|
||||
Function(FunctionType */*ty*/) : procEntry(0),depth(0),flg(0),cbParam(0),m_dfsLast(0),numBBs(0),
|
||||
hasCase(false),liveAnal(0)
|
||||
{
|
||||
type = new FunctionType;
|
||||
callingConv(CConv::UNKNOWN);
|
||||
}
|
||||
|
||||
public:
|
||||
FunctionType * type;
|
||||
CConv * m_call_conv;
|
||||
uint32_t procEntry; /* label number */
|
||||
std::string name; /* Meaningful name for this proc */
|
||||
STATE state; /* Entry state */
|
||||
int depth; /* Depth at which we found it - for printing */
|
||||
uint32_t flg; /* Combination of Icode & Proc flags */
|
||||
int16_t cbParam; /* Probable no. of bytes of parameters */
|
||||
STKFRAME args; /* Array of arguments */
|
||||
LOCAL_ID localId; /* Local identifiers */
|
||||
ID retVal; /* Return value - identifier */
|
||||
|
||||
/* Icodes and control flow graph */
|
||||
CIcodeRec Icode; /* Object with ICODE records */
|
||||
FunctionCfg m_actual_cfg;
|
||||
std::vector<BB*> m_dfsLast;
|
||||
std::map<int,BB*> m_ip_to_bb;
|
||||
// * (reverse postorder) order */
|
||||
size_t numBBs; /* Number of BBs in the graph cfg */
|
||||
bool hasCase; /* Procedure has a case node */
|
||||
|
||||
/* For interprocedural live analysis */
|
||||
LivenessSet liveIn; /* Registers used before defined */
|
||||
LivenessSet liveOut; /* Registers that may be used in successors */
|
||||
bool liveAnal; /* Procedure has been analysed already */
|
||||
|
||||
virtual ~Function() {
|
||||
delete type;
|
||||
}
|
||||
public:
|
||||
static Function *Create(FunctionType *ty=0,int /*Linkage*/=0,const std::string &nm="",void */*module*/=0)
|
||||
{
|
||||
Function *r=new Function(ty);
|
||||
r->name = nm;
|
||||
return r;
|
||||
}
|
||||
FunctionType *getFunctionType() const {
|
||||
return type;
|
||||
}
|
||||
CConv *callingConv() const { return m_call_conv;}
|
||||
void callingConv(CConv::Type v);
|
||||
|
||||
// bool anyFlagsSet(uint32_t t) { return (flg&t)!=0;}
|
||||
bool hasRegArgs() const { return (flg & REG_ARGS)!=0;}
|
||||
bool isLibrary() const { return (flg & PROC_ISLIB)!=0;}
|
||||
void compoundCond();
|
||||
void writeProcComments();
|
||||
void lowLevelAnalysis();
|
||||
void bindIcodeOff();
|
||||
void dataFlow(LivenessSet &liveOut);
|
||||
void compressCFG();
|
||||
void highLevelGen();
|
||||
void structure(derSeq *derivedG);
|
||||
derSeq *checkReducibility();
|
||||
void createCFG();
|
||||
void markImpure();
|
||||
void findImmedDom();
|
||||
void FollowCtrl(CALL_GRAPH *pcallGraph, STATE *pstate);
|
||||
void process_operands(ICODE &pIcode, STATE *pstate);
|
||||
bool process_JMP(ICODE &pIcode, STATE *pstate, CALL_GRAPH *pcallGraph);
|
||||
bool process_CALL(ICODE &pIcode, CALL_GRAPH *pcallGraph, STATE *pstate);
|
||||
void freeCFG();
|
||||
void codeGen(std::ostream &fs);
|
||||
void mergeFallThrough(BB *pBB);
|
||||
void structIfs();
|
||||
void structLoops(derSeq *derivedG);
|
||||
void buildCFG(Disassembler &ds);
|
||||
void controlFlowAnalysis();
|
||||
void newRegArg(iICODE picode, iICODE ticode);
|
||||
void writeProcComments(std::ostream &ostr);
|
||||
|
||||
void displayCFG();
|
||||
void displayStats();
|
||||
void processHliCall(Expr *exp, iICODE picode);
|
||||
|
||||
void preprocessReturnDU(LivenessSet &_liveOut);
|
||||
Expr * adjustActArgType(Expr *_exp, hlType forType);
|
||||
std::string writeCall(Function *tproc, STKFRAME &args, int *numLoc);
|
||||
void processDosInt(STATE *pstate, PROG &prog, bool done);
|
||||
ICODE *translate_DIV(LLInst *ll, ICODE &_Icode);
|
||||
ICODE *translate_XCHG(LLInst *ll, ICODE &_Icode);
|
||||
protected:
|
||||
void extractJumpTableRange(ICODE& pIcode, STATE *pstate, JumpTable &table);
|
||||
bool followAllTableEntries(JumpTable &table, uint32_t cs, ICODE &pIcode, CALL_GRAPH *pcallGraph, STATE *pstate);
|
||||
bool removeInEdge_Flag_and_ProcessLatch(BB *pbb, BB *a, BB *b);
|
||||
bool Case_X_and_Y(BB* pbb, BB* thenBB, BB* elseBB);
|
||||
bool Case_X_or_Y(BB* pbb, BB* thenBB, BB* elseBB);
|
||||
bool Case_notX_or_Y(BB* pbb, BB* thenBB, BB* elseBB);
|
||||
bool Case_notX_and_Y(BB* pbb, BB* thenBB, BB* elseBB);
|
||||
void replaceInEdge(BB* where, BB* which, BB* with);
|
||||
void processExpPush(int &numHlIcodes, iICODE picode);
|
||||
|
||||
// TODO: replace those with friend visitor ?
|
||||
void propLongReg(int loc_ident_idx, const ID &pLocId);
|
||||
void propLongStk(int i, const ID &pLocId);
|
||||
void propLongGlb(int i, const ID &pLocId);
|
||||
void processTargetIcode(iICODE picode, int &numHlIcodes, iICODE ticode, bool isLong);
|
||||
|
||||
int findBackwarLongDefs(int loc_ident_idx, const ID &pLocId, iICODE iter);
|
||||
int findForwardLongUses(int loc_ident_idx, const ID &pLocId, iICODE beg);
|
||||
void structCases();
|
||||
void findExps();
|
||||
void genDU1();
|
||||
void elimCondCodes();
|
||||
void liveRegAnalysis(LivenessSet &in_liveOut);
|
||||
void findIdioms();
|
||||
void propLong();
|
||||
void genLiveKtes();
|
||||
bool findDerivedSeq(derSeq &derivedGi);
|
||||
bool nextOrderGraph(derSeq &derivedGi);
|
||||
private:
|
||||
bool decodeIndirectJMP(ICODE &pIcode, STATE *pstate, CALL_GRAPH *pcallGraph);
|
||||
bool decodeIndirectJMP2(ICODE &pIcode, STATE *pstate, CALL_GRAPH *pcallGraph);
|
||||
};
|
||||
namespace llvm {
|
||||
template<> struct ilist_traits<typename ::Function>
|
||||
: public ilist_default_traits<typename ::Function> {
|
||||
|
||||
// createSentinel is used to get hold of the node that marks the end of the
|
||||
// list... (same trick used here as in ilist_traits<Instruction>)
|
||||
typename ::Function *createSentinel() const {
|
||||
return static_cast<typename ::Function*>(&Sentinel);
|
||||
}
|
||||
static void destroySentinel(typename ::Function*) {}
|
||||
|
||||
typename ::Function *provideInitialHead() const { return createSentinel(); }
|
||||
typename ::Function *ensureHead(::Function*) const { return createSentinel(); }
|
||||
static void noteHead(typename ::Function*, typename ::Function*) {}
|
||||
|
||||
private:
|
||||
mutable ilist_node<typename ::Function> Sentinel;
|
||||
};
|
||||
}
|
||||
typedef llvm::iplist<Function> FunctionListType;
|
||||
typedef FunctionListType lFunction;
|
||||
typedef lFunction::iterator ilFunction;
|
||||
|
||||
@ -1,413 +1,413 @@
|
||||
#include "dcc.h"
|
||||
#include "DccFrontend.h"
|
||||
#include "project.h"
|
||||
#include "disassem.h"
|
||||
#include "CallGraph.h"
|
||||
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
class Loader
|
||||
{
|
||||
bool loadIntoProject(IProject *);
|
||||
};
|
||||
|
||||
struct PSP { /* PSP structure */
|
||||
uint16_t int20h; /* interrupt 20h */
|
||||
uint16_t eof; /* segment, end of allocation block */
|
||||
uint8_t res1; /* reserved */
|
||||
uint8_t dosDisp[5]; /* far call to DOS function dispatcher */
|
||||
uint8_t int22h[4]; /* vector for terminate routine */
|
||||
uint8_t int23h[4]; /* vector for ctrl+break routine */
|
||||
uint8_t int24h[4]; /* vector for error routine */
|
||||
uint8_t res2[22]; /* reserved */
|
||||
uint16_t segEnv; /* segment address of environment block */
|
||||
uint8_t res3[34]; /* reserved */
|
||||
uint8_t int21h[6]; /* opcode for int21h and far return */
|
||||
uint8_t res4[6]; /* reserved */
|
||||
uint8_t fcb1[16]; /* default file control block 1 */
|
||||
uint8_t fcb2[16]; /* default file control block 2 */
|
||||
uint8_t res5[4]; /* reserved */
|
||||
uint8_t cmdTail[0x80]; /* command tail and disk transfer area */
|
||||
};
|
||||
|
||||
static struct MZHeader { /* EXE file header */
|
||||
uint8_t sigLo; /* .EXE signature: 0x4D 0x5A */
|
||||
uint8_t sigHi;
|
||||
uint16_t lastPageSize; /* Size of the last page */
|
||||
uint16_t numPages; /* Number of pages in the file */
|
||||
uint16_t numReloc; /* Number of relocation items */
|
||||
uint16_t numParaHeader; /* # of paragraphs in the header */
|
||||
uint16_t minAlloc; /* Minimum number of paragraphs */
|
||||
uint16_t maxAlloc; /* Maximum number of paragraphs */
|
||||
uint16_t initSS; /* Segment displacement of stack */
|
||||
uint16_t initSP; /* Contents of SP at entry */
|
||||
uint16_t checkSum; /* Complemented checksum */
|
||||
uint16_t initIP; /* Contents of IP at entry */
|
||||
uint16_t initCS; /* Segment displacement of code */
|
||||
uint16_t relocTabOffset; /* Relocation table offset */
|
||||
uint16_t overlayNum; /* Overlay number */
|
||||
} header;
|
||||
|
||||
#define EXE_RELOCATION 0x10 /* EXE images rellocated to above PSP */
|
||||
|
||||
//static void LoadImage(char *filename);
|
||||
static void displayMemMap(void);
|
||||
/****************************************************************************
|
||||
* displayLoadInfo - Displays low level loader type info.
|
||||
***************************************************************************/
|
||||
void PROG::displayLoadInfo(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("File type is %s\n", (fCOM)?"COM":"EXE");
|
||||
if (! fCOM) {
|
||||
printf("Signature = %02X%02X\n", header.sigLo, header.sigHi);
|
||||
printf("File size %% 512 = %04X\n", LH(&header.lastPageSize));
|
||||
printf("File size / 512 = %04X pages\n", LH(&header.numPages));
|
||||
printf("# relocation items = %04X\n", LH(&header.numReloc));
|
||||
printf("Offset to load image = %04X paras\n", LH(&header.numParaHeader));
|
||||
printf("Minimum allocation = %04X paras\n", LH(&header.minAlloc));
|
||||
printf("Maximum allocation = %04X paras\n", LH(&header.maxAlloc));
|
||||
}
|
||||
printf("Load image size = %04" PRIiPTR "\n", cbImage - sizeof(PSP));
|
||||
printf("Initial SS:SP = %04X:%04X\n", initSS, initSP);
|
||||
printf("Initial CS:IP = %04X:%04X\n", initCS, initIP);
|
||||
|
||||
if (option.VeryVerbose && cReloc)
|
||||
{
|
||||
printf("\nRelocation Table\n");
|
||||
for (i = 0; i < cReloc; i++)
|
||||
{
|
||||
printf("%06X -> [%04X]\n", relocTable[i],LH(image() + relocTable[i]));
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* fill - Fills line for displayMemMap()
|
||||
****************************************************************************/
|
||||
static void fill(int ip, char *bf)
|
||||
{
|
||||
PROG &prog(Project::get()->prog);
|
||||
static uint8_t type[4] = {'.', 'd', 'c', 'x'};
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < 16; i++, ip++)
|
||||
{
|
||||
*bf++ = ' ';
|
||||
*bf++ = (ip < prog.cbImage)? type[(prog.map[ip >> 2] >> ((ip & 3) * 2)) & 3]: ' ';
|
||||
}
|
||||
*bf = '\0';
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* displayMemMap - Displays the memory bitmap
|
||||
****************************************************************************/
|
||||
static void displayMemMap(void)
|
||||
{
|
||||
PROG &prog(Project::get()->prog);
|
||||
|
||||
char c, b1[33], b2[33], b3[33];
|
||||
uint8_t i;
|
||||
int ip = 0;
|
||||
|
||||
printf("\nMemory Map\n");
|
||||
while (ip < prog.cbImage)
|
||||
{
|
||||
fill(ip, b1);
|
||||
printf("%06X %s\n", ip, b1);
|
||||
ip += 16;
|
||||
for (i = 3, c = b1[1]; i < 32 && c == b1[i]; i += 2)
|
||||
; /* Check if all same */
|
||||
if (i > 32)
|
||||
{
|
||||
fill(ip, b2); /* Skip until next two are not same */
|
||||
fill(ip+16, b3);
|
||||
if (! (strcmp(b1, b2) || strcmp(b1, b3)))
|
||||
{
|
||||
printf(" :\n");
|
||||
do
|
||||
{
|
||||
ip += 16;
|
||||
fill(ip+16, b1);
|
||||
} while (! strcmp(b1, b2));
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
DccFrontend::DccFrontend(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* FrontEnd - invokes the loader, parser, disassembler (if asm1), icode
|
||||
* rewritter, and displays any useful information.
|
||||
****************************************************************************/
|
||||
bool DccFrontend::FrontEnd ()
|
||||
{
|
||||
|
||||
/* Do depth first flow analysis building call graph and procedure list,
|
||||
* and attaching the I-code to each procedure */
|
||||
parse (*Project::get());
|
||||
|
||||
if (option.asm1)
|
||||
{
|
||||
qWarning() << "dcc: writing assembler file "<<asm1_name<<'\n';
|
||||
}
|
||||
|
||||
/* Search through code looking for impure references and flag them */
|
||||
Disassembler ds(1);
|
||||
for(Function &f : Project::get()->pProcList)
|
||||
{
|
||||
f.markImpure();
|
||||
if (option.asm1)
|
||||
{
|
||||
ds.disassem(&f);
|
||||
}
|
||||
}
|
||||
if (option.Interact)
|
||||
{
|
||||
interactDis(&Project::get()->pProcList.front(), 0); /* Interactive disassembler */
|
||||
}
|
||||
|
||||
/* Converts jump target addresses to icode offsets */
|
||||
for(Function &f : Project::get()->pProcList)
|
||||
{
|
||||
f.bindIcodeOff();
|
||||
}
|
||||
/* Print memory bitmap */
|
||||
if (option.Map)
|
||||
displayMemMap();
|
||||
return(true); // we no longer own proj !
|
||||
}
|
||||
struct DosLoader {
|
||||
protected:
|
||||
void prepareImage(PROG &prog,size_t sz,QFile &fp) {
|
||||
/* Allocate a block of memory for the program. */
|
||||
prog.cbImage = sz + sizeof(PSP);
|
||||
prog.Imagez = new uint8_t [prog.cbImage];
|
||||
prog.Imagez[0] = 0xCD; /* Fill in PSP int 20h location */
|
||||
prog.Imagez[1] = 0x20; /* for termination checking */
|
||||
/* Read in the image past where a PSP would go */
|
||||
if (sz != fp.read((char *)prog.Imagez + sizeof(PSP),sz))
|
||||
fatalError(CANNOT_READ, fp.fileName().toLocal8Bit().data());
|
||||
}
|
||||
};
|
||||
struct ComLoader : public DosLoader {
|
||||
bool canLoad(QFile &fp) {
|
||||
fp.seek(0);
|
||||
char sig[2];
|
||||
if(2==fp.read(sig,2)) {
|
||||
return not (sig[0] == 0x4D && sig[1] == 0x5A);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool load(PROG &prog,QFile &fp) {
|
||||
fp.seek(0);
|
||||
/* COM file
|
||||
* In this case the load module size is just the file length
|
||||
*/
|
||||
auto cb = fp.size();
|
||||
|
||||
/* COM programs start off with an ORG 100H (to leave room for a PSP)
|
||||
* This is also the implied start address so if we load the image
|
||||
* at offset 100H addresses should all line up properly again.
|
||||
*/
|
||||
prog.initCS = 0;
|
||||
prog.initIP = 0x100;
|
||||
prog.initSS = 0;
|
||||
prog.initSP = 0xFFFE;
|
||||
prog.cReloc = 0;
|
||||
|
||||
prepareImage(prog,cb,fp);
|
||||
|
||||
|
||||
/* Set up memory map */
|
||||
cb = (prog.cbImage + 3) / 4;
|
||||
prog.map = (uint8_t *)malloc(cb);
|
||||
memset(prog.map, BM_UNKNOWN, (size_t)cb);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
struct ExeLoader : public DosLoader {
|
||||
bool canLoad(QFile &fp) {
|
||||
if(fp.size()<sizeof(header))
|
||||
return false;
|
||||
MZHeader tmp_header;
|
||||
fp.seek(0);
|
||||
fp.read((char *)&tmp_header, sizeof(header));
|
||||
if(not (tmp_header.sigLo == 0x4D && tmp_header.sigHi == 0x5A))
|
||||
return false;
|
||||
|
||||
/* This is a typical DOS kludge! */
|
||||
if (LH(&header.relocTabOffset) == 0x40)
|
||||
{
|
||||
qDebug() << "Don't understand new EXE format";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool load(PROG &prog,QFile &fp) {
|
||||
/* Read rest of header */
|
||||
fp.seek(0);
|
||||
if (fp.read((char *)&header, sizeof(header)) != sizeof(header))
|
||||
return false;
|
||||
|
||||
/* Calculate the load module size.
|
||||
* This is the number of pages in the file
|
||||
* less the length of the header and reloc table
|
||||
* less the number of bytes unused on last page
|
||||
*/
|
||||
uint32_t cb = (uint32_t)LH(&header.numPages) * 512 - (uint32_t)LH(&header.numParaHeader) * 16;
|
||||
if (header.lastPageSize)
|
||||
{
|
||||
cb -= 512 - LH(&header.lastPageSize);
|
||||
}
|
||||
|
||||
/* We quietly ignore minAlloc and maxAlloc since for our
|
||||
* purposes it doesn't really matter where in real memory
|
||||
* the program would end up. EXE programs can't really rely on
|
||||
* their load location so setting the PSP segment to 0 is fine.
|
||||
* Certainly programs that prod around in DOS or BIOS are going
|
||||
* to have to load DS from a constant so it'll be pretty
|
||||
* obvious.
|
||||
*/
|
||||
prog.initCS = (int16_t)LH(&header.initCS) + EXE_RELOCATION;
|
||||
prog.initIP = (int16_t)LH(&header.initIP);
|
||||
prog.initSS = (int16_t)LH(&header.initSS) + EXE_RELOCATION;
|
||||
prog.initSP = (int16_t)LH(&header.initSP);
|
||||
prog.cReloc = (int16_t)LH(&header.numReloc);
|
||||
|
||||
/* Allocate the relocation table */
|
||||
if (prog.cReloc)
|
||||
{
|
||||
prog.relocTable.resize(prog.cReloc);
|
||||
fp.seek(LH(&header.relocTabOffset));
|
||||
|
||||
/* Read in seg:offset pairs and convert to Image ptrs */
|
||||
uint8_t buf[4];
|
||||
for (int i = 0; i < prog.cReloc; i++)
|
||||
{
|
||||
fp.read((char *)buf,4);
|
||||
prog.relocTable[i] = LH(buf) + (((int)LH(buf+2) + EXE_RELOCATION)<<4);
|
||||
}
|
||||
}
|
||||
/* Seek to start of image */
|
||||
uint32_t start_of_image= LH(&header.numParaHeader) * 16;
|
||||
fp.seek(start_of_image);
|
||||
/* Allocate a block of memory for the program. */
|
||||
prepareImage(prog,cb,fp);
|
||||
|
||||
/* Set up memory map */
|
||||
cb = (prog.cbImage + 3) / 4;
|
||||
prog.map = (uint8_t *)malloc(cb);
|
||||
memset(prog.map, BM_UNKNOWN, (size_t)cb);
|
||||
|
||||
/* Relocate segment constants */
|
||||
for(uint32_t v : prog.relocTable) {
|
||||
uint8_t *p = &prog.Imagez[v];
|
||||
uint16_t w = (uint16_t)LH(p) + EXE_RELOCATION;
|
||||
*p++ = (uint8_t)(w & 0x00FF);
|
||||
*p = (uint8_t)((w & 0xFF00) >> 8);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
/*****************************************************************************
|
||||
* LoadImage
|
||||
****************************************************************************/
|
||||
bool Project::load()
|
||||
{
|
||||
// addTask(loaderSelection,PreCond(BinaryImage))
|
||||
// addTask(applyLoader,PreCond(Loader))
|
||||
const char *fname = binary_path().toLocal8Bit().data();
|
||||
QFile finfo(binary_path());
|
||||
/* Open the input file */
|
||||
if(!finfo.open(QFile::ReadOnly)) {
|
||||
fatalError(CANNOT_OPEN, fname);
|
||||
}
|
||||
/* Read in first 2 bytes to check EXE signature */
|
||||
if (finfo.size()<=2)
|
||||
{
|
||||
fatalError(CANNOT_READ, fname);
|
||||
}
|
||||
ComLoader com_loader;
|
||||
ExeLoader exe_loader;
|
||||
if(exe_loader.canLoad(finfo)) {
|
||||
prog.fCOM = false;
|
||||
return exe_loader.load(prog,finfo);
|
||||
}
|
||||
if(com_loader.canLoad(finfo)) {
|
||||
prog.fCOM = true;
|
||||
return com_loader.load(prog,finfo);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
uint32_t SynthLab;
|
||||
/* Parses the program, builds the call graph, and returns the list of
|
||||
* procedures found */
|
||||
void DccFrontend::parse(Project &proj)
|
||||
{
|
||||
PROG &prog(proj.prog);
|
||||
STATE state;
|
||||
|
||||
/* Set initial state */
|
||||
state.setState(rES, 0); /* PSP segment */
|
||||
state.setState(rDS, 0);
|
||||
state.setState(rCS, prog.initCS);
|
||||
state.setState(rSS, prog.initSS);
|
||||
state.setState(rSP, prog.initSP);
|
||||
state.IP = ((uint32_t)prog.initCS << 4) + prog.initIP;
|
||||
SynthLab = SYNTHESIZED_MIN;
|
||||
|
||||
/* Check for special settings of initial state, based on idioms of the
|
||||
startup code */
|
||||
state.checkStartup();
|
||||
Function *start_proc;
|
||||
/* Make a struct for the initial procedure */
|
||||
if (prog.offMain != -1)
|
||||
{
|
||||
start_proc = proj.createFunction(0,"main");
|
||||
start_proc->retVal.loc = REG_FRAME;
|
||||
start_proc->retVal.type = TYPE_WORD_SIGN;
|
||||
start_proc->retVal.id.regi = rAX;
|
||||
/* We know where main() is. Start the flow of control from there */
|
||||
start_proc->procEntry = prog.offMain;
|
||||
/* In medium and large models, the segment of main may (will?) not be
|
||||
the same as the initial CS segment (of the startup code) */
|
||||
state.setState(rCS, prog.segMain);
|
||||
state.IP = prog.offMain;
|
||||
}
|
||||
else
|
||||
{
|
||||
start_proc = proj.createFunction(0,"start");
|
||||
/* Create initial procedure at program start address */
|
||||
start_proc->procEntry = (uint32_t)state.IP;
|
||||
}
|
||||
|
||||
/* The state info is for the first procedure */
|
||||
start_proc->state = state;
|
||||
|
||||
/* Set up call graph initial node */
|
||||
proj.callGraph = new CALL_GRAPH;
|
||||
proj.callGraph->proc = start_proc;
|
||||
|
||||
/* This proc needs to be called to set things up for LibCheck(), which
|
||||
checks a proc to see if it is a know C (etc) library */
|
||||
SetupLibCheck();
|
||||
//BUG: proj and g_proj are 'live' at this point !
|
||||
|
||||
/* Recursively build entire procedure list */
|
||||
start_proc->FollowCtrl(proj.callGraph, &state);
|
||||
|
||||
/* This proc needs to be called to clean things up from SetupLibCheck() */
|
||||
CleanupLibCheck();
|
||||
}
|
||||
#include "dcc.h"
|
||||
#include "DccFrontend.h"
|
||||
#include "project.h"
|
||||
#include "disassem.h"
|
||||
#include "CallGraph.h"
|
||||
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
class Loader
|
||||
{
|
||||
bool loadIntoProject(IProject *);
|
||||
};
|
||||
|
||||
struct PSP { /* PSP structure */
|
||||
uint16_t int20h; /* interrupt 20h */
|
||||
uint16_t eof; /* segment, end of allocation block */
|
||||
uint8_t res1; /* reserved */
|
||||
uint8_t dosDisp[5]; /* far call to DOS function dispatcher */
|
||||
uint8_t int22h[4]; /* vector for terminate routine */
|
||||
uint8_t int23h[4]; /* vector for ctrl+break routine */
|
||||
uint8_t int24h[4]; /* vector for error routine */
|
||||
uint8_t res2[22]; /* reserved */
|
||||
uint16_t segEnv; /* segment address of environment block */
|
||||
uint8_t res3[34]; /* reserved */
|
||||
uint8_t int21h[6]; /* opcode for int21h and far return */
|
||||
uint8_t res4[6]; /* reserved */
|
||||
uint8_t fcb1[16]; /* default file control block 1 */
|
||||
uint8_t fcb2[16]; /* default file control block 2 */
|
||||
uint8_t res5[4]; /* reserved */
|
||||
uint8_t cmdTail[0x80]; /* command tail and disk transfer area */
|
||||
};
|
||||
|
||||
static struct MZHeader { /* EXE file header */
|
||||
uint8_t sigLo; /* .EXE signature: 0x4D 0x5A */
|
||||
uint8_t sigHi;
|
||||
uint16_t lastPageSize; /* Size of the last page */
|
||||
uint16_t numPages; /* Number of pages in the file */
|
||||
uint16_t numReloc; /* Number of relocation items */
|
||||
uint16_t numParaHeader; /* # of paragraphs in the header */
|
||||
uint16_t minAlloc; /* Minimum number of paragraphs */
|
||||
uint16_t maxAlloc; /* Maximum number of paragraphs */
|
||||
uint16_t initSS; /* Segment displacement of stack */
|
||||
uint16_t initSP; /* Contents of SP at entry */
|
||||
uint16_t checkSum; /* Complemented checksum */
|
||||
uint16_t initIP; /* Contents of IP at entry */
|
||||
uint16_t initCS; /* Segment displacement of code */
|
||||
uint16_t relocTabOffset; /* Relocation table offset */
|
||||
uint16_t overlayNum; /* Overlay number */
|
||||
} header;
|
||||
|
||||
#define EXE_RELOCATION 0x10 /* EXE images rellocated to above PSP */
|
||||
|
||||
//static void LoadImage(char *filename);
|
||||
static void displayMemMap(void);
|
||||
/****************************************************************************
|
||||
* displayLoadInfo - Displays low level loader type info.
|
||||
***************************************************************************/
|
||||
void PROG::displayLoadInfo(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("File type is %s\n", (fCOM)?"COM":"EXE");
|
||||
if (! fCOM) {
|
||||
printf("Signature = %02X%02X\n", header.sigLo, header.sigHi);
|
||||
printf("File size %% 512 = %04X\n", LH(&header.lastPageSize));
|
||||
printf("File size / 512 = %04X pages\n", LH(&header.numPages));
|
||||
printf("# relocation items = %04X\n", LH(&header.numReloc));
|
||||
printf("Offset to load image = %04X paras\n", LH(&header.numParaHeader));
|
||||
printf("Minimum allocation = %04X paras\n", LH(&header.minAlloc));
|
||||
printf("Maximum allocation = %04X paras\n", LH(&header.maxAlloc));
|
||||
}
|
||||
printf("Load image size = %04" PRIiPTR "\n", cbImage - sizeof(PSP));
|
||||
printf("Initial SS:SP = %04X:%04X\n", initSS, initSP);
|
||||
printf("Initial CS:IP = %04X:%04X\n", initCS, initIP);
|
||||
|
||||
if (option.VeryVerbose && cReloc)
|
||||
{
|
||||
printf("\nRelocation Table\n");
|
||||
for (i = 0; i < cReloc; i++)
|
||||
{
|
||||
printf("%06X -> [%04X]\n", relocTable[i],LH(image() + relocTable[i]));
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* fill - Fills line for displayMemMap()
|
||||
****************************************************************************/
|
||||
static void fill(int ip, char *bf)
|
||||
{
|
||||
PROG &prog(Project::get()->prog);
|
||||
static uint8_t type[4] = {'.', 'd', 'c', 'x'};
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < 16; i++, ip++)
|
||||
{
|
||||
*bf++ = ' ';
|
||||
*bf++ = (ip < prog.cbImage)? type[(prog.map[ip >> 2] >> ((ip & 3) * 2)) & 3]: ' ';
|
||||
}
|
||||
*bf = '\0';
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* displayMemMap - Displays the memory bitmap
|
||||
****************************************************************************/
|
||||
static void displayMemMap(void)
|
||||
{
|
||||
PROG &prog(Project::get()->prog);
|
||||
|
||||
char c, b1[33], b2[33], b3[33];
|
||||
uint8_t i;
|
||||
int ip = 0;
|
||||
|
||||
printf("\nMemory Map\n");
|
||||
while (ip < prog.cbImage)
|
||||
{
|
||||
fill(ip, b1);
|
||||
printf("%06X %s\n", ip, b1);
|
||||
ip += 16;
|
||||
for (i = 3, c = b1[1]; i < 32 && c == b1[i]; i += 2)
|
||||
; /* Check if all same */
|
||||
if (i > 32)
|
||||
{
|
||||
fill(ip, b2); /* Skip until next two are not same */
|
||||
fill(ip+16, b3);
|
||||
if (! (strcmp(b1, b2) || strcmp(b1, b3)))
|
||||
{
|
||||
printf(" :\n");
|
||||
do
|
||||
{
|
||||
ip += 16;
|
||||
fill(ip+16, b1);
|
||||
} while (! strcmp(b1, b2));
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
DccFrontend::DccFrontend(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* FrontEnd - invokes the loader, parser, disassembler (if asm1), icode
|
||||
* rewritter, and displays any useful information.
|
||||
****************************************************************************/
|
||||
bool DccFrontend::FrontEnd ()
|
||||
{
|
||||
|
||||
/* Do depth first flow analysis building call graph and procedure list,
|
||||
* and attaching the I-code to each procedure */
|
||||
parse (*Project::get());
|
||||
|
||||
if (option.asm1)
|
||||
{
|
||||
qWarning() << "dcc: writing assembler file "<<asm1_name<<'\n';
|
||||
}
|
||||
|
||||
/* Search through code looking for impure references and flag them */
|
||||
Disassembler ds(1);
|
||||
for(Function &f : Project::get()->pProcList)
|
||||
{
|
||||
f.markImpure();
|
||||
if (option.asm1)
|
||||
{
|
||||
ds.disassem(&f);
|
||||
}
|
||||
}
|
||||
if (option.Interact)
|
||||
{
|
||||
interactDis(&Project::get()->pProcList.front(), 0); /* Interactive disassembler */
|
||||
}
|
||||
|
||||
/* Converts jump target addresses to icode offsets */
|
||||
for(Function &f : Project::get()->pProcList)
|
||||
{
|
||||
f.bindIcodeOff();
|
||||
}
|
||||
/* Print memory bitmap */
|
||||
if (option.Map)
|
||||
displayMemMap();
|
||||
return(true); // we no longer own proj !
|
||||
}
|
||||
struct DosLoader {
|
||||
protected:
|
||||
void prepareImage(PROG &prog,size_t sz,QFile &fp) {
|
||||
/* Allocate a block of memory for the program. */
|
||||
prog.cbImage = sz + sizeof(PSP);
|
||||
prog.Imagez = new uint8_t [prog.cbImage];
|
||||
prog.Imagez[0] = 0xCD; /* Fill in PSP int 20h location */
|
||||
prog.Imagez[1] = 0x20; /* for termination checking */
|
||||
/* Read in the image past where a PSP would go */
|
||||
if (sz != fp.read((char *)prog.Imagez + sizeof(PSP),sz))
|
||||
fatalError(CANNOT_READ, fp.fileName().toLocal8Bit().data());
|
||||
}
|
||||
};
|
||||
struct ComLoader : public DosLoader {
|
||||
bool canLoad(QFile &fp) {
|
||||
fp.seek(0);
|
||||
char sig[2];
|
||||
if(2==fp.read(sig,2)) {
|
||||
return not (sig[0] == 0x4D && sig[1] == 0x5A);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool load(PROG &prog,QFile &fp) {
|
||||
fp.seek(0);
|
||||
/* COM file
|
||||
* In this case the load module size is just the file length
|
||||
*/
|
||||
auto cb = fp.size();
|
||||
|
||||
/* COM programs start off with an ORG 100H (to leave room for a PSP)
|
||||
* This is also the implied start address so if we load the image
|
||||
* at offset 100H addresses should all line up properly again.
|
||||
*/
|
||||
prog.initCS = 0;
|
||||
prog.initIP = 0x100;
|
||||
prog.initSS = 0;
|
||||
prog.initSP = 0xFFFE;
|
||||
prog.cReloc = 0;
|
||||
|
||||
prepareImage(prog,cb,fp);
|
||||
|
||||
|
||||
/* Set up memory map */
|
||||
cb = (prog.cbImage + 3) / 4;
|
||||
prog.map = (uint8_t *)malloc(cb);
|
||||
memset(prog.map, BM_UNKNOWN, (size_t)cb);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
struct ExeLoader : public DosLoader {
|
||||
bool canLoad(QFile &fp) {
|
||||
if(fp.size()<sizeof(header))
|
||||
return false;
|
||||
MZHeader tmp_header;
|
||||
fp.seek(0);
|
||||
fp.read((char *)&tmp_header, sizeof(header));
|
||||
if(not (tmp_header.sigLo == 0x4D && tmp_header.sigHi == 0x5A))
|
||||
return false;
|
||||
|
||||
/* This is a typical DOS kludge! */
|
||||
if (LH(&header.relocTabOffset) == 0x40)
|
||||
{
|
||||
qDebug() << "Don't understand new EXE format";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool load(PROG &prog,QFile &fp) {
|
||||
/* Read rest of header */
|
||||
fp.seek(0);
|
||||
if (fp.read((char *)&header, sizeof(header)) != sizeof(header))
|
||||
return false;
|
||||
|
||||
/* Calculate the load module size.
|
||||
* This is the number of pages in the file
|
||||
* less the length of the header and reloc table
|
||||
* less the number of bytes unused on last page
|
||||
*/
|
||||
uint32_t cb = (uint32_t)LH(&header.numPages) * 512 - (uint32_t)LH(&header.numParaHeader) * 16;
|
||||
if (header.lastPageSize)
|
||||
{
|
||||
cb -= 512 - LH(&header.lastPageSize);
|
||||
}
|
||||
|
||||
/* We quietly ignore minAlloc and maxAlloc since for our
|
||||
* purposes it doesn't really matter where in real memory
|
||||
* the program would end up. EXE programs can't really rely on
|
||||
* their load location so setting the PSP segment to 0 is fine.
|
||||
* Certainly programs that prod around in DOS or BIOS are going
|
||||
* to have to load DS from a constant so it'll be pretty
|
||||
* obvious.
|
||||
*/
|
||||
prog.initCS = (int16_t)LH(&header.initCS) + EXE_RELOCATION;
|
||||
prog.initIP = (int16_t)LH(&header.initIP);
|
||||
prog.initSS = (int16_t)LH(&header.initSS) + EXE_RELOCATION;
|
||||
prog.initSP = (int16_t)LH(&header.initSP);
|
||||
prog.cReloc = (int16_t)LH(&header.numReloc);
|
||||
|
||||
/* Allocate the relocation table */
|
||||
if (prog.cReloc)
|
||||
{
|
||||
prog.relocTable.resize(prog.cReloc);
|
||||
fp.seek(LH(&header.relocTabOffset));
|
||||
|
||||
/* Read in seg:offset pairs and convert to Image ptrs */
|
||||
uint8_t buf[4];
|
||||
for (int i = 0; i < prog.cReloc; i++)
|
||||
{
|
||||
fp.read((char *)buf,4);
|
||||
prog.relocTable[i] = LH(buf) + (((int)LH(buf+2) + EXE_RELOCATION)<<4);
|
||||
}
|
||||
}
|
||||
/* Seek to start of image */
|
||||
uint32_t start_of_image= LH(&header.numParaHeader) * 16;
|
||||
fp.seek(start_of_image);
|
||||
/* Allocate a block of memory for the program. */
|
||||
prepareImage(prog,cb,fp);
|
||||
|
||||
/* Set up memory map */
|
||||
cb = (prog.cbImage + 3) / 4;
|
||||
prog.map = (uint8_t *)malloc(cb);
|
||||
memset(prog.map, BM_UNKNOWN, (size_t)cb);
|
||||
|
||||
/* Relocate segment constants */
|
||||
for(uint32_t v : prog.relocTable) {
|
||||
uint8_t *p = &prog.Imagez[v];
|
||||
uint16_t w = (uint16_t)LH(p) + EXE_RELOCATION;
|
||||
*p++ = (uint8_t)(w & 0x00FF);
|
||||
*p = (uint8_t)((w & 0xFF00) >> 8);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
/*****************************************************************************
|
||||
* LoadImage
|
||||
****************************************************************************/
|
||||
bool Project::load()
|
||||
{
|
||||
// addTask(loaderSelection,PreCond(BinaryImage))
|
||||
// addTask(applyLoader,PreCond(Loader))
|
||||
const char *fname = binary_path().toLocal8Bit().data();
|
||||
QFile finfo(binary_path());
|
||||
/* Open the input file */
|
||||
if(!finfo.open(QFile::ReadOnly)) {
|
||||
fatalError(CANNOT_OPEN, fname);
|
||||
}
|
||||
/* Read in first 2 bytes to check EXE signature */
|
||||
if (finfo.size()<=2)
|
||||
{
|
||||
fatalError(CANNOT_READ, fname);
|
||||
}
|
||||
ComLoader com_loader;
|
||||
ExeLoader exe_loader;
|
||||
if(exe_loader.canLoad(finfo)) {
|
||||
prog.fCOM = false;
|
||||
return exe_loader.load(prog,finfo);
|
||||
}
|
||||
if(com_loader.canLoad(finfo)) {
|
||||
prog.fCOM = true;
|
||||
return com_loader.load(prog,finfo);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
uint32_t SynthLab;
|
||||
/* Parses the program, builds the call graph, and returns the list of
|
||||
* procedures found */
|
||||
void DccFrontend::parse(Project &proj)
|
||||
{
|
||||
PROG &prog(proj.prog);
|
||||
STATE state;
|
||||
|
||||
/* Set initial state */
|
||||
state.setState(rES, 0); /* PSP segment */
|
||||
state.setState(rDS, 0);
|
||||
state.setState(rCS, prog.initCS);
|
||||
state.setState(rSS, prog.initSS);
|
||||
state.setState(rSP, prog.initSP);
|
||||
state.IP = ((uint32_t)prog.initCS << 4) + prog.initIP;
|
||||
SynthLab = SYNTHESIZED_MIN;
|
||||
|
||||
/* Check for special settings of initial state, based on idioms of the
|
||||
startup code */
|
||||
state.checkStartup();
|
||||
ilFunction start_proc;
|
||||
/* Make a struct for the initial procedure */
|
||||
if (prog.offMain != -1)
|
||||
{
|
||||
start_proc = proj.createFunction(0,"main");
|
||||
start_proc->retVal.loc = REG_FRAME;
|
||||
start_proc->retVal.type = TYPE_WORD_SIGN;
|
||||
start_proc->retVal.id.regi = rAX;
|
||||
/* We know where main() is. Start the flow of control from there */
|
||||
start_proc->procEntry = prog.offMain;
|
||||
/* In medium and large models, the segment of main may (will?) not be
|
||||
the same as the initial CS segment (of the startup code) */
|
||||
state.setState(rCS, prog.segMain);
|
||||
state.IP = prog.offMain;
|
||||
}
|
||||
else
|
||||
{
|
||||
start_proc = proj.createFunction(0,"start");
|
||||
/* Create initial procedure at program start address */
|
||||
start_proc->procEntry = (uint32_t)state.IP;
|
||||
}
|
||||
|
||||
/* The state info is for the first procedure */
|
||||
start_proc->state = state;
|
||||
|
||||
/* Set up call graph initial node */
|
||||
proj.callGraph = new CALL_GRAPH;
|
||||
proj.callGraph->proc = start_proc;
|
||||
|
||||
/* This proc needs to be called to set things up for LibCheck(), which
|
||||
checks a proc to see if it is a know C (etc) library */
|
||||
SetupLibCheck();
|
||||
//BUG: proj and g_proj are 'live' at this point !
|
||||
|
||||
/* Recursively build entire procedure list */
|
||||
start_proc->FollowCtrl(proj.callGraph, &state);
|
||||
|
||||
/* This proc needs to be called to clean things up from SetupLibCheck() */
|
||||
CleanupLibCheck();
|
||||
}
|
||||
|
||||
2510
src/parser.cpp
2510
src/parser.cpp
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user