diff --git a/include/CallConvention.h b/include/CallConvention.h index 4c41633..71a828f 100644 --- a/include/CallConvention.h +++ b/include/CallConvention.h @@ -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; }; diff --git a/include/Enums.h b/include/Enums.h index d7def3a..28c0e7c 100644 --- a/include/Enums.h +++ b/include/Enums.h @@ -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 */ diff --git a/include/Procedure.h b/include/Procedure.h index af7396a..1e4347d 100644 --- a/include/Procedure.h +++ b/include/Procedure.h @@ -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 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 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 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 = new FunctionType; + 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;} diff --git a/include/icode.h b/include/icode.h index 3736371..f0c666c 100644 --- a/include/icode.h +++ b/include/icode.h @@ -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 diff --git a/include/locident.h b/include/locident.h index 8b72881..1bab516 100644 --- a/include/locident.h +++ b/include/locident.h @@ -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) */ diff --git a/include/project.h b/include/project.h index 05e11d2..4b09f8d 100644 --- a/include/project.h +++ b/include/project.h @@ -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; + DosLoader * m_selected_loader; public: - DosLoader * m_selected_loader; 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 - bool addCommand() { - return m_project_command_stream.add(new COMMANDCLASS); - } - void dumpAllErrors(); + + bool addCommand(Command *cmd) { return m_project_command_stream.add(cmd); } + void dumpAllErrors(); + void setLoader(DosLoader *ins); public slots: - void onCommandStreamFinished(bool state); + 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; diff --git a/include/types.h b/include/types.h index a9a7724..cec5bea 100644 --- a/include/types.h +++ b/include/types.h @@ -105,6 +105,8 @@ struct TypeContainer return 4; case TYPE_FLOAT: return 4; + case TYPE_PTR: + return 2; default: return ~0; } diff --git a/src/CallConvention.cpp b/src/CallConvention.cpp index 88b7d7f..5dd6d09 100644 --- a/src/CallConvention.cpp +++ b/src/CallConvention.cpp @@ -1,9 +1,89 @@ +#include "CallConvention.h" + +#include "Procedure.h" + +#include #include #include -#include "CallConvention.h" -#include +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 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 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); +} diff --git a/src/Command.cpp b/src/Command.cpp index ba7d9c0..74c25d8 100644 --- a/src/Command.cpp +++ b/src/Command.cpp @@ -1,58 +1,75 @@ #include "Command.h" +#include "dcc.h" #include "project.h" #include "Loaders.h" #include -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; } diff --git a/src/Command.h b/src/Command.h index 042166a..fe510f2 100644 --- a/src/Command.h +++ b/src/Command.h @@ -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 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 diff --git a/src/DccFrontend.cpp b/src/DccFrontend.cpp index d659d78..2c00368 100644 --- a/src/DccFrontend.cpp +++ b/src/DccFrontend.cpp @@ -5,6 +5,7 @@ #include "project.h" #include "disassem.h" #include "CallGraph.h" +#include "Command.h" #include #include @@ -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); diff --git a/src/Procedure.cpp b/src/Procedure.cpp index 62f445c..5d72ad7 100644 --- a/src/Procedure.cpp +++ b/src/Procedure.cpp @@ -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); } diff --git a/src/ast.cpp b/src/ast.cpp index 5c83a03..3d89321 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -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(); } diff --git a/src/backend.cpp b/src/backend.cpp index 5781ce5..7ba081d 100644 --- a/src/backend.cpp +++ b/src/backend.cpp @@ -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+" ("; diff --git a/src/chklib.cpp b/src/chklib.cpp index 6dd614b..a170dd9 100644 --- a/src/chklib.cpp +++ b/src/chklib.cpp @@ -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; } } diff --git a/src/comwrite.cpp b/src/comwrite.cpp index fd71cd5..764fa6f 100644 --- a/src/comwrite.cpp +++ b/src/comwrite.cpp @@ -239,21 +239,24 @@ 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: - ostr << " * Return value in register al.\n"; - break; - case TYPE_WORD_SIGN: case TYPE_WORD_UNSIGN: - ostr << " * Return value in register ax.\n"; - break; - case TYPE_LONG_SIGN: case TYPE_LONG_UNSIGN: - ostr << " * Return value in registers dx:ax.\n"; - break; - default: - fprintf(stderr,"Unknown retval type %d",this->retVal.type); - break; - } /* eos */ + 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: + ostr << " * Return value in register ax.\n"; + break; + 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",getReturnType()); + break; + } /* eos */ } /* Calling convention */ diff --git a/src/dataflow.cpp b/src/dataflow.cpp index 3931a81..c4711a9 100644 --- a/src/dataflow.cpp +++ b/src/dataflow.cpp @@ -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); } } } diff --git a/src/dcc.cpp b/src/dcc.cpp index 3554d85..270b599 100644 --- a/src/dcc.cpp +++ b/src/dcc.cpp @@ -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) diff --git a/src/graph.cpp b/src/graph.cpp index d358306..c58cdf0 100644 --- a/src/graph.cpp +++ b/src/graph.cpp @@ -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 &dfsLast, int *first, int *last); diff --git a/src/icode.cpp b/src/icode.cpp index c62d8f1..c1928ce 100644 --- a/src/icode.cpp +++ b/src/icode.cpp @@ -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; diff --git a/src/idioms.cpp b/src/idioms.cpp index f4990a3..79a3f14 100644 --- a/src/idioms.cpp +++ b/src/idioms.cpp @@ -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*/); } diff --git a/src/parser.cpp b/src/parser.cpp index bb5b41c..c1282bd 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -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); } diff --git a/src/procs.cpp b/src/procs.cpp index 9c07520..4f046ac 100644 --- a/src/procs.cpp +++ b/src/procs.cpp @@ -14,7 +14,6 @@ #include #include -extern Project g_proj; /* Static indentation buffer */ static constexpr int indSize=81; /* size of indentation buffer; max 20 */ static char indentBuf[indSize] = diff --git a/src/project.cpp b/src/project.cpp index e186569..4cbd1f2 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -9,7 +9,6 @@ #include 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()) + m_selected_loader = ldr; + emit loaderSelected(); +} +bool Project::addLoadCommands(QString fname) +{ + if(!addCommand(new LoaderSelection(fname))) return false; - if(!addCommand()) { + if(!addCommand(new LoaderApplication(fname))) { return false; } return true; diff --git a/src/udm.cpp b/src/udm.cpp index dc569e0..9bd455b 100644 --- a/src/udm.cpp +++ b/src/udm.cpp @@ -13,7 +13,6 @@ #include #include #include -extern Project g_proj; //static void displayCFG(Function * pProc); //static void displayDfs(BB * pBB);