From 70deac67cfa559cff70f040b0f4ff0ea674fd1e8 Mon Sep 17 00:00:00 2001 From: Wei Guangjing Date: Tue, 7 Dec 2010 15:28:33 -0500 Subject: [PATCH] 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 --- src/cmd/8l/asm.c | 1 + src/cmd/8l/l.h | 1 + src/cmd/8l/obj.c | 2 + src/cmd/ld/pe.c | 207 +++++++++++++++++++++++------- src/cmd/ld/pe.h | 2 + src/pkg/runtime/windows/386/sys.s | 8 -- src/pkg/runtime/windows/mem.c | 5 + src/pkg/runtime/windows/os.h | 8 -- src/pkg/runtime/windows/thread.c | 103 +++++---------- 9 files changed, 206 insertions(+), 131 deletions(-) diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c index 3900dd2a1fa..956a2fe6e45 100644 --- a/src/cmd/8l/asm.c +++ b/src/cmd/8l/asm.c @@ -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); diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h index fd0b6424480..a14a2bf2a6b 100644 --- a/src/cmd/8l/l.h +++ b/src/cmd/8l/l.h @@ -168,6 +168,7 @@ enum SRODATA, SDATA, SMACHO, /* Mach-O __nl_symbol_ptr */ + SWINDOWS, SBSS, SXREF, diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c index 1c3407206df..b6ebc1a9bff 100644 --- a/src/cmd/8l/obj.c +++ b/src/cmd/8l/obj.c @@ -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']) diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c index 953611969d1..82c6941f251 100644 --- a/src/cmd/ld/pe.c +++ b/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; ihash) { + 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); diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h index 38180052f91..f8161cc4a67 100644 --- a/src/cmd/ld/pe.h +++ b/src/cmd/ld/pe.h @@ -120,3 +120,5 @@ enum { void peinit(void); void asmbpe(void); +void dope(void); + diff --git a/src/pkg/runtime/windows/386/sys.s b/src/pkg/runtime/windows/386/sys.s index c191feb61db..7f99b34de86 100644 --- a/src/pkg/runtime/windows/386/sys.s +++ b/src/pkg/runtime/windows/386/sys.s @@ -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. diff --git a/src/pkg/runtime/windows/mem.c b/src/pkg/runtime/windows/mem.c index c113c40c32a..15ccd9551d6 100644 --- a/src/pkg/runtime/windows/mem.c +++ b/src/pkg/runtime/windows/mem.c @@ -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) { diff --git a/src/pkg/runtime/windows/os.h b/src/pkg/runtime/windows/os.h index f247ce99661..445e5b5f454 100644 --- a/src/pkg/runtime/windows/os.h +++ b/src/pkg/runtime/windows/os.h @@ -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); diff --git a/src/pkg/runtime/windows/thread.c b/src/pkg/runtime/windows/thread.c index 6d961beea1b..9a6f121aba9 100644 --- a/src/pkg/runtime/windows/thread.c +++ b/src/pkg/runtime/windows/thread.c @@ -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; ievent); 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).