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

📄 directcall.cpp

📁 UC Library Extensions UnderC comes with a pocket implementation of the standard C++ libraries, wh
💻 CPP
📖 第 1 页 / 共 3 页
字号:
  if (p) {
      // (1)the current DLL handle needs to be non-NULL, but doesn't have to be sensible
      // This is just to force Parser::declare_function() to call add_dll_function()
      // below
      set_dll_handle((void*)-1);
      // (2)The modifier flag will be passed to add_dll_function(), so we give it
      // a special value so it will pick up the pointer directly....
      Parser::state.modifier = UseAddr;
      mDirectAddr = p;
  } else {
      set_current_lib_file(0);
      mDirectAddr = NULL;
  }
}

bool add_dll_function(Function *pfn, int modifier, string& name)
{
  PClass pc = pfn->class_context();
  CALLFN proc;

  // *change 0.9.4  Need explicit extern "C" now - (used to simply be class context)
  // *add    1.1.4  Implicit self-link for those systems which need it...
  if (modifier == UseAddr) proc = (CALLFN) mDirectAddr;
#ifdef CANNOT_SELF_LINK
  else if (get_dll_handle()==IMPLICIT_LINK) {
    name = pfn->name(); // *fix 1.2.4 pass back name in case we can't find     
    proc = lookup_self_link(pc,name);
  }
#endif  
  else if(! Parser::in_extern_C()) { // mangled C++ name 
    proc = (CALLFN)Import::load_method_entry(pfn,name);      
	if (name=="") name = "?" + pfn->name();
  } else { // extern "C"
    name = pfn->name();
    if (modifier == Stdcall) name = "_" + name + "@" + itos(pfn->signature()->byte_size());     
    proc = (CALLFN)get_proc_address(s_lib,name.c_str());
  }
  if (!proc) return false; 

  if (pc != NULL) pc->set_imported();

  Sig ssig(pfn->return_type());
  Signature *sig = pfn->signature();
  Signature::iterator tli;
  for(tli = sig->begin(); tli != sig->end(); ++tli) ssig << (Type)*tli;
  ssig.set_const(sig->is_const());  // *fix 1.1.0  Must respect constness of signature!

  // *fix 1.2.3 Important also to mke the signature reflect any extra unnamed arguments....
 if (sig->stdarg()) ssig << t_void;  // the convention used by the parser...


// *fix 1.1.0 We can now distinguish between ordinary cdecl method calls (GCC)
// and so-called '__thiscall' calls (MS)
// *add 1.2.3 Note that direct imports into the DLL are NOT stdcall under Linux!
  int calling_convention = Function::CDECL;
  if (modifier == Stdcall || modifier == Api 
#ifdef _WIN32
      || modifier == UseAddr
#endif
   ) 
      calling_convention = Function::_STDCALL;

  if(pfn->is_method()) {
    if (pc->import_scheme()->uses_stdmethod()) calling_convention = Function::STDMETHOD;
  }

  add(ssig,pfn->name().c_str(),proc,false,calling_convention);

  return true;
}



//----------------------- generating native stubs -------------------------
// Basically this is a mad (and v. limited) x86 macro assembler.

typedef unsigned long ulong;
typedef char *pchar;
typedef short *& pshort;
typedef ulong *& pulong;

// Disable some silly warnings:
// truncation of const value and 'int' to 'short'.
#pragma warning(disable:4309) 
#pragma warning(disable:4305)

void emit1(pchar& pc, char ch)      {  *pc++ = ch; }
void emit2(pchar& pc, short s)      {  *pshort(pc)++ = s; }
void emit4(pchar& pc, ulong l)      {  *pulong(pc)++ = l;}
void pushc(pchar& pc, ulong val)    { emit1(pc,0x68); emit4(pc,val); }
void pushv(pchar& pc, void *ptr)    { emit2(pc,0x35FF); emit4(pc,(ulong)ptr); }     
void popv(pchar& pc, void *ptr)     { emit2(pc,0x058F); emit4(pc,(ulong)ptr); }     
void callf(pchar& pc, void *pfn) {
  emit1(pc,0xBA);   emit4(pc,(ulong)pfn);     // mov edx, offset copy array
  emit2(pc,0xD2FF);                                   // call edx
}
void mov_acc(pchar& pc, ulong val)  { emit1(pc,0xB8);   emit4(pc,val);  }    // mov eax,...
void mov_ptr(pchar& pc, void *val)  { emit1(pc,0xB9);   emit4(pc,(ulong)val);  } // mov ecx..
void copy_acc(pchar& pc, void *ptr) { emit1(pc,0xA1);   emit4(pc,(ulong)ptr);  }
void copy_cx(pchar& pc, void *ptr)  { emit2(pc,0x0D89); emit4(pc,(ulong)ptr); }               
void sub_esp(pchar& pc, int val)    { emit2(pc,0xEC81);   emit4(pc,(ulong)val); }
void push_qword(pchar& pc, void *ptr) { emit2(pc,0x05DD); emit4(pc,(ulong)ptr); }
void ret(pchar& pc)                 { emit1(pc,(char)0xC3);   }

void *generate_native_stub(Function *pfn)
{
// The stub must copy the arguments by calling copy_array(), and then calls Engine::execute().
  char cde_buff[200];
  Signature *sig = pfn->signature();
  
  int no_args = sig->byte_size()/sizeof(int);
  void *rra = new ulong;
  ArgBlock *xargs = new ArgBlock;
  int flags = Engine::ARGS_PASSED;
  char *pc = cde_buff;
  // *fix 1.1.4     Plain function callbacks are often cdecl...but think about this!
  // *change 1.2.3  Functions export as cdecl, unless __stdcall is used;
  //                MS methods don't and GCC methods do; determined by is_cdecl().
  bool fun_is_cdecl;
  if (pfn->is_method()) {
      fun_is_cdecl = pfn->is_cdecl();
  } else 
      fun_is_cdecl = pfn->export_as_cdecl();
  
  popv(pc,rra);                                                    // save return addr
  if (pfn->is_method())  {
      if (pfn->class_context()->import_scheme()->uses_stdmethod()) // is this a stdmethod call?
           copy_cx(pc,&xargs->OPtr);                                // obj ptr was in ecx
      else {
         popv(pc,&xargs->OPtr);                                     // obj ptr was on the stack
         no_args++;                                                // as an _extra_ arg
	  }
      flags = flags | Engine::METHOD_CALL;
  }
  Type rt = pfn->return_type();
  if (rt.is_double()) flags = flags | Engine::RETURN_64; else
  if (!rt.is_void()) flags = flags | Engine::RETURN_32;
  if (no_args > 0) {
  // two different strategies here, depending on the compiler
#ifndef __GNUC__
    mov_ptr(pc,xargs);
    mov_acc(pc,no_args);                                          // call copy_array
    callf(pc,(void *)&copy_array);                                
  // copy_array mucks w/ ESP by explicitly popping the arguments;
  // cdecl calls assume that caller will sort out ESP.
 
   if (fun_is_cdecl) 
     sub_esp(pc, sizeof(int)*no_args);                            // restore esp if cdecl
  #else
    pushc(pc,(unsigned long)xargs);
    pushc(pc,no_args);
    callf(pc,(void *)&copy_array);
    sub_esp(pc, -8);                  // because copy_array is cdecl...
    if (! fun_is_cdecl)              // if we're NOT cdecl then clean up like a good boy!
      sub_esp(pc, -sizeof(int)*no_args);
    
  #endif				 
  }
  pushc(pc,(ulong)xargs);
  pushc(pc,flags);
  pushc(pc,(ulong)pfn->fun_block());
  callf(pc,(void *)&Engine::stub_execute);                        // and call the stack engine!
  if (flags & Engine::RETURN_32) copy_acc(pc,&xargs->ret1);       // put result in eax, if needed
  else
  if (flags & Engine::RETURN_64)  push_qword(pc,&xargs->ret2);    // or onto fp stack *add 1.1.1
  pushv(pc,rra);                                                  // restore return addr & return
  ret(pc);

  // and copy the code block
  int sz = (ulong)pc - (ulong)cde_buff;
  char *cp = new char[sz+1];
  memcpy(cp,cde_buff,sz+1);
  return cp;
}


// *add 1.1.4 The Linux tool chain currently doesn't allow you to link to self,
//            so we have to explicitly specify self-exports. 
#ifndef CANNOT_SELF_LINK
 static const int sNoSelfLink = false;
#else
 static const int sNoSelfLink = true;
#endif

//-------------------- shared library management ----------------
static string s_file;

bool set_current_lib_file(char *file)
{
 if (!file) {
   s_lib = NULL;
   cleanup_ordinal_lookup();
 } else {
// *add 1.1.2 Linking to #self finds the actual full path of UC pgm
  // *fix 1.1.4 It's now #pragma dlink $self,etc! (otherwise argues with prepro)
  if (file[0]=='#') file[0] = '$';
  bool explicit_link = true;
  if (strcmp(file,"$self")==0) {// self-linking case!
// *ch 1.2.9 patch
#ifdef _WIN32    
    file = Main::uc_exec_name();
#else
    file = "";
#endif    
	explicit_link = ! sNoSelfLink;
  } else
    if (strcmp(file,"$caller")==0) {
      file = NULL;
    }
  // *add 1.1.2 Try looking in the UC_LIB directory!
   string sfile = file ? file : "$caller";
   if (explicit_link) {
     s_lib = load_library(file);
     if (!s_lib) {
	   sfile = Main::uc_lib_dir() + sfile;
	   s_lib = load_library(sfile.c_str());
	 }
   } else s_lib = IMPLICIT_LINK;  
   lib_list.push_back(s_lib);
   if (!s_lib) return false;
// *fix 1.1.4 Subsequent #lib where the loaded DLL is the same - don't reset!
   if (sfile != s_file) { 
	   Import::reset(true);
	   s_file = sfile;
   }
 }
 return true;
}

string get_current_lib_file()
{ return s_file; }

void unload_library(Handle hlib)
{
    set_dll_handle(hlib);
	Import::reset(false);
    if (hlib != IMPLICIT_LINK && hlib != NULL) {
        free_library(hlib);
        cleanup_ordinal_lookup();
    } 
}

// *fix 1.2.4 if passed NULL (i.e. no current DLL _importing_ taking place)
// this function will try to unload the last handle loaded.
void unload_lib(Handle hlib)
{ 
  if (hlib == NULL) {
    hlib = lib_list.back();
  }
  unload_library(hlib);
  lib_list.remove(hlib);
  s_lib = NULL;
} 

void *get_dll_handle() { return (void *)s_lib; }

void set_dll_handle(void *dl)
{ 
	s_lib = (Handle)dl;
}

// Looking up DLL entries using ordinal lookup
typedef std::map<string,int> SIMap;
static SIMap *s_ord_lookup;
static bool s_lookup_is_ordinal;

bool using_ordinal_lookup()
{ return s_ord_lookup != NULL; }

int lookup_ordinal(const char *name)
{
    SIMap::iterator simi = s_ord_lookup->find(name);
    if (simi != s_ord_lookup->end()) return simi->second;
    else return 0;
}

// *change 1.2.2 (Eric) imp file format is now more relaxed;
// (a) ignore any line that begins with a "# ", and 
// (b) everything after the mangled name
// *add 1.2.4 Will look in UC LIB directory a la .DLLs
// *add 1.2.4 UC2 type means that value is not ordinal but address
int convert_ordinal(char *buf)
{
  if (s_lookup_is_ordinal)
    return atoi(buf);
  else {
    unsigned long l;
    sscanf(buf,"%x",&l);
    return (int)l;  
  }
}

bool lookup_is_ordinal()
{ return s_lookup_is_ordinal; }

bool generate_ordinal_lookup(const char *index_file)
{
  string name,magic,compiler;
  char buf[1024];
  ifstream in;
  in.open(index_file);
  if (! in || in.eof()) {
    string  sfile = Main::uc_lib_dir() + index_file;
    in.open(sfile.c_str());
    if (! in || in.eof()) {
      cerr << "cannot find '" << sfile << "'\n";
      return false;
    }  
  }  
  in >> magic >> compiler;
  if (magic != "UC1" && magic != "UC2") return false;
  s_lookup_is_ordinal = magic == "UC1";
  if (! Import::set_scheme(compiler)) return false;
  s_ord_lookup = new SIMap;
  // *fix 1.2.3a (Eric) Attempted to read ordinal twice
  while (! in.eof()) {
    in >> buf;
    if (*buf && *buf != '#') {
      in >> name;
      (*s_ord_lookup)[name] = convert_ordinal(buf);
    }
    in.getline(buf,sizeof(buf));
  }
  return true;
}

void cleanup_ordinal_lookup()
{
    delete s_ord_lookup;
    s_ord_lookup = NULL;
}

// *fix 1.2.3 Under Win32, it is a Bad Idea to try free the process handle.
void finis()
{
 Handle process_handle = get_process_handle();
 HandleList::iterator ili;
 for(ili = lib_list.begin(); ili != lib_list.end(); ++ili) {
      Handle lib = *ili;
      if (lib != process_handle) 
         unload_library(lib);
 }
}

CALLFN lookup_self_link(PClass pc,const string& name) { return NULL; }



}  // namespace Builtin

⌨️ 快捷键说明

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