1
0
mirror of https://github.com/golang/go synced 2024-11-26 00:57:56 -07:00

8l : add dynimport to import table in Windows PE, initial make cgo dll work.

R=rsc, brainman, Joe Poirier, mattn
CC=golang-dev
https://golang.org/cl/2166041
This commit is contained in:
Wei Guangjing 2010-12-07 15:28:33 -05:00 committed by Russ Cox
parent 836643400c
commit 70deac67cf
9 changed files with 206 additions and 131 deletions

View File

@ -820,6 +820,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
case SDATA: case SDATA:
case SELFDATA: case SELFDATA:
case SMACHO: case SMACHO:
case SWINDOWS:
if(!s->reachable) if(!s->reachable)
continue; continue;
put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype); put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype);

View File

@ -168,6 +168,7 @@ enum
SRODATA, SRODATA,
SDATA, SDATA,
SMACHO, /* Mach-O __nl_symbol_ptr */ SMACHO, /* Mach-O __nl_symbol_ptr */
SWINDOWS,
SBSS, SBSS,
SXREF, SXREF,

View File

@ -320,6 +320,8 @@ main(int argc, char *argv[])
doelf(); doelf();
if(HEADTYPE == 6) if(HEADTYPE == 6)
domacho(); domacho();
if(HEADTYPE == 10)
dope();
dostkoff(); dostkoff();
if(debug['p']) if(debug['p'])
if(debug['1']) if(debug['1'])

View File

@ -45,6 +45,25 @@ static IMAGE_FILE_HEADER fh;
static IMAGE_OPTIONAL_HEADER oh; static IMAGE_OPTIONAL_HEADER oh;
static IMAGE_SECTION_HEADER sh[16]; static IMAGE_SECTION_HEADER sh[16];
typedef struct Imp Imp;
struct Imp {
Sym* s;
long va;
long vb;
Imp* next;
};
typedef struct Dll Dll;
struct Dll {
char* name;
int count;
Imp* ms;
Dll* next;
};
static Dll* dr;
static int ndll, nimp, nsize;
static IMAGE_SECTION_HEADER* static IMAGE_SECTION_HEADER*
addpesection(char *name, int sectsize, int filesize, Segment *s) addpesection(char *name, int sectsize, int filesize, Segment *s)
{ {
@ -122,66 +141,160 @@ strput(char *s)
cput('\0'); cput('\0');
} }
static void static Dll*
addimports(vlong fileoff) initdynimport(void)
{ {
IMAGE_IMPORT_DESCRIPTOR ds[2], *d; Imp *m;
char *dllname = "kernel32.dll"; Dll *d;
struct { Sym *s;
char *name; int i;
uint32 thunk; Sym *dynamic;
} *f, fs[] = {
{ "GetProcAddress", 0 },
{ "LoadLibraryExA", 0 },
{ 0, 0 }
};
uint32 size = 0; dr = nil;
memset(ds, 0, sizeof(ds)); ndll = 0;
size += sizeof(ds); nimp = 0;
ds[0].Name = size; nsize = 0;
size += strlen(dllname) + 1;
for(f=fs; f->name; f++) { for(i=0; i<NHASH; i++)
f->thunk = size; for(s = hash[i]; s != S; s = s->hash) {
size += sizeof(uint16) + strlen(f->name) + 1; if(!s->reachable || !s->dynimpname)
continue;
nimp++;
for(d = dr; d != nil; d = d->next) {
if(strcmp(d->name,s->dynimplib) == 0) {
m = mal(sizeof *m);
m->s = s;
m->next = d->ms;
d->ms = m;
d->count++;
nsize += strlen(s->dynimpname)+2+1;
break;
}
}
if(d == nil) {
d = mal(sizeof *d);
d->name = s->dynimplib;
d->count = 1;
d->next = dr;
dr = d;
m = mal(sizeof *m);
m->s = s;
m->next = 0;
d->ms = m;
ndll++;
nsize += strlen(s->dynimpname)+2+1;
nsize += strlen(s->dynimplib)+1;
}
} }
ds[0].FirstThunk = size;
for(f=fs; f->name; f++)
size += sizeof(fs[0].thunk);
nsize += 20*ndll + 20;
nsize += 4*nimp + 4*ndll;
dynamic = lookup(".windynamic", 0);
dynamic->reachable = 1;
dynamic->type = SWINDOWS;
for(d = dr; d != nil; d = d->next) {
for(m = d->ms; m != nil; m = m->next) {
m->s->type = SWINDOWS | SSUB;
m->s->sub = dynamic->sub;
dynamic->sub = m->s;
m->s->value = dynamic->size;
dynamic->size += 4;
}
dynamic->size += 4;
}
return dr;
}
static void
addimports(vlong fileoff, IMAGE_SECTION_HEADER *datsect)
{
IMAGE_SECTION_HEADER *isect; IMAGE_SECTION_HEADER *isect;
isect = addpesection(".idata", size, size, 0); uint32 va;
int noff, aoff, o, last_fn, last_name_off, iat_off;
Imp *m;
Dll *d;
Sym* dynamic;
isect = addpesection(".idata", nsize, nsize, 0);
isect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA| isect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
va = isect->VirtualAddress;
uint32 va = isect->VirtualAddress;
oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = va; oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = va;
oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize; oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize;
ds[0].Name += va;
ds[0].FirstThunk += va;
for(f=fs; f->name; f++)
f->thunk += va;
seek(cout, fileoff, 0); seek(cout, fileoff, 0);
for(d=ds; ; d++) {
lputl(d->OriginalFirstThunk); dynamic = lookup(".windynamic", 0);
lputl(d->TimeDateStamp); iat_off = dynamic->value - PEBASE; // FirstThunk allocated in .data
lputl(d->ForwarderChain); oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = iat_off;
lputl(d->Name); oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size;
lputl(d->FirstThunk);
if(!d->Name) noff = va + 20*ndll + 20;
break; aoff = noff + 4*nimp + 4*ndll;
last_fn = 0;
last_name_off = aoff;
for(d = dr; d != nil; d = d->next) {
lputl(noff);
lputl(0);
lputl(0);
lputl(last_name_off);
lputl(iat_off);
last_fn = d->count;
noff += 4*last_fn + 4;
aoff += 4*last_fn + 4;
iat_off += 4*last_fn + 4;
last_name_off += strlen(d->name)+1;
} }
strput(dllname); lputl(0); //end
for(f=fs; f->name; f++) { lputl(0);
lputl(0);
lputl(0);
lputl(0);
// put OriginalFirstThunk
o = last_name_off;
for(d = dr; d != nil; d = d->next) {
for(m = d->ms; m != nil; m = m->next) {
lputl(o);
o += 2 + strlen(m->s->dynimpname) + 1;
}
lputl(0);
}
// put names
for(d = dr; d != nil; d = d->next) {
strput(d->name);
}
// put hint+name
for(d = dr; d != nil; d = d->next) {
for(m = d->ms; m != nil; m = m->next) {
wputl(0); wputl(0);
strput(f->name); strput(m->s->dynimpname);
} }
for(f=fs; f->name; f++) }
lputl(f->thunk);
strnput("", isect->SizeOfRawData - size); strnput("", isect->SizeOfRawData - nsize);
cflush(); cflush();
// put FirstThunk
o = last_name_off;
seek(cout, datsect->PointerToRawData + dynamic->value - PEBASE - datsect->VirtualAddress, 0);
for(d = dr; d != nil; d = d->next) {
for(m = d->ms; m != nil; m = m->next) {
lputl(o);
o += 2 + strlen(m->s->dynimpname) + 1;
}
lputl(0);
}
cflush();
seek(cout, 0, 2);
}
void
dope(void)
{
initdynimport();
} }
void void
@ -210,7 +323,7 @@ asmbpe(void)
d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA| d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
addimports(nextfileoff); addimports(nextfileoff, d);
fh.NumberOfSections = nsect; fh.NumberOfSections = nsect;
fh.TimeDateStamp = time(0); fh.TimeDateStamp = time(0);

View File

@ -120,3 +120,5 @@ enum {
void peinit(void); void peinit(void);
void asmbpe(void); void asmbpe(void);
void dope(void);

View File

@ -4,14 +4,6 @@
#include "386/asm.h" #include "386/asm.h"
TEXT runtime·get_kernel_module(SB),7,$0
MOVL 0x30(FS), AX // get PEB
MOVL 0x0c(AX), AX // get PEB_LDR_DATA
MOVL 0x1c(AX), AX // get init order module list
MOVL (AX), AX // get next entry (kernel module)
MOVL 0x08(AX), AX // get base of module
RET
// void *stdcall_raw(void *fn, int32 count, uintptr *args) // void *stdcall_raw(void *fn, int32 count, uintptr *args)
TEXT runtime·stdcall_raw(SB),7,$4 TEXT runtime·stdcall_raw(SB),7,$4
// Copy arguments from stack. // Copy arguments from stack.

View File

@ -25,6 +25,11 @@ abort(int8 *name)
runtime·throw(name); runtime·throw(name);
} }
#pragma dynimport runtime·VirtualAlloc VirtualAlloc "kernel32.dll"
#pragma dynimport runtime·VirtualFree VirtualFree "kernel32.dll"
void *runtime·VirtualAlloc;
void *runtime·VirtualFree;
void* void*
runtime·SysAlloc(uintptr n) runtime·SysAlloc(uintptr n)
{ {

View File

@ -2,16 +2,8 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// The following function allows one to dynamically
// resolve DLL function names.
// The arguments are strings.
void *runtime·get_proc_addr(void *library, void *name);
extern void *runtime·VirtualAlloc;
extern void *runtime·VirtualFree;
extern void *runtime·LoadLibraryEx; extern void *runtime·LoadLibraryEx;
extern void *runtime·GetProcAddress; extern void *runtime·GetProcAddress;
extern void *runtime·GetLastError;
#define runtime·goargs runtime·windows_goargs #define runtime·goargs runtime·windows_goargs
void runtime·windows_goargs(void); void runtime·windows_goargs(void);

View File

@ -5,7 +5,15 @@
#include "runtime.h" #include "runtime.h"
#include "os.h" #include "os.h"
extern void *runtime·get_kernel_module(void); #pragma dynimport runtime·LoadLibraryEx LoadLibraryExA "kernel32.dll"
#pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll"
#pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll"
#pragma dynimport runtime·ExitProcess ExitProcess "kernel32.dll"
#pragma dynimport runtime·GetStdHandle GetStdHandle "kernel32.dll"
#pragma dynimport runtime·SetEvent SetEvent "kernel32.dll"
#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll"
#pragma dynimport runtime·GetLastError GetLastError "kernel32.dll"
#pragma dynimport runtime·SetLastError SetLastError "kernel32.dll"
// Also referenced by external packages // Also referenced by external packages
void *runtime·CloseHandle; void *runtime·CloseHandle;
@ -13,71 +21,37 @@ void *runtime·ExitProcess;
void *runtime·GetStdHandle; void *runtime·GetStdHandle;
void *runtime·SetEvent; void *runtime·SetEvent;
void *runtime·WriteFile; void *runtime·WriteFile;
void *runtime·VirtualAlloc;
void *runtime·VirtualFree;
void *runtime·LoadLibraryEx; void *runtime·LoadLibraryEx;
void *runtime·GetProcAddress; void *runtime·GetProcAddress;
void *runtime·GetLastError; void *runtime·GetLastError;
void *runtime·SetLastError; void *runtime·SetLastError;
static void *CreateEvent; #pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll"
static void *CreateThread; #pragma dynimport runtime·CreateThread CreateThread "kernel32.dll"
static void *WaitForSingleObject; #pragma dynimport runtime·GetModuleHandle GetModuleHandleA "kernel32.dll"
#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll"
static void* void *runtime·CreateEvent;
get_proc_addr2(byte *base, byte *name) void *runtime·CreateThread;
{ void *runtime·GetModuleHandle;
byte *pe_header, *exports; void *runtime·WaitForSingleObject;
uint32 entries, *addr, *names, i;
uint16 *ordinals;
pe_header = base+*(uint32*)(base+0x3c);
exports = base+*(uint32*)(pe_header+0x78);
entries = *(uint32*)(exports+0x18);
addr = (uint32*)(base+*(uint32*)(exports+0x1c));
names = (uint32*)(base+*(uint32*)(exports+0x20));
ordinals = (uint16*)(base+*(uint32*)(exports+0x24));
for(i=0; i<entries; i++) {
byte *s = base+names[i];
if(runtime·strcmp(name, s) == 0)
break;
}
if(i == entries)
return 0;
return base+addr[ordinals[i]];
}
void void
runtime·osinit(void) runtime·osinit(void)
{ {
void *base;
base = runtime·get_kernel_module();
runtime·GetProcAddress = get_proc_addr2(base, (byte*)"GetProcAddress");
runtime·LoadLibraryEx = get_proc_addr2(base, (byte*)"LoadLibraryExA");
runtime·CloseHandle = runtime·get_proc_addr("kernel32.dll", "CloseHandle");
CreateEvent = runtime·get_proc_addr("kernel32.dll", "CreateEventA");
CreateThread = runtime·get_proc_addr("kernel32.dll", "CreateThread");
runtime·ExitProcess = runtime·get_proc_addr("kernel32.dll", "ExitProcess");
runtime·GetStdHandle = runtime·get_proc_addr("kernel32.dll", "GetStdHandle");
runtime·SetEvent = runtime·get_proc_addr("kernel32.dll", "SetEvent");
runtime·VirtualAlloc = runtime·get_proc_addr("kernel32.dll", "VirtualAlloc");
runtime·VirtualFree = runtime·get_proc_addr("kernel32.dll", "VirtualFree");
WaitForSingleObject = runtime·get_proc_addr("kernel32.dll", "WaitForSingleObject");
runtime·WriteFile = runtime·get_proc_addr("kernel32.dll", "WriteFile");
runtime·GetLastError = runtime·get_proc_addr("kernel32.dll", "GetLastError");
runtime·SetLastError = runtime·get_proc_addr("kernel32.dll", "SetLastError");
} }
// The arguments are strings. #pragma dynimport runtime·GetCommandLine GetCommandLineW "kernel32.dll"
void* #pragma dynimport runtime·CommandLineToArgv CommandLineToArgvW "shell32.dll"
runtime·get_proc_addr(void *library, void *name) #pragma dynimport runtime·GetEnvironmentStrings GetEnvironmentStringsW "kernel32.dll"
{ #pragma dynimport runtime·FreeEnvironmentStrings FreeEnvironmentStringsW "kernel32.dll"
void *base; #pragma dynimport runtime·LocalFree LocalFree "kernel32.dll"
base = runtime·stdcall(runtime·LoadLibraryEx, 3, library, 0, 0); void *runtime·GetCommandLine;
return runtime·stdcall(runtime·GetProcAddress, 2, base, name); void *runtime·CommandLineToArgv;
} void *runtime·GetEnvironmentStrings;
void *runtime·FreeEnvironmentStrings;
void *runtime·LocalFree;
void void
runtime·windows_goargs(void) runtime·windows_goargs(void)
@ -85,22 +59,15 @@ runtime·windows_goargs(void)
extern Slice os·Args; extern Slice os·Args;
extern Slice os·Envs; extern Slice os·Envs;
void *gcl, *clta, *ges, *fes, *lf;
uint16 *cmd, *env, **argv; uint16 *cmd, *env, **argv;
String *gargv; String *gargv;
String *genvv; String *genvv;
int32 i, argc, envc; int32 i, argc, envc;
uint16 *envp; uint16 *envp;
gcl = runtime·get_proc_addr("kernel32.dll", "GetCommandLineW"); cmd = runtime·stdcall(runtime·GetCommandLine, 0);
clta = runtime·get_proc_addr("shell32.dll", "CommandLineToArgvW"); env = runtime·stdcall(runtime·GetEnvironmentStrings, 0);
ges = runtime·get_proc_addr("kernel32.dll", "GetEnvironmentStringsW"); argv = runtime·stdcall(runtime·CommandLineToArgv, 2, cmd, &argc);
lf = runtime·get_proc_addr("kernel32.dll", "LocalFree");
fes = runtime·get_proc_addr("kernel32.dll", "FreeEnvironmentStringsW");
cmd = runtime·stdcall(gcl, 0);
env = runtime·stdcall(ges, 0);
argv = runtime·stdcall(clta, 2, cmd, &argc);
envc = 0; envc = 0;
for(envp=env; *envp; envc++) for(envp=env; *envp; envc++)
@ -124,8 +91,8 @@ runtime·windows_goargs(void)
os·Envs.len = envc; os·Envs.len = envc;
os·Envs.cap = envc; os·Envs.cap = envc;
runtime·stdcall(lf, 1, argv); runtime·stdcall(runtime·LocalFree, 1, argv);
runtime·stdcall(fes, 1, env); runtime·stdcall(runtime·FreeEnvironmentStrings, 1, env);
} }
void void
@ -161,7 +128,7 @@ initevent(void **pevent)
{ {
void *event; void *event;
event = runtime·stdcall(CreateEvent, 4, 0, 0, 0, 0); event = runtime·stdcall(runtime·CreateEvent, 4, 0, 0, 0, 0);
if(!runtime·casp(pevent, 0, event)) { if(!runtime·casp(pevent, 0, event)) {
// Someone else filled it in. Use theirs. // Someone else filled it in. Use theirs.
runtime·stdcall(runtime·CloseHandle, 1, event); runtime·stdcall(runtime·CloseHandle, 1, event);
@ -176,7 +143,7 @@ eventlock(Lock *l)
initevent(&l->event); initevent(&l->event);
if(runtime·xadd(&l->key, 1) > 1) // someone else has it; wait if(runtime·xadd(&l->key, 1) > 1) // someone else has it; wait
runtime·stdcall(WaitForSingleObject, 2, l->event, -1); runtime·stdcall(runtime·WaitForSingleObject, 2, l->event, -1);
} }
static void static void
@ -237,7 +204,7 @@ runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
USED(g); // assuming g = m->g0 USED(g); // assuming g = m->g0
USED(fn); // assuming fn = mstart USED(fn); // assuming fn = mstart
runtime·stdcall(CreateThread, 6, 0, 0, runtime·tstart_stdcall, m, 0, 0); runtime·stdcall(runtime·CreateThread, 6, 0, 0, runtime·tstart_stdcall, m, 0, 0);
} }
// Called to initialize a new m (including the bootstrap m). // Called to initialize a new m (including the bootstrap m).