📄 dlmain.c
字号:
/******************************************************
Copyright(c) 版权所有,1998-2003微逻辑。保留所有权利。
******************************************************/
/*****************************************************
文件说明:dynlink loader模块
版本号:1.0.0
开发时期:2003-04-40
作者:ZB
修改记录:
1. 2003-08-26...ZB: 去处PAGE_NOCACHE标志,此标志降低了系统性能。
******************************************************/
#include <ewindows.h>
#include <elf.h>
#include <romheader.h> //Add by zb.
#include <epcore.h>
#include <edevice.h> //Add by zb.
#include <eassert.h> //Add by zb.
#include <estring.h> //Add by zb.
#include <module.h> //Add by zb.
#include <coresrv.h>
#include <diskio.h>
//#define __dlmalloc malloc
//#define __dlfree free
#define __dlmalloc _kalloc
#define __dlfree _kfree
//#define RETAILMSG(TONE_DLL, EdbgOutputDebugString
#define __dlexit(exp)
#define __dlassert(exp) ASSERT(exp)
//#define ROM_MODULE 1
//#define ROM_FILE 2
//#define RAM_FILE 3
#include "dlstruct.h"
ElfW(Addr) __dllookup_value (const char *name, struct __dlmodule *module);
#include <dlarch.h>
#include "dldyn.h"
#define INVALID_SET_FILE_POINTER 1
#define ALIGN_SIZE 0x10000
#define ALIGN_ELF_SIZE 0x1000
#define ALIGN(addr,align) (((addr))&(~(align-1)))
#define ALIGNUP(addr,align) (((addr)+(align)-1)&(~(align-1)))
//#define PAGE_WRITECOPY 1
////////////////////////////////////////////////////////////////////////
typedef void (*__dlinit_fun) (int, char **, char **);
typedef void (*__dlfinit_fun)(void);
extern struct __dlmodule *__dl_loaded;
extern unsigned int __dl_nloaded;
////////////////////////////////////////////////////////////////////////
//NOTE:2003-09-04...ZB
// fix __dlclean_module()'s free bug.
//unsigned int __dlclean_module (struct __dlmodule *module);
unsigned int __dlclean_module (struct __dlmodule *module, BOOL bNested);
//NOTE:2003-09-04...ZB
struct __dlmodule * __dlload_module (PMODULE_HANDLE lpHandle, const char *name);
void __dlsetup_hash (struct __dlmodule* module);
int __dlopen_dependence (struct __dlmodule* module, unsigned int mode);
//---------------------------------------------------------------------
static ElfW(Addr) __dllookup_symbol (const char *name, struct __dlmodule *module,
const ElfW(Sym) **ref, struct __dlscope_elem *symbol_scope[],
int reloc_type, int explicit_mode);
static void __dlcall_init (struct __dlmodule *module, int argc, char **argv, char **env);
static void __dlinit_module (struct __dlmodule *module, int argc, char **argv, char **env);
static struct __dlmodule * __dlmap_module (HANDLE hFile, ElfW(Ehdr) *ehdr, ELF_INFO *pElfinfo, PMODULE_HANDLE lpHandle,
UINT flag);
static struct __dlmodule * __dlmap_rom_module (HANDLE hFile, ElfW(Ehdr) *ehdr, ELF_INFO *pElfinfo);
static struct __dlmodule* __dlopen_module (const char * name, unsigned int mode, struct __dlmodule *caller,
PMODULE_HANDLE lpHandle);
static char * __dlfind_module (const char *name, struct __dlmodule *caller);
static unsigned int __dlcheck_elf (const Elf32_Ehdr *ehdr);
static unsigned int __dlhash (const unsigned char *name);
static int __dllookup (const char *undef_name, unsigned long int hash,
const ElfW(Sym) *ref,
struct __dlsym_val *result,
struct __dlscope_elem *scope, size_t i,
struct __dlmodule *skip, int noexec, int noplt);
////////////////////////////////////////////////////////////////////////
UINT GetSharedDirectory (LPSTR lpBuff, UINT nSize)
{
const LPSTR lpDir = "\\system\\shared";
UINT nLen = strlen (lpDir);
if (nLen < nSize)
strcpy (lpBuff, lpDir);
return nLen;
}
#undef GetSystemDirectory
UINT GetSystemDirectory (LPSTR lpBuff, UINT nSize)
{
const LPSTR lpDir = "\\system";
UINT nLen = strlen (lpDir);
if (nLen < nSize)
strcpy (lpBuff, lpDir);
return nLen;
}
char *strdup(const char *p)
{
size_t n;
char *dup;
RETAILMSG(TONE_DLL, ("--In strdup \n"));
n = strlen(p);
dup = (char *)__dlmalloc(n + 1);
if (dup == NULL)
return NULL;
memset (dup, 0, n+1);
memcpy (dup, p, n);
return dup;
}
static unsigned int __dlfileexist (const char *p)
{
/* WIN32_FIND_DATA wfd;
HANDLE hFind;
hFind = FindFirstFile (p, &wfd);
*/
DWORD dwAttr;
RETAILMSG(TONE_DLL, ("--In * __dlfileexist: %s \n", p));
RETAILMSG(TONE_DLL, ("--In * __dlfileexist %x \n", GetFileAttributes));
RETAILMSG(TONE_DLL, ("--get GetFileAttributes : %x \n", GetFileAttributes));
dwAttr = GetFileAttributes (p);
//RETAILMSG(TONE_DLL, ("--file %s attribute: %x \n", dwAttr);
//if (dwAttr == (DWORD)-1)
if(dwAttr == (DWORD)12345678)
return 0;
if (dwAttr&FILE_ATTRIBUTE_DIRECTORY)
return 0;
return 1;
}
////////////////////////////////////////////////////////////////////////
static void __dlcall_init (struct __dlmodule *module, int argc, char **argv, char **env)
{
if (module->l_init_called)
return;
module->l_init_called = 1;
if (module->l_type == lt_executable)
return;
if (module->l_info[DT_INIT] == NULL
&& module->l_info[DT_INIT_ARRAY] == NULL)
return;
if (module->l_info[DT_INIT] != NULL)
{
__dlinit_fun init = (__dlinit_fun)(module->l_addr + module->l_info[DT_INIT]->d_un.d_ptr);
init (argc, argv, env);
}
if (module->l_info[DT_INIT_ARRAY] != NULL)
{
unsigned int i;
unsigned int nfun;
ElfW(Addr) *addrs;
nfun = module->l_info[DT_INIT_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr));
addrs = (ElfW(Addr) *) (module->l_info[DT_INIT_ARRAY]->d_un.d_ptr
+ module->l_addr);
for (i = 0; i < nfun; ++i)
((__dlinit_fun) addrs[i]) (argc, argv, env);
}
}
static void __dlinit_module (struct __dlmodule *module, int argc, char **argv, char **env)
{
unsigned int i;
/* Stupid users forced the ELF specification to be changed. It now
says that the dynamic loader is responsible for determining the
order in which the constructors have to run. The constructors
for all dependencies of an object must run before the constructor
for the object itself. Circular dependencies are left unspecified.
This is highly questionable since it puts the burden on the dynamic
loader which has to find the dependencies at runtime instead of
letting the user do it right. Stupidity rules! */
i = module->l_searchlist.r_nlist;
while (i-- > 0)
__dlcall_init (module->l_initfini[i], argc, argv, env);
}
static unsigned int __dlhash (const unsigned char *name)
{
unsigned long int hash = 0;
//The below is added by zb
if(name == NULL)
return hash;
if (*name != '\0')
{
hash = *name++;
if (*name != '\0')
{
hash = (hash << 4) + *name++;
if (*name != '\0')
{
hash = (hash << 4) + *name++;
if (*name != '\0')
{
hash = (hash << 4) + *name++;
if (*name != '\0')
{
hash = (hash << 4) + *name++;
while (*name != '\0')
{
unsigned long int hi;
hash = (hash << 4) + *name++;
hi = hash & 0xf0000000;
/* The algorithm specified in the ELF ABI is as
follows:
if (hi != 0)
hash ^= hi >> 24;
hash &= ~hi;
But the following is equivalent and a lot
faster, especially on modern processors. */
hash ^= hi;
hash ^= hi >> 24;
}
}
}
}
}
}
return hash;
}
void __dlsetup_hash (struct __dlmodule* module)
{
Elf_Symndx *hash;
Elf_Symndx nchain;
if (!module->l_info[DT_HASH])
return;
hash = (void *)(module->l_addr + module->l_info[DT_HASH]->d_un.d_ptr);
module->l_nbuckets = *hash++;
nchain = *hash++;
module->l_nchain = nchain; //zb added...
module->l_buckets = hash;
hash += module->l_nbuckets;
module->l_chain = hash;
}
/* read file from the offset, return readed bytes
*/
static __inline unsigned int read_file (HANDLE hFile, char *buff, unsigned int size,
unsigned int offset)
{
unsigned int read;
__dlassert (buff != NULL);
if (SetFilePointer (hFile, offset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
return 0;
if (! ReadFile (hFile, buff, size, (LPDWORD)&read, NULL))
return 0;
return read;
}
/* lookup functions. We return a value > 0 if we
found the symbol, the value 0 if nothing is found and < 0 if
something bad happened. */
#define DEBUG_dllookup 0
static int __dllookup (const char *undef_name, unsigned long int hash, const ElfW(Sym) *ref,
struct __dlsym_val *result, struct __dlscope_elem *scope, size_t i,
struct __dlmodule *skip, int noexec, int noplt)
{
struct __dlmodule **list = scope->r_list;
size_t n = scope->r_nlist;
struct __dlmodule *module;
//RETAILMSG(TONE_DLL, ("scope->r_nlist: %x\r\n", scope->r_nlist);
do
{
const ElfW(Sym) *symtab;
const char *strtab;
// const ElfW(Half) *verstab;
Elf_Symndx symidx;
const ElfW(Sym) *sym;
module = list[i];
/* Here come the extra test needed for `__dllookup_symbol_skip'. */
if (skip != NULL && module == skip)
continue;
/* Don't search the executable when resolving a copy reloc. */
if (noexec && module->l_type == lt_executable)
continue;
// RETAILMSG(TONE_DLL, ("-->hash value: %x\r\n", hash);
symtab = (const void *) D_PTR (module, l_info[DT_SYMTAB]);
strtab = (const void *) D_PTR (module, l_info[DT_STRTAB]);
// verstab = module->l_versyms;
/* Search the appropriate hash bucket in this object's symbol table
for a definition for the same symbol name. */
DEBUGMSG( DEBUG_dllookup, ("__dllookup: lookup in module: %s.\r\n", module->l_name ) );
for (symidx = module->l_buckets[hash % module->l_nbuckets];
symidx != STN_UNDEF;
symidx = module->l_chain[symidx])
{
sym = &symtab[symidx];
/* No value. */
if (sym->st_value == 0 || ((noplt||module->l_type == lt_executable) && sym->st_shndx == SHN_UNDEF))
continue;
/* Ignore all but STT_NOTYPE, STT_OBJECT and STT_FUNC entries
since these are no code/data definitions. */
if ( ELF32_ST_TYPE(sym->st_info) > STT_FUNC)
continue;
/* Not the symbol we are looking for. */
if (sym != ref && strcmp (strtab + sym->st_name, undef_name))
continue;
/* There cannot be another entry for this symbol so stop here. */
switch (ELF32_ST_BIND(sym->st_info))
{
case STB_WEAK:
case STB_GLOBAL:
/* Global definition. Just what we need. */
RETAILMSG(TONE_DLL, ("undef_name: %s, module->l_name: %s\n", undef_name, module->l_name));
result->s = sym;
result->m = module;
return 1;
default:
/* Local symbols are ignored. */
break;
}
}
}
while (++i < n);
/* We have not found anything until now. */
return 0;
}
/* find the module position
return NULL if can't find
*/
static char *__dlfind_module (const char *name, struct __dlmodule *caller)
{
const char *file;
char dir[MAX_PATH];
const char *p = name;
RETAILMSG(TONE_DLL, ("--0want find module %s \n", name));
RETAILMSG(TONE_DLL, ("--len %d \n", strlen(name)));
if (__dlfileexist (name))
{
RETAILMSG(TONE_DLL, ("--find module %s OK\n", name));
return strdup (name);
}
// if (caller == NULL)
// return NULL;
while(*p){
if(*p == '\\') //是绝对路径,没有找到就return...
return 0;
else
p ++;
}
// file = strrchr (name, '\\');
// if (file == NULL)
// file = name; /* name without directory info */
// else{
//file ++; /* skip '\\' */
// RETAILMSG(TONE_DLL, ("--have path! \n"));
// return NULL; //if with directory info...
// }
/*
if (caller && caller->l_origin != NULL)
{
RETAILMSG(TONE_DLL, ("--origin : %s \n", caller->l_origin));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -