Implement two new switch idioms closes #14

This commit is contained in:
nemerle 2016-04-23 20:05:11 +02:00
parent 5c85c92d1a
commit 12ee08f87e
3 changed files with 2018 additions and 1837 deletions

View File

@ -1,258 +1,261 @@
#pragma once #pragma once
#include <llvm/ADT/ilist.h> #include <llvm/ADT/ilist.h>
//#include <llvm/ADT/ilist_node.h> //#include <llvm/ADT/ilist_node.h>
#include <bitset> #include <bitset>
#include <map> #include <map>
#include "BasicBlock.h" #include "BasicBlock.h"
#include "locident.h" #include "locident.h"
#include "state.h" #include "state.h"
#include "icode.h" #include "icode.h"
#include "StackFrame.h" #include "StackFrame.h"
#include "CallConvention.h" #include "CallConvention.h"
/* PROCEDURE NODE */ /* PROCEDURE NODE */
struct CALL_GRAPH; struct CALL_GRAPH;
struct Expr; struct Expr;
struct Disassembler; struct Disassembler;
struct Function; struct Function;
struct CALL_GRAPH; struct CALL_GRAPH;
struct PROG; struct PROG;
struct Function; struct Function;
namespace llvm namespace llvm
{ {
// Traits for intrusive list of basic blocks... // Traits for intrusive list of basic blocks...
template<> template<>
struct ilist_traits<BB> : public ilist_default_traits<BB> struct ilist_traits<BB> : public ilist_default_traits<BB>
{ {
// createSentinel is used to get hold of the node that marks the end of the // 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>) // list... (same trick used here as in ilist_traits<Instruction>)
BB *createSentinel() const { BB *createSentinel() const {
return static_cast<BB*>(&Sentinel); return static_cast<BB*>(&Sentinel);
} }
static void destroySentinel(BB*) {} static void destroySentinel(BB*) {}
BB *provideInitialHead() const { return createSentinel(); } BB *provideInitialHead() const { return createSentinel(); }
BB *ensureHead(BB*) const { return createSentinel(); } BB *ensureHead(BB*) const { return createSentinel(); }
static void noteHead(BB*, BB*) {} static void noteHead(BB*, BB*) {}
//static ValueSymbolTable *getSymTab(Function *ItemParent); //static ValueSymbolTable *getSymTab(Function *ItemParent);
private: private:
mutable ilist_half_node<BB> Sentinel; mutable ilist_half_node<BB> Sentinel;
}; };
} }
/* Procedure FLAGS */ /* Procedure FLAGS */
enum PROC_FLAGS enum PROC_FLAGS
{ {
PROC_BADINST=0x00000100,/* Proc contains invalid or 386 instruction */ PROC_BADINST=0x00000100,/* Proc contains invalid or 386 instruction */
PROC_IJMP =0x00000200,/* Proc incomplete due to indirect jmp */ PROC_IJMP =0x00000200,/* Proc incomplete due to indirect jmp */
PROC_ICALL =0x00000400, /* Proc incomplete due to indirect call */ PROC_ICALL =0x00000400, /* Proc incomplete due to indirect call */
PROC_HLL =0x00001000, /* Proc is likely to be from a HLL */ PROC_HLL =0x00001000, /* Proc is likely to be from a HLL */
// CALL_PASCAL =0x00002000, /* Proc uses Pascal calling convention */ // CALL_PASCAL =0x00002000, /* Proc uses Pascal calling convention */
// CALL_C =0x00004000, /* Proc uses C calling convention */ // CALL_C =0x00004000, /* Proc uses C calling convention */
// CALL_UNKNOWN=0x00008000, /* Proc uses unknown calling convention */ // CALL_UNKNOWN=0x00008000, /* Proc uses unknown calling convention */
PROC_NEAR =0x00010000, /* Proc exits with near return */ PROC_NEAR =0x00010000, /* Proc exits with near return */
PROC_FAR =0x00020000, /* Proc exits with far return */ PROC_FAR =0x00020000, /* Proc exits with far return */
GRAPH_IRRED =0x00100000, /* Proc generates an irreducible graph */ GRAPH_IRRED =0x00100000, /* Proc generates an irreducible graph */
SI_REGVAR =0x00200000, /* SI is used as a stack variable */ SI_REGVAR =0x00200000, /* SI is used as a stack variable */
DI_REGVAR =0x00400000, /* DI is used as a stack variable */ DI_REGVAR =0x00400000, /* DI is used as a stack variable */
PROC_IS_FUNC=0x00800000, /* Proc is a function */ PROC_IS_FUNC=0x00800000, /* Proc is a function */
REG_ARGS =0x01000000, /* Proc has registers as arguments */ REG_ARGS =0x01000000, /* Proc has registers as arguments */
// PROC_VARARG =0x02000000, /* Proc has variable arguments */ // PROC_VARARG =0x02000000, /* Proc has variable arguments */
PROC_OUTPUT =0x04000000, /* C for this proc has been output */ PROC_OUTPUT =0x04000000, /* C for this proc has been output */
PROC_RUNTIME=0x08000000, /* Proc is part of the runtime support */ PROC_RUNTIME=0x08000000, /* Proc is part of the runtime support */
PROC_ISLIB =0x10000000, /* Proc is a library function */ PROC_ISLIB =0x10000000, /* Proc is a library function */
PROC_ASM =0x20000000, /* Proc is an intrinsic assembler routine */ PROC_ASM =0x20000000, /* Proc is an intrinsic assembler routine */
PROC_IS_HLL =0x40000000 /* Proc has HLL prolog code */ PROC_IS_HLL =0x40000000 /* Proc has HLL prolog code */
//#define CALL_MASK 0xFFFF9FFF /* Masks off CALL_C and CALL_PASCAL */ //#define CALL_MASK 0xFFFF9FFF /* Masks off CALL_C and CALL_PASCAL */
}; };
struct FunctionType struct FunctionType
{ {
bool m_vararg=false; bool m_vararg=false;
bool isVarArg() const {return m_vararg;} bool isVarArg() const {return m_vararg;}
}; };
struct Assignment struct Assignment
{ {
Expr *lhs; Expr *lhs;
Expr *rhs; Expr *rhs;
}; };
struct JumpTable struct JumpTable
{ {
uint32_t start; uint32_t start;
uint32_t finish; uint32_t finish;
bool valid() {return start<finish;} bool valid() {return start<finish;}
size_t size() { return (finish-start)/2;} size_t size() { return (finish-start)/2;}
size_t entrySize() { return 2;} size_t entrySize() { return 2;}
void pruneEntries(uint16_t cs); void pruneEntries(uint16_t cs);
}; };
class FunctionCfg class FunctionCfg
{ {
std::list<BB*> m_listBB; /* Ptr. to BB list/CFG */ std::list<BB*> m_listBB; /* Ptr. to BB list/CFG */
public: public:
typedef std::list<BB*>::iterator iterator; typedef std::list<BB*>::iterator iterator;
iterator begin() { iterator begin() {
return m_listBB.begin(); return m_listBB.begin();
} }
iterator end() { iterator end() {
return m_listBB.end(); return m_listBB.end();
} }
BB * &front() { return m_listBB.front();} BB * &front() { return m_listBB.front();}
void nodeSplitting() void nodeSplitting()
{ {
/* Converts the irreducible graph G into an equivalent reducible one, by /* Converts the irreducible graph G into an equivalent reducible one, by
* means of node splitting. */ * means of node splitting. */
fprintf(stderr,"Attempt to perform node splitting: NOT IMPLEMENTED\n"); fprintf(stderr,"Attempt to perform node splitting: NOT IMPLEMENTED\n");
} }
void push_back(BB *v) { m_listBB.push_back(v);} void push_back(BB *v) { m_listBB.push_back(v);}
}; };
struct Function : public llvm::ilist_node<Function> struct Function : public llvm::ilist_node<Function>
{ {
typedef llvm::iplist<BB> BasicBlockListType; typedef llvm::iplist<BB> BasicBlockListType;
// BasicBlock iterators... // BasicBlock iterators...
typedef BasicBlockListType::iterator iterator; typedef BasicBlockListType::iterator iterator;
typedef BasicBlockListType::const_iterator const_iterator; typedef BasicBlockListType::const_iterator const_iterator;
protected: protected:
BasicBlockListType BasicBlocks; ///< The basic blocks BasicBlockListType BasicBlocks; ///< The basic blocks
Function(FunctionType */*ty*/) : procEntry(0),depth(0),flg(0),cbParam(0),m_dfsLast(0),numBBs(0), Function(FunctionType */*ty*/) : procEntry(0),depth(0),flg(0),cbParam(0),m_dfsLast(0),numBBs(0),
hasCase(false),liveAnal(0) hasCase(false),liveAnal(0)
{ {
type = new FunctionType; type = new FunctionType;
callingConv(CConv::UNKNOWN); callingConv(CConv::UNKNOWN);
} }
public: public:
FunctionType * type; FunctionType * type;
CConv * m_call_conv; CConv * m_call_conv;
uint32_t procEntry; /* label number */ uint32_t procEntry; /* label number */
std::string name; /* Meaningful name for this proc */ std::string name; /* Meaningful name for this proc */
STATE state; /* Entry state */ STATE state; /* Entry state */
int depth; /* Depth at which we found it - for printing */ int depth; /* Depth at which we found it - for printing */
uint32_t flg; /* Combination of Icode & Proc flags */ uint32_t flg; /* Combination of Icode & Proc flags */
int16_t cbParam; /* Probable no. of bytes of parameters */ int16_t cbParam; /* Probable no. of bytes of parameters */
STKFRAME args; /* Array of arguments */ STKFRAME args; /* Array of arguments */
LOCAL_ID localId; /* Local identifiers */ LOCAL_ID localId; /* Local identifiers */
ID retVal; /* Return value - identifier */ ID retVal; /* Return value - identifier */
/* Icodes and control flow graph */ /* Icodes and control flow graph */
CIcodeRec Icode; /* Object with ICODE records */ CIcodeRec Icode; /* Object with ICODE records */
FunctionCfg m_actual_cfg; FunctionCfg m_actual_cfg;
std::vector<BB*> m_dfsLast; std::vector<BB*> m_dfsLast;
std::map<int,BB*> m_ip_to_bb; std::map<int,BB*> m_ip_to_bb;
// * (reverse postorder) order */ // * (reverse postorder) order */
size_t numBBs; /* Number of BBs in the graph cfg */ size_t numBBs; /* Number of BBs in the graph cfg */
bool hasCase; /* Procedure has a case node */ bool hasCase; /* Procedure has a case node */
/* For interprocedural live analysis */ /* For interprocedural live analysis */
LivenessSet liveIn; /* Registers used before defined */ LivenessSet liveIn; /* Registers used before defined */
LivenessSet liveOut; /* Registers that may be used in successors */ LivenessSet liveOut; /* Registers that may be used in successors */
bool liveAnal; /* Procedure has been analysed already */ bool liveAnal; /* Procedure has been analysed already */
virtual ~Function() { virtual ~Function() {
delete type; delete type;
} }
public: public:
static Function *Create(FunctionType *ty=0,int /*Linkage*/=0,const std::string &nm="",void */*module*/=0) static Function *Create(FunctionType *ty=0,int /*Linkage*/=0,const std::string &nm="",void */*module*/=0)
{ {
Function *r=new Function(ty); Function *r=new Function(ty);
r->name = nm; r->name = nm;
return r; return r;
} }
FunctionType *getFunctionType() const { FunctionType *getFunctionType() const {
return type; return type;
} }
CConv *callingConv() const { return m_call_conv;} CConv *callingConv() const { return m_call_conv;}
void callingConv(CConv::Type v); void callingConv(CConv::Type v);
// bool anyFlagsSet(uint32_t t) { return (flg&t)!=0;} // bool anyFlagsSet(uint32_t t) { return (flg&t)!=0;}
bool hasRegArgs() const { return (flg & REG_ARGS)!=0;} bool hasRegArgs() const { return (flg & REG_ARGS)!=0;}
bool isLibrary() const { return (flg & PROC_ISLIB)!=0;} bool isLibrary() const { return (flg & PROC_ISLIB)!=0;}
void compoundCond(); void compoundCond();
void writeProcComments(); void writeProcComments();
void lowLevelAnalysis(); void lowLevelAnalysis();
void bindIcodeOff(); void bindIcodeOff();
void dataFlow(LivenessSet &liveOut); void dataFlow(LivenessSet &liveOut);
void compressCFG(); void compressCFG();
void highLevelGen(); void highLevelGen();
void structure(derSeq *derivedG); void structure(derSeq *derivedG);
derSeq *checkReducibility(); derSeq *checkReducibility();
void createCFG(); void createCFG();
void markImpure(); void markImpure();
void findImmedDom(); void findImmedDom();
void FollowCtrl(CALL_GRAPH *pcallGraph, STATE *pstate); void FollowCtrl(CALL_GRAPH *pcallGraph, STATE *pstate);
void process_operands(ICODE &pIcode, STATE *pstate); void process_operands(ICODE &pIcode, STATE *pstate);
bool process_JMP(ICODE &pIcode, STATE *pstate, CALL_GRAPH *pcallGraph); bool process_JMP(ICODE &pIcode, STATE *pstate, CALL_GRAPH *pcallGraph);
bool process_CALL(ICODE &pIcode, CALL_GRAPH *pcallGraph, STATE *pstate); bool process_CALL(ICODE &pIcode, CALL_GRAPH *pcallGraph, STATE *pstate);
void freeCFG(); void freeCFG();
void codeGen(std::ostream &fs); void codeGen(std::ostream &fs);
void mergeFallThrough(BB *pBB); void mergeFallThrough(BB *pBB);
void structIfs(); void structIfs();
void structLoops(derSeq *derivedG); void structLoops(derSeq *derivedG);
void buildCFG(Disassembler &ds); void buildCFG(Disassembler &ds);
void controlFlowAnalysis(); void controlFlowAnalysis();
void newRegArg(iICODE picode, iICODE ticode); void newRegArg(iICODE picode, iICODE ticode);
void writeProcComments(std::ostream &ostr); void writeProcComments(std::ostream &ostr);
void displayCFG(); void displayCFG();
void displayStats(); void displayStats();
void processHliCall(Expr *exp, iICODE picode); void processHliCall(Expr *exp, iICODE picode);
void preprocessReturnDU(LivenessSet &_liveOut); void preprocessReturnDU(LivenessSet &_liveOut);
Expr * adjustActArgType(Expr *_exp, hlType forType); Expr * adjustActArgType(Expr *_exp, hlType forType);
std::string writeCall(Function *tproc, STKFRAME &args, int *numLoc); std::string writeCall(Function *tproc, STKFRAME &args, int *numLoc);
void processDosInt(STATE *pstate, PROG &prog, bool done); void processDosInt(STATE *pstate, PROG &prog, bool done);
ICODE *translate_DIV(LLInst *ll, ICODE &_Icode); ICODE *translate_DIV(LLInst *ll, ICODE &_Icode);
ICODE *translate_XCHG(LLInst *ll, ICODE &_Icode); ICODE *translate_XCHG(LLInst *ll, ICODE &_Icode);
protected: protected:
void extractJumpTableRange(ICODE& pIcode, STATE *pstate, JumpTable &table); void extractJumpTableRange(ICODE& pIcode, STATE *pstate, JumpTable &table);
bool followAllTableEntries(JumpTable &table, uint32_t cs, ICODE &pIcode, CALL_GRAPH *pcallGraph, STATE *pstate); 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 removeInEdge_Flag_and_ProcessLatch(BB *pbb, BB *a, BB *b);
bool Case_X_and_Y(BB* pbb, BB* thenBB, BB* elseBB); bool Case_X_and_Y(BB* pbb, BB* thenBB, BB* elseBB);
bool Case_X_or_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_or_Y(BB* pbb, BB* thenBB, BB* elseBB);
bool Case_notX_and_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 replaceInEdge(BB* where, BB* which, BB* with);
void processExpPush(int &numHlIcodes, iICODE picode); void processExpPush(int &numHlIcodes, iICODE picode);
// TODO: replace those with friend visitor ? // TODO: replace those with friend visitor ?
void propLongReg(int loc_ident_idx, const ID &pLocId); void propLongReg(int loc_ident_idx, const ID &pLocId);
void propLongStk(int i, const ID &pLocId); void propLongStk(int i, const ID &pLocId);
void propLongGlb(int i, const ID &pLocId); void propLongGlb(int i, const ID &pLocId);
void processTargetIcode(iICODE picode, int &numHlIcodes, iICODE ticode, bool isLong); void processTargetIcode(iICODE picode, int &numHlIcodes, iICODE ticode, bool isLong);
int findBackwarLongDefs(int loc_ident_idx, const ID &pLocId, iICODE iter); int findBackwarLongDefs(int loc_ident_idx, const ID &pLocId, iICODE iter);
int findForwardLongUses(int loc_ident_idx, const ID &pLocId, iICODE beg); int findForwardLongUses(int loc_ident_idx, const ID &pLocId, iICODE beg);
void structCases(); void structCases();
void findExps(); void findExps();
void genDU1(); void genDU1();
void elimCondCodes(); void elimCondCodes();
void liveRegAnalysis(LivenessSet &in_liveOut); void liveRegAnalysis(LivenessSet &in_liveOut);
void findIdioms(); void findIdioms();
void propLong(); void propLong();
void genLiveKtes(); void genLiveKtes();
bool findDerivedSeq(derSeq &derivedGi); bool findDerivedSeq(derSeq &derivedGi);
bool nextOrderGraph(derSeq &derivedGi); bool nextOrderGraph(derSeq &derivedGi);
}; private:
namespace llvm { bool decodeIndirectJMP(ICODE &pIcode, STATE *pstate, CALL_GRAPH *pcallGraph);
template<> struct ilist_traits<typename ::Function> bool decodeIndirectJMP2(ICODE &pIcode, STATE *pstate, CALL_GRAPH *pcallGraph);
: public ilist_default_traits<typename ::Function> { };
namespace llvm {
// createSentinel is used to get hold of the node that marks the end of the template<> struct ilist_traits<typename ::Function>
// list... (same trick used here as in ilist_traits<Instruction>) : public ilist_default_traits<typename ::Function> {
typename ::Function *createSentinel() const {
return static_cast<typename ::Function*>(&Sentinel); // 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>)
static void destroySentinel(typename ::Function*) {} typename ::Function *createSentinel() const {
return static_cast<typename ::Function*>(&Sentinel);
typename ::Function *provideInitialHead() const { return createSentinel(); } }
typename ::Function *ensureHead(::Function*) const { return createSentinel(); } static void destroySentinel(typename ::Function*) {}
static void noteHead(typename ::Function*, typename ::Function*) {}
typename ::Function *provideInitialHead() const { return createSentinel(); }
private: typename ::Function *ensureHead(::Function*) const { return createSentinel(); }
mutable ilist_node<typename ::Function> Sentinel; static void noteHead(typename ::Function*, typename ::Function*) {}
};
} private:
typedef llvm::iplist<Function> FunctionListType; mutable ilist_node<typename ::Function> Sentinel;
typedef FunctionListType lFunction; };
typedef lFunction::iterator ilFunction; }
typedef llvm::iplist<Function> FunctionListType;
typedef FunctionListType lFunction;
typedef lFunction::iterator ilFunction;

View File

@ -1,413 +1,413 @@
#include "dcc.h" #include "dcc.h"
#include "DccFrontend.h" #include "DccFrontend.h"
#include "project.h" #include "project.h"
#include "disassem.h" #include "disassem.h"
#include "CallGraph.h" #include "CallGraph.h"
#include <QtCore/QFileInfo> #include <QtCore/QFileInfo>
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <cstdio> #include <cstdio>
class Loader class Loader
{ {
bool loadIntoProject(IProject *); bool loadIntoProject(IProject *);
}; };
struct PSP { /* PSP structure */ struct PSP { /* PSP structure */
uint16_t int20h; /* interrupt 20h */ uint16_t int20h; /* interrupt 20h */
uint16_t eof; /* segment, end of allocation block */ uint16_t eof; /* segment, end of allocation block */
uint8_t res1; /* reserved */ uint8_t res1; /* reserved */
uint8_t dosDisp[5]; /* far call to DOS function dispatcher */ uint8_t dosDisp[5]; /* far call to DOS function dispatcher */
uint8_t int22h[4]; /* vector for terminate routine */ uint8_t int22h[4]; /* vector for terminate routine */
uint8_t int23h[4]; /* vector for ctrl+break routine */ uint8_t int23h[4]; /* vector for ctrl+break routine */
uint8_t int24h[4]; /* vector for error routine */ uint8_t int24h[4]; /* vector for error routine */
uint8_t res2[22]; /* reserved */ uint8_t res2[22]; /* reserved */
uint16_t segEnv; /* segment address of environment block */ uint16_t segEnv; /* segment address of environment block */
uint8_t res3[34]; /* reserved */ uint8_t res3[34]; /* reserved */
uint8_t int21h[6]; /* opcode for int21h and far return */ uint8_t int21h[6]; /* opcode for int21h and far return */
uint8_t res4[6]; /* reserved */ uint8_t res4[6]; /* reserved */
uint8_t fcb1[16]; /* default file control block 1 */ uint8_t fcb1[16]; /* default file control block 1 */
uint8_t fcb2[16]; /* default file control block 2 */ uint8_t fcb2[16]; /* default file control block 2 */
uint8_t res5[4]; /* reserved */ uint8_t res5[4]; /* reserved */
uint8_t cmdTail[0x80]; /* command tail and disk transfer area */ uint8_t cmdTail[0x80]; /* command tail and disk transfer area */
}; };
static struct MZHeader { /* EXE file header */ static struct MZHeader { /* EXE file header */
uint8_t sigLo; /* .EXE signature: 0x4D 0x5A */ uint8_t sigLo; /* .EXE signature: 0x4D 0x5A */
uint8_t sigHi; uint8_t sigHi;
uint16_t lastPageSize; /* Size of the last page */ uint16_t lastPageSize; /* Size of the last page */
uint16_t numPages; /* Number of pages in the file */ uint16_t numPages; /* Number of pages in the file */
uint16_t numReloc; /* Number of relocation items */ uint16_t numReloc; /* Number of relocation items */
uint16_t numParaHeader; /* # of paragraphs in the header */ uint16_t numParaHeader; /* # of paragraphs in the header */
uint16_t minAlloc; /* Minimum number of paragraphs */ uint16_t minAlloc; /* Minimum number of paragraphs */
uint16_t maxAlloc; /* Maximum number of paragraphs */ uint16_t maxAlloc; /* Maximum number of paragraphs */
uint16_t initSS; /* Segment displacement of stack */ uint16_t initSS; /* Segment displacement of stack */
uint16_t initSP; /* Contents of SP at entry */ uint16_t initSP; /* Contents of SP at entry */
uint16_t checkSum; /* Complemented checksum */ uint16_t checkSum; /* Complemented checksum */
uint16_t initIP; /* Contents of IP at entry */ uint16_t initIP; /* Contents of IP at entry */
uint16_t initCS; /* Segment displacement of code */ uint16_t initCS; /* Segment displacement of code */
uint16_t relocTabOffset; /* Relocation table offset */ uint16_t relocTabOffset; /* Relocation table offset */
uint16_t overlayNum; /* Overlay number */ uint16_t overlayNum; /* Overlay number */
} header; } header;
#define EXE_RELOCATION 0x10 /* EXE images rellocated to above PSP */ #define EXE_RELOCATION 0x10 /* EXE images rellocated to above PSP */
//static void LoadImage(char *filename); //static void LoadImage(char *filename);
static void displayMemMap(void); static void displayMemMap(void);
/**************************************************************************** /****************************************************************************
* displayLoadInfo - Displays low level loader type info. * displayLoadInfo - Displays low level loader type info.
***************************************************************************/ ***************************************************************************/
void PROG::displayLoadInfo(void) void PROG::displayLoadInfo(void)
{ {
int i; int i;
printf("File type is %s\n", (fCOM)?"COM":"EXE"); printf("File type is %s\n", (fCOM)?"COM":"EXE");
if (! fCOM) { if (! fCOM) {
printf("Signature = %02X%02X\n", header.sigLo, header.sigHi); printf("Signature = %02X%02X\n", header.sigLo, header.sigHi);
printf("File size %% 512 = %04X\n", LH(&header.lastPageSize)); printf("File size %% 512 = %04X\n", LH(&header.lastPageSize));
printf("File size / 512 = %04X pages\n", LH(&header.numPages)); printf("File size / 512 = %04X pages\n", LH(&header.numPages));
printf("# relocation items = %04X\n", LH(&header.numReloc)); printf("# relocation items = %04X\n", LH(&header.numReloc));
printf("Offset to load image = %04X paras\n", LH(&header.numParaHeader)); printf("Offset to load image = %04X paras\n", LH(&header.numParaHeader));
printf("Minimum allocation = %04X paras\n", LH(&header.minAlloc)); printf("Minimum allocation = %04X paras\n", LH(&header.minAlloc));
printf("Maximum allocation = %04X paras\n", LH(&header.maxAlloc)); printf("Maximum allocation = %04X paras\n", LH(&header.maxAlloc));
} }
printf("Load image size = %04" PRIiPTR "\n", cbImage - sizeof(PSP)); printf("Load image size = %04" PRIiPTR "\n", cbImage - sizeof(PSP));
printf("Initial SS:SP = %04X:%04X\n", initSS, initSP); printf("Initial SS:SP = %04X:%04X\n", initSS, initSP);
printf("Initial CS:IP = %04X:%04X\n", initCS, initIP); printf("Initial CS:IP = %04X:%04X\n", initCS, initIP);
if (option.VeryVerbose && cReloc) if (option.VeryVerbose && cReloc)
{ {
printf("\nRelocation Table\n"); printf("\nRelocation Table\n");
for (i = 0; i < cReloc; i++) for (i = 0; i < cReloc; i++)
{ {
printf("%06X -> [%04X]\n", relocTable[i],LH(image() + relocTable[i])); printf("%06X -> [%04X]\n", relocTable[i],LH(image() + relocTable[i]));
} }
} }
printf("\n"); printf("\n");
} }
/***************************************************************************** /*****************************************************************************
* fill - Fills line for displayMemMap() * fill - Fills line for displayMemMap()
****************************************************************************/ ****************************************************************************/
static void fill(int ip, char *bf) static void fill(int ip, char *bf)
{ {
PROG &prog(Project::get()->prog); PROG &prog(Project::get()->prog);
static uint8_t type[4] = {'.', 'd', 'c', 'x'}; static uint8_t type[4] = {'.', 'd', 'c', 'x'};
uint8_t i; uint8_t i;
for (i = 0; i < 16; i++, ip++) for (i = 0; i < 16; i++, ip++)
{ {
*bf++ = ' '; *bf++ = ' ';
*bf++ = (ip < prog.cbImage)? type[(prog.map[ip >> 2] >> ((ip & 3) * 2)) & 3]: ' '; *bf++ = (ip < prog.cbImage)? type[(prog.map[ip >> 2] >> ((ip & 3) * 2)) & 3]: ' ';
} }
*bf = '\0'; *bf = '\0';
} }
/***************************************************************************** /*****************************************************************************
* displayMemMap - Displays the memory bitmap * displayMemMap - Displays the memory bitmap
****************************************************************************/ ****************************************************************************/
static void displayMemMap(void) static void displayMemMap(void)
{ {
PROG &prog(Project::get()->prog); PROG &prog(Project::get()->prog);
char c, b1[33], b2[33], b3[33]; char c, b1[33], b2[33], b3[33];
uint8_t i; uint8_t i;
int ip = 0; int ip = 0;
printf("\nMemory Map\n"); printf("\nMemory Map\n");
while (ip < prog.cbImage) while (ip < prog.cbImage)
{ {
fill(ip, b1); fill(ip, b1);
printf("%06X %s\n", ip, b1); printf("%06X %s\n", ip, b1);
ip += 16; ip += 16;
for (i = 3, c = b1[1]; i < 32 && c == b1[i]; i += 2) for (i = 3, c = b1[1]; i < 32 && c == b1[i]; i += 2)
; /* Check if all same */ ; /* Check if all same */
if (i > 32) if (i > 32)
{ {
fill(ip, b2); /* Skip until next two are not same */ fill(ip, b2); /* Skip until next two are not same */
fill(ip+16, b3); fill(ip+16, b3);
if (! (strcmp(b1, b2) || strcmp(b1, b3))) if (! (strcmp(b1, b2) || strcmp(b1, b3)))
{ {
printf(" :\n"); printf(" :\n");
do do
{ {
ip += 16; ip += 16;
fill(ip+16, b1); fill(ip+16, b1);
} while (! strcmp(b1, b2)); } while (! strcmp(b1, b2));
} }
} }
} }
printf("\n"); printf("\n");
} }
DccFrontend::DccFrontend(QObject *parent) : DccFrontend::DccFrontend(QObject *parent) :
QObject(parent) QObject(parent)
{ {
} }
/***************************************************************************** /*****************************************************************************
* FrontEnd - invokes the loader, parser, disassembler (if asm1), icode * FrontEnd - invokes the loader, parser, disassembler (if asm1), icode
* rewritter, and displays any useful information. * rewritter, and displays any useful information.
****************************************************************************/ ****************************************************************************/
bool DccFrontend::FrontEnd () bool DccFrontend::FrontEnd ()
{ {
/* Do depth first flow analysis building call graph and procedure list, /* Do depth first flow analysis building call graph and procedure list,
* and attaching the I-code to each procedure */ * and attaching the I-code to each procedure */
parse (*Project::get()); parse (*Project::get());
if (option.asm1) if (option.asm1)
{ {
qWarning() << "dcc: writing assembler file "<<asm1_name<<'\n'; qWarning() << "dcc: writing assembler file "<<asm1_name<<'\n';
} }
/* Search through code looking for impure references and flag them */ /* Search through code looking for impure references and flag them */
Disassembler ds(1); Disassembler ds(1);
for(Function &f : Project::get()->pProcList) for(Function &f : Project::get()->pProcList)
{ {
f.markImpure(); f.markImpure();
if (option.asm1) if (option.asm1)
{ {
ds.disassem(&f); ds.disassem(&f);
} }
} }
if (option.Interact) if (option.Interact)
{ {
interactDis(&Project::get()->pProcList.front(), 0); /* Interactive disassembler */ interactDis(&Project::get()->pProcList.front(), 0); /* Interactive disassembler */
} }
/* Converts jump target addresses to icode offsets */ /* Converts jump target addresses to icode offsets */
for(Function &f : Project::get()->pProcList) for(Function &f : Project::get()->pProcList)
{ {
f.bindIcodeOff(); f.bindIcodeOff();
} }
/* Print memory bitmap */ /* Print memory bitmap */
if (option.Map) if (option.Map)
displayMemMap(); displayMemMap();
return(true); // we no longer own proj ! return(true); // we no longer own proj !
} }
struct DosLoader { struct DosLoader {
protected: protected:
void prepareImage(PROG &prog,size_t sz,QFile &fp) { void prepareImage(PROG &prog,size_t sz,QFile &fp) {
/* Allocate a block of memory for the program. */ /* Allocate a block of memory for the program. */
prog.cbImage = sz + sizeof(PSP); prog.cbImage = sz + sizeof(PSP);
prog.Imagez = new uint8_t [prog.cbImage]; prog.Imagez = new uint8_t [prog.cbImage];
prog.Imagez[0] = 0xCD; /* Fill in PSP int 20h location */ prog.Imagez[0] = 0xCD; /* Fill in PSP int 20h location */
prog.Imagez[1] = 0x20; /* for termination checking */ prog.Imagez[1] = 0x20; /* for termination checking */
/* Read in the image past where a PSP would go */ /* Read in the image past where a PSP would go */
if (sz != fp.read((char *)prog.Imagez + sizeof(PSP),sz)) if (sz != fp.read((char *)prog.Imagez + sizeof(PSP),sz))
fatalError(CANNOT_READ, fp.fileName().toLocal8Bit().data()); fatalError(CANNOT_READ, fp.fileName().toLocal8Bit().data());
} }
}; };
struct ComLoader : public DosLoader { struct ComLoader : public DosLoader {
bool canLoad(QFile &fp) { bool canLoad(QFile &fp) {
fp.seek(0); fp.seek(0);
char sig[2]; char sig[2];
if(2==fp.read(sig,2)) { if(2==fp.read(sig,2)) {
return not (sig[0] == 0x4D && sig[1] == 0x5A); return not (sig[0] == 0x4D && sig[1] == 0x5A);
} }
return false; return false;
} }
bool load(PROG &prog,QFile &fp) { bool load(PROG &prog,QFile &fp) {
fp.seek(0); fp.seek(0);
/* COM file /* COM file
* In this case the load module size is just the file length * In this case the load module size is just the file length
*/ */
auto cb = fp.size(); auto cb = fp.size();
/* COM programs start off with an ORG 100H (to leave room for a PSP) /* 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 * This is also the implied start address so if we load the image
* at offset 100H addresses should all line up properly again. * at offset 100H addresses should all line up properly again.
*/ */
prog.initCS = 0; prog.initCS = 0;
prog.initIP = 0x100; prog.initIP = 0x100;
prog.initSS = 0; prog.initSS = 0;
prog.initSP = 0xFFFE; prog.initSP = 0xFFFE;
prog.cReloc = 0; prog.cReloc = 0;
prepareImage(prog,cb,fp); prepareImage(prog,cb,fp);
/* Set up memory map */ /* Set up memory map */
cb = (prog.cbImage + 3) / 4; cb = (prog.cbImage + 3) / 4;
prog.map = (uint8_t *)malloc(cb); prog.map = (uint8_t *)malloc(cb);
memset(prog.map, BM_UNKNOWN, (size_t)cb); memset(prog.map, BM_UNKNOWN, (size_t)cb);
return true; return true;
} }
}; };
struct ExeLoader : public DosLoader { struct ExeLoader : public DosLoader {
bool canLoad(QFile &fp) { bool canLoad(QFile &fp) {
if(fp.size()<sizeof(header)) if(fp.size()<sizeof(header))
return false; return false;
MZHeader tmp_header; MZHeader tmp_header;
fp.seek(0); fp.seek(0);
fp.read((char *)&tmp_header, sizeof(header)); fp.read((char *)&tmp_header, sizeof(header));
if(not (tmp_header.sigLo == 0x4D && tmp_header.sigHi == 0x5A)) if(not (tmp_header.sigLo == 0x4D && tmp_header.sigHi == 0x5A))
return false; return false;
/* This is a typical DOS kludge! */ /* This is a typical DOS kludge! */
if (LH(&header.relocTabOffset) == 0x40) if (LH(&header.relocTabOffset) == 0x40)
{ {
qDebug() << "Don't understand new EXE format"; qDebug() << "Don't understand new EXE format";
return false; return false;
} }
return true; return true;
} }
bool load(PROG &prog,QFile &fp) { bool load(PROG &prog,QFile &fp) {
/* Read rest of header */ /* Read rest of header */
fp.seek(0); fp.seek(0);
if (fp.read((char *)&header, sizeof(header)) != sizeof(header)) if (fp.read((char *)&header, sizeof(header)) != sizeof(header))
return false; return false;
/* Calculate the load module size. /* Calculate the load module size.
* This is the number of pages in the file * This is the number of pages in the file
* less the length of the header and reloc table * less the length of the header and reloc table
* less the number of bytes unused on last page * less the number of bytes unused on last page
*/ */
uint32_t cb = (uint32_t)LH(&header.numPages) * 512 - (uint32_t)LH(&header.numParaHeader) * 16; uint32_t cb = (uint32_t)LH(&header.numPages) * 512 - (uint32_t)LH(&header.numParaHeader) * 16;
if (header.lastPageSize) if (header.lastPageSize)
{ {
cb -= 512 - LH(&header.lastPageSize); cb -= 512 - LH(&header.lastPageSize);
} }
/* We quietly ignore minAlloc and maxAlloc since for our /* We quietly ignore minAlloc and maxAlloc since for our
* purposes it doesn't really matter where in real memory * purposes it doesn't really matter where in real memory
* the program would end up. EXE programs can't really rely on * the program would end up. EXE programs can't really rely on
* their load location so setting the PSP segment to 0 is fine. * their load location so setting the PSP segment to 0 is fine.
* Certainly programs that prod around in DOS or BIOS are going * Certainly programs that prod around in DOS or BIOS are going
* to have to load DS from a constant so it'll be pretty * to have to load DS from a constant so it'll be pretty
* obvious. * obvious.
*/ */
prog.initCS = (int16_t)LH(&header.initCS) + EXE_RELOCATION; prog.initCS = (int16_t)LH(&header.initCS) + EXE_RELOCATION;
prog.initIP = (int16_t)LH(&header.initIP); prog.initIP = (int16_t)LH(&header.initIP);
prog.initSS = (int16_t)LH(&header.initSS) + EXE_RELOCATION; prog.initSS = (int16_t)LH(&header.initSS) + EXE_RELOCATION;
prog.initSP = (int16_t)LH(&header.initSP); prog.initSP = (int16_t)LH(&header.initSP);
prog.cReloc = (int16_t)LH(&header.numReloc); prog.cReloc = (int16_t)LH(&header.numReloc);
/* Allocate the relocation table */ /* Allocate the relocation table */
if (prog.cReloc) if (prog.cReloc)
{ {
prog.relocTable.resize(prog.cReloc); prog.relocTable.resize(prog.cReloc);
fp.seek(LH(&header.relocTabOffset)); fp.seek(LH(&header.relocTabOffset));
/* Read in seg:offset pairs and convert to Image ptrs */ /* Read in seg:offset pairs and convert to Image ptrs */
uint8_t buf[4]; uint8_t buf[4];
for (int i = 0; i < prog.cReloc; i++) for (int i = 0; i < prog.cReloc; i++)
{ {
fp.read((char *)buf,4); fp.read((char *)buf,4);
prog.relocTable[i] = LH(buf) + (((int)LH(buf+2) + EXE_RELOCATION)<<4); prog.relocTable[i] = LH(buf) + (((int)LH(buf+2) + EXE_RELOCATION)<<4);
} }
} }
/* Seek to start of image */ /* Seek to start of image */
uint32_t start_of_image= LH(&header.numParaHeader) * 16; uint32_t start_of_image= LH(&header.numParaHeader) * 16;
fp.seek(start_of_image); fp.seek(start_of_image);
/* Allocate a block of memory for the program. */ /* Allocate a block of memory for the program. */
prepareImage(prog,cb,fp); prepareImage(prog,cb,fp);
/* Set up memory map */ /* Set up memory map */
cb = (prog.cbImage + 3) / 4; cb = (prog.cbImage + 3) / 4;
prog.map = (uint8_t *)malloc(cb); prog.map = (uint8_t *)malloc(cb);
memset(prog.map, BM_UNKNOWN, (size_t)cb); memset(prog.map, BM_UNKNOWN, (size_t)cb);
/* Relocate segment constants */ /* Relocate segment constants */
for(uint32_t v : prog.relocTable) { for(uint32_t v : prog.relocTable) {
uint8_t *p = &prog.Imagez[v]; uint8_t *p = &prog.Imagez[v];
uint16_t w = (uint16_t)LH(p) + EXE_RELOCATION; uint16_t w = (uint16_t)LH(p) + EXE_RELOCATION;
*p++ = (uint8_t)(w & 0x00FF); *p++ = (uint8_t)(w & 0x00FF);
*p = (uint8_t)((w & 0xFF00) >> 8); *p = (uint8_t)((w & 0xFF00) >> 8);
} }
return true; return true;
} }
}; };
/***************************************************************************** /*****************************************************************************
* LoadImage * LoadImage
****************************************************************************/ ****************************************************************************/
bool Project::load() bool Project::load()
{ {
// addTask(loaderSelection,PreCond(BinaryImage)) // addTask(loaderSelection,PreCond(BinaryImage))
// addTask(applyLoader,PreCond(Loader)) // addTask(applyLoader,PreCond(Loader))
const char *fname = binary_path().toLocal8Bit().data(); const char *fname = binary_path().toLocal8Bit().data();
QFile finfo(binary_path()); QFile finfo(binary_path());
/* Open the input file */ /* Open the input file */
if(!finfo.open(QFile::ReadOnly)) { if(!finfo.open(QFile::ReadOnly)) {
fatalError(CANNOT_OPEN, fname); fatalError(CANNOT_OPEN, fname);
} }
/* Read in first 2 bytes to check EXE signature */ /* Read in first 2 bytes to check EXE signature */
if (finfo.size()<=2) if (finfo.size()<=2)
{ {
fatalError(CANNOT_READ, fname); fatalError(CANNOT_READ, fname);
} }
ComLoader com_loader; ComLoader com_loader;
ExeLoader exe_loader; ExeLoader exe_loader;
if(exe_loader.canLoad(finfo)) { if(exe_loader.canLoad(finfo)) {
prog.fCOM = false; prog.fCOM = false;
return exe_loader.load(prog,finfo); return exe_loader.load(prog,finfo);
} }
if(com_loader.canLoad(finfo)) { if(com_loader.canLoad(finfo)) {
prog.fCOM = true; prog.fCOM = true;
return com_loader.load(prog,finfo); return com_loader.load(prog,finfo);
} }
return false; return false;
} }
uint32_t SynthLab; uint32_t SynthLab;
/* Parses the program, builds the call graph, and returns the list of /* Parses the program, builds the call graph, and returns the list of
* procedures found */ * procedures found */
void DccFrontend::parse(Project &proj) void DccFrontend::parse(Project &proj)
{ {
PROG &prog(proj.prog); PROG &prog(proj.prog);
STATE state; STATE state;
/* Set initial state */ /* Set initial state */
state.setState(rES, 0); /* PSP segment */ state.setState(rES, 0); /* PSP segment */
state.setState(rDS, 0); state.setState(rDS, 0);
state.setState(rCS, prog.initCS); state.setState(rCS, prog.initCS);
state.setState(rSS, prog.initSS); state.setState(rSS, prog.initSS);
state.setState(rSP, prog.initSP); state.setState(rSP, prog.initSP);
state.IP = ((uint32_t)prog.initCS << 4) + prog.initIP; state.IP = ((uint32_t)prog.initCS << 4) + prog.initIP;
SynthLab = SYNTHESIZED_MIN; SynthLab = SYNTHESIZED_MIN;
/* Check for special settings of initial state, based on idioms of the /* Check for special settings of initial state, based on idioms of the
startup code */ startup code */
state.checkStartup(); state.checkStartup();
Function *start_proc; ilFunction start_proc;
/* Make a struct for the initial procedure */ /* Make a struct for the initial procedure */
if (prog.offMain != -1) if (prog.offMain != -1)
{ {
start_proc = proj.createFunction(0,"main"); start_proc = proj.createFunction(0,"main");
start_proc->retVal.loc = REG_FRAME; start_proc->retVal.loc = REG_FRAME;
start_proc->retVal.type = TYPE_WORD_SIGN; start_proc->retVal.type = TYPE_WORD_SIGN;
start_proc->retVal.id.regi = rAX; start_proc->retVal.id.regi = rAX;
/* We know where main() is. Start the flow of control from there */ /* We know where main() is. Start the flow of control from there */
start_proc->procEntry = prog.offMain; start_proc->procEntry = prog.offMain;
/* In medium and large models, the segment of main may (will?) not be /* In medium and large models, the segment of main may (will?) not be
the same as the initial CS segment (of the startup code) */ the same as the initial CS segment (of the startup code) */
state.setState(rCS, prog.segMain); state.setState(rCS, prog.segMain);
state.IP = prog.offMain; state.IP = prog.offMain;
} }
else else
{ {
start_proc = proj.createFunction(0,"start"); start_proc = proj.createFunction(0,"start");
/* Create initial procedure at program start address */ /* Create initial procedure at program start address */
start_proc->procEntry = (uint32_t)state.IP; start_proc->procEntry = (uint32_t)state.IP;
} }
/* The state info is for the first procedure */ /* The state info is for the first procedure */
start_proc->state = state; start_proc->state = state;
/* Set up call graph initial node */ /* Set up call graph initial node */
proj.callGraph = new CALL_GRAPH; proj.callGraph = new CALL_GRAPH;
proj.callGraph->proc = start_proc; proj.callGraph->proc = start_proc;
/* This proc needs to be called to set things up for LibCheck(), which /* 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 */ checks a proc to see if it is a know C (etc) library */
SetupLibCheck(); SetupLibCheck();
//BUG: proj and g_proj are 'live' at this point ! //BUG: proj and g_proj are 'live' at this point !
/* Recursively build entire procedure list */ /* Recursively build entire procedure list */
start_proc->FollowCtrl(proj.callGraph, &state); start_proc->FollowCtrl(proj.callGraph, &state);
/* This proc needs to be called to clean things up from SetupLibCheck() */ /* This proc needs to be called to clean things up from SetupLibCheck() */
CleanupLibCheck(); CleanupLibCheck();
} }

File diff suppressed because it is too large Load Diff