diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-04-20 15:44:41 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-04-20 15:44:41 +0200 |
commit | 50104cc32a498f7517a51c8dc93106c51c7a54b4 (patch) | |
tree | 47af80be259cc7c45d0eaec7d42e61fa38c8e4fb /src/cmd/ld | |
parent | c072558b90f1bbedc2022b0f30c8b1ac4712538e (diff) | |
download | golang-upstream/2011.03.07.1.tar.gz |
Imported Upstream version 2011.03.07.1upstream/2011.03.07.1
Diffstat (limited to 'src/cmd/ld')
-rw-r--r-- | src/cmd/ld/data.c | 6 | ||||
-rw-r--r-- | src/cmd/ld/dwarf.c | 42 | ||||
-rw-r--r-- | src/cmd/ld/go.c | 33 | ||||
-rw-r--r-- | src/cmd/ld/lib.c | 207 | ||||
-rw-r--r-- | src/cmd/ld/lib.h | 37 | ||||
-rw-r--r-- | src/cmd/ld/macho.c | 7 | ||||
-rw-r--r-- | src/cmd/ld/pe.c | 8 | ||||
-rw-r--r-- | src/cmd/ld/pe.h | 3 |
8 files changed, 312 insertions, 31 deletions
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index 0551232cf..a20b057ce 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -241,7 +241,7 @@ dynrelocsym(Sym *s) { Reloc *r; - if(thechar == '8' && HEADTYPE == 10) { // Windows PE + if(HEADTYPE == Hwindows) { Sym *rel, *targ; rel = lookup(".rel", 0); @@ -898,9 +898,9 @@ address(void) segdata.rwx = 06; segdata.vaddr = va; segdata.fileoff = va - segtext.vaddr + segtext.fileoff; - if((thechar == '6' || thechar == '8') && HEADTYPE == 10) // Windows PE + if(HEADTYPE == Hwindows) segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN); - if(thechar == '8' && HEADTYPE == 2) { // Plan 9 + if(HEADTYPE == Hplan9x32) { segdata.vaddr = va = rnd(va, 4096); segdata.fileoff = segtext.fileoff + segtext.filelen; } diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c index 5df3515f5..5ba4b7c64 100644 --- a/src/cmd/ld/dwarf.c +++ b/src/cmd/ld/dwarf.c @@ -772,6 +772,9 @@ enum { KindUnsafePointer, KindNoPointers = 1<<7, + + // size of Type interface header + CommonType structure. + CommonSize = 2*PtrSize+ 4*PtrSize + 8, }; static Reloc* @@ -849,59 +852,59 @@ decodetype_size(Sym *s) static Sym* decodetype_arrayelem(Sym *s) { - return decode_reloc_sym(s, 5*PtrSize + 8); // 0x1c / 0x30 + return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 } static vlong decodetype_arraylen(Sym *s) { - return decode_inuxi(s->p + 6*PtrSize + 8, PtrSize); + return decode_inuxi(s->p + CommonSize+PtrSize, PtrSize); } // Type.PtrType.elem static Sym* decodetype_ptrelem(Sym *s) { - return decode_reloc_sym(s, 5*PtrSize + 8); // 0x1c / 0x30 + return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 } // Type.MapType.key, elem static Sym* decodetype_mapkey(Sym *s) { - return decode_reloc_sym(s, 5*PtrSize + 8); // 0x1c / 0x30 + return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 } static Sym* decodetype_mapvalue(Sym *s) { - return decode_reloc_sym(s, 6*PtrSize + 8); // 0x20 / 0x38 + return decode_reloc_sym(s, CommonSize+PtrSize); // 0x20 / 0x38 } // Type.ChanType.elem static Sym* decodetype_chanelem(Sym *s) { - return decode_reloc_sym(s, 5*PtrSize + 8); // 0x1c / 0x30 + return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 } // Type.FuncType.dotdotdot static int decodetype_funcdotdotdot(Sym *s) { - return s->p[5*PtrSize + 8]; + return s->p[CommonSize]; } // Type.FuncType.in.len static int decodetype_funcincount(Sym *s) { - return decode_inuxi(s->p + 7*PtrSize + 8, 4); + return decode_inuxi(s->p + CommonSize+2*PtrSize, 4); } static int decodetype_funcoutcount(Sym *s) { - return decode_inuxi(s->p + 8*PtrSize + 16, 4); + return decode_inuxi(s->p + CommonSize+3*PtrSize + 2*4, 4); } static Sym* @@ -909,7 +912,7 @@ decodetype_funcintype(Sym *s, int i) { Reloc *r; - r = decode_reloc(s, 6*PtrSize + 8); + r = decode_reloc(s, CommonSize + PtrSize); if (r == nil) return nil; return decode_reloc_sym(r->sym, r->add + i * PtrSize); @@ -920,7 +923,7 @@ decodetype_funcouttype(Sym *s, int i) { Reloc *r; - r = decode_reloc(s, 7*PtrSize + 16); + r = decode_reloc(s, CommonSize + 2*PtrSize + 2*4); if (r == nil) return nil; return decode_reloc_sym(r->sym, r->add + i * PtrSize); @@ -930,15 +933,18 @@ decodetype_funcouttype(Sym *s, int i) static int decodetype_structfieldcount(Sym *s) { - return decode_inuxi(s->p + 6*PtrSize + 8, 4); // 0x20 / 0x38 + return decode_inuxi(s->p + CommonSize + PtrSize, 4); } -// Type.StructType.fields[]-> name, typ and offset. sizeof(structField) = 5*PtrSize +enum { + StructFieldSize = 5*PtrSize +}; +// Type.StructType.fields[]-> name, typ and offset. static char* decodetype_structfieldname(Sym *s, int i) { // go.string."foo" 0x28 / 0x40 - s = decode_reloc_sym(s, 6*PtrSize + 0x10 + i*5*PtrSize); + s = decode_reloc_sym(s, CommonSize + PtrSize + 2*4 + i*StructFieldSize); if (s == nil) // embedded structs have a nil name. return nil; s = decode_reloc_sym(s, 0); // string."foo" @@ -950,20 +956,20 @@ decodetype_structfieldname(Sym *s, int i) static Sym* decodetype_structfieldtype(Sym *s, int i) { - return decode_reloc_sym(s, 8*PtrSize + 0x10 + i*5*PtrSize); // 0x30 / 0x50 + return decode_reloc_sym(s, CommonSize + PtrSize + 2*4 + i*StructFieldSize + 2*PtrSize); } static vlong decodetype_structfieldoffs(Sym *s, int i) { - return decode_inuxi(s->p + 10*PtrSize + 0x10 + i*5*PtrSize, 4); // 0x38 / 0x60 + return decode_inuxi(s->p + CommonSize + PtrSize + 2*4 + i*StructFieldSize + 4*PtrSize, 4); } // InterfaceTYpe.methods.len static vlong decodetype_ifacemethodcount(Sym *s) { - return decode_inuxi(s->p + 6*PtrSize + 8, 4); + return decode_inuxi(s->p + CommonSize + PtrSize, 4); } @@ -2302,7 +2308,7 @@ writegdbscript(void) static void align(vlong size) { - if((thechar == '6' || thechar == '8') && HEADTYPE == 10) // Only Windows PE need section align. + if(HEADTYPE == Hwindows) // Only Windows PE need section align. strnput("", rnd(size, PEFILEALIGN) - size); } diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c index 2c6a6d084..3c1e230b4 100644 --- a/src/cmd/ld/go.c +++ b/src/cmd/ld/go.c @@ -550,6 +550,8 @@ mark(Sym *s) if(s == S || s->reachable) return; + if(strncmp(s->name, "weak.", 5) == 0) + return; s->reachable = 1; if(s->text) marktext(s); @@ -654,6 +656,37 @@ deadcode(void) textp = nil; else last->next = nil; + + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->hash) + if(strncmp(s->name, "weak.", 5) == 0) { + s->special = 1; // do not lay out in data segment + s->reachable = 1; + } +} + +void +doweak(void) +{ + int i; + Sym *s, *t; + + // resolve weak references only if + // target symbol will be in binary anyway. + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->hash) { + if(strncmp(s->name, "weak.", 5) == 0) { + t = lookup(s->name+5, s->version); + if(t->type != 0 && t->reachable) { + s->value = t->value; + s->type = t->type; + } else { + s->type = SCONST; + s->value = 0; + } + continue; + } + } } void diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index c144d4295..e645502b3 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -31,6 +31,8 @@ #include "l.h" #include "lib.h" +#include "../../pkg/runtime/stack.h" + #include <ar.h> int iconv(Fmt*); @@ -1084,3 +1086,208 @@ be64(uchar *b) Endian be = { be16, be32, be64 }; Endian le = { le16, le32, le64 }; + +typedef struct Chain Chain; +struct Chain +{ + Sym *sym; + Chain *up; + int limit; // limit on entry to sym +}; + +static int stkcheck(Chain*, int); +static void stkprint(Chain*, int); +static void stkbroke(Chain*, int); +static Sym *morestack; +static Sym *newstack; + +enum +{ + HasLinkRegister = (thechar == '5'), + CallSize = (!HasLinkRegister)*PtrSize, // bytes of stack required for a call +}; + +void +dostkcheck(void) +{ + Chain ch; + Sym *s; + + morestack = lookup("runtime.morestack", 0); + newstack = lookup("runtime.newstack", 0); + + // First the nosplits on their own. + for(s = textp; s != nil; s = s->next) { + if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) == 0) + continue; + cursym = s; + ch.up = nil; + ch.sym = s; + ch.limit = StackLimit - CallSize; + stkcheck(&ch, 0); + s->stkcheck = 1; + } + + // Check calling contexts. + // Some nosplits get called a little further down, + // like newproc and deferproc. We could hard-code + // that knowledge but it's more robust to look at + // the actual call sites. + for(s = textp; s != nil; s = s->next) { + if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) != 0) + continue; + cursym = s; + ch.up = nil; + ch.sym = s; + ch.limit = StackLimit - CallSize; + stkcheck(&ch, 0); + } +} + +static int +stkcheck(Chain *up, int depth) +{ + Chain ch, ch1; + Prog *p; + Sym *s; + int limit, prolog; + + limit = up->limit; + s = up->sym; + p = s->text; + + // Small optimization: don't repeat work at top. + if(s->stkcheck && limit == StackLimit-CallSize) + return 0; + + if(depth > 100) { + diag("nosplit stack check too deep"); + stkbroke(up, 0); + return -1; + } + + if(p == nil || p->link == nil) { + // external function. + // should never be called directly. + // only diagnose the direct caller. + if(depth == 1) + diag("call to external function %s", s->name); + return -1; + } + + if(limit < 0) { + stkbroke(up, limit); + return -1; + } + + // morestack looks like it calls functions, + // but it switches the stack pointer first. + if(s == morestack) + return 0; + + ch.up = up; + prolog = (s->text->textflag & NOSPLIT) == 0; + for(p = s->text; p != P; p = p->link) { + limit -= p->spadj; + if(prolog && p->spadj != 0) { + // The first stack adjustment in a function with a + // split-checking prologue marks the end of the + // prologue. Assuming the split check is correct, + // after the adjustment there should still be at least + // StackLimit bytes available below the stack pointer. + // If this is not the top call in the chain, no need + // to duplicate effort, so just stop. + if(depth > 0) + return 0; + prolog = 0; + limit = StackLimit; + } + if(limit < 0) { + stkbroke(up, limit); + return -1; + } + if(iscall(p)) { + limit -= CallSize; + ch.limit = limit; + if(p->to.type == D_BRANCH) { + // Direct call. + ch.sym = p->to.sym; + if(stkcheck(&ch, depth+1) < 0) + return -1; + } else { + // Indirect call. Assume it is a splitting function, + // so we have to make sure it can call morestack. + limit -= CallSize; + ch.sym = nil; + ch1.limit = limit; + ch1.up = &ch; + ch1.sym = morestack; + if(stkcheck(&ch1, depth+2) < 0) + return -1; + limit += CallSize; + } + limit += CallSize; + } + + } + return 0; +} + +static void +stkbroke(Chain *ch, int limit) +{ + diag("nosplit stack overflow"); + stkprint(ch, limit); +} + +static void +stkprint(Chain *ch, int limit) +{ + char *name; + + if(ch->sym) + name = ch->sym->name; + else + name = "function pointer"; + + if(ch->up == nil) { + // top of chain. ch->sym != nil. + if(ch->sym->text->textflag & NOSPLIT) + print("\t%d\tassumed on entry to %s\n", ch->limit, name); + else + print("\t%d\tguaranteed after split check in %s\n", ch->limit, name); + } else { + stkprint(ch->up, ch->limit + (!HasLinkRegister)*PtrSize); + if(!HasLinkRegister) + print("\t%d\ton entry to %s\n", ch->limit, name); + } + if(ch->limit != limit) + print("\t%d\tafter %s uses %d\n", limit, name, ch->limit - limit); +} + +int +headtype(char *name) +{ + int i; + + for(i=0; headers[i].name; i++) + if(strcmp(name, headers[i].name) == 0) { + headstring = headers[i].name; + return headers[i].val; + } + fprint(2, "unknown header type -H %s\n", name); + errorexit(); + return -1; // not reached +} + +void +undef(void) +{ + int i; + Sym *s; + + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->hash) + if(s->type == SXREF) + diag("%s(%d): not defined", s->name, s->version); +} diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h index 16dfb0dc3..adde2c9ff 100644 --- a/src/cmd/ld/lib.h +++ b/src/cmd/ld/lib.h @@ -74,7 +74,6 @@ extern int nlibdir; extern int cout; EXTERN char* INITENTRY; -EXTERN char thechar; EXTERN char* thestring; EXTERN Library* library; EXTERN int libraryp; @@ -167,6 +166,9 @@ void adddynlib(char*); int archreloc(Reloc*, Sym*, vlong*); void adddynsym(Sym*); void addexport(void); +void dostkcheck(void); +void undef(void); +void doweak(void); int pathchar(void); void* mal(uint32); @@ -208,3 +210,36 @@ enum { ArchiveObj, Pkgdef }; + +/* executable header types */ +enum { + Hgarbunix = 0, // garbage unix + Hnoheader, // no header + Hunixcoff, // unix coff + Hrisc, // aif for risc os + Hplan9x32, // plan 9 32-bit format + Hplan9x64, // plan 9 64-bit format + Hmsdoscom, // MS-DOS .COM + Hnetbsd, // NetBSD + Hmsdosexe, // fake MS-DOS .EXE + Hixp1200, // IXP1200 (raw) + Helf, // ELF32 + Hipaq, // ipaq + Hdarwin, // Apple Mach-O + Hlinux, // Linux ELF + Hnacl, // Google Native Client + Hfreebsd, // FreeBSD ELF + Hwindows, // MS Windows PE + Htiny // tiny (os image) +}; + +typedef struct Header Header; +struct Header { + char *name; + int val; +}; + +EXTERN char* headstring; +extern Header headers[]; + +int headtype(char*); diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c index 402e0ec63..c8d7c4a6d 100644 --- a/src/cmd/ld/macho.c +++ b/src/cmd/ld/macho.c @@ -276,7 +276,6 @@ asmbmacho(void) vlong v, w; vlong va; int a, i; - char *pkgroot; MachoHdr *mh; MachoSect *msect; MachoSeg *ms; @@ -428,12 +427,6 @@ asmbmacho(void) ml->data[0] = 12; /* offset to string */ strcpy((char*)&ml->data[1], "/usr/lib/dyld"); - if(ndylib > 0) { /* add reference to where .so files are installed */ - pkgroot = smprint("%s/pkg/%s_%s", goroot, goos, goarch); - ml = newMachoLoad(0x80000000 | 0x1c, 1+(strlen(pkgroot)+1+7)/8*2); /* LC_RPATH */ - ml->data[0] = 12; /* offset of string from beginning of load */ - strcpy((char*)&ml->data[1], pkgroot); - } for(i=0; i<ndylib; i++) { ml = newMachoLoad(12, 4+(strlen(dylib[i])+1+7)/8*2); /* LC_LOAD_DYLIB */ ml->data[0] = 24; /* offset of string from beginning of load */ diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c index 2c34daab4..e72b0b2a0 100644 --- a/src/cmd/ld/pe.c +++ b/src/cmd/ld/pe.c @@ -500,6 +500,7 @@ asmbpe(void) IMAGE_FILE_EXECUTABLE_IMAGE|IMAGE_FILE_DEBUG_STRIPPED; if (pe64) { fh.SizeOfOptionalHeader = sizeof(oh64); + fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; set(Magic, 0x20b); // PE32+ } else { fh.SizeOfOptionalHeader = sizeof(oh); @@ -525,8 +526,11 @@ asmbpe(void) set(MinorSubsystemVersion, 0); set(SizeOfImage, nextsectoff); set(SizeOfHeaders, PEFILEHEADR); - set(Subsystem, 3); // WINDOWS_CUI - set(SizeOfStackReserve, 0x00200000); + if(strcmp(headstring, "windowsgui") == 0) + set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI); + else + set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_CUI); + set(SizeOfStackReserve, 0x0040000); set(SizeOfStackCommit, 0x00001000); set(SizeOfHeapReserve, 0x00100000); set(SizeOfHeapCommit, 0x00001000); diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h index 6dbf6a5be..2180fb88c 100644 --- a/src/cmd/ld/pe.h +++ b/src/cmd/ld/pe.h @@ -131,6 +131,9 @@ enum { IMAGE_DIRECTORY_ENTRY_IAT = 12, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14, + + IMAGE_SUBSYSTEM_WINDOWS_GUI = 2, + IMAGE_SUBSYSTEM_WINDOWS_CUI = 3, }; void peinit(void); |