mirror of
https://github.com/golang/go
synced 2024-11-20 10:04:45 -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:
parent
836643400c
commit
70deac67cf
@ -820,6 +820,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
|
||||
case SDATA:
|
||||
case SELFDATA:
|
||||
case SMACHO:
|
||||
case SWINDOWS:
|
||||
if(!s->reachable)
|
||||
continue;
|
||||
put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype);
|
||||
|
@ -168,6 +168,7 @@ enum
|
||||
SRODATA,
|
||||
SDATA,
|
||||
SMACHO, /* Mach-O __nl_symbol_ptr */
|
||||
SWINDOWS,
|
||||
SBSS,
|
||||
|
||||
SXREF,
|
||||
|
@ -320,6 +320,8 @@ main(int argc, char *argv[])
|
||||
doelf();
|
||||
if(HEADTYPE == 6)
|
||||
domacho();
|
||||
if(HEADTYPE == 10)
|
||||
dope();
|
||||
dostkoff();
|
||||
if(debug['p'])
|
||||
if(debug['1'])
|
||||
|
207
src/cmd/ld/pe.c
207
src/cmd/ld/pe.c
@ -45,6 +45,25 @@ static IMAGE_FILE_HEADER fh;
|
||||
static IMAGE_OPTIONAL_HEADER oh;
|
||||
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*
|
||||
addpesection(char *name, int sectsize, int filesize, Segment *s)
|
||||
{
|
||||
@ -122,66 +141,160 @@ strput(char *s)
|
||||
cput('\0');
|
||||
}
|
||||
|
||||
static void
|
||||
addimports(vlong fileoff)
|
||||
static Dll*
|
||||
initdynimport(void)
|
||||
{
|
||||
IMAGE_IMPORT_DESCRIPTOR ds[2], *d;
|
||||
char *dllname = "kernel32.dll";
|
||||
struct {
|
||||
char *name;
|
||||
uint32 thunk;
|
||||
} *f, fs[] = {
|
||||
{ "GetProcAddress", 0 },
|
||||
{ "LoadLibraryExA", 0 },
|
||||
{ 0, 0 }
|
||||
};
|
||||
Imp *m;
|
||||
Dll *d;
|
||||
Sym *s;
|
||||
int i;
|
||||
Sym *dynamic;
|
||||
|
||||
uint32 size = 0;
|
||||
memset(ds, 0, sizeof(ds));
|
||||
size += sizeof(ds);
|
||||
ds[0].Name = size;
|
||||
size += strlen(dllname) + 1;
|
||||
for(f=fs; f->name; f++) {
|
||||
f->thunk = size;
|
||||
size += sizeof(uint16) + strlen(f->name) + 1;
|
||||
dr = nil;
|
||||
ndll = 0;
|
||||
nimp = 0;
|
||||
nsize = 0;
|
||||
|
||||
for(i=0; i<NHASH; i++)
|
||||
for(s = hash[i]; s != S; s = s->hash) {
|
||||
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;
|
||||
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|
|
||||
IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
|
||||
|
||||
uint32 va = isect->VirtualAddress;
|
||||
va = isect->VirtualAddress;
|
||||
oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = va;
|
||||
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);
|
||||
for(d=ds; ; d++) {
|
||||
lputl(d->OriginalFirstThunk);
|
||||
lputl(d->TimeDateStamp);
|
||||
lputl(d->ForwarderChain);
|
||||
lputl(d->Name);
|
||||
lputl(d->FirstThunk);
|
||||
if(!d->Name)
|
||||
break;
|
||||
|
||||
dynamic = lookup(".windynamic", 0);
|
||||
iat_off = dynamic->value - PEBASE; // FirstThunk allocated in .data
|
||||
oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = iat_off;
|
||||
oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size;
|
||||
|
||||
noff = va + 20*ndll + 20;
|
||||
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);
|
||||
for(f=fs; f->name; f++) {
|
||||
wputl(0);
|
||||
strput(f->name);
|
||||
lputl(0); //end
|
||||
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);
|
||||
}
|
||||
for(f=fs; f->name; f++)
|
||||
lputl(f->thunk);
|
||||
strnput("", isect->SizeOfRawData - size);
|
||||
// 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);
|
||||
strput(m->s->dynimpname);
|
||||
}
|
||||
}
|
||||
|
||||
strnput("", isect->SizeOfRawData - nsize);
|
||||
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
|
||||
@ -210,7 +323,7 @@ asmbpe(void)
|
||||
d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
|
||||
IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
|
||||
|
||||
addimports(nextfileoff);
|
||||
addimports(nextfileoff, d);
|
||||
|
||||
fh.NumberOfSections = nsect;
|
||||
fh.TimeDateStamp = time(0);
|
||||
|
@ -120,3 +120,5 @@ enum {
|
||||
|
||||
void peinit(void);
|
||||
void asmbpe(void);
|
||||
void dope(void);
|
||||
|
||||
|
@ -4,14 +4,6 @@
|
||||
|
||||
#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)
|
||||
TEXT runtime·stdcall_raw(SB),7,$4
|
||||
// Copy arguments from stack.
|
||||
|
@ -25,6 +25,11 @@ abort(int8 *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*
|
||||
runtime·SysAlloc(uintptr n)
|
||||
{
|
||||
|
@ -2,16 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// 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·GetProcAddress;
|
||||
extern void *runtime·GetLastError;
|
||||
|
||||
#define runtime·goargs runtime·windows_goargs
|
||||
void runtime·windows_goargs(void);
|
||||
|
@ -5,7 +5,15 @@
|
||||
#include "runtime.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
|
||||
void *runtime·CloseHandle;
|
||||
@ -13,71 +21,37 @@ void *runtime·ExitProcess;
|
||||
void *runtime·GetStdHandle;
|
||||
void *runtime·SetEvent;
|
||||
void *runtime·WriteFile;
|
||||
void *runtime·VirtualAlloc;
|
||||
void *runtime·VirtualFree;
|
||||
void *runtime·LoadLibraryEx;
|
||||
void *runtime·GetProcAddress;
|
||||
void *runtime·GetLastError;
|
||||
void *runtime·SetLastError;
|
||||
|
||||
static void *CreateEvent;
|
||||
static void *CreateThread;
|
||||
static void *WaitForSingleObject;
|
||||
#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll"
|
||||
#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll"
|
||||
#pragma dynimport runtime·GetModuleHandle GetModuleHandleA "kernel32.dll"
|
||||
#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll"
|
||||
|
||||
static void*
|
||||
get_proc_addr2(byte *base, byte *name)
|
||||
{
|
||||
byte *pe_header, *exports;
|
||||
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 *runtime·CreateEvent;
|
||||
void *runtime·CreateThread;
|
||||
void *runtime·GetModuleHandle;
|
||||
void *runtime·WaitForSingleObject;
|
||||
|
||||
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.
|
||||
void*
|
||||
runtime·get_proc_addr(void *library, void *name)
|
||||
{
|
||||
void *base;
|
||||
#pragma dynimport runtime·GetCommandLine GetCommandLineW "kernel32.dll"
|
||||
#pragma dynimport runtime·CommandLineToArgv CommandLineToArgvW "shell32.dll"
|
||||
#pragma dynimport runtime·GetEnvironmentStrings GetEnvironmentStringsW "kernel32.dll"
|
||||
#pragma dynimport runtime·FreeEnvironmentStrings FreeEnvironmentStringsW "kernel32.dll"
|
||||
#pragma dynimport runtime·LocalFree LocalFree "kernel32.dll"
|
||||
|
||||
base = runtime·stdcall(runtime·LoadLibraryEx, 3, library, 0, 0);
|
||||
return runtime·stdcall(runtime·GetProcAddress, 2, base, name);
|
||||
}
|
||||
void *runtime·GetCommandLine;
|
||||
void *runtime·CommandLineToArgv;
|
||||
void *runtime·GetEnvironmentStrings;
|
||||
void *runtime·FreeEnvironmentStrings;
|
||||
void *runtime·LocalFree;
|
||||
|
||||
void
|
||||
runtime·windows_goargs(void)
|
||||
@ -85,22 +59,15 @@ runtime·windows_goargs(void)
|
||||
extern Slice os·Args;
|
||||
extern Slice os·Envs;
|
||||
|
||||
void *gcl, *clta, *ges, *fes, *lf;
|
||||
uint16 *cmd, *env, **argv;
|
||||
String *gargv;
|
||||
String *genvv;
|
||||
int32 i, argc, envc;
|
||||
uint16 *envp;
|
||||
|
||||
gcl = runtime·get_proc_addr("kernel32.dll", "GetCommandLineW");
|
||||
clta = runtime·get_proc_addr("shell32.dll", "CommandLineToArgvW");
|
||||
ges = runtime·get_proc_addr("kernel32.dll", "GetEnvironmentStringsW");
|
||||
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);
|
||||
cmd = runtime·stdcall(runtime·GetCommandLine, 0);
|
||||
env = runtime·stdcall(runtime·GetEnvironmentStrings, 0);
|
||||
argv = runtime·stdcall(runtime·CommandLineToArgv, 2, cmd, &argc);
|
||||
|
||||
envc = 0;
|
||||
for(envp=env; *envp; envc++)
|
||||
@ -124,8 +91,8 @@ runtime·windows_goargs(void)
|
||||
os·Envs.len = envc;
|
||||
os·Envs.cap = envc;
|
||||
|
||||
runtime·stdcall(lf, 1, argv);
|
||||
runtime·stdcall(fes, 1, env);
|
||||
runtime·stdcall(runtime·LocalFree, 1, argv);
|
||||
runtime·stdcall(runtime·FreeEnvironmentStrings, 1, env);
|
||||
}
|
||||
|
||||
void
|
||||
@ -161,7 +128,7 @@ initevent(void **pevent)
|
||||
{
|
||||
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)) {
|
||||
// Someone else filled it in. Use theirs.
|
||||
runtime·stdcall(runtime·CloseHandle, 1, event);
|
||||
@ -176,7 +143,7 @@ eventlock(Lock *l)
|
||||
initevent(&l->event);
|
||||
|
||||
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
|
||||
@ -237,7 +204,7 @@ runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
|
||||
USED(g); // assuming g = m->g0
|
||||
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).
|
||||
|
Loading…
Reference in New Issue
Block a user