1
0
mirror of https://github.com/golang/go synced 2024-10-05 08:21:22 -06:00
go/src/pkg/runtime/windows/thread.c
Russ Cox 19fd5c787f 5l, 6l, 8l: link pclntab and symtab as ordinary rodata symbols
That is, move the pc/ln table and the symbol table
into the read-only data segment.  This eliminates
the need for a special load command to map the
symbol table into memory, which makes the
information available on systems that couldn't handle
the magic load to 0x99000000, like NaCl and ARM QEMU
and Linux without config_highmem=y.  It also
eliminates an #ifdef and some clumsy code to
find the symbol table on Windows.

The bad news is that the binary appears to be bigger
than it used to be.  This is not actually the case, though:
the same amount of data is being mapped into memory
as before, and the tables are still read-only, so they're
still shared across multiple instances of the binary as
they were before.  The difference is just that the tables
aren't squirreled away in some section that "size" doesn't
know to look at.

This is a checkpoint.
It probably breaks Windows and breaks NaCl more
than it used to be broken, but those will be fixed.
The logic involving -s needs to be revisited too.

Fixes #871.

R=ken2
CC=golang-dev
https://golang.org/cl/2587041
2010-10-19 18:07:19 -04:00

269 lines
5.4 KiB
C

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "runtime.h"
#include "os.h"
extern void *get_kernel_module(void);
// Also referenced by external packages
void *CloseHandle;
void *ExitProcess;
void *GetStdHandle;
void *SetEvent;
void *WriteFile;
void *VirtualAlloc;
void *VirtualFree;
void *LoadLibraryEx;
void *GetProcAddress;
void *GetLastError;
void *SetLastError;
static void *CreateEvent;
static void *CreateThread;
static void *WaitForSingleObject;
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(!strcmp(name, s))
break;
}
if(i == entries)
return 0;
return base+addr[ordinals[i]];
}
void
osinit(void)
{
void *base;
base = get_kernel_module();
GetProcAddress = get_proc_addr2(base, (byte*)"GetProcAddress");
LoadLibraryEx = get_proc_addr2(base, (byte*)"LoadLibraryExA");
CloseHandle = get_proc_addr("kernel32.dll", "CloseHandle");
CreateEvent = get_proc_addr("kernel32.dll", "CreateEventA");
CreateThread = get_proc_addr("kernel32.dll", "CreateThread");
ExitProcess = get_proc_addr("kernel32.dll", "ExitProcess");
GetStdHandle = get_proc_addr("kernel32.dll", "GetStdHandle");
SetEvent = get_proc_addr("kernel32.dll", "SetEvent");
VirtualAlloc = get_proc_addr("kernel32.dll", "VirtualAlloc");
VirtualFree = get_proc_addr("kernel32.dll", "VirtualFree");
WaitForSingleObject = get_proc_addr("kernel32.dll", "WaitForSingleObject");
WriteFile = get_proc_addr("kernel32.dll", "WriteFile");
GetLastError = get_proc_addr("kernel32.dll", "GetLastError");
SetLastError = get_proc_addr("kernel32.dll", "SetLastError");
}
// The arguments are strings.
void*
get_proc_addr(void *library, void *name)
{
void *base;
base = stdcall(LoadLibraryEx, 3, library, 0, 0);
return stdcall(GetProcAddress, 2, base, name);
}
void
windows_goargs(void)
{
extern Slice os·Args;
extern Slice os·Envs;
void *gcl, *clta, *ges, *fes;
uint16 *cmd, *env, **argv;
String *gargv;
String *genvv;
int32 i, argc, envc;
uint16 *envp;
gcl = get_proc_addr("kernel32.dll", "GetCommandLineW");
clta = get_proc_addr("shell32.dll", "CommandLineToArgvW");
ges = get_proc_addr("kernel32.dll", "GetEnvironmentStringsW");
fes = get_proc_addr("kernel32.dll", "FreeEnvironmentStringsW");
cmd = stdcall(gcl, 0);
env = stdcall(ges, 0);
argv = stdcall(clta, 2, cmd, &argc);
envc = 0;
for(envp=env; *envp; envc++)
envp += findnullw(envp)+1;
gargv = malloc(argc*sizeof gargv[0]);
genvv = malloc(envc*sizeof genvv[0]);
for(i=0; i<argc; i++)
gargv[i] = gostringw(argv[i]);
os·Args.array = (byte*)gargv;
os·Args.len = argc;
os·Args.cap = argc;
envp = env;
for(i=0; i<envc; i++) {
genvv[i] = gostringw(envp);
envp += findnullw(envp)+1;
}
os·Envs.array = (byte*)genvv;
os·Envs.len = envc;
os·Envs.cap = envc;
stdcall(fes, 1, env);
}
void
exit(int32 code)
{
stdcall(ExitProcess, 1, code);
}
int32
write(int32 fd, void *buf, int32 n)
{
void *handle;
uint32 written;
written = 0;
switch(fd) {
case 1:
handle = stdcall(GetStdHandle, 1, -11);
break;
case 2:
handle = stdcall(GetStdHandle, 1, -12);
break;
default:
return -1;
}
stdcall(WriteFile, 5, handle, buf, n, &written, 0);
return written;
}
// Thread-safe allocation of an event.
static void
initevent(void **pevent)
{
void *event;
event = stdcall(CreateEvent, 4, 0, 0, 0, 0);
if(!casp(pevent, 0, event)) {
// Someone else filled it in. Use theirs.
stdcall(CloseHandle, 1, event);
}
}
static void
eventlock(Lock *l)
{
// Allocate event if needed.
if(l->event == 0)
initevent(&l->event);
if(xadd(&l->key, 1) > 1) // someone else has it; wait
stdcall(WaitForSingleObject, 2, l->event, -1);
}
static void
eventunlock(Lock *l)
{
if(xadd(&l->key, -1) > 0) // someone else is waiting
stdcall(SetEvent, 1, l->event);
}
void
lock(Lock *l)
{
if(m->locks < 0)
throw("lock count");
m->locks++;
eventlock(l);
}
void
unlock(Lock *l)
{
m->locks--;
if(m->locks < 0)
throw("lock count");
eventunlock(l);
}
void
destroylock(Lock *l)
{
if(l->event != 0)
stdcall(CloseHandle, 1, l->event);
}
void
noteclear(Note *n)
{
eventlock(&n->lock);
}
void
notewakeup(Note *n)
{
eventunlock(&n->lock);
}
void
notesleep(Note *n)
{
eventlock(&n->lock);
eventunlock(&n->lock); // Let other sleepers find out too.
}
void
newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
USED(stk);
USED(g); // assuming g = m->g0
USED(fn); // assuming fn = mstart
stdcall(CreateThread, 6, 0, 0, tstart_stdcall, m, 0, 0);
}
// Called to initialize a new m (including the bootstrap m).
void
minit(void)
{
}
// Calling stdcall on os stack.
#pragma textflag 7
void *
stdcall(void *fn, int32 count, ...)
{
return stdcall_raw(fn, count, (uintptr*)(&count + 1));
}
void
syscall(StdcallParams *p)
{
uintptr a;
·entersyscall();
// TODO(brainman): Move calls to SetLastError and GetLastError
// to stdcall_raw to speed up syscall.
a = 0;
stdcall_raw(SetLastError, 1, &a);
p->r = (uintptr)stdcall_raw((void*)p->fn, p->n, p->args);
p->err = (uintptr)stdcall_raw(GetLastError, 0, &a);
·exitsyscall();
}