summaryrefslogtreecommitdiff
path: root/src/cmd/ld
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/ld')
-rw-r--r--src/cmd/ld/data.c6
-rw-r--r--src/cmd/ld/dwarf.c42
-rw-r--r--src/cmd/ld/go.c33
-rw-r--r--src/cmd/ld/lib.c207
-rw-r--r--src/cmd/ld/lib.h37
-rw-r--r--src/cmd/ld/macho.c7
-rw-r--r--src/cmd/ld/pe.c8
-rw-r--r--src/cmd/ld/pe.h3
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);