/* 

RUN COFF FILE...

Author: Matthew W. Coan
Date: Fri Sep 20 14:28:09 EDT 2013

*/
#include <windows.h>
#undef N_BTMASK
#undef N_BTSHFT
#undef N_TSHIFT
#undef N_TMASK
#undef ISPTR
#undef ISFCN
#undef ISARY
#undef ISTAG
#include "coff.h"
#include "str.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <vector>
#include <map>
#include <fstream>
#include <iostream>
#include <cctype>
//#include "bfsream.h"

using namespace std;
using namespace string_tools;

#define  YESNO(x) (x?"yes":"no")

void usage(void);

typedef int (*pf_t)();

const size_t GOTO_SIZE = 12-5;
const size_t GOTO_OFF = 6-5;
char GOTO32[GOTO_SIZE]= {
//-112, -112, -112, -112, -112, 
//-112,
-71, 0, 0, 0, 0, 
-1, -31, 
};

class Symbol {
public:
   string name;
   size_t address;
   char * pointer;
   bool is_ext;
   Symbol() {
     address = 0;
     pointer = 0;
     is_ext = false;
   }
};

class Reloc {
public:
  size_t address;
  size_t index;
  Reloc() {
    address = 0;
    index = 0;
  }
};

class Section {
public:
   string name;
   char * buffer;
   size_t size;
   vector< Reloc* > reloc_vec;
   Section() {
     buffer = 0;
     size = 0;
   }
   ~Section() {
     if(buffer) {
        delete [] buffer;
     }
     for(size_t i = 0; i < reloc_vec.size(); i++) {
        delete reloc_vec[i];
     }
     reloc_vec.clear();
   }
   void add_relocation(Reloc * r) {
     reloc_vec.push_back(r);
   }
};

class ObjectCode;

class Linker {
public:
   typedef vector< ObjectCode* > obj_vector_type;
   typedef vector< Symbol* > sym_vector_type;
   typedef vector< void* > dll_vector_type;
private:
   obj_vector_type obj_vec;
   sym_vector_type sym_vec;
   dll_vector_type dll_vec;
public:
   Linker();
   ~Linker();
   int run(int argc, char ** argv);
   bool has_symbol(const string & name);
   ObjectCode * get_symbol(const string & name);
   void ext_link();
   friend class ObjectCode;
};

class ObjectCode {
public:
   typedef vector< Section* > section_vector_type;
   typedef vector< Symbol* > symbol_vector_type;
  
private:
   char * sym_tbl;
   int str_length;
   long section_seek;
   long symptr;
   long nsyms;
   fstream coffFile;
   unsigned long nrSect;
   unsigned long flags;
   Section * p_section;
   section_vector_type section_vec;
   symbol_vector_type symbol_vec;
   char * entry_point;
   char * buffer;
   char * code;
   char * data;
   char * bss;
   string file_name;
   Linker * linker;
   size_t code_size;

public:
   ObjectCode(const string & file_name, Linker * ld) {
      linker = ld;
      this->file_name = file_name;
      sym_tbl = 0;
      str_length = 0;
      section_seek = 0;
      symptr = 0;
      nsyms = 0;
      code_size = 0;
      //coffFile = 0;
      nrSect = 0;
      flags = 0;
      p_section = 0;
      entry_point = 0;
      buffer = 0;
      code = 0;
      data = 0;
      bss = 0;
   }

   ~ObjectCode() {
      if(sym_tbl) {
         delete [] sym_tbl;
      }
      size_t i;
      for(i = 0; i < section_vec.size(); i++) {
         delete section_vec[i];
      }
      section_vec.clear();
      /*
      for(i = 0; symbol_vec.size(); i++) {
        delete symbol_vec[i];
      }
      symbol_vec.clear();
      */
      //if(bss)
        //delete [] bss;
   }

   void read(char * buffer, size_t size) {
      coffFile.read(buffer,size);
      if(coffFile.eof()) {
         coffFile.clear();
      }
   }

   const char * get_symbol_name(const unsigned short t);
   const char * get_storage_class(const unsigned short t);
   const char * get_type(unsigned int code);
   void read_file_header();
   void read_strings();
   void read_symbols();
   void read_aout(FILHDR * section);
   void read_header(SCNHDR * section);
   void read_bss(SCNHDR * section);
   void read_data(SCNHDR * section);
   void read_text(SCNHDR * section);
   void read_lineno(SCNHDR * section);
   void read_sections();
   bool has_symbol(const string & str);
   char  * get_symbol(const string & str);
   void load();
   void link();
   void run();
   friend void Linker::ext_link();
};

void Linker::ext_link()
{
    Section * p_sect;
    Symbol * p_symbol;
    Reloc * p_reloc;
    char * ptr;
    ObjectCode * obj;

    for(size_t a = 0; a < obj_vec.size(); a++) {
        for(size_t i = 0; i < obj_vec[a]->section_vec.size(); i++) {
            for(size_t j = 0; j < obj_vec[a]->section_vec[i]->reloc_vec.size(); j++) {
                p_sect = obj_vec[a]->section_vec[i];
                p_reloc = p_sect->reloc_vec[j];
                p_symbol = obj_vec[a]->symbol_vec[p_reloc->index];
                if(p_symbol->name[0] != '.' && strcmp(p_symbol->name.c_str(), "_printf") != 0) {
                    obj = get_symbol(p_symbol->name);
                    if(obj) {
                        if(strcmp(obj_vec[a]->file_name.c_str(), obj->file_name.c_str()) != 0) {
                            cout << "NAME: " << obj_vec[a]->file_name.c_str() 
                                 << ":" << p_symbol->name.c_str() 
                                 << ":" << obj->file_name.c_str() << endl;
                            p_symbol->pointer = obj->get_symbol(p_symbol->name);
                        }
                    }
                }
            }
        }
    }
}

char* ObjectCode::get_symbol(const string & name)
{
  char * ptr = code;
  size_t i,j;
  for(i = 0; i < symbol_vec.size(); i++) {
    if(symbol_vec[i]->name.size() != 0) {
      if(strcmp(symbol_vec[i]->name.c_str(),name.c_str()) == 0 && symbol_vec[i]->is_ext == false) {
        cout << "FOUND: "<< symbol_vec[i]->name.c_str() << endl;
        if(symbol_vec[i]->pointer != 0) {
          ptr = code+symbol_vec[i]->address;
          break;
        }
      }
    }
  }
  return ptr;
}

bool Linker::has_symbol(const string & name)
{
    bool ret = false;
    for(size_t i = 0; i < obj_vec.size(); i++) {
        if(obj_vec[i]->has_symbol(name)) {
          ret = true;
          break;
        }
    }
    return ret;
}

bool ObjectCode::has_symbol(const string & sym)
{
    bool ret = false;
    for(size_t i = 0; i < symbol_vec.size(); i++) {
       if(strcmp(symbol_vec[i]->name.c_str(), sym.c_str()) == 0 && symbol_vec[i]->is_ext == false) {
          ret = true;
          break;
       }
    }
    return ret;
}

Linker::Linker()
{
}

Linker::~Linker()
{
    size_t i;
    for(i = 0; i < obj_vec.size(); i++) {
        delete obj_vec[i];
    }
    obj_vec.clear();
    for(i = 0; i < dll_vec.size(); i++) {
       CloseHandle(dll_vec[i]);
    }
    dll_vec.clear();
}

void ObjectCode::link() {
    Reloc * p_reloc = 0;
    Section * p_sect = 0;
    Symbol * p_symbol = 0;
    char * ptr = 0;
    size_t i,j;
    map< size_t, size_t > tbl;
    size_t n_relocate = 0;
    bool did_invert = false;
    cout << "printf=" << (size_t)printf << endl;
    cout << "GOTO_SIZE=" << GOTO_SIZE << endl;
    for(i = 0; i < section_vec.size(); i++) {
        for(j = 0; j < section_vec[i]->reloc_vec.size(); j++) {
            p_sect = section_vec[i];
            p_reloc = p_sect->reloc_vec[j];
            p_symbol = symbol_vec[p_reloc->index];
            if((p_reloc->address)?(code[p_reloc->address-1] == -24):(false)) {
                size_t index = 0xFFFFFFFF - (0xFFFFFFFF - (p_reloc->address + 4 - 1));
                if(tbl.find(index) == tbl.end()) {
                    //char * temp = new char[p_sect->size + (n_relocate * GOTO_SIZE) + GOTO_SIZE + GOTO_SIZE];
                    //memcpy(temp,code,p_sect->size + (n_relocate * GOTO_SIZE)+GOTO_SIZE+GOTO_SIZE);
                    //delete [] code;
                    //code = temp;
                    //buffer = code;
                    //(*(size_t*)(GOTO32+GOTO_OFF)) = (size_t)p_symbol->pointer;
                    //memcpy(code+(p_sect->size + (n_relocate * GOTO_SIZE)),GOTO32,GOTO_SIZE);
                    tbl[index] = p_sect->size + (n_relocate * GOTO_SIZE);
                    n_relocate++;
                    cout << index << " ---> " << tbl[index] << endl;
                }
            }
        }
        for(j = 0; j < section_vec[i]->reloc_vec.size(); j++) {
            p_sect = section_vec[i];
            cout << "SECTION_SIZE=" << p_sect->size << endl;
            p_reloc = p_sect->reloc_vec[j];
            p_symbol = symbol_vec[p_reloc->index];
            ptr = p_symbol->pointer;
            cout << p_reloc->address << " -> " << (size_t)ptr << endl;
            char * p = (char*)(code + p_reloc->address);
            if((p>code)?(*(p-1) == -24):(0)) {
                cout << "index=" << p_reloc->index << endl;
                cout << "symbol=" << p_symbol->name.c_str() << endl;
                cout << "section=" << p_sect->name.c_str() << endl;
                cout << "---" << endl;
                cout << (int)(*(p-1)) << ", ";
                for(size_t k = 0; k < 5; k++) {
                  cout << (int)p[k] << ", ";
                }
                cout << endl;
                cout << "---" << endl;
                
                char ch = p[0];
                char buffer[100];
                sprintf(buffer, "%d", ch);
                unsigned int ival = atoi(buffer);
                cout << "ival=" << ival << endl;

                size_t value = 0xFFFFFFFF - *(size_t*)p;
                cout << "value=" << value << "\n";
                
                //p_symbol = symbol_vec[ival-1];

                //if(ival < symbol_vec.size() && ival >= 0) {
                  //p_symbol = symbol_vec[ival];
                //}
                cout << "p_symbol=" << p_symbol->name.c_str() << endl;
                cout << "INVERT 1: " << (0xFFFFFFFF - ival) << endl;

                did_invert = true;

                //*(p-1) = 0xE8;
                cout << value << " ===> " << tbl[value] << endl;
                
                (*(size_t*)p) = /*tbl[value];*/tbl[value]/*p_sect->size*/ - ((p+4)-code);///*11;*/0xFFFFFFFF - ival - 2;
                
                //code[i] = 234;
                
                //(*(size_t*)p) = (size_t)code + p_sect->size;
                //(*(size_t*)p) = 0xFFFFFFFF - (size_t)p_symbol->pointer;
                //(*(size_t*)p) = 0xFFFFFFFF - (size_t)printf;
                /*p[0] = ival;
                p[1] = 0;
                p[2] = 0;
                p[3] = 0;*/
                //(*(char*)(p-1)) = 0xFF / 3;
                //(*(char*)(p-1)) = 0x9A;
                
            }
            else {
                (*(size_t*)p) += (size_t)ptr;
            }
cout << "addr: " << (*(size_t*)p) << endl;
        } 
    }

    if(false == did_invert)
    for(i = 0; i < code_size; i++) {
      if(code[i] == -24) {
         //(*(size_t*)&code[i+1]) = (size_t)printf;
         //code[i] = 234;
          char * p = &code[i+1]; 
          cout << "index=" << p_reloc->index << endl;
          cout << "symbol=" << p_symbol->name.c_str() << endl;
          cout << "section=" << p_sect->name.c_str() << endl;
          cout << "---" << endl;
          cout << (int)(*(p-1)) << ", ";
          for(size_t k = 0; k < 5; k++) {
            cout << (int)p[k] << ", ";
          }
          cout << endl;
          cout << "---" << endl;
          
          char ch = p[0];
          char buffer[100];
          sprintf(buffer, "%d", ch);
          unsigned int ival = atoi(buffer);
          cout << "ival=" << ival << endl;

          cout << "INVERT 2: " << (0xFFFFFFFF - ival) << endl;

          //if(ival < symbol_vec.size() && ival >= 0) {
            //p_symbol = symbol_vec[ival];
          //}

          cout << "p_symbol=" << p_symbol->name.c_str() << endl;
          
          size_t value = 0xFFFFFFFF - *(size_t*)p;
          cout << "value=" << value << "\n";

          cout << value << " ==> " << tbl[value] << endl;
          /*
          if(ival < symbol_vec.size()) {
              p_symbol = symbol_vec[ival];
              cout << ival << " == " << p_symbol->name.c_str() << endl;
          }
          */
          /*
          p[0] = ival;
          p[1] = 0;
          p[2] = 0;
          p[3] = 0;
          */
          //*(p-1) = 0xE8;

          (*(size_t*)p) = /*tbl[value];*//*p_sect->size*/tbl[value]-((p+4)-code);///*11;*/0xFFFFFFFF - ival - 2;
          
          //(*(char*)(p-1)) = 0xFF / 3;
          //cin.get();cin.get();
      }
    }
    cout << endl;
    
    for(i = 0; i < code_size+GOTO_SIZE+GOTO_SIZE; i++) {
       cout << (int)code[i] << ", ";
       if(i % 4 == 0)
          cout << endl;
    }
    cout << endl;

}

const char *
ObjectCode::get_symbol_name(const unsigned short t)
{
  const char * ret = "UNKNOWN";
  switch(t) {
      case DT_NON:
      ret = "NON";
      break;
     case DT_PTR:
      ret = "PTR";
      break;
      case DT_FCN:
      ret = "FCN";
      break;
      case DT_ARY:
      ret = "ARY";
      break;
      default:
      ret = "UNKNOWN";
  }
  return ret;
}

const char * 
ObjectCode::get_storage_class(const unsigned short t)
{
   const char * ret = "";
   switch(t) {
      case C_EFCN:
      ret = "EFCN";
      break;
      case C_NULL:
      ret = "NULL";
      break;
      case C_AUTO:
      ret = "AUTO";
      break;
      case C_EXT:
      ret = "EXT";
      break;
      case C_STAT:
      ret = "STAT";
      break;
      case C_REG:
      ret = "REG";
      break;
      case C_EXTDEF:
      ret = "EXTDEF";
      break;
      case C_LABEL:
      ret = "LABEL";
      break;
      case C_ULABEL:
      ret = "ULABEL";
      break;
      case C_MOS:
      ret = "MOS";
      break;
      case C_ARG:
      ret = "ARG";
      break;
      case C_STRTAG:
      ret = "STRING";
      break;
      case C_MOU:
      ret = "MOU";
      break;
      case C_UNTAG:
      ret = "UNTAG";
      break;
      case C_TPDEF:
      ret = "TPDEF";
      break;
      case C_USTATIC:
      ret = "USTATIC";
      break;
      case C_ENTAG:
      ret = "ENTAG";
      break;
      case C_MOE: 
      ret = "MOE";
      break;
      case C_REGPARM:
      ret = "REGPARM";
      break;
      case C_FIELD:
      ret = "FIELD";
      break;
      case C_AUTOARG:
      ret = "AUTOARG";
      break;
      case C_LASTENT:
      ret = "LASTENT";
      break;
      case C_BLOCK:
      ret = "BLOCK";
      break;
      case C_FCN:
      ret = "FCN";
      break;
      case C_EOS:
      ret = "EOS";
      break;
      case C_FILE:
      ret = "FILE";
      break;
      case C_LINE:
      ret = "LINE";
      break;
      case C_ALIAS:
      ret = "ALIAS";
      break;
      case C_HIDDEN:
      ret = "HIDDEN";
      break;
      default:
      ret = "UNKNWN";
      break;
   }
   return ret;
}

const char * ObjectCode::get_type(unsigned int code)
{
  const char * ret = "UNKNOWN";
  switch(code) {
      case T_NULL:
      ret = "NULL";
      break;
      case T_VOID:
      ret = "VOID";
      break;
      case T_CHAR:
      ret = "CHAR";
      break;
      case T_SHORT:
      ret = "SHORT";
      break;
      case T_INT:
      ret = "INT";
      break;
      case T_LONG:
      ret = "LONG";
      break;
      case T_FLOAT:
      ret = "FLOAT";
      break;
      case T_DOUBLE:
      ret = "DOUBLE";
      break;
      case T_STRUCT:
      ret = "STRUCT";
      break;
      case T_UNION:
      ret = "UNION";
      break;
      case T_ENUM:
      ret = "ENUM";
      break;
      case T_MOE:
      ret = "MOE";
      break;
      case T_UCHAR:
      ret = "UCHAR";
      break;
      case T_USHORT:
      ret = "USHORT";
      break;
      case T_LNGDBL:
      ret = "LNGDBL";
      break;
      case T_UINT:
      ret = "UINT";
      break;
      case T_ULONG:
      ret = "ULONG";
      break;
  }
  return ret;
}

void
ObjectCode::read_file_header()
{
  FILHDR buf;
  read((char*)&buf,FILHSZ);
  
  if(I386BADMAG(buf))
  {
    throw "Error: no coff File\n";
  }

  nrSect = buf.f_nscns;
  flags = buf.f_flags;
  symptr = buf.f_symptr;
  nsyms = buf.f_nsyms;

  cout << "\n\nFile Header:\n";
  cout << "***********************************************\n";
  cout << "Number of Sections:          " << nrSect << endl;
  cout << "Timestamp:                   " << ctime((time_t*)&buf.f_timdat) << endl;
  cout << "Number of Symtab entries:    " << buf.f_nsyms << endl;
  cout << "Size of optional Header:     " << buf.f_opthdr << endl;

  cout << "\nFlags:\n";
  cout << "-Relocations in File:        " << YESNO(flags&F_RELFLG) << endl;
  cout << "-Executeble File:            " << YESNO(flags&F_EXEC) << endl;
  cout << "-No Line Number Information: " << YESNO(flags&F_LNNO) << endl;
  cout << "-Local Symbols removed:      " << YESNO(flags&F_LSYMS) << endl;
  cout << "-32 Bit Little Endian File:  " << YESNO(flags&0x0100) << endl;

  read_aout(&buf);

  section_seek = FILHSZ + buf.f_opthdr;
}

void
ObjectCode::read_strings()
{
  int strings;

  strings = symptr+sizeof(SYMENT)*nsyms;

  coffFile.seekg(strings, ios::beg);

  read((char*)&str_length,sizeof(long));

cout << "STRING_LENGTH=" << str_length << endl;
//cin.get();cin.get();

  if(str_length) { 
    str_length -= 4;

    sym_tbl = new char [str_length];

    memset(sym_tbl, 0, str_length);

    coffFile.seekg(strings+4, ios::beg);

    read(sym_tbl, str_length);

    char * str_ptr = sym_tbl;
    do {
      cout << str_ptr << endl;
      while(*str_ptr++ != '\0') {
        ;
      }
    }
    while(str_ptr < (sym_tbl+str_length));
  }
}

void
ObjectCode::read_symbols()
{
  SYMENT sym;
  AUXENT aux;
  int i,j,k;
  int count = 1;
  int offset = 0;

  coffFile.seekg(symptr, ios::beg);
  char * temp = data;
  Symbol * p_symbol = 0;
  for(j = 0; j < nsyms;) {
      memset(&sym,0,sizeof(sym));
      read((char*)&sym,sizeof(sym)-2);
      long off  = coffFile.tellg();
      p_symbol = new Symbol();
      p_symbol->name = sym.e_name;
/*
cout << "NAME:" << p_symbol->name.c_str() << endl;
cout << "SCLASS=" << (int)sym.e_sclass << endl;
cout << "SCNUM=" << sym.e_scnum << endl;
cin.get();cin.get();
*/

      if(sym.e_scnum == 1) {
          p_symbol->pointer = bss + sym.e_value;
      }
      else if(sym.e_scnum == 3) {
          p_symbol->pointer = data + sym.e_value;
      }
      else {
          p_symbol->pointer = data;
      }
      p_symbol->address = sym.e_value;
/*
cout << "SYMBOL=" << p_symbol->name.c_str() << endl;
cout << "E_SCLASS=" << (int)sym.e_sclass << endl;
cout << "E_TYPE=" << (int)sym.e_type << endl;
cout << "E_SCNUM=" << (int)sym.e_scnum << endl;
cin.get();cin.get();
*/
      if(sym.e_scnum == 0) {
          p_symbol->is_ext = true;
      }

      if(strcmp(p_symbol->name.c_str(), "_printf") == 0) {
          p_symbol->pointer = (char*)printf;
      }

      void * ptr;

      for(size_t i = 0; i < linker->dll_vec.size(); i++) {
         if((ptr=GetProcAddress((HINSTANCE)linker->dll_vec[i], p_symbol->name.c_str())) != 0) {
            p_symbol->pointer = (char*)ptr;
            break;
         }
      }

      symbol_vec.push_back(p_symbol);

      j++;

      if(sym.e_numaux > 0) {
        for(k = 0; k < sym.e_numaux; k++) {
            memset(&aux,0,sizeof(aux));
            read((char*)&aux,sizeof(aux)-2);
            j++;
            p_symbol = new Symbol();
            symbol_vec.push_back(p_symbol);
        }
      }
   }
   data = temp;
}

void ObjectCode::read_aout(FILHDR * buf)
{
  int rc;
  GNU_AOUT gnu_aout;
  AOUTHDR aout;
  if(buf->f_opthdr>0)
  {
    if(buf->f_opthdr==sizeof(GNU_AOUT))
    {
      read((char*)&gnu_aout,sizeof(GNU_AOUT));
      cerr << "\nOptional GNU-aout Header:\n"
          << "-Entry Point: "
          << ((GNU_AOUT*)buf)->entry << "\n";
    }
    else if(buf->f_opthdr==AOUTSZ)
    {
      read((char*)&aout,AOUTSZ);
      cerr << "\nOptional aout Header:\n"
           << "-Entry Point: " << aout.entry << "\n";
    }
    else
    {
      cerr << "\nUnknown optional Header..\n";
    }
  }
}

void ObjectCode::read_header(SCNHDR * buf)
{
    int rc;
    read((char*)buf,SCNHSZ);
    flags=buf->s_flags;

    cout << "\n\nSection: " << buf->s_name << endl;
    cout << "***********************************************\n";
    cout << "Physical Adress:                 " << buf->s_paddr << "\n";
    cout << "Virtual Adress:                  " << buf->s_vaddr << "\n";
    cout << "Section Size:                    " << buf->s_size << "\n";
    cout << "Relocation entries:              " << buf->s_nreloc << "\n";
    cout << "Line number entries:             " << buf->s_nlnno << "\n";
    cout << "Relocation Data Address:         " << buf->s_relptr << "\n";

    if(buf->s_relptr) {
      coffFile.seekg(buf->s_relptr - buf->s_size, ios::beg);
    }

    cout << "\nFlags:\n";
    cout << "-contains only executable code:  " << YESNO(flags&STYP_TEXT) << endl;
    cout << "-contains only initialized data: " << YESNO(flags&STYP_DATA) << endl;
    cout << "-defines uninitialized data,\n";
    cout << " and has no data stored in the\n";
    cout << " coff file for it:" << YESNO(flags&STYP_BSS) << endl
         << endl;

    if(flags&STYP_TEXT) {
       cout << "CODE*********\n";
    }
    if(flags&STYP_DATA) {
       cout << "DATA*********\n";
    }
    if(flags&STYP_BSS) {
       cout << "BSS**********\n";
    }
}

void ObjectCode::read_bss(SCNHDR * buf)
{
    if(flags&STYP_BSS && buf->s_size != 0) {
        buffer = new char[buf->s_size];
        memset(buffer, 0, buf->s_size);
        read(buffer,buf->s_size);

        cout << "\n\nBSS Section: " << buf->s_name << endl;
        cout << "***********************************************\n";
        cout << "Physical Adress:                 " << buf->s_paddr << "\n";
        cout << "Virtual Adress:                  " << buf->s_vaddr << "\n";
        cout << "Section Size:                    " << buf->s_size << "\n";
        cout << "Relocation entries:              " << buf->s_nreloc << "\n";
        cout << "Line number entries:             " << buf->s_nlnno << "\n";
        cout << "Relocation Data Address:         " << buf->s_relptr << "\n";

        p_section->name = "bss";
        bss = p_section->buffer = new char[buf->s_size];
        memset(p_section->buffer, 0, buf->s_size);
        p_section->size = buf->s_size;
        
        //delete [] buffer;
    }
}

void ObjectCode::read_data(SCNHDR * buf)
{
    int j;
    if(flags&STYP_DATA && buf->s_size != 0) {
       buffer = new char[buf->s_size];
       data = buffer;
       memset(buffer, 0, buf->s_size);
       read(buffer,buf->s_size);
       for(j = 0; j < buf->s_size; j++) {
          if(buffer[j] != '\0') {
             cout << buffer[j];
          }
       }  
       p_section->name = "data";
       p_section->buffer = buffer;
       p_section->size = buf->s_size;
       //delete [] buffer;
    }
}

void ObjectCode::read_text(SCNHDR * buf)
{
    int j;
    RELOC * relocation;
    if(flags&STYP_TEXT && buf->s_size != 0) {
       buffer = new char[buf->s_size+GOTO_SIZE+GOTO_SIZE];
       code = buffer;
       code_size = buf->s_size;
       p_section->name = "text";
       p_section->buffer = buffer;
       p_section->size = buf->s_size;
       memset(buffer, 0, buf->s_size);
       read(buffer,buf->s_size);
       
       (*(size_t*)(GOTO32+GOTO_OFF)) = (size_t)printf;
       memcpy(buffer+p_section->size, GOTO32, GOTO_SIZE);
       (*(size_t*)(GOTO32+GOTO_OFF)) = (size_t)getchar;
       memcpy(buffer+p_section->size+GOTO_SIZE, GOTO32, GOTO_SIZE);
       
cout << "DLL_VECTOR_SIZE=" << linker->dll_vec.size() << endl;
cout << "SYMBOL_COUNT=" << symbol_vec.size() << endl;
       for(j = 1; j <= buf->s_size+GOTO_SIZE+GOTO_SIZE; j++) {
          cout << (int)buffer[j-1] << ",";
          if((j % 5) == 0) {
             cout << "\n";
          }
       }  
       cout << "\n";
       
       coffFile.seekg(buf->s_relptr, ios::beg);
       RELOC relocation;
       for(j = 0; j < buf->s_nreloc; j++) {
          read((char*)&relocation, sizeof(RELOC));
          //p_section->reloc_vec.push_back(new Reloc(relocation.r_vaddr,relocation.r_symndx));
          cout << "Relocation address: " << relocation.r_vaddr << endl;
          cout << "Symbol index: " << relocation.r_symndx << endl;
          //cout << "Pointer: " << symbol_vec[relocation.r_symndx]->name.c_str() << endl;
          cout << "Symbol type: " << get_storage_class(relocation.r_type) << endl;
          //cout << "Symbol temp1: " << relocation.temp1 << endl;
          //cout << "Symbol temp2: " << relocation.temp2 << endl;
          Reloc * p_reloc = new Reloc(); 
          p_reloc->address = relocation.r_vaddr;
          p_reloc->index = relocation.r_symndx; 
          p_section->add_relocation(p_reloc);
       }
       //delete [] buffer;
    }
}

void ObjectCode::run() {
    pf_t pf = (pf_t)code;
    cout << "pf next..." << endl;
    int rc = pf();
    cout << "result=" << rc << endl;
}

void ObjectCode::read_lineno(SCNHDR * section)
{
  if(section->s_nlnno) {
    cout << "**************LINE NO*****************" << endl;
  }
}

void ObjectCode::read_sections() 
{
  int currSect;
  SCNHDR section;

  for(currSect = 0; currSect < nrSect; currSect++) {
    coffFile.seekg(section_seek, ios::beg);

    read_header(&section);

    section_seek += sizeof(SCNHDR);

    p_section = new Section();

    section_vec.push_back(p_section);

    read_bss(&section);

    read_data(&section);

    read_text(&section);

    read_lineno(&section);

    p_section = 0;
  }
}

void ObjectCode::load()
{
      coffFile.open(file_name.c_str(), ios::in|ios::binary);
      if(coffFile.fail()) {
          throw "unable to open COFF file for reading...";
      }

      read_file_header();

      read_sections();

      read_strings();

      read_symbols();

      for(size_t i = 0; i < symbol_vec.size(); i++) {
         cout << "[" << i << "]--> "<< symbol_vec[i]->name.c_str() << endl;
      }

      coffFile.close();
}

ObjectCode * Linker::get_symbol(const string & sym)
{
   ObjectCode * obj = 0, * obj_ptr;
   for(size_t i = 0; i < obj_vec.size(); i++) {
      obj_ptr = obj_vec[i];
      if(obj_ptr->has_symbol(sym)) {
        obj = obj_ptr;
        break;
      }
   }
   return obj;
}

int Linker::run(int argc, char ** argv) {
  ObjectCode * obj_ptr = 0;
  size_t i;
  HANDLE hDLL;
  for(i = 1; i < argc; i++) {
      if(ends_with(argv[i], ".dll")) {
          hDLL = LoadLibrary(argv[i]);
          dll_vec.push_back(hDLL);
      }
      else if(ends_with(argv[i], ".obj")) {
          obj_ptr = new ObjectCode(argv[i], this);

          obj_vec.push_back(obj_ptr);

          //obj_ptr->load();
      }
      else {
        throw "bad linker file...";
      }
  }

  for(i = 0; i < obj_vec.size(); i++) {
     obj_vec[i]->load();
  }

  ext_link();

  for(i = 0; i < obj_vec.size(); i++) {
      obj_vec[i]->link();
  }

  ObjectCode * entry_ptr = 0;

  entry_ptr = get_symbol("_main");

  if(entry_ptr == 0) {
      throw "no main entry point...";
  }

  entry_ptr->run();

  return 0;
}

int main(int argc, char** argv)
{
  int rc = 0;

  if(argc < 2) {
     usage();
  }

  try {
     Linker linker;
     rc = linker.run(argc,argv);
  }
  catch(const char * message) {
     cerr << message << endl;
     rc = 1;
  }
  catch(...) {
     cerr << "exception..." << endl;
     rc = 1;   
  }

  exit(rc);

  return rc;
}

void usage()
{
  cout << "Usage: runcoff <coff-file>\n";
  exit(0);
}
