Move Function closer to LLVM interface ( FunctionType etc. )

A few more places are using Commands.
This commit is contained in:
nemerle 2016-04-28 16:25:58 +02:00
parent 0684062130
commit 3d5a907b30
25 changed files with 416 additions and 151 deletions

View File

@ -4,30 +4,35 @@
class QTextStream;
struct CConv {
enum Type {
enum CC_Type {
UNKNOWN=0,
C,
PASCAL
};
virtual void processHLI(Function *func, Expr *_exp, iICODE picode)=0;
//! given return and argument types fill Function's STKFRAME and return locations
virtual void calculateStackLayout(Function *func)=0;
virtual void writeComments(QTextStream &)=0;
static CConv * create(Type v);
static CConv * create(CC_Type v);
protected:
};
struct C_CallingConvention : public CConv {
virtual void processHLI(Function *func, Expr *_exp, iICODE picode);
virtual void writeComments(QTextStream &);
virtual void processHLI(Function *func, Expr *_exp, iICODE picode) override;
virtual void writeComments(QTextStream &) override;
void calculateStackLayout(Function *func) override;
private:
int processCArg(Function *callee, Function *pProc, ICODE *picode, size_t numArgs);
};
struct Pascal_CallingConvention : public CConv {
virtual void processHLI(Function *func, Expr *_exp, iICODE picode);
virtual void writeComments(QTextStream &);
virtual void processHLI(Function *func, Expr *_exp, iICODE picode) override;
virtual void writeComments(QTextStream &) override;
void calculateStackLayout(Function *func) override;
};
struct Unknown_CallingConvention : public CConv {
void processHLI(Function *func, Expr *_exp, iICODE picode) {}
virtual void writeComments(QTextStream &);
void processHLI(Function *func, Expr *_exp, iICODE picode) override {}
void calculateStackLayout(Function *func) override;
virtual void writeComments(QTextStream &) override;
};

View File

@ -263,7 +263,8 @@ enum hlType
TYPE_STR, /* string */
TYPE_CONST, /* constant (any type) */
TYPE_FLOAT, /* floating point */
TYPE_DOUBLE /* double precision float */
TYPE_DOUBLE, /* double precision float */
TYPE_FUNC
};
/* Operand is defined, used or both flag */

View File

@ -63,7 +63,7 @@ enum PROC_FLAGS
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 */
//PROC_IS_FUNC=0x00800000, /* Proc is a function - determined by return type */
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 */
@ -74,10 +74,43 @@ enum PROC_FLAGS
//#define CALL_MASK 0xFFFF9FFF /* Masks off CALL_C and CALL_PASCAL */
};
struct FunctionType
struct Type {
hlType dcc_type;
};
struct FunctionType : public Type
{
CConv * m_call_conv;
std::vector<Type> ContainedTys;
ID retVal; /* Return value - identifier */
bool m_vararg=false;
unsigned getNumParams() const { return ContainedTys.size(); }
bool isVarArg() const {return m_vararg;}
void setReturnType(hlType t) {
retVal.type = t;
}
void setReturnLocation(const LONGID_TYPE &v) {
retVal.loc = REG_FRAME;
retVal.longId() = v;
}
void setReturnLocation(eReg reg) {
retVal.loc = REG_FRAME;
retVal.id.regi = reg;
}
hlType getReturnType() const { return retVal.type; }
void addArgument(hlType hl) {
ContainedTys.push_back(Type {hl});
}
void clearArguments() { ContainedTys.clear(); }
void setCallingConvention(CConv::CC_Type cc);
static FunctionType *get(Type result,std::vector<Type> params, bool vararg_func) {
FunctionType * res = new FunctionType;
res->setReturnType(result.dcc_type);
std::swap(res->ContainedTys,params);
res->m_vararg = vararg_func;
return res;
}
};
struct Assignment
{
@ -121,16 +154,17 @@ struct Function : public llvm::ilist_node<Function>
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),
Function(FunctionType *ty) : procEntry(0),depth(0),flg(0),cbParam(0),m_dfsLast(0),numBBs(0),
hasCase(false),liveAnal(0)
{
type = ty;
if(!ty) // No type was provided, create it
type = new FunctionType;
callingConv(CConv::UNKNOWN);
}
public:
FunctionType * type;
CConv * m_call_conv;
uint32_t procEntry; /* label number */
QString name; /* Meaningful name for this proc */
STATE state; /* Entry state */
@ -139,7 +173,6 @@ public:
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 */
@ -165,11 +198,14 @@ public:
r->name = nm;
return r;
}
hlType getReturnType() const {
return getFunctionType()->getReturnType();
}
FunctionType *getFunctionType() const {
return type;
}
CConv *callingConv() const { return m_call_conv;}
void callingConv(CConv::Type v);
CConv *callingConv() const { return type->m_call_conv;}
void callingConv(CConv::CC_Type v);
// bool anyFlagsSet(uint32_t t) { return (flg&t)!=0;}
bool hasRegArgs() const { return (flg & REG_ARGS)!=0;}

View File

@ -313,7 +313,7 @@ struct LLOperand
{
return not (*this == LLOperand());
}
void addProcInformation(int param_count, CConv::Type call_conv);
void addProcInformation(int param_count, CConv::CC_Type call_conv);
bool isImmediate() const { return immed;}
void setImmediate(bool x) { immed=x;}
bool compound() const {return is_compound;} // dx:ax pair

View File

@ -104,10 +104,7 @@ public:
char macro[10]; /* Macro for this identifier */
QString name; /* Identifier's name */
union ID_UNION { /* Different types of identifiers */
friend struct ID;
protected:
LONG_STKID_TYPE longStkId; /* For TYPE_LONG_(UN)SIGN on the stack */
public:
eReg regi; /* For TYPE_BYTE(WORD)_(UN)SIGN registers */
struct { /* For TYPE_BYTE(WORD)_(UN)SIGN on the stack */
uint8_t regOff; /* register offset (if any) */

View File

@ -21,7 +21,10 @@ class QString;
class SourceMachine;
struct CALL_GRAPH;
struct DosLoader;
struct SegOffAddr {
uint16_t seg;
uint32_t addr;
};
class Project : public QObject
{
Q_OBJECT
@ -30,8 +33,8 @@ public:
typedef FunctionListType lFunction;
typedef FunctionListType::iterator ilFunction;
public:
DosLoader * m_selected_loader;
public:
uint32_t SynthLab; //!< Last snthetic lab idx
SYMTAB symtab; //!< Global symbol table
FunctionListType pProcList; //!< List of located functions
@ -50,10 +53,11 @@ public:
void create(const QString &a);
bool addLoadCommands();
bool addLoadCommands(QString fname);
void processAllCommands();
void resetCommandsAndErrorState();
const QString & output_path() const {return m_output_path;}
const QString & project_name() const {return m_project_name;}
const QString & binary_path() const {return m_fname;}
@ -76,13 +80,16 @@ public:
const FunctionListType &functions() const { return pProcList; }
FunctionListType &functions() { return pProcList; }
template<class COMMANDCLASS>
bool addCommand() {
return m_project_command_stream.add(new COMMANDCLASS);
}
bool addCommand(Command *cmd) { return m_project_command_stream.add(cmd); }
void dumpAllErrors();
void setLoader(DosLoader *ins);
public slots:
void onCommandStreamFinished(bool state);
void onNewFunctionDiscovered(SegOffAddr ip,QString name,FunctionType *ft);
signals:
void newFunctionCreated(Function &);
void loaderSelected();
protected:
void initialize();
void writeGlobSymTable();
@ -95,4 +102,3 @@ protected:
CommandContext m_command_ctx;
};
//extern Project g_proj;

View File

@ -105,6 +105,8 @@ struct TypeContainer
return 4;
case TYPE_FLOAT:
return 4;
case TYPE_PTR:
return 2;
default:
return ~0;
}

View File

@ -1,9 +1,89 @@
#include "CallConvention.h"
#include "Procedure.h"
#include <QtCore/QTextStream>
#include <ostream>
#include <cassert>
#include "CallConvention.h"
#include <QtCore/QTextStream>
static void calculateReturnLocations(Function *func) {
switch(func->getReturnType()) {
case TYPE_LONG_SIGN:
case TYPE_LONG_UNSIGN:
func->getFunctionType()->setReturnLocation(LONGID_TYPE(rDX,rAX));
break;
case TYPE_WORD_SIGN:
case TYPE_WORD_UNSIGN:
func->getFunctionType()->setReturnLocation(rAX);
break;
case TYPE_BYTE_SIGN:
case TYPE_BYTE_UNSIGN:
func->getFunctionType()->setReturnLocation(rAL);
break;
}
}
static void calculateArgLocations_allOnStack(Function *func) {
FunctionType *type = func->type;
int stack_offset=2;
if(func->args.size() == type->ContainedTys.size())
return;
func->args.resize(type->ContainedTys.size());
func->args.numArgs=0;
for(Type & argtype : type->ContainedTys) {
STKSYM &arg(func->args[func->args.numArgs]);
arg.label= stack_offset;
arg.size = TypeContainer::typeSize(argtype.dcc_type);
arg.type = argtype.dcc_type;
arg.setArgName(func->args.numArgs);
stack_offset+=arg.size;
func->args.maxOff=stack_offset;
func->args.numArgs++;
}
func->cbParam = stack_offset;
}
CConv *CConv::create(Type v)
static void rebuildArguments_FromStackLayout(Function *func) {
STKFRAME &stk(func->args);
std::map<int,const STKSYM *> arg_locations;
FunctionType *f;
for(const STKSYM & s: stk) {
if(s.label>0) {
arg_locations[s.label] = &s;
}
}
if(arg_locations.empty())
return;
std::vector<Type> argtypes;
auto stack_loc_iter = arg_locations.begin();
for(int i=stack_loc_iter->first; i<=arg_locations.rbegin()->first; ) {
int till_next_loc=stack_loc_iter->first-i;
if(till_next_loc==0) {
int entry_size=stack_loc_iter->second->size;
argtypes.push_back({stack_loc_iter->second->type});
i+=entry_size;
++stack_loc_iter;
} else {
if(till_next_loc>=4) {
argtypes.push_back({TYPE_LONG_SIGN});
i+=4;
} else if(till_next_loc>=2) {
argtypes.push_back({TYPE_WORD_SIGN});
i+=2;
} else {
argtypes.push_back({TYPE_BYTE_SIGN});
i+=1;
}
}
}
f = FunctionType::get({func->type->getReturnType()},argtypes,func->type->isVarArg());
f->retVal = func->type->retVal;
delete func->type;
func->type = f;
}
CConv *CConv::create(CC_Type v)
{
static C_CallingConvention *c_call = nullptr;
static Pascal_CallingConvention *p_call = nullptr;
@ -27,11 +107,31 @@ void C_CallingConvention::writeComments(QTextStream & ostr)
{
ostr << " * C calling convention.\n";
}
void C_CallingConvention::calculateStackLayout(Function *func)
{
calculateReturnLocations(func);
rebuildArguments_FromStackLayout(func);
calculateArgLocations_allOnStack(func);
}
void Pascal_CallingConvention::writeComments(QTextStream & ostr)
{
ostr << " * Pascal calling convention.\n";
}
void Pascal_CallingConvention::calculateStackLayout(Function *func)
{
calculateReturnLocations(func);
//TODO: pascal args are passed in reverse order ?
rebuildArguments_FromStackLayout(func);
calculateArgLocations_allOnStack(func);
}
void Unknown_CallingConvention::writeComments(QTextStream & ostr)
{
ostr << " * Unknown calling convention.\n";
}
void Unknown_CallingConvention::calculateStackLayout(Function *func)
{
calculateReturnLocations(func);
rebuildArguments_FromStackLayout(func);
calculateArgLocations_allOnStack(func);
}

View File

@ -1,58 +1,75 @@
#include "Command.h"
#include "dcc.h"
#include "project.h"
#include "Loaders.h"
#include <QFile>
bool LoaderSelection::execute(CommandContext * ctx, Project *p)
bool LoaderSelection::execute(CommandContext * ctx)
{
if(p->binary_path().isEmpty()) {
ctx->recordFailure(this,QString("No executable path set in project %1").arg(p->project_name()));
Project *proj=ctx->proj;
if(nullptr==proj) {
ctx->recordFailure(this,"No active project ");
return false;
}
if(m_filename.isEmpty()) {
ctx->recordFailure(this,"No executable path given to loader selector");
return false;
}
QFile finfo(p->binary_path());
QFile finfo(m_filename);
/* Open the input file */
if(not finfo.open(QFile::ReadOnly)) {
ctx->recordFailure(this,QString("Cannot open file %1").arg(p->binary_path()));
ctx->recordFailure(this,QString("Cannot open file %1").arg(m_filename));
return false;
}
/* Read in first 2 bytes to check EXE signature */
if (finfo.size()<=2)
{
ctx->recordFailure(this,QString("File %1 is too small").arg(p->binary_path()));
ctx->recordFailure(this,QString("File %1 is too small").arg(m_filename));
}
ComLoader com_loader;
ExeLoader exe_loader;
if(exe_loader.canLoad(finfo)) {
p->m_selected_loader = new ExeLoader;
proj->setLoader(new ExeLoader);
return true;
}
if(com_loader.canLoad(finfo)) {
p->m_selected_loader = new ComLoader;
proj->setLoader(new ExeLoader);
return true;
}
ctx->recordFailure(this,QString("None of the available loaders can load file %1").arg(p->binary_path()));
ctx->recordFailure(this,QString("None of the available loaders can load file %1").arg(m_filename));
return true;
}
bool LoaderApplication::execute(CommandContext * ctx, Project *p)
bool LoaderApplication::execute(CommandContext * ctx)
{
if(!p)
return false;
if(!p->m_selected_loader) {
ctx->recordFailure(this,QString("No loader selected for project %1").arg(p->project_name()));
Project *proj=ctx->proj;
if(nullptr==proj) {
ctx->recordFailure(this,"No active project ");
return false;
}
QFile finfo(p->binary_path());
if(!proj->m_selected_loader) {
ctx->recordFailure(this,QString("No loader selected for project %1").arg(proj->project_name()));
return false;
}
QFile finfo(m_filename);
if(not finfo.open(QFile::ReadOnly)) {
ctx->recordFailure(this,QString("Cannot open file %1").arg(p->binary_path()));
ctx->recordFailure(this,QString("Cannot open file %1").arg(m_filename));
return false;
}
return p->m_selected_loader->load(p->prog,finfo);
bool load_res = proj->m_selected_loader->load(proj->prog,finfo);
if(!load_res) {
ctx->recordFailure(this,QString("Failure during load: %1").arg(m_filename));
return false;
}
if (option.verbose)
proj->prog.displayLoadInfo();
return true;
}
bool CommandStream::add(Command * c) {
@ -70,7 +87,7 @@ void CommandStream::processAll(CommandContext *ctx)
{
while(not m_commands.isEmpty()) {
Command *cmd = m_commands.takeFirst();
if(false==cmd->execute(ctx,ctx->proj)) {
if(false==cmd->execute(ctx)) {
emit streamCompleted(false);
break;
}

View File

@ -33,7 +33,7 @@ class Command
public:
Command(QString n,CommandLevel level) : m_command_name(n),m_level(level) {}
QString name() const { return m_command_name;}
virtual bool execute(CommandContext *,Project *) { return false; }
virtual bool execute(CommandContext *) { return false; }
};
class CompoundCommand : public Command {
QVector<Command *> m_contained;
@ -43,9 +43,9 @@ public:
void addCommand(Command *c) {
m_contained.push_back(c);
}
bool execute(CommandContext * ctx,Project *v) {
bool execute(CommandContext * ctx) {
for(Command * c : m_contained) {
if(!c->execute(ctx,v))
if(!c->execute(ctx))
return false;
}
return true;
@ -65,17 +65,21 @@ public:
signals:
void streamCompleted(bool success);
};
// Effect: loader has been selected and set in current project
class LoaderSelection : public Command {
QString m_filename;
public:
virtual ~LoaderSelection() {}
LoaderSelection() : Command("Select loader",eProject) {}
bool execute(CommandContext * ctx,Project *) override;
LoaderSelection(QString f) : Command("Select loader",eProject),m_filename(f) {}
bool execute(CommandContext * ctx) override;
};
// trigger Project->m_selected_loader has changed
// Effect: the PROG object is loaded using the current loader
class LoaderApplication : public Command {
QString m_filename;
public:
virtual ~LoaderApplication() {}
LoaderApplication() : Command("Apply loader",eProject) {}
bool execute(CommandContext * ctx,Project *) override;
LoaderApplication(QString f) : Command("Apply loader",eProject),m_filename(f) {}
bool execute(CommandContext * ctx) override;
};
#endif // COMMAND_H

View File

@ -5,6 +5,7 @@
#include "project.h"
#include "disassem.h"
#include "CallGraph.h"
#include "Command.h"
#include <QtCore/QFileInfo>
#include <QtCore/QDebug>
@ -320,6 +321,71 @@ struct ExeLoader : public DosLoader {
/*****************************************************************************
* LoadImage
****************************************************************************/
struct MachineStateInitialization : public Command {
public:
MachineStateInitialization() : Command("Initialize simulated machine state",eProject) {}
bool execute(CommandContext *ctx) override
{
assert(ctx && ctx->proj);
Project &proj(*ctx->proj);
const PROG &prog(proj.prog);
proj.m_entry_state.setState(rES, 0); /* PSP segment */
proj.m_entry_state.setState(rDS, 0);
proj.m_entry_state.setState(rCS, prog.initCS);
proj.m_entry_state.setState(rSS, prog.initSS);
proj.m_entry_state.setState(rSP, prog.initSP);
proj.m_entry_state.IP = ((uint32_t)prog.initCS << 4) + prog.initIP;
proj.SynthLab = SYNTHESIZED_MIN;
return true;
}
};
struct FindMain : public Command {
FindMain() : Command("Locate the main entry point",eProject) {
}
bool execute(CommandContext *ctx) {
Project &proj(*ctx->proj);
const PROG &prog(proj.prog);
if(ctx->proj->m_entry_state.IP==0) {
ctx->recordFailure(this,"Cannot search for main func when no entry point was found");
return false;
}
/* Check for special settings of initial state, based on idioms of the startup code */
ctx->proj->m_entry_state.checkStartup();
if (prog.offMain != -1)
{
FunctionType *main_type = FunctionType::get(Type{TYPE_WORD_SIGN},{ Type{TYPE_WORD_SIGN},Type{TYPE_PTR} },false);
main_type->setCallingConvention(CConv::C);
proj.onNewFunctionDiscovered( SegOffAddr {prog.segMain,prog.offMain},"main",main_type);
//TODO: main arguments and return values should depend on detected compiler/library
}
else
{
FunctionType *main_type = FunctionType::get(Type{TYPE_UNKNOWN},{ Type{TYPE_UNKNOWN} },false);
main_type->setCallingConvention(CConv::UNKNOWN);
/* Create initial procedure at program start address */
proj.onNewFunctionDiscovered( SegOffAddr {prog.segMain,proj.m_entry_state.IP},"start",main_type);
}
return true;
}
};
struct AddFunction : public Command {
QString m_name;
uint16_t m_seg;
uint32_t m_addr;
FunctionType *m_type;
AddFunction(QString name,uint16_t seg,uint32_t address,FunctionType *f) : Command("Create function",eProject),
m_name(name),
m_seg(seg),
m_addr(address)
{}
bool execute(CommandContext *ctx) override {
}
};
void DccFrontend::initializeMachineState(Project &proj)
{
const PROG &prog(proj.prog);
@ -339,10 +405,11 @@ void DccFrontend::createEntryProc(Project &proj)
/* 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;
//TODO: main arguments and return values should depend on detected compiler/library
FunctionType *main_type = FunctionType::get(Type{TYPE_WORD_SIGN},{ Type{TYPE_WORD_SIGN},Type{TYPE_PTR} },false);
start_proc = proj.createFunction(main_type,"main");
start_proc->callingConv(CConv::C);
/* 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
@ -369,18 +436,14 @@ void DccFrontend::createEntryProc(Project &proj)
void DccFrontend::parse(Project &proj)
{
/* Set initial state */
initializeMachineState(proj);
/* Check for special settings of initial state, based on idioms of the
startup code */
proj.m_entry_state.checkStartup();
proj.addCommand(new MachineStateInitialization);
proj.addCommand(new FindMain);
createEntryProc(proj);
/* 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 */
proj.prog.bSigs = SetupLibCheck();
//BUG: proj and g_proj are 'live' at this point !
/* Recursively build entire procedure list */
proj.callGraph->proc->FollowCtrl(proj.callGraph, &proj.m_entry_state);

View File

@ -35,6 +35,13 @@ void JumpTable::pruneEntries(uint16_t cs)
}
void Function::callingConv(CConv::Type v) {
m_call_conv=CConv::create(v);
void Function::callingConv(CConv::CC_Type v) {
type->setCallingConvention(v);
getFunctionType()->m_call_conv->calculateStackLayout(this);
}
void FunctionType::setCallingConvention(CConv::CC_Type cc)
{
m_call_conv=CConv::create(cc);
assert(m_call_conv);
}

View File

@ -897,10 +897,10 @@ QString FuncNode::walkCondExpr(Function *pProc, int *numLoc) const
int FuncNode::hlTypeSize(Function *) const
{
return hlSize[call.proc->retVal.type];
return hlSize[call.proc->getReturnType()];
}
hlType FuncNode::expType(Function *) const
{
return call.proc->retVal.type;
return call.proc->getReturnType();
}

View File

@ -226,8 +226,8 @@ void Function::codeGen (QIODevice &fs)
/* Write procedure/function header */
cCode.init();
if (flg & PROC_IS_FUNC) /* Function */
ostr << QString("\n%1 %2 (").arg(TypeContainer::typeName(retVal.type)).arg(name);
if (getReturnType() != TYPE_UNKNOWN) /* Function flg & PROC_IS_FUNC*/
ostr << QString("\n%1 %2 (").arg(TypeContainer::typeName(getReturnType())).arg(name);
else /* Procedure */
ostr << "\nvoid "+name+" (";

View File

@ -480,27 +480,32 @@ bool LibCheck(Function & pProc)
pProc.callingConv(CConv::C);
if (i != NIL)
{
PH_FUNC_STRUCT &phfunc(pFunc[i]);
/* Allocate space for the arg struct, and copy the hlType to
the appropriate field */
arg = pFunc[i].firstArg;
pProc.args.numArgs = pFunc[i].numArg;
pProc.args.resize(pFunc[i].numArg);
for (j=0; j < pFunc[i].numArg; j++)
arg = phfunc.firstArg;
pProc.args.numArgs = phfunc.numArg;
pProc.args.resize(phfunc.numArg);
pProc.getFunctionType()->clearArguments();
for (j=0; j < phfunc.numArg; j++)
{
pProc.getFunctionType()->addArgument(pArg[arg]);
pProc.args[j].type = pArg[arg++];
}
if (pFunc[i].typ != TYPE_UNKNOWN)
if (phfunc.typ != TYPE_UNKNOWN)
{
pProc.retVal.type = pFunc[i].typ;
pProc.flg |= PROC_IS_FUNC;
switch (pProc.retVal.type) {
case TYPE_LONG_SIGN: case TYPE_LONG_UNSIGN:
pProc.type->setReturnType(phfunc.typ);
switch (pProc.getReturnType()) {
case TYPE_LONG_SIGN:
case TYPE_LONG_UNSIGN:
pProc.liveOut.setReg(rDX).addReg(rAX);
break;
case TYPE_WORD_SIGN: case TYPE_WORD_UNSIGN:
case TYPE_WORD_SIGN:
case TYPE_WORD_UNSIGN:
pProc.liveOut.setReg(rAX);
break;
case TYPE_BYTE_SIGN: case TYPE_BYTE_UNSIGN:
case TYPE_BYTE_SIGN:
case TYPE_BYTE_UNSIGN:
pProc.liveOut.setReg(rAL);
break;
case TYPE_STR:
@ -510,10 +515,11 @@ bool LibCheck(Function & pProc)
break;
default:
qCritical() << QString("Unknown retval type %1 for %2 in LibCheck")
.arg(pProc.retVal.type).arg(pProc.name);
.arg(pProc.getReturnType()).arg(pProc.name);
/*** other types are not considered yet ***/
}
}
pProc.getFunctionType()->m_call_conv->calculateStackLayout(&pProc);
pProc.getFunctionType()->m_vararg = pFunc[i].bVararg;
}
}

View File

@ -239,9 +239,9 @@ void Function::writeProcComments(QTextStream &ostr)
if (this->flg & PROC_ASM)
{
ostr << " * Untranslatable routine. Assembler provided.\n";
if (this->flg & PROC_IS_FUNC)
switch (this->retVal.type) { // TODO: Functions return value in various regs
case TYPE_BYTE_SIGN: case TYPE_BYTE_UNSIGN:
switch (getReturnType()) { // TODO: Functions return value in various regs
case TYPE_BYTE_SIGN:
case TYPE_BYTE_UNSIGN:
ostr << " * Return value in register al.\n";
break;
case TYPE_WORD_SIGN: case TYPE_WORD_UNSIGN:
@ -250,8 +250,11 @@ void Function::writeProcComments(QTextStream &ostr)
case TYPE_LONG_SIGN: case TYPE_LONG_UNSIGN:
ostr << " * Return value in registers dx:ax.\n";
break;
case TYPE_UNKNOWN:
// void return type
break;
default:
fprintf(stderr,"Unknown retval type %d",this->retVal.type);
fprintf(stderr,"Unknown retval type %d",getReturnType());
break;
} /* eos */
}

View File

@ -321,12 +321,12 @@ void Function::liveRegAnalysis (LivenessSet &in_liveOut)
pbb->liveOut = in_liveOut;
/* Get return expression of function */
if (flg & PROC_IS_FUNC)
if (getReturnType()!=TYPE_UNKNOWN)
{
auto picode = pbb->rbegin(); /* icode of function return */
if (picode->hl()->opcode == HLI_RET)
{
picode->hlU()->expr(AstIdent::idID(&retVal, &localId, (++pbb->rbegin()).base()));
picode->hlU()->expr(AstIdent::idID(&type->retVal, &localId, (++pbb->rbegin()).base()));
picode->du.use = in_liveOut;
}
}
@ -353,7 +353,7 @@ void Function::liveRegAnalysis (LivenessSet &in_liveOut)
}
else /* library routine */
{
if ( (pcallee->flg & PROC_IS_FUNC) and /* returns a value */
if ( (pcallee->getReturnType()!=TYPE_UNKNOWN) and /* returns a value */
(pcallee->liveOut & pbb->edges[0].BBptr->liveIn).any()
)
pbb->liveOut = pcallee->liveOut;
@ -363,7 +363,7 @@ void Function::liveRegAnalysis (LivenessSet &in_liveOut)
if ((not (pcallee->flg & PROC_ISLIB)) or ( pbb->liveOut.any() ))
{
switch (pcallee->retVal.type) {
switch (pcallee->getReturnType()) {
case TYPE_LONG_SIGN:
case TYPE_LONG_UNSIGN:
ticode.du1.setDef(rAX).addDef(rDX);
@ -461,7 +461,7 @@ bool BB::FindUseBeforeDef(eReg regi, int defRegIdx, iICODE start_at)
* on optimized code. */
void BB::ProcessUseDefForFunc(eReg regi, int defRegIdx, ICODE &picode)
{
if (not ((picode.hl()->opcode == HLI_CALL) and (picode.hl()->call.proc->flg & PROC_IS_FUNC)))
if (not ((picode.hl()->opcode == HLI_CALL) and (picode.hl()->call.proc->getReturnType()!=TYPE_UNKNOWN)))
return;
BB *tbb = this->edges[0].BBptr;
@ -971,7 +971,7 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
case HLI_CALL:
ticode = picode->du1.idx[0].uses.front();
ti_hl = ticode->hlU();
_retVal = &_icHl.call.proc->retVal;
_retVal = &_icHl.call.proc->type->retVal;
switch (ti_hl->opcode)
{
case HLI_ASSIGN:
@ -1095,7 +1095,7 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
case HLI_JCOND:
_exp = _icHl.call.toAst();
_retVal = &picode->hl()->call.proc->retVal;
_retVal = &picode->hl()->call.proc->type->retVal;
res = Expr::insertSubTreeLongReg (_exp,
ticode->hlU()->exp.v,
locals.newLongReg ( _retVal->type, _retVal->longId(), picode.base()));
@ -1146,7 +1146,7 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
if ( not _icHl.call.proc->isLibrary() and (not picode->du1.used(0)) and (picode->du1.getNumRegsDef() > 0))
{
_exp = new FuncNode(_icHl.call.proc, _icHl.call.args);
auto lhs = AstIdent::idID (&_icHl.call.proc->retVal, &locals, picode.base());
auto lhs = AstIdent::idID (&_icHl.call.proc->type->retVal, &locals, picode.base());
picode->setAsgn(lhs, _exp);
}
}
@ -1183,7 +1183,6 @@ void Function::preprocessReturnDU(LivenessSet &_liveOut)
if(not _liveOut.any())
return;
}
flg |= PROC_IS_FUNC;
isAx = _liveOut.testReg(rAX);
isBx = _liveOut.testReg(rBX);
isCx = _liveOut.testReg(rCX);
@ -1219,53 +1218,55 @@ void Function::preprocessReturnDU(LivenessSet &_liveOut)
if (isAx and isDx) /* long or pointer */
{
retVal.type = TYPE_LONG_SIGN;
retVal.loc = REG_FRAME;
retVal.longId() = LONGID_TYPE(rDX,rAX);
type->setReturnType(TYPE_LONG_SIGN);
type->m_call_conv->calculateStackLayout(this);
/*idx = */localId.newLongReg(TYPE_LONG_SIGN, LONGID_TYPE(rDX,rAX), Icode.begin());
localId.propLongId (rAX, rDX, "");
}
else if (isAx or isBx or isCx or isDx) /* uint16_t */
{
retVal.type = TYPE_WORD_SIGN;
retVal.loc = REG_FRAME;
eReg selected_reg;
if (isAx)
retVal.id.regi = rAX;
selected_reg = rAX;
else if (isBx)
retVal.id.regi = rBX;
selected_reg = rBX;
else if (isCx)
retVal.id.regi = rCX;
selected_reg = rCX;
else
retVal.id.regi = rDX;
/*idx = */localId.newByteWordReg(TYPE_WORD_SIGN,retVal.id.regi);
selected_reg = rDX;
type->setReturnType(TYPE_WORD_SIGN);
type->m_call_conv->calculateStackLayout(this);
/*idx = */localId.newByteWordReg(TYPE_WORD_SIGN,selected_reg);
}
else if(isAL or isBL or isCL or isDL)
{
retVal.type = TYPE_BYTE_SIGN;
retVal.loc = REG_FRAME;
eReg selected_reg;
if (isAL)
retVal.id.regi = rAL;
selected_reg = rAL;
else if (isBL)
retVal.id.regi = rBL;
selected_reg = rBL;
else if (isCL)
retVal.id.regi = rCL;
selected_reg = rCL;
else
retVal.id.regi = rDL;
/*idx = */localId.newByteWordReg(TYPE_BYTE_SIGN,retVal.id.regi);
selected_reg = rDL;
type->setReturnType(TYPE_BYTE_SIGN);
type->m_call_conv->calculateStackLayout(this);
/*idx = */localId.newByteWordReg(TYPE_BYTE_SIGN,selected_reg);
}
else if(isAH or isBH or isCH or isDH)
{
retVal.type = TYPE_BYTE_SIGN;
retVal.loc = REG_FRAME;
eReg selected_reg;
if (isAH)
retVal.id.regi = rAH;
selected_reg = rAH;
else if (isBH)
retVal.id.regi = rBH;
selected_reg = rBH;
else if (isCH)
retVal.id.regi = rCH;
selected_reg = rCH;
else
retVal.id.regi = rDH;
/*idx = */localId.newByteWordReg(TYPE_BYTE_SIGN,retVal.id.regi);
selected_reg = rDH;
type->setReturnType(TYPE_BYTE_SIGN);
type->m_call_conv->calculateStackLayout(this);
/*idx = */localId.newByteWordReg(TYPE_BYTE_SIGN,selected_reg);
}
}
}

View File

@ -193,7 +193,7 @@ int main(int argc, char **argv)
proj->create(option.filename);
DccFrontend fe(&app);
proj->addLoadCommands();
proj->addLoadCommands(option.filename);
proj->processAllCommands();
if(proj->m_error_state) {
proj->dumpAllErrors();
@ -201,6 +201,7 @@ int main(int argc, char **argv)
}
if (option.verbose)
proj->prog.displayLoadInfo();
if(false==fe.FrontEnd ())
return -1;
if(option.asm1)

View File

@ -16,7 +16,6 @@
using namespace std;
using namespace boost;
extern Project g_proj;
//static BB * rmJMP(Function * pProc, int marker, BB * pBB);
//static void mergeFallThrough(Function * pProc, BB * pBB);
//static void dfsNumbering(BB * pBB, std::vector<BB*> &dfsLast, int *first, int *last);

View File

@ -89,7 +89,7 @@ bool LLOperand::isReg() const
{
return (regi>=rAX) and (regi<=rTMP);
}
void LLOperand::addProcInformation(int param_count, CConv::Type call_conv)
void LLOperand::addProcInformation(int param_count, CConv::CC_Type call_conv)
{
proc.proc->cbParam = (int16_t)param_count;
proc.cb = param_count;

View File

@ -124,11 +124,10 @@ void Function::findIdioms()
/* Check for library functions that return a long register.
* Propagate this result */
if (pIcode->ll()->src().proc.proc != nullptr)
if ((pIcode->ll()->src().proc.proc->flg & PROC_ISLIB) and
(pIcode->ll()->src().proc.proc->flg & PROC_IS_FUNC))
if ( pIcode->ll()->src().proc.proc->flg & PROC_ISLIB )
{
if ((pIcode->ll()->src().proc.proc->retVal.type==TYPE_LONG_SIGN)
or (pIcode->ll()->src().proc.proc->retVal.type == TYPE_LONG_UNSIGN))
if ((pIcode->ll()->src().proc.proc->getReturnType()==TYPE_LONG_SIGN)
or (pIcode->ll()->src().proc.proc->getReturnType() == TYPE_LONG_UNSIGN))
localId.newLongReg(TYPE_LONG_SIGN, LONGID_TYPE(rDX,rAX), pIcode/*ip*/);
}

View File

@ -1032,8 +1032,9 @@ static void use (opLoc d, ICODE & pIcode, Function * pProc, STATE * pstate, int
{
if (pm->regi == INDEX_BP) /* indexed on bp */
{
if (pm->off >= 2)
if (pm->off >= 2) {
pProc->args.updateFrameOff ( pm->off, size, eDuVal::USE);
}
else if (pm->off < 0)
pProc->localId.newByteWordStk (TYPE_WORD_SIGN, pm->off, 0);
}

View File

@ -14,7 +14,6 @@
#include <cstring>
#include <cassert>
extern Project g_proj;
/* Static indentation buffer */
static constexpr int indSize=81; /* size of indentation buffer; max 20 */
static char indentBuf[indSize] =

View File

@ -9,7 +9,6 @@
#include <utility>
using namespace std;
//Project g_proj;
QString asm1_name, asm2_name; /* Assembler output filenames */
SYMTAB symtab; /* Global symbol table */
STATS stats; /* cfg statistics */
@ -59,11 +58,25 @@ ilFunction Project::findByEntry(uint32_t entry)
[entry](const Function &f) { return f.procEntry==entry; });
return iter;
}
void Project::onNewFunctionDiscovered(SegOffAddr ip, QString name, FunctionType *ft) {
FIXME;
auto proc = createFunction(ft,name);
// FIXME: use provided segment addr !
proc->procEntry = ip.addr;
if(name=="main") {
/* In medium and large models, the segment of main may (will?) not be
the same as the initial CS segment (of the startup code) */
m_entry_state.setState(rCS, prog.segMain);
m_entry_state.IP = prog.offMain;
}
}
ilFunction Project::createFunction(FunctionType *f,const QString &name)
{
pProcList.push_back(Function::Create(f,0,name,0));
return (++pProcList.rbegin()).base();
ilFunction iter = (++pProcList.rbegin()).base();
emit newFunctionCreated(*iter);
return iter;
}
int Project::getSymIdxByAdd(uint32_t adr)
@ -123,11 +136,17 @@ void Project::dumpAllErrors() {
qDebug() << QString("%1 command failed with : %2").arg(v.first->name()).arg(v.second);
}
}
bool Project::addLoadCommands()
void Project::setLoader(DosLoader * ldr)
{
if(!addCommand<LoaderSelection>())
m_selected_loader = ldr;
emit loaderSelected();
}
bool Project::addLoadCommands(QString fname)
{
if(!addCommand(new LoaderSelection(fname)))
return false;
if(!addCommand<LoaderApplication>()) {
if(!addCommand(new LoaderApplication(fname))) {
return false;
}
return true;

View File

@ -13,7 +13,6 @@
#include <cassert>
#include <stdio.h>
#include <CallGraph.h>
extern Project g_proj;
//static void displayCFG(Function * pProc);
//static void displayDfs(BB * pBB);