// Handle relocations found in ELF object files.
case 256 + R_ARM_PLT32:
r->type = D_CALL;
- if(targ->dynimpname != nil && !targ->dynexport) {
+ if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic)) {
addpltsym(targ);
r->sym = lookup(".plt", 0);
r->add = braddoff(r->add, targ->plt / 4);
return;
case 256 + R_ARM_GOT32: // R_ARM_GOT_BREL
- if(targ->dynimpname == nil || targ->dynexport) {
+ if(targ->dynimpname == nil || (targ->cgoexport & CgoExportDynamic)) {
addgotsyminternal(targ);
} else {
addgotsym(targ);
return;
case 256 + R_ARM_GOT_PREL: // GOT(S) + A - P
- if(targ->dynimpname == nil || targ->dynexport) {
+ if(targ->dynimpname == nil || (targ->cgoexport & CgoExportDynamic)) {
addgotsyminternal(targ);
} else {
addgotsym(targ);
case 256 + R_ARM_CALL:
r->type = D_CALL;
- if(targ->dynimpname != nil && !targ->dynexport) {
+ if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic)) {
addpltsym(targ);
r->sym = lookup(".plt", 0);
r->add = braddoff(r->add, targ->plt / 4);
return;
case 256 + R_ARM_ABS32:
- if(targ->dynimpname != nil && !targ->dynexport)
+ if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic))
diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ->name);
r->type = D_ADDR;
return;
case 256 + R_ARM_PC24:
case 256 + R_ARM_JUMP24:
r->type = D_CALL;
- if(targ->dynimpname != nil && !targ->dynexport) {
+ if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic)) {
addpltsym(targ);
r->sym = lookup(".plt", 0);
r->add = braddoff(r->add, targ->plt / 4);
}
// Handle references to ELF symbols from our own object files.
- if(targ->dynimpname == nil || targ->dynexport)
+ if(targ->dynimpname == nil || (targ->cgoexport & CgoExportDynamic))
return;
switch(r->type) {
/* type */
t = STB_GLOBAL << 4;
- if(s->dynexport && (s->type&SMASK) == STEXT)
+ if((s->cgoexport & CgoExportDynamic) && (s->type&SMASK) == STEXT)
t |= STT_FUNC;
else
t |= STT_OBJECT;
adduint8(d, 0);
/* shndx */
- if(!s->dynexport && s->dynimpname != nil)
+ if(!(s->cgoexport & CgoExportDynamic) && s->dynimpname != nil)
adduint16(d, SHN_UNDEF);
else {
switch(s->type) {
short version;
uchar dupok;
uchar reachable;
- uchar dynexport;
+ uchar cgoexport;
uchar leaf;
int32 dynid;
int32 plt;
INITRND = -1;
INITENTRY = 0;
LIBINITENTRY = 0;
+ linkmode = LinkInternal; // TODO: LinkAuto once everything works.
nuxiinit();
p = getgoarm();
flagcount("v", "print link trace", &debug['v']);
flagcount("w", "disable DWARF generation", &debug['w']);
flagcount("shared", "generate shared object", &flag_shared);
+ // TODO: link mode flag
flagparse(&argc, &argv, usage);
reloc();
asmb();
undef();
+ hostlink();
if(debug['c'])
print("ARM size = %d\n", armsize);
// Handle relocations found in ELF object files.
case 256 + R_X86_64_PC32:
- if(targ->dynimpname != nil && !targ->dynexport)
+ if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic))
diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ->name);
if(targ->type == 0 || targ->type == SXREF)
diag("unknown symbol %s in pcrel", targ->name);
case 256 + R_X86_64_PLT32:
r->type = D_PCREL;
r->add += 4;
- if(targ->dynimpname != nil && !targ->dynexport) {
+ if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic)) {
addpltsym(targ);
r->sym = lookup(".plt", 0);
r->add += targ->plt;
return;
case 256 + R_X86_64_GOTPCREL:
- if(targ->dynimpname == nil || targ->dynexport) {
+ if(targ->dynimpname == nil || (targ->cgoexport & CgoExportDynamic)) {
// have symbol
if(r->off >= 2 && s->p[r->off-2] == 0x8b) {
// turn MOVQ of GOT entry into LEAQ of symbol itself
return;
case 256 + R_X86_64_64:
- if(targ->dynimpname != nil && !targ->dynexport)
+ if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic))
diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ->name);
r->type = D_ADDR;
return;
case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 0:
// TODO: What is the difference between all these?
r->type = D_ADDR;
- if(targ->dynimpname != nil && !targ->dynexport)
+ if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic))
diag("unexpected reloc for dynamic symbol %s", targ->name);
return;
case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1:
- if(targ->dynimpname != nil && !targ->dynexport) {
+ if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic)) {
addpltsym(targ);
r->sym = lookup(".plt", 0);
r->add = targ->plt;
case 512 + MACHO_X86_64_RELOC_SIGNED_2*2 + 1:
case 512 + MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
r->type = D_PCREL;
- if(targ->dynimpname != nil && !targ->dynexport)
+ if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic))
diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name);
return;
case 512 + MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
- if(targ->dynimpname == nil || targ->dynexport) {
+ if(targ->dynimpname == nil || (targ->cgoexport & CgoExportDynamic)) {
// have symbol
// turn MOVQ of GOT entry into LEAQ of symbol itself
if(r->off < 2 || s->p[r->off-2] != 0x8b) {
}
// fall through
case 512 + MACHO_X86_64_RELOC_GOT*2 + 1:
- if(targ->dynimpname == nil || targ->dynexport)
+ if(targ->dynimpname == nil || (targ->cgoexport & CgoExportDynamic))
diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
addgotsym(targ);
r->type = D_PCREL;
}
// Handle references to ELF symbols from our own object files.
- if(targ->dynimpname == nil || targ->dynexport)
+ if(targ->dynimpname == nil || (targ->cgoexport & CgoExportDynamic))
return;
switch(r->type) {
adduint32(d, addstring(lookup(".dynstr", 0), name));
/* type */
t = STB_GLOBAL << 4;
- if(s->dynexport && (s->type&SMASK) == STEXT)
+ if((s->cgoexport & CgoExportDynamic) && (s->type&SMASK) == STEXT)
t |= STT_FUNC;
else
t |= STT_OBJECT;
adduint8(d, 0);
/* section where symbol is defined */
- if(!s->dynexport && s->dynimpname != nil)
+ if(!(s->cgoexport & CgoExportDynamic) && s->dynimpname != nil)
adduint16(d, SHN_UNDEF);
else {
switch(s->type) {
/* size of object */
adduint64(d, s->size);
- if(!s->dynexport && s->dynimplib && needlib(s->dynimplib)) {
+ if(!(s->cgoexport & CgoExportDynamic) && s->dynimplib && needlib(s->dynimplib)) {
elfwritedynent(lookup(".dynamic", 0), DT_NEEDED,
addstring(lookup(".dynstr", 0), s->dynimplib));
}
short version;
uchar dupok;
uchar reachable;
- uchar dynexport;
+ uchar cgoexport;
uchar special;
uchar stkcheck;
uchar hide;
INITRND = -1;
INITENTRY = 0;
LIBINITENTRY = 0;
+ linkmode = LinkInternal; // TODO: LinkAuto once everything works.
nuxiinit();
flagcount("1", "use alternate profiling code", &debug['1']);
flagcount("shared", "generate shared object", &flag_shared);
flagparse(&argc, &argv, usage);
+
+ // TODO: link mode flag instead of isobj
+ if(isobj)
+ linkmode = LinkExternal;
if(argc != 1)
usage();
reloc();
asmb();
undef();
+ hostlink();
if(debug['v']) {
Bprint(&bso, "%5.2f cpu time\n", cputime());
Bprint(&bso, "%d symbols\n", nsymbol);
// Handle relocations found in ELF object files.
case 256 + R_386_PC32:
- if(targ->dynimpname != nil && !targ->dynexport)
+ if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic))
diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ->name);
if(targ->type == 0 || targ->type == SXREF)
diag("unknown symbol %s in pcrel", targ->name);
case 256 + R_386_PLT32:
r->type = D_PCREL;
r->add += 4;
- if(targ->dynimpname != nil && !targ->dynexport) {
+ if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic)) {
addpltsym(targ);
r->sym = lookup(".plt", 0);
r->add += targ->plt;
return;
case 256 + R_386_GOT32:
- if(targ->dynimpname == nil || targ->dynexport) {
+ if(targ->dynimpname == nil || (targ->cgoexport & CgoExportDynamic)) {
// have symbol
// turn MOVL of GOT entry into LEAL of symbol itself
if(r->off < 2 || s->p[r->off-2] != 0x8b) {
return;
case 256 + R_386_32:
- if(targ->dynimpname != nil && !targ->dynexport)
+ if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic))
diag("unexpected R_386_32 relocation for dynamic symbol %s", targ->name);
r->type = D_ADDR;
return;
case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 0:
r->type = D_ADDR;
- if(targ->dynimpname != nil && !targ->dynexport)
+ if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic))
diag("unexpected reloc for dynamic symbol %s", targ->name);
return;
case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1:
- if(targ->dynimpname != nil && !targ->dynexport) {
+ if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic)) {
addpltsym(targ);
r->sym = lookup(".plt", 0);
r->add = targ->plt;
return;
case 512 + MACHO_FAKE_GOTPCREL:
- if(targ->dynimpname == nil || targ->dynexport) {
+ if(targ->dynimpname == nil || (targ->cgoexport & CgoExportDynamic)) {
// have symbol
// turn MOVL of GOT entry into LEAL of symbol itself
if(r->off < 2 || s->p[r->off-2] != 0x8b) {
}
// Handle references to ELF symbols from our own object files.
- if(targ->dynimpname == nil || targ->dynexport)
+ if(targ->dynimpname == nil || (targ->cgoexport & CgoExportDynamic))
return;
switch(r->type) {
/* type */
t = STB_GLOBAL << 4;
- if(s->dynexport && (s->type&SMASK) == STEXT)
+ if((s->cgoexport & CgoExportDynamic) && (s->type&SMASK) == STEXT)
t |= STT_FUNC;
else
t |= STT_OBJECT;
adduint8(d, 0);
/* shndx */
- if(!s->dynexport && s->dynimpname != nil)
+ if(!(s->cgoexport & CgoExportDynamic) && s->dynimpname != nil)
adduint16(d, SHN_UNDEF);
else {
switch(s->type) {
short version;
uchar dupok;
uchar reachable;
- uchar dynexport;
+ uchar cgoexport;
uchar special;
uchar stkcheck;
uchar hide;
INITRND = -1;
INITENTRY = 0;
LIBINITENTRY = 0;
+ linkmode = LinkInternal; // TODO: LinkAuto once everything works.
nuxiinit();
flagcount("1", "use alternate profiling code", &debug['1']);
flagcount("u", "reject unsafe packages", &debug['u']);
flagcount("v", "print link trace", &debug['v']);
flagcount("w", "disable DWARF generation", &debug['w']);
+ // TODO: link mode flag
flagparse(&argc, &argv, usage);
reloc();
asmb();
undef();
+ hostlink();
+
if(debug['v']) {
Bprint(&bso, "%5.2f cpu time\n", cputime());
Bprint(&bso, "%d symbols\n", nsymbol);
s->maxr = 4;
else
s->maxr <<= 1;
- s->r = realloc(s->r, s->maxr*sizeof s->r[0]);
- if(s->r == 0) {
- diag("out of memory");
- errorexit();
- }
+ s->r = erealloc(s->r, s->maxr*sizeof s->r[0]);
memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]);
}
return &s->r[s->nr++];
for(r=s->r; r<s->r+s->nr; r++) {
if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256)
adddynrel(s, r);
- if(flag_shared && r->sym != S && (r->sym->dynimpname == nil || r->sym->dynexport) && r->type == D_ADDR
+ if(flag_shared && r->sym != S && (r->sym->dynimpname == nil || (r->sym->cgoexport & CgoExportDynamic)) && r->type == D_ADDR
&& (s == got || s->type == SDATA || s->type == SGOSTRING || s->type == STYPE || s->type == SRODATA)) {
// Create address based RELATIVE relocation
adddynrela(rel, s, r);
s->maxp = 8;
while(s->maxp < siz)
s->maxp <<= 1;
- s->p = realloc(s->p, s->maxp);
- if(s->p == nil) {
- diag("out of memory");
- errorexit();
- }
+ s->p = erealloc(s->p, s->maxp);
memset(s->p+s->np, 0, s->maxp-s->np);
}
s->np = siz;
if (n >= ftabsize) {
s = ftabsize;
ftabsize = 1 + n + (n >> 2);
- ftab = realloc(ftab, ftabsize * sizeof(ftab[0]));
+ ftab = erealloc(ftab, ftabsize * sizeof(ftab[0]));
memset(ftab + s, 0, (ftabsize - s) * sizeof(ftab[0]));
}
if (histfilesize == histfilecap) {
histfilecap = 2 * histfilecap + 2;
- histfile = realloc(histfile, histfilecap * sizeof(char*));
+ histfile = erealloc(histfile, histfilecap * sizeof(char*));
}
if (histfilesize == 0)
histfile[histfilesize++] = "<eof>";
includestacksize += 1;
includestacksize <<= 2;
// print("checknesting: growing to %d\n", includestacksize);
- includestack = realloc(includestack, includestacksize * sizeof *includestack);
+ includestack = erealloc(includestack, includestacksize * sizeof *includestack);
}
}
lang = guesslang(histfile[1]);
finddebugruntimepath();
- dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, strdup(histfile[1]));
+ dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, estrdup(histfile[1]));
newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT,lang, 0);
newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart - lineo, 0);
newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s->text->pc, 0);
if(x->name[0] == name[0] && strcmp(x->name, name) == 0)
return x;
x = mal(sizeof *x);
- x->name = strdup(name);
+ x->name = estrdup(name);
x->hash = ihash[h];
ihash[h] = x;
nimport++;
static int parsemethod(char**, char*, char**);
static int parsepkgdata(char*, char*, char**, char*, char**, char**, char**);
-static Sym **dynexp;
-
void
ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence)
{
char *p, *ep, *prefix, *name, *def;
Import *x;
- file = strdup(file);
+ file = estrdup(file);
p = data;
ep = data + len;
while(parsepkgdata(file, pkg, &p, ep, &prefix, &name, &def) > 0) {
x = ilookup(name);
if(x->prefix == nil) {
x->prefix = prefix;
- x->def = strdup(def);
+ x->def = estrdup(def);
x->file = file;
} else if(strcmp(x->prefix, prefix) != 0) {
fprint(2, "%s: conflicting definitions for %s\n", argv0, name);
n++;
if(n == 0)
- return strdup(t0);
+ return estrdup(t0);
// use malloc, not mal, so that caller can free
w0 = malloc(strlen(t0) + strlen(pkg)*n);
*next++ = '\0';
free(p0);
- p0 = strdup(p); // save for error message
+ p0 = estrdup(p); // save for error message
nf = tokenize(p, f, nelem(f));
if(strcmp(f[0], "cgo_import_dynamic") == 0) {
continue;
}
- // TODO: cgo_export_static
+ if(strcmp(f[0], "cgo_export_static") == 0 || strcmp(f[0], "cgo_export_dynamic") == 0) {
+ // TODO: Make Mach-O code happier. Right now it sees the dynimpname and
+ // includes CgoExportStatic symbols in the dynamic table, and then dyld
+ // cannot find them when we run the binary. Disabling Windows too
+ // because it probably has the same issue.
+ if(strcmp(f[0], "cgo_export_static") == 0 && (HEADTYPE == Hdarwin || HEADTYPE == Hwindows))
+ continue;
- if(strcmp(f[0], "cgo_export_dynamic") == 0) {
if(nf < 2 || nf > 3)
goto err;
local = f[1];
fprint(2, "%s: symbol is both imported and exported: %s\n", argv0, local);
nerrors++;
}
- s->dynexport = 1;
+
+ if(strcmp(f[0], "cgo_export_static") == 0)
+ s->cgoexport |= CgoExportStatic;
+ else
+ s->cgoexport |= CgoExportDynamic;
if(s->dynimpname == nil) {
s->dynimpname = remote;
if(ndynexp%32 == 0)
- dynexp = realloc(dynexp, (ndynexp+32)*sizeof dynexp[0]);
+ dynexp = erealloc(dynexp, (ndynexp+32)*sizeof dynexp[0]);
dynexp[ndynexp++] = s;
} else if(strcmp(s->dynimpname, remote) != 0) {
fprint(2, "%s: conflicting cgo_export directives: %s as %s and %s\n", argv0, s->name, s->dynimpname, remote);
return;
}
free(interpreter);
- interpreter = strdup(f[1]);
+ interpreter = estrdup(f[1]);
}
continue;
}
if(nf != 2)
goto err;
if(nldflag%32 == 0)
- ldflag = realloc(ldflag, (nldflag+32)*sizeof ldflag[0]);
- ldflag[nldflag++] = strdup(f[1]);
+ ldflag = erealloc(ldflag, (nldflag+32)*sizeof ldflag[0]);
+ ldflag[nldflag++] = estrdup(f[1]);
continue;
}
}
if(strcmp(p->path, path) == 0)
return p;
p = mal(sizeof *p);
- p->path = strdup(path);
+ p->path = estrdup(path);
p->next = phash[h];
phash[h] = p;
p->all = pkgall;
i->mimpby *= 2;
if(i->mimpby == 0)
i->mimpby = 16;
- i->impby = realloc(i->impby, i->mimpby*sizeof i->impby[0]);
+ i->impby = erealloc(i->impby, i->mimpby*sizeof i->impby[0]);
}
i->impby[i->nimpby++] = p;
free(pkg);
s->sub = sect->sym->sub;
sect->sym->sub = s;
s->type = sect->sym->type | (s->type&~SMASK) | SSUB;
- if(!s->dynexport) {
+ if(!(s->cgoexport & CgoExportDynamic)) {
s->dynimplib = nil; // satisfy dynimport
s->dynimpname = nil; // satisfy dynimport
}
s->size = (sym+1)->value - sym->value;
else
s->size = sect->addr + sect->size - sym->value;
- if(!s->dynexport) {
+ if(!(s->cgoexport & CgoExportDynamic)) {
s->dynimplib = nil; // satisfy dynimport
s->dynimpname = nil; // satisfy dynimport
}
static int maxlibdir = 0;
static int cout = -1;
+static void hostlinksetup(void);
+
char* goroot;
char* goarch;
char* goos;
maxlibdir = 8;
else
maxlibdir *= 2;
- p = realloc(libdir, maxlibdir * sizeof(*p));
- if (p == nil) {
- print("too many -L's: %d\n", nlibdir);
- usage();
- }
+ p = erealloc(libdir, maxlibdir * sizeof(*p));
libdir = p;
}
libdir[nlibdir++] = arg;
#endif
cout = create(outfile, 1, 0775);
if(cout < 0) {
- diag("cannot create %s", outfile);
+ diag("cannot create %s: %r", outfile);
errorexit();
}
if(libraryp == nlibrary){
nlibrary = 50 + 2*libraryp;
- library = realloc(library, sizeof library[0] * nlibrary);
+ library = erealloc(library, sizeof library[0] * nlibrary);
}
l = &library[libraryp++];
void
loadlib(void)
{
- int i;
+ int i, w, x;
loadinternal("runtime");
if(thechar == '5')
objfile(library[i].file, library[i].pkg);
}
+ // If we got this far in automatic mode, there were no
+ // cgo uses that suggest we need external mode.
+ // Switch to internal.
+ if(linkmode == LinkAuto)
+ linkmode = LinkInternal;
+
+ // Now that we know the link mode, trim the dynexp list.
+ x = CgoExportDynamic;
+ if(linkmode == LinkExternal)
+ x = CgoExportStatic;
+ w = 0;
+ for(i=0; i<ndynexp; i++)
+ if(dynexp[i]->cgoexport & x)
+ dynexp[w++] = dynexp[i];
+ ndynexp = w;
+
+ // In internal link mode, read the host object files.
+ if(linkmode == LinkInternal)
+ hostobjs();
+ else
+ hostlinksetup();
+
// We've loaded all the code now.
// If there are no dynamic libraries needed, gcc disables dynamic linking.
// Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
/* load it as a regular file */
l = Bseek(f, 0L, 2);
Bseek(f, 0L, 0);
- ldobj(f, pkg, l, file, FileObj);
+ ldobj(f, pkg, l, file, file, FileObj);
Bterm(f);
free(pkg);
return;
l--;
snprint(pname, sizeof pname, "%s(%.*s)", file, utfnlen(arhdr.name, l), arhdr.name);
l = atolwhex(arhdr.size);
- ldobj(f, pkg, l, pname, ArchiveObj);
+ ldobj(f, pkg, l, pname, file, ArchiveObj);
}
out:
free(pkg);
}
+static void
+dowrite(int fd, char *p, int n)
+{
+ int m;
+
+ while(n > 0) {
+ m = write(fd, p, n);
+ if(m <= 0) {
+ cursym = S;
+ diag("write error: %r");
+ errorexit();
+ }
+ n -= m;
+ p += m;
+ }
+}
+
+typedef struct Hostobj Hostobj;
+
+struct Hostobj
+{
+ void (*ld)(Biobuf*, char*, int64, char*);
+ char *pkg;
+ char *pn;
+ char *file;
+ int64 off;
+ int64 len;
+};
+
+Hostobj *hostobj;
+int nhostobj;
+int mhostobj;
+
+// These packages can use internal linking mode.
+// Others trigger external mode.
+const char *internalpkg[] = {
+ "net",
+ "os/user",
+ "runtime/cgo"
+};
+
+void
+ldhostobj(void (*ld)(Biobuf*, char*, int64, char*), Biobuf *f, char *pkg, int64 len, char *pn, char *file)
+{
+ int i, isinternal;
+ Hostobj *h;
+
+ isinternal = 0;
+ for(i=0; i<nelem(internalpkg); i++) {
+ if(strcmp(pkg, internalpkg[i]) == 0) {
+ isinternal = 1;
+ break;
+ }
+ }
+
+ if(!isinternal && linkmode == LinkAuto)
+ linkmode = LinkExternal;
+
+ if(nhostobj >= mhostobj) {
+ if(mhostobj == 0)
+ mhostobj = 16;
+ else
+ mhostobj *= 2;
+ hostobj = erealloc(hostobj, mhostobj*sizeof hostobj[0]);
+ }
+ h = &hostobj[nhostobj++];
+ h->ld = ld;
+ h->pkg = pkg;
+ h->pn = estrdup(pn);
+ h->file = estrdup(file);
+ h->off = Boffset(f);
+ h->len = len;
+}
+
+void
+hostobjs(void)
+{
+ int i;
+ Biobuf *f;
+ Hostobj *h;
+
+ for(i=0; i<nhostobj; i++) {
+ h = &hostobj[i];
+ f = Bopen(h->file, OREAD);
+ if(f == nil) {
+ cursym = S;
+ diag("cannot reopen %s: %r", h->pn);
+ errorexit();
+ }
+ Bseek(f, h->off, 0);
+ h->ld(f, h->pkg, h->len, h->pn);
+ Bterm(f);
+ }
+}
+
+static char *tmpdir;
+
+static void
+rmtemp(void)
+{
+ removeall(tmpdir);
+}
+
+static void
+hostlinksetup(void)
+{
+ char *p;
+
+ if(linkmode != LinkExternal)
+ return;
+
+ // create temporary directory and arrange cleanup
+ // TODO: Add flag to specify tempdir, which is then not cleaned up.
+ tmpdir = mktempdir();
+ atexit(rmtemp);
+
+ // change our output to temporary object file
+ close(cout);
+ p = smprint("%s/go.o", tmpdir);
+ cout = create(p, 1, 0775);
+ if(cout < 0) {
+ diag("cannot create %s: %r", p);
+ errorexit();
+ }
+ free(p);
+}
+
+void
+hostlink(void)
+{
+ char *p, **argv;
+ int i, w, n, argc, len;
+ Hostobj *h;
+ Biobuf *f;
+ static char buf[64<<10];
+
+ if(linkmode != LinkExternal)
+ return;
+
+ argv = malloc((10+nhostobj+nldflag)*sizeof argv[0]);
+ argc = 0;
+ // TODO: Add command-line flag to override gcc path and specify additional leading options.
+ // TODO: Add command-line flag to specify additional trailing options.
+ argv[argc++] = "gcc";
+ if(!debug['s'])
+ argv[argc++] = "-ggdb";
+ argv[argc++] = "-o";
+ argv[argc++] = outfile;
+
+ // Force global symbols to be exported for dlopen, etc.
+ // NOTE: May not work on OS X or Windows. We'll see.
+ argv[argc++] = "-rdynamic";
+
+ // already wrote main object file
+ // copy host objects to temporary directory
+ for(i=0; i<nhostobj; i++) {
+ h = &hostobj[i];
+ f = Bopen(h->file, OREAD);
+ if(f == nil) {
+ cursym = S;
+ diag("cannot reopen %s: %r", h->pn);
+ errorexit();
+ }
+ Bseek(f, h->off, 0);
+ p = smprint("%s/%06d.o", tmpdir, i);
+ argv[argc++] = p;
+ w = create(p, 1, 0775);
+ if(w < 0) {
+ diag("cannot create %s: %r", p);
+ errorexit();
+ }
+ len = h->len;
+ while(len > 0 && (n = Bread(f, buf, sizeof buf)) > 0){
+ if(n > len)
+ n = len;
+ dowrite(w, buf, n);
+ len -= n;
+ }
+ if(close(w) < 0) {
+ diag("cannot write %s: %r", p);
+ errorexit();
+ }
+ Bterm(f);
+ }
+
+ argv[argc++] = smprint("%s/go.o", tmpdir);
+ for(i=0; i<nldflag; i++)
+ argv[argc++] = ldflag[i];
+ argv[argc] = nil;
+
+ quotefmtinstall();
+ if(debug['v']) {
+ Bprint(&bso, "host link:");
+ for(i=0; i<argc; i++)
+ Bprint(&bso, " %q", argv[i]);
+ Bprint(&bso, "\n");
+ Bflush(&bso);
+ }
+
+ if(runcmd(argv) < 0) {
+ diag("%s: running %s failed: %r", argv0, argv[0]);
+ errorexit();
+ }
+}
+
void
-ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
+ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence)
{
char *line;
int n, c1, c2, c3, c4;
eof = Boffset(f) + len;
- pn = strdup(pn);
+ pn = estrdup(pn);
c1 = Bgetc(f);
c2 = Bgetc(f);
magic = c1<<24 | c2<<16 | c3<<8 | c4;
if(magic == 0x7f454c46) { // \x7F E L F
- ldelf(f, pkg, len, pn);
- free(pn);
+ ldhostobj(ldelf, f, pkg, len, pn, file);
return;
}
if((magic&~1) == 0xfeedface || (magic&~0x01000000) == 0xcefaedfe) {
- ldmacho(f, pkg, len, pn);
- free(pn);
+ ldhostobj(ldmacho, f, pkg, len, pn, file);
return;
}
if(c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86) {
- ldpe(f, pkg, len, pn);
- free(pn);
+ ldhostobj(ldpe, f, pkg, len, pn, file);
return;
}
line[n] = '\0';
if(n-10 > strlen(t)) {
if(theline == nil)
- theline = strdup(line+10);
+ theline = estrdup(line+10);
else if(strcmp(theline, line+10) != 0) {
line[n] = '\0';
diag("%s: object is [%s] expected [%s]", pn, line+10, theline);
vlong coutpos;
-static void
-dowrite(int fd, char *p, int n)
-{
- int m;
-
- while(n > 0) {
- m = write(fd, p, n);
- if(m <= 0) {
- cursym = S;
- diag("write error: %r");
- errorexit();
- }
- n -= m;
- p += m;
- }
-}
-
void
cflush(void)
{
put(s, s->name, 'T', s->value, s->size, s->version, 0);
for(s=allsym; s!=S; s=s->allsym) {
- if(s->hide)
+ if(s->hide || (s->name[0] == '.' && s->version == 0))
continue;
switch(s->type&SMASK) {
case SCONST:
Bprint(&bso, "symsize = %ud\n", symsize);
Bflush(&bso);
}
+
+char*
+estrdup(char *p)
+{
+ p = strdup(p);
+ if(p == nil) {
+ cursym = S;
+ diag("out of memory");
+ errorexit();
+ }
+ return p;
+}
+
+void*
+erealloc(void *p, long n)
+{
+ p = realloc(p, n);
+ if(p == nil) {
+ cursym = S;
+ diag("out of memory");
+ errorexit();
+ }
+ return p;
+}
EXTERN int32 nsymbol;
EXTERN char* thestring;
EXTERN int ndynexp;
+EXTERN Sym** dynexp;
EXTERN int nldflag;
EXTERN char** ldflag;
EXTERN int havedynamic;
EXTERN char* tracksym;
EXTERN char* interpreter;
+enum
+{
+ LinkAuto = 0,
+ LinkInternal,
+ LinkExternal,
+};
+EXTERN int linkmode;
+
+// for dynexport field of Sym
+enum
+{
+ CgoExportDynamic = 1<<0,
+ CgoExportStatic = 1<<1,
+};
+
EXTERN Segment segtext;
EXTERN Segment segdata;
EXTERN Segment segsym;
void adddynrela(Sym*, Sym*, Reloc*);
Sym* lookuprel(void);
void ldobj1(Biobuf *f, char*, int64 len, char *pn);
-void ldobj(Biobuf*, char*, int64, char*, int);
+void ldobj(Biobuf*, char*, int64, char*, char*, int);
void ldelf(Biobuf*, char*, int64, char*);
void ldmacho(Biobuf*, char*, int64, char*);
void ldpe(Biobuf*, char*, int64, char*);
void setinterp(char*);
Sym* listsort(Sym*, int(*cmp)(Sym*, Sym*), int);
int valuecmp(Sym*, Sym*);
+void hostobjs(void);
+void hostlink(void);
+char* estrdup(char*);
+void* erealloc(void*, long);
int pathchar(void);
void* mal(uint32);
mload = 1;
else
mload *= 2;
- load = realloc(load, mload*sizeof load[0]);
- if(load == nil) {
- diag("out of memory");
- errorexit();
- }
+ load = erealloc(load, mload*sizeof load[0]);
}
if(macho64 && (ndata & 1))
load_budget += 4096;
}
- if(ndylib%32 == 0) {
- dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]);
- if(dylib == nil) {
- diag("out of memory");
- errorexit();
- }
- }
+ if(ndylib%32 == 0)
+ dylib = erealloc(dylib, (ndylib+32)*sizeof dylib[0]);
dylib[ndylib++] = lib;
}
dr = nil;
m = nil;
for(s = allsym; s != S; s = s->allsym) {
- if(!s->reachable || !s->dynimpname || s->dynexport)
+ if(!s->reachable || !s->dynimpname || (s->cgoexport & CgoExportDynamic))
continue;
for(d = dr; d != nil; d = d->next) {
if(strcmp(d->name,s->dynimplib) == 0) {
nexport = 0;
for(s = allsym; s != S; s = s->allsym) {
- if(!s->reachable || !s->dynimpname || !s->dynexport)
+ if(!s->reachable || !s->dynimpname || !(s->cgoexport & CgoExportDynamic))
continue;
if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) {
diag("pe dynexport table is full");
// One pass for each binding: STB_LOCAL, STB_GLOBAL,
// maybe one day STB_WEAK.
- bind = (ver || (x->type & SHIDDEN)) ? STB_LOCAL : STB_GLOBAL;
+ bind = STB_GLOBAL;
+ if(ver || (x->type & SHIDDEN))
+ bind = STB_LOCAL;
+
+ // In external linking mode, we have to invoke gcc with -rdynamic
+ // to get the exported symbols put into the dynamic symbol table.
+ // To avoid filling the dynamic table with lots of unnecessary symbols,
+ // mark all Go symbols local (not global) in the final executable.
+ if(linkmode == LinkExternal && !(x->cgoexport&CgoExportStatic))
+ bind = STB_LOCAL;
+
if(bind != elfbind)
return;
// void crosscall2(void (*fn)(void *, int), void *, int);
//
// We need to export the symbol crosscall2 in order to support
-// callbacks from shared libraries.
-#pragma dynexport crosscall2 crosscall2
+// callbacks from shared libraries. This applies regardless of
+// linking mode.
+#pragma cgo_export_static crosscall2
+#pragma cgo_export_dynamic crosscall2
// Allocate memory. This allocates the requested number of bytes in
// memory controlled by the Go runtime. The allocated memory will be
{
runtime·throw("runtime: cgo not implemented");
}
+
+// For cgo-using programs with external linking,
+// export "main" (defined in assembly) so that libc can handle basic
+// C runtime startup and call the Go program as if it were
+// the C main function.
+#pragma cgo_export_static main