⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mangle.cpp

📁 UC Library Extensions UnderC comes with a pocket implementation of the standard C++ libraries, wh
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* mangle.cpp
 * Mangling C++ external symbols
 * UnderC C++ interpreter
 * Steve Donovan, 2001
 * This is GPL'd software, and the usual disclaimers apply.
 * See LICENCE
 *
 * 2nd version, January 2002
 * Exports the Mangle namespace
 * The symbol manglers are all classes derived from Mangler, which
 * supplies basic common policy, and scheme-specific methods which are
 * overriden by MSMangler, GCC2Mangler, etc. (The 'template pattern')
 **/
 
#include "common.h"
#include "std_utils.h"
#include "mangle.h"
#include <stdio.h>

template <class T>
int find_index(const std::list<T>& ls, T t)
{
  int i;
  typename std::list<T>::const_iterator li = ls.begin();
  for(i = 0; li != ls.end(); li++) {
     if (t == *li) return i;
     i++;
  }
  return -1;
}

// *fix 1.2.0L Change in the encoding of GCC dtors from 2.95 to 2.96
// (this assumes that the GCC 2 compiler under Win32 is MinGW 1)
#ifndef _WIN32
#if __GNUC__ == 2 && _GNUC_MINOR__ == 95
#define GCC_DTOR "_$_"
#else
#define GCC_DTOR "_._"
#endif
#else
#define GCC_DTOR "_$_"
#endif

const int MAX_SIG_LEN = 25, BUFF_SIZE = 256;

//namespace {
 struct OpNames { char* cname; char* mname; }; 
 char *i2a(int i);  // at the end of this file...
 char *i2ax(int i);
 char *lookup_opname(OpNames *popn, const char *n);

 static char buff[BUFF_SIZE];
 std::list<Class *> mClassList;
 std::list<Type> mArgTypes;
//}

class OutputBuffer {
protected:
private:
  char *m_p;
  char *m_buff;
  char *m_mark_p;
public:
  OutputBuffer()
  {
   m_buff = buff;
   reset();
  }
 
  void reset()
  {
    m_p = m_buff;
    mClassList.clear();
    mArgTypes.clear();
  }

  void end()
  { 
    *m_p = 0;
  }

  void set_mark()
  {
      m_mark_p = m_p;
  }

  void restore_mark()
  {
      m_p = m_mark_p;
  }

  char read_mark(int i)
  {
      return m_mark_p[i];
  }

  void outs(const char *p)
  {
      strcpy(m_p,p);
      m_p += strlen(p);
  }

  void out(char ch)
  {
      *m_p++ = ch;
  }

  void outi(int i)
  {
    outs(i2a(i));
  }

  void outx(int i)
  { 
    outs(i2ax(i));
  }

  char *ptr()
  {
    return m_buff;
  }

};
	
class Mangler: public OutputBuffer {
protected:
  char *m_begin_name;
  char *m_rpt_type;
  char *m_void_args;  
  char *m_end_stdarg; 
  char *m_end_args;
  char *m_plain_function;
  char *m_function_ptr;
  char *m_method_ptr;
  char *m_enum;
  char *m_end_function_ptr;
  bool m_use_return_type;
  char *m_plain_obj;
  char *m_const_attrib;
  char *m_plain_attrib;
  char  m_ref_chr;
  char  m_array_char;
  char  m_ptr_char;
  bool m_method_type_first;
  bool m_convention_first;
  char *m_namespace;
  char *m_collect_repeats;
  char *m_template_name;
  char *m_template_args;
  char *m_end_class;
  char *m_method_ptr_type;
  Function *m_fn;
  bool  m_dont_lookup_class;
  bool m_within_signature;
  bool m_discard_sig_types;
public:

  virtual void out_method_type(int) {}
  virtual char type_encode(Type t) { return 0; }
  virtual bool simple_type(Type t) { return false; }
  virtual void do_calling_convention() {}
  virtual void out_simple_classname(const string& name) {}
  virtual void out_fun_name(string fun_name) {};

  Mangler()
  :  m_dont_lookup_class(false) { }
  
  virtual void out_class_ref(Type t)
  {
   out_ref_ptr(t);
   out_classname(t.as_class());
  }

  void out_classname(Class *pc) 
  {
    string name=pc->name();
    if (pc->get_template()) {
	   outs(m_template_name);
	   name = pc->get_template()->name();
    }
    out_simple_classname(name);
    if (pc->get_template()) {
          TypeList& tl = pc->get_template()->type_parms();
	  Type t = tl.front();
	  outs(m_template_args);
	  // *fix 1.1.2 Always put out template type parms in full....
	  m_dont_lookup_class = true;
          out_type(t);
	  m_dont_lookup_class = false;
     }
     if (m_namespace && pc->inside_namespace()) {
          outs(m_namespace);
          outs(pc->inside_namespace()->name().c_str());
     }
     outs(m_end_class);
 }


  void out_type(Type t) 
  { 
      if (t.is_signature()) {
	   if (t.as_signature()->class_ptr() == NULL) { // NOT a method
          outs(m_function_ptr);
       } else {
          outs(m_method_ptr);
          out_classname(t.as_signature()->class_ptr());
          outs(m_method_ptr_type);
       }  
       m_within_signature = true;
	   do_signature(t.as_signature());
       m_within_signature = false;
       outs(m_end_function_ptr);
      } 
      else if (t.is_class()) out_class_ref(t);
      else if (t.is_enum()) {  // *add 1.2.1 Mangling enum arguments
         out_ref_ptr(t);       // *fix 1.2.3 (Eric) handle pointers to enums, etc 
         outs(m_enum);
         out_simple_classname(t.as_enum()->name());
         outs(m_end_class);
      }
	  else {
	    out_ref_ptr(t);
		out(type_encode(t));
      }
   }

 void out_attrib(Type t) 
 {
    outs(t.is_const()  ? m_const_attrib : m_plain_attrib);
 }


  void out_ref_ptr(Type t)
  {
  // put out ref/ptr attributes 
      if (t.is_ref_or_ptr()) {
         if(t.is_reference())  {
           out(m_ref_chr);  out_attrib(t);
         } 
         if(t.is_pointer()) {
		   char pc = m_array_char;
		   if (!t.is_array()) pc = m_ptr_char;
           for(int i = 0; i < t.pointer_depth(); i++) {
                 out(pc);
      //..the type system can't currently represent _multiple const attributes_
                 if (i==0) out_attrib(t);   else outs(m_plain_attrib);
         }
       }
      } else // GCC requires a class to have at least one attrib.
      if (t.is_class() && ! m_dont_lookup_class) outs(m_plain_obj);     
  }

  virtual void do_void_args()
  {
    outs(m_void_args);   // (void)
  }

  // *fix 1.2.1 The two passes (collection and output) have been made into one. This simplifies
  // matters and ensures that types inside function pointer signatures are found in the correct
  // order. The special case of repeat codes is handled by setting a marker in the output.
  // *fix 1.2.1 GCC mangling doesn't do this compression trick on any embedded function pointer signatures.
  void do_signature(Signature *sig)
  {
      bool stdarg = sig->stdarg();
      if (m_use_return_type) { 
	  // bit of a hack - this applies to MS only...
      //*fix 1.2.3a Ctors taking method ptr arguments were miscoded.....   
        if ((m_fn->is_constructor() || m_fn->is_destructor()) && !m_within_signature) out('@');
        else {
            // *fix 1.2.3 (Eric) Functions returning enums are encoded like those returning objects
           Type rtype = sig->return_type();
	   if ((rtype.is_class() || rtype.is_enum()) && !rtype.is_ref_or_ptr()) outs("?A");
	   out_type(rtype);
        }
      } 
      if (sig->begin() == sig->end()) do_void_args();
      else {
        // encode each type in turn;  any non-simple repeated types are kept in a list and
        // refered to by index.  Some schemes (e.g. GCC) will collect repeated types together
        int last_idx=-1, idx, n_repeats;
        bool add_to_list;
        Signature::iterator sigi;
	// *fix 1.2.4 GCC regards the class of a member function as
	// a type to be considered in the type list...
	if (m_collect_repeats && m_fn->class_context()) {
	  Type ct(m_fn->class_context());	  
	  mArgTypes.push_back(ct);
	}
	for(sigi = sig->begin(); sigi != sig->end(); sigi++) {
           Type t = *sigi;
           idx = -1;
           add_to_list = false;
           if (! simple_type(t) && ! (m_within_signature && m_discard_sig_types)) { 
               // does this arglist already have this type?
               idx = find_index(mArgTypes,t);
               // if not, put it in the list of argument types
               add_to_list = (idx == -1);
            } 
            if (idx == -1) {
                out_type(t); 
                if (add_to_list) mArgTypes.push_back(t);
                last_idx = -1;
            } else { // a repeated type is represented by its index
                if (idx == last_idx && m_collect_repeats) { // matches last repeated type!
                  if (read_mark(0)==*m_rpt_type) n_repeats = 1;
                  else n_repeats = int(read_mark(1)-'0');
                  ++n_repeats;
                  restore_mark();
                  outs(m_collect_repeats);
                  outi(n_repeats);
                  outi(idx);
                } else { // write out a type reference, setting the mark for later!
                  set_mark();
                  outs(m_rpt_type);
                  outi(idx);
                }
                last_idx = idx;
            }
       }
       // cdecl-style arbitrary arguments
      if(stdarg) outs(m_end_stdarg); else outs(m_end_args); 
      }
   }


 char *mangle(Function *pfn)
 {
   reset();
   m_fn = pfn;
   outs(m_begin_name);
   out_fun_name(pfn->name());
   PClass pc = pfn->class_context();
   if (pc != NULL) { // is a method
     int access = m_fn->fun_entry()->reference()->access();
	 if (m_method_type_first)   out_method_type(access);
     out_classname(pc);
     if (! m_method_type_first) out_method_type(access);
	 mClassList.push_back(pc);
   } else
   outs(m_plain_function); 

 // any arguments
   if (m_convention_first)   do_calling_convention();
   do_signature(m_fn->signature());
   if (! m_convention_first) do_calling_convention();

 // end output string
   end();
   return ptr();
 }

};

OpNames ms_funs[] = {
     {"=","4"},
     {"+","H"},
     {"-","G"},
	 {"==","8"},
	 {"!=","9"},
     {"++","E"},
     {"--","F"},
     {"<<","6"},
     {">>","5"},
     {"[]","A"},
     {"<","M"},
     {">","O"},
     {"+=","Y"},
     // *add 1.2.1 Peter H's extra operators...
     {"-=","Z"},
     {"*=","X"},
     {"/=","_0"},
     // *add 1.2.3a Conversion operators
     {"__T__","B"},
     {NULL,NULL}
};

class MSMangler: public Mangler {
public:
 MSMangler()
 {
  m_begin_name = "?";
  m_rpt_type = "";
  m_void_args = "XZ";  
  m_end_stdarg = "ZZ"; 
  m_end_args = "@Z";
  m_plain_function = "@Y";
  m_function_ptr = "P6A"; // cdecl! Our problem is that it isn't
  	                      // part of the signature!!
  // *fix 1.2.3a 
  m_method_ptr = "P8";    
  m_method_ptr_type = "AE";  // a hack - wd be "BE" for const signatures...

  m_end_function_ptr = "";
  m_use_return_type = true;
  m_plain_obj = "";
  m_const_attrib = "B";
  m_plain_attrib = "A";
  m_ref_chr = 'A';
  m_array_char = 'Q';
  m_ptr_char = 'P';
  m_method_type_first = false;
  m_convention_first = true;
  m_collect_repeats = NULL;

  m_end_class = "@@";
  m_template_name = "?$";
  m_template_args = "@";
  m_namespace = NULL; // "@"; for now!

  m_discard_sig_types = false;
  m_enum = "W4";

}

 bool simple_type(Type t) // MSMangler
 {
     return t.is_number() && !t.is_reference();
 }

 void out_simple_classname(const string& name) // MSMangler
 {
    outs(name.c_str());
 }

 void do_calling_convention() // MSMangler
 {
    // if (m_fn->is_cdecl()) out('A');  else 
     if (m_fn->is_method()) out('E');  else
	 out('A');    
     //if (m_fn->is_stdcall()) out('G'); 
 }

 char type_encode(Type t) // MSMangler
 {
   	char ch;
	 if (t.is_void()) ch = 'X'; else
	 if (t.is_bool()) { out('_'); ch = 'N'; } // weird encoding!
	 else
     if (t.is_int()) {
         if(t.is_unsigned()) {
            if (t.is_char()) ch = 'E'; else
            if (t.is_short()) ch = 'G'; else
            if (t.is_long()) ch = 'K';
            else ch = 'I'; // plain 'int'
         } else {
            if (t.is_char()) ch = 'D'; else
            if (t.is_short()) ch = 'F'; else
            if (t.is_long()) ch = 'J';
            else ch = 'H';
         }
      } else
      if (t.is_float()) {
         if (t.is_double()) ch = 'N';
         else ch = 'M';
      } else //if(t.is_class()) ch = 'V';
         return 0;
      return ch;      
    }

  void out_fun_name(string fun_name) // MSMangler
  {
     const char *name = fun_name.c_str();
     if (m_fn->is_constructor()) outs("?0");  else
     if (m_fn->is_destructor()) outs("?1"); else 
     {
      char *mn = lookup_opname(ms_funs,name);
	  if (mn != NULL) { out('?'); outs(mn); }
	  else { 
	  // methods (as op. to operators & constructors) refer to the class as #1, not #0.
	  // presumably there's something already in the list!
	    mClassList.push_back(NULL);
        outs(name);
        out('@');
      }
     }
   }

   void out_method_type(int access) // MSMangler
   {
	char ch;
	char *pch;
	switch(access) {
	case Public:    pch = "SUQ"; break;
	case Protected: pch = "KMI"; break;
	case Private:   pch = "CEA"; break;
	default:        pch = "SUQ"; break;
	}
	if (m_fn->is_static()) ch = pch[0]; else
	if (m_fn->is_virtual()) ch = pch[1]; 
    else ch = pch[2];
    out(ch);
    if (!m_fn->is_static()) out(m_fn->is_const()  ? 'B' : 'A');
   }

   void out_class_ref(Type t) // MSMangler
   {
   // MS optimizes the usual pattern for repeated class refs.
       PClass pc = t.as_class(); 
       int idx = find_index(mClassList,pc);
	   if (m_dont_lookup_class) idx = -1;
       // *fix 1.2.3 Structs are now mangled correctly, since we keep a struct flag
       char cc = pc->is_struct() ? 'U' : 'V';
       if (idx != -1) {    // we matched a _previously emitted_ class...
			out_ref_ptr(t);
			out(cc);  
			outi(idx);
			out('@');
       } else {  

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -