Commit 60f783d9 authored by Russ Cox's avatar Russ Cox

cmd/ld: host linking support for linux/amd64

Still to do: non-linux and non-amd64.
It may work on other ELF-based amd64 systems too, but untested.

"go test -ldflags -hostobj $GOROOT/misc/cgo/test" passes.

Much may yet change, but this seems a reasonable checkpoint.

R=iant
CC=golang-dev
https://golang.org/cl/7369057
parent 8aafb44b
...@@ -125,7 +125,7 @@ adddynrel(Sym *s, Reloc *r) ...@@ -125,7 +125,7 @@ adddynrel(Sym *s, Reloc *r)
// Handle relocations found in ELF object files. // Handle relocations found in ELF object files.
case 256 + R_ARM_PLT32: case 256 + R_ARM_PLT32:
r->type = D_CALL; r->type = D_CALL;
if(targ->dynimpname != nil && !targ->dynexport) { if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic)) {
addpltsym(targ); addpltsym(targ);
r->sym = lookup(".plt", 0); r->sym = lookup(".plt", 0);
r->add = braddoff(r->add, targ->plt / 4); r->add = braddoff(r->add, targ->plt / 4);
...@@ -138,7 +138,7 @@ adddynrel(Sym *s, Reloc *r) ...@@ -138,7 +138,7 @@ adddynrel(Sym *s, Reloc *r)
return; return;
case 256 + R_ARM_GOT32: // R_ARM_GOT_BREL case 256 + R_ARM_GOT32: // R_ARM_GOT_BREL
if(targ->dynimpname == nil || targ->dynexport) { if(targ->dynimpname == nil || (targ->cgoexport & CgoExportDynamic)) {
addgotsyminternal(targ); addgotsyminternal(targ);
} else { } else {
addgotsym(targ); addgotsym(targ);
...@@ -149,7 +149,7 @@ adddynrel(Sym *s, Reloc *r) ...@@ -149,7 +149,7 @@ adddynrel(Sym *s, Reloc *r)
return; return;
case 256 + R_ARM_GOT_PREL: // GOT(S) + A - P 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); addgotsyminternal(targ);
} else { } else {
addgotsym(targ); addgotsym(targ);
...@@ -171,7 +171,7 @@ adddynrel(Sym *s, Reloc *r) ...@@ -171,7 +171,7 @@ adddynrel(Sym *s, Reloc *r)
case 256 + R_ARM_CALL: case 256 + R_ARM_CALL:
r->type = D_CALL; r->type = D_CALL;
if(targ->dynimpname != nil && !targ->dynexport) { if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic)) {
addpltsym(targ); addpltsym(targ);
r->sym = lookup(".plt", 0); r->sym = lookup(".plt", 0);
r->add = braddoff(r->add, targ->plt / 4); r->add = braddoff(r->add, targ->plt / 4);
...@@ -184,7 +184,7 @@ adddynrel(Sym *s, Reloc *r) ...@@ -184,7 +184,7 @@ adddynrel(Sym *s, Reloc *r)
return; return;
case 256 + R_ARM_ABS32: 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); diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ->name);
r->type = D_ADDR; r->type = D_ADDR;
return; return;
...@@ -201,7 +201,7 @@ adddynrel(Sym *s, Reloc *r) ...@@ -201,7 +201,7 @@ adddynrel(Sym *s, Reloc *r)
case 256 + R_ARM_PC24: case 256 + R_ARM_PC24:
case 256 + R_ARM_JUMP24: case 256 + R_ARM_JUMP24:
r->type = D_CALL; r->type = D_CALL;
if(targ->dynimpname != nil && !targ->dynexport) { if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic)) {
addpltsym(targ); addpltsym(targ);
r->sym = lookup(".plt", 0); r->sym = lookup(".plt", 0);
r->add = braddoff(r->add, targ->plt / 4); r->add = braddoff(r->add, targ->plt / 4);
...@@ -210,7 +210,7 @@ adddynrel(Sym *s, Reloc *r) ...@@ -210,7 +210,7 @@ adddynrel(Sym *s, Reloc *r)
} }
// Handle references to ELF symbols from our own object files. // Handle references to ELF symbols from our own object files.
if(targ->dynimpname == nil || targ->dynexport) if(targ->dynimpname == nil || (targ->cgoexport & CgoExportDynamic))
return; return;
switch(r->type) { switch(r->type) {
...@@ -464,7 +464,7 @@ adddynsym(Sym *s) ...@@ -464,7 +464,7 @@ adddynsym(Sym *s)
/* type */ /* type */
t = STB_GLOBAL << 4; t = STB_GLOBAL << 4;
if(s->dynexport && (s->type&SMASK) == STEXT) if((s->cgoexport & CgoExportDynamic) && (s->type&SMASK) == STEXT)
t |= STT_FUNC; t |= STT_FUNC;
else else
t |= STT_OBJECT; t |= STT_OBJECT;
...@@ -472,7 +472,7 @@ adddynsym(Sym *s) ...@@ -472,7 +472,7 @@ adddynsym(Sym *s)
adduint8(d, 0); adduint8(d, 0);
/* shndx */ /* shndx */
if(!s->dynexport && s->dynimpname != nil) if(!(s->cgoexport & CgoExportDynamic) && s->dynimpname != nil)
adduint16(d, SHN_UNDEF); adduint16(d, SHN_UNDEF);
else { else {
switch(s->type) { switch(s->type) {
......
...@@ -137,7 +137,7 @@ struct Sym ...@@ -137,7 +137,7 @@ struct Sym
short version; short version;
uchar dupok; uchar dupok;
uchar reachable; uchar reachable;
uchar dynexport; uchar cgoexport;
uchar leaf; uchar leaf;
int32 dynid; int32 dynid;
int32 plt; int32 plt;
......
...@@ -82,6 +82,7 @@ main(int argc, char *argv[]) ...@@ -82,6 +82,7 @@ main(int argc, char *argv[])
INITRND = -1; INITRND = -1;
INITENTRY = 0; INITENTRY = 0;
LIBINITENTRY = 0; LIBINITENTRY = 0;
linkmode = LinkInternal; // TODO: LinkAuto once everything works.
nuxiinit(); nuxiinit();
p = getgoarm(); p = getgoarm();
...@@ -126,6 +127,7 @@ main(int argc, char *argv[]) ...@@ -126,6 +127,7 @@ main(int argc, char *argv[])
flagcount("v", "print link trace", &debug['v']); flagcount("v", "print link trace", &debug['v']);
flagcount("w", "disable DWARF generation", &debug['w']); flagcount("w", "disable DWARF generation", &debug['w']);
flagcount("shared", "generate shared object", &flag_shared); flagcount("shared", "generate shared object", &flag_shared);
// TODO: link mode flag
flagparse(&argc, &argv, usage); flagparse(&argc, &argv, usage);
...@@ -268,6 +270,7 @@ main(int argc, char *argv[]) ...@@ -268,6 +270,7 @@ main(int argc, char *argv[])
reloc(); reloc();
asmb(); asmb();
undef(); undef();
hostlink();
if(debug['c']) if(debug['c'])
print("ARM size = %d\n", armsize); print("ARM size = %d\n", armsize);
......
...@@ -131,7 +131,7 @@ adddynrel(Sym *s, Reloc *r) ...@@ -131,7 +131,7 @@ adddynrel(Sym *s, Reloc *r)
// Handle relocations found in ELF object files. // Handle relocations found in ELF object files.
case 256 + R_X86_64_PC32: 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); diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ->name);
if(targ->type == 0 || targ->type == SXREF) if(targ->type == 0 || targ->type == SXREF)
diag("unknown symbol %s in pcrel", targ->name); diag("unknown symbol %s in pcrel", targ->name);
...@@ -142,7 +142,7 @@ adddynrel(Sym *s, Reloc *r) ...@@ -142,7 +142,7 @@ adddynrel(Sym *s, Reloc *r)
case 256 + R_X86_64_PLT32: case 256 + R_X86_64_PLT32:
r->type = D_PCREL; r->type = D_PCREL;
r->add += 4; r->add += 4;
if(targ->dynimpname != nil && !targ->dynexport) { if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic)) {
addpltsym(targ); addpltsym(targ);
r->sym = lookup(".plt", 0); r->sym = lookup(".plt", 0);
r->add += targ->plt; r->add += targ->plt;
...@@ -150,7 +150,7 @@ adddynrel(Sym *s, Reloc *r) ...@@ -150,7 +150,7 @@ adddynrel(Sym *s, Reloc *r)
return; return;
case 256 + R_X86_64_GOTPCREL: case 256 + R_X86_64_GOTPCREL:
if(targ->dynimpname == nil || targ->dynexport) { if(targ->dynimpname == nil || (targ->cgoexport & CgoExportDynamic)) {
// have symbol // have symbol
if(r->off >= 2 && s->p[r->off-2] == 0x8b) { if(r->off >= 2 && s->p[r->off-2] == 0x8b) {
// turn MOVQ of GOT entry into LEAQ of symbol itself // turn MOVQ of GOT entry into LEAQ of symbol itself
...@@ -171,7 +171,7 @@ adddynrel(Sym *s, Reloc *r) ...@@ -171,7 +171,7 @@ adddynrel(Sym *s, Reloc *r)
return; return;
case 256 + R_X86_64_64: 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); diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ->name);
r->type = D_ADDR; r->type = D_ADDR;
return; return;
...@@ -182,12 +182,12 @@ adddynrel(Sym *s, Reloc *r) ...@@ -182,12 +182,12 @@ adddynrel(Sym *s, Reloc *r)
case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 0: case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 0:
// TODO: What is the difference between all these? // TODO: What is the difference between all these?
r->type = D_ADDR; 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); diag("unexpected reloc for dynamic symbol %s", targ->name);
return; return;
case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1: case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1:
if(targ->dynimpname != nil && !targ->dynexport) { if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic)) {
addpltsym(targ); addpltsym(targ);
r->sym = lookup(".plt", 0); r->sym = lookup(".plt", 0);
r->add = targ->plt; r->add = targ->plt;
...@@ -201,12 +201,12 @@ adddynrel(Sym *s, Reloc *r) ...@@ -201,12 +201,12 @@ adddynrel(Sym *s, Reloc *r)
case 512 + MACHO_X86_64_RELOC_SIGNED_2*2 + 1: case 512 + MACHO_X86_64_RELOC_SIGNED_2*2 + 1:
case 512 + MACHO_X86_64_RELOC_SIGNED_4*2 + 1: case 512 + MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
r->type = D_PCREL; 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); diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name);
return; return;
case 512 + MACHO_X86_64_RELOC_GOT_LOAD*2 + 1: 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 // have symbol
// turn MOVQ of GOT entry into LEAQ of symbol itself // turn MOVQ of GOT entry into LEAQ of symbol itself
if(r->off < 2 || s->p[r->off-2] != 0x8b) { if(r->off < 2 || s->p[r->off-2] != 0x8b) {
...@@ -219,7 +219,7 @@ adddynrel(Sym *s, Reloc *r) ...@@ -219,7 +219,7 @@ adddynrel(Sym *s, Reloc *r)
} }
// fall through // fall through
case 512 + MACHO_X86_64_RELOC_GOT*2 + 1: 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); diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
addgotsym(targ); addgotsym(targ);
r->type = D_PCREL; r->type = D_PCREL;
...@@ -229,7 +229,7 @@ adddynrel(Sym *s, Reloc *r) ...@@ -229,7 +229,7 @@ adddynrel(Sym *s, Reloc *r)
} }
// Handle references to ELF symbols from our own object files. // Handle references to ELF symbols from our own object files.
if(targ->dynimpname == nil || targ->dynexport) if(targ->dynimpname == nil || (targ->cgoexport & CgoExportDynamic))
return; return;
switch(r->type) { switch(r->type) {
...@@ -470,7 +470,7 @@ adddynsym(Sym *s) ...@@ -470,7 +470,7 @@ adddynsym(Sym *s)
adduint32(d, addstring(lookup(".dynstr", 0), name)); adduint32(d, addstring(lookup(".dynstr", 0), name));
/* type */ /* type */
t = STB_GLOBAL << 4; t = STB_GLOBAL << 4;
if(s->dynexport && (s->type&SMASK) == STEXT) if((s->cgoexport & CgoExportDynamic) && (s->type&SMASK) == STEXT)
t |= STT_FUNC; t |= STT_FUNC;
else else
t |= STT_OBJECT; t |= STT_OBJECT;
...@@ -480,7 +480,7 @@ adddynsym(Sym *s) ...@@ -480,7 +480,7 @@ adddynsym(Sym *s)
adduint8(d, 0); adduint8(d, 0);
/* section where symbol is defined */ /* section where symbol is defined */
if(!s->dynexport && s->dynimpname != nil) if(!(s->cgoexport & CgoExportDynamic) && s->dynimpname != nil)
adduint16(d, SHN_UNDEF); adduint16(d, SHN_UNDEF);
else { else {
switch(s->type) { switch(s->type) {
...@@ -510,7 +510,7 @@ adddynsym(Sym *s) ...@@ -510,7 +510,7 @@ adddynsym(Sym *s)
/* size of object */ /* size of object */
adduint64(d, s->size); 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, elfwritedynent(lookup(".dynamic", 0), DT_NEEDED,
addstring(lookup(".dynstr", 0), s->dynimplib)); addstring(lookup(".dynstr", 0), s->dynimplib));
} }
......
...@@ -144,7 +144,7 @@ struct Sym ...@@ -144,7 +144,7 @@ struct Sym
short version; short version;
uchar dupok; uchar dupok;
uchar reachable; uchar reachable;
uchar dynexport; uchar cgoexport;
uchar special; uchar special;
uchar stkcheck; uchar stkcheck;
uchar hide; uchar hide;
......
...@@ -83,6 +83,7 @@ main(int argc, char *argv[]) ...@@ -83,6 +83,7 @@ main(int argc, char *argv[])
INITRND = -1; INITRND = -1;
INITENTRY = 0; INITENTRY = 0;
LIBINITENTRY = 0; LIBINITENTRY = 0;
linkmode = LinkInternal; // TODO: LinkAuto once everything works.
nuxiinit(); nuxiinit();
flagcount("1", "use alternate profiling code", &debug['1']); flagcount("1", "use alternate profiling code", &debug['1']);
...@@ -123,6 +124,10 @@ main(int argc, char *argv[]) ...@@ -123,6 +124,10 @@ main(int argc, char *argv[])
flagparse(&argc, &argv, usage); flagparse(&argc, &argv, usage);
// TODO: link mode flag instead of isobj
if(isobj)
linkmode = LinkExternal;
if(argc != 1) if(argc != 1)
usage(); usage();
...@@ -282,6 +287,7 @@ main(int argc, char *argv[]) ...@@ -282,6 +287,7 @@ main(int argc, char *argv[])
reloc(); reloc();
asmb(); asmb();
undef(); undef();
hostlink();
if(debug['v']) { if(debug['v']) {
Bprint(&bso, "%5.2f cpu time\n", cputime()); Bprint(&bso, "%5.2f cpu time\n", cputime());
Bprint(&bso, "%d symbols\n", nsymbol); Bprint(&bso, "%d symbols\n", nsymbol);
......
...@@ -128,7 +128,7 @@ adddynrel(Sym *s, Reloc *r) ...@@ -128,7 +128,7 @@ adddynrel(Sym *s, Reloc *r)
// Handle relocations found in ELF object files. // Handle relocations found in ELF object files.
case 256 + R_386_PC32: 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); diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ->name);
if(targ->type == 0 || targ->type == SXREF) if(targ->type == 0 || targ->type == SXREF)
diag("unknown symbol %s in pcrel", targ->name); diag("unknown symbol %s in pcrel", targ->name);
...@@ -139,7 +139,7 @@ adddynrel(Sym *s, Reloc *r) ...@@ -139,7 +139,7 @@ adddynrel(Sym *s, Reloc *r)
case 256 + R_386_PLT32: case 256 + R_386_PLT32:
r->type = D_PCREL; r->type = D_PCREL;
r->add += 4; r->add += 4;
if(targ->dynimpname != nil && !targ->dynexport) { if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic)) {
addpltsym(targ); addpltsym(targ);
r->sym = lookup(".plt", 0); r->sym = lookup(".plt", 0);
r->add += targ->plt; r->add += targ->plt;
...@@ -147,7 +147,7 @@ adddynrel(Sym *s, Reloc *r) ...@@ -147,7 +147,7 @@ adddynrel(Sym *s, Reloc *r)
return; return;
case 256 + R_386_GOT32: case 256 + R_386_GOT32:
if(targ->dynimpname == nil || targ->dynexport) { if(targ->dynimpname == nil || (targ->cgoexport & CgoExportDynamic)) {
// have symbol // have symbol
// turn MOVL of GOT entry into LEAL of symbol itself // turn MOVL of GOT entry into LEAL of symbol itself
if(r->off < 2 || s->p[r->off-2] != 0x8b) { if(r->off < 2 || s->p[r->off-2] != 0x8b) {
...@@ -175,19 +175,19 @@ adddynrel(Sym *s, Reloc *r) ...@@ -175,19 +175,19 @@ adddynrel(Sym *s, Reloc *r)
return; return;
case 256 + R_386_32: 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); diag("unexpected R_386_32 relocation for dynamic symbol %s", targ->name);
r->type = D_ADDR; r->type = D_ADDR;
return; return;
case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 0: case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 0:
r->type = D_ADDR; 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); diag("unexpected reloc for dynamic symbol %s", targ->name);
return; return;
case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1: case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1:
if(targ->dynimpname != nil && !targ->dynexport) { if(targ->dynimpname != nil && !(targ->cgoexport & CgoExportDynamic)) {
addpltsym(targ); addpltsym(targ);
r->sym = lookup(".plt", 0); r->sym = lookup(".plt", 0);
r->add = targ->plt; r->add = targ->plt;
...@@ -198,7 +198,7 @@ adddynrel(Sym *s, Reloc *r) ...@@ -198,7 +198,7 @@ adddynrel(Sym *s, Reloc *r)
return; return;
case 512 + MACHO_FAKE_GOTPCREL: case 512 + MACHO_FAKE_GOTPCREL:
if(targ->dynimpname == nil || targ->dynexport) { if(targ->dynimpname == nil || (targ->cgoexport & CgoExportDynamic)) {
// have symbol // have symbol
// turn MOVL of GOT entry into LEAL of symbol itself // turn MOVL of GOT entry into LEAL of symbol itself
if(r->off < 2 || s->p[r->off-2] != 0x8b) { if(r->off < 2 || s->p[r->off-2] != 0x8b) {
...@@ -217,7 +217,7 @@ adddynrel(Sym *s, Reloc *r) ...@@ -217,7 +217,7 @@ adddynrel(Sym *s, Reloc *r)
} }
// Handle references to ELF symbols from our own object files. // Handle references to ELF symbols from our own object files.
if(targ->dynimpname == nil || targ->dynexport) if(targ->dynimpname == nil || (targ->cgoexport & CgoExportDynamic))
return; return;
switch(r->type) { switch(r->type) {
...@@ -461,7 +461,7 @@ adddynsym(Sym *s) ...@@ -461,7 +461,7 @@ adddynsym(Sym *s)
/* type */ /* type */
t = STB_GLOBAL << 4; t = STB_GLOBAL << 4;
if(s->dynexport && (s->type&SMASK) == STEXT) if((s->cgoexport & CgoExportDynamic) && (s->type&SMASK) == STEXT)
t |= STT_FUNC; t |= STT_FUNC;
else else
t |= STT_OBJECT; t |= STT_OBJECT;
...@@ -469,7 +469,7 @@ adddynsym(Sym *s) ...@@ -469,7 +469,7 @@ adddynsym(Sym *s)
adduint8(d, 0); adduint8(d, 0);
/* shndx */ /* shndx */
if(!s->dynexport && s->dynimpname != nil) if(!(s->cgoexport & CgoExportDynamic) && s->dynimpname != nil)
adduint16(d, SHN_UNDEF); adduint16(d, SHN_UNDEF);
else { else {
switch(s->type) { switch(s->type) {
......
...@@ -126,7 +126,7 @@ struct Sym ...@@ -126,7 +126,7 @@ struct Sym
short version; short version;
uchar dupok; uchar dupok;
uchar reachable; uchar reachable;
uchar dynexport; uchar cgoexport;
uchar special; uchar special;
uchar stkcheck; uchar stkcheck;
uchar hide; uchar hide;
......
...@@ -90,6 +90,7 @@ main(int argc, char *argv[]) ...@@ -90,6 +90,7 @@ main(int argc, char *argv[])
INITRND = -1; INITRND = -1;
INITENTRY = 0; INITENTRY = 0;
LIBINITENTRY = 0; LIBINITENTRY = 0;
linkmode = LinkInternal; // TODO: LinkAuto once everything works.
nuxiinit(); nuxiinit();
flagcount("1", "use alternate profiling code", &debug['1']); flagcount("1", "use alternate profiling code", &debug['1']);
...@@ -125,6 +126,7 @@ main(int argc, char *argv[]) ...@@ -125,6 +126,7 @@ main(int argc, char *argv[])
flagcount("u", "reject unsafe packages", &debug['u']); flagcount("u", "reject unsafe packages", &debug['u']);
flagcount("v", "print link trace", &debug['v']); flagcount("v", "print link trace", &debug['v']);
flagcount("w", "disable DWARF generation", &debug['w']); flagcount("w", "disable DWARF generation", &debug['w']);
// TODO: link mode flag
flagparse(&argc, &argv, usage); flagparse(&argc, &argv, usage);
...@@ -308,6 +310,8 @@ main(int argc, char *argv[]) ...@@ -308,6 +310,8 @@ main(int argc, char *argv[])
reloc(); reloc();
asmb(); asmb();
undef(); undef();
hostlink();
if(debug['v']) { if(debug['v']) {
Bprint(&bso, "%5.2f cpu time\n", cputime()); Bprint(&bso, "%5.2f cpu time\n", cputime());
Bprint(&bso, "%d symbols\n", nsymbol); Bprint(&bso, "%d symbols\n", nsymbol);
......
...@@ -135,11 +135,7 @@ addrel(Sym *s) ...@@ -135,11 +135,7 @@ addrel(Sym *s)
s->maxr = 4; s->maxr = 4;
else else
s->maxr <<= 1; s->maxr <<= 1;
s->r = realloc(s->r, s->maxr*sizeof s->r[0]); s->r = erealloc(s->r, s->maxr*sizeof s->r[0]);
if(s->r == 0) {
diag("out of memory");
errorexit();
}
memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]); memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]);
} }
return &s->r[s->nr++]; return &s->r[s->nr++];
...@@ -300,7 +296,7 @@ dynrelocsym(Sym *s) ...@@ -300,7 +296,7 @@ dynrelocsym(Sym *s)
for(r=s->r; r<s->r+s->nr; r++) { for(r=s->r; r<s->r+s->nr; r++) {
if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256) if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256)
adddynrel(s, r); 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)) { && (s == got || s->type == SDATA || s->type == SGOSTRING || s->type == STYPE || s->type == SRODATA)) {
// Create address based RELATIVE relocation // Create address based RELATIVE relocation
adddynrela(rel, s, r); adddynrela(rel, s, r);
...@@ -342,11 +338,7 @@ symgrow(Sym *s, int32 siz) ...@@ -342,11 +338,7 @@ symgrow(Sym *s, int32 siz)
s->maxp = 8; s->maxp = 8;
while(s->maxp < siz) while(s->maxp < siz)
s->maxp <<= 1; s->maxp <<= 1;
s->p = realloc(s->p, s->maxp); s->p = erealloc(s->p, s->maxp);
if(s->p == nil) {
diag("out of memory");
errorexit();
}
memset(s->p+s->np, 0, s->maxp-s->np); memset(s->p+s->np, 0, s->maxp-s->np);
} }
s->np = siz; s->np = siz;
......
...@@ -1260,7 +1260,7 @@ dwarfaddfrag(int n, char *frag) ...@@ -1260,7 +1260,7 @@ dwarfaddfrag(int n, char *frag)
if (n >= ftabsize) { if (n >= ftabsize) {
s = ftabsize; s = ftabsize;
ftabsize = 1 + n + (n >> 2); 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])); memset(ftab + s, 0, (ftabsize - s) * sizeof(ftab[0]));
} }
...@@ -1342,7 +1342,7 @@ addhistfile(char *zentry) ...@@ -1342,7 +1342,7 @@ addhistfile(char *zentry)
if (histfilesize == histfilecap) { if (histfilesize == histfilecap) {
histfilecap = 2 * histfilecap + 2; histfilecap = 2 * histfilecap + 2;
histfile = realloc(histfile, histfilecap * sizeof(char*)); histfile = erealloc(histfile, histfilecap * sizeof(char*));
} }
if (histfilesize == 0) if (histfilesize == 0)
histfile[histfilesize++] = "<eof>"; histfile[histfilesize++] = "<eof>";
...@@ -1412,7 +1412,7 @@ checknesting(void) ...@@ -1412,7 +1412,7 @@ checknesting(void)
includestacksize += 1; includestacksize += 1;
includestacksize <<= 2; includestacksize <<= 2;
// print("checknesting: growing to %d\n", includestacksize); // print("checknesting: growing to %d\n", includestacksize);
includestack = realloc(includestack, includestacksize * sizeof *includestack); includestack = erealloc(includestack, includestacksize * sizeof *includestack);
} }
} }
...@@ -1651,7 +1651,7 @@ writelines(void) ...@@ -1651,7 +1651,7 @@ writelines(void)
lang = guesslang(histfile[1]); lang = guesslang(histfile[1]);
finddebugruntimepath(); 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_language, DW_CLS_CONSTANT,lang, 0);
newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart - lineo, 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); newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s->text->pc, 0);
......
...@@ -59,7 +59,7 @@ ilookup(char *name) ...@@ -59,7 +59,7 @@ ilookup(char *name)
if(x->name[0] == name[0] && strcmp(x->name, name) == 0) if(x->name[0] == name[0] && strcmp(x->name, name) == 0)
return x; return x;
x = mal(sizeof *x); x = mal(sizeof *x);
x->name = strdup(name); x->name = estrdup(name);
x->hash = ihash[h]; x->hash = ihash[h];
ihash[h] = x; ihash[h] = x;
nimport++; nimport++;
...@@ -71,8 +71,6 @@ static void loadcgo(char*, char*, char*, int); ...@@ -71,8 +71,6 @@ static void loadcgo(char*, char*, char*, int);
static int parsemethod(char**, char*, char**); static int parsemethod(char**, char*, char**);
static int parsepkgdata(char*, char*, char**, char*, char**, char**, char**); static int parsepkgdata(char*, char*, char**, char*, char**, char**, char**);
static Sym **dynexp;
void void
ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence) ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence)
{ {
...@@ -205,14 +203,14 @@ loadpkgdata(char *file, char *pkg, char *data, int len) ...@@ -205,14 +203,14 @@ loadpkgdata(char *file, char *pkg, char *data, int len)
char *p, *ep, *prefix, *name, *def; char *p, *ep, *prefix, *name, *def;
Import *x; Import *x;
file = strdup(file); file = estrdup(file);
p = data; p = data;
ep = data + len; ep = data + len;
while(parsepkgdata(file, pkg, &p, ep, &prefix, &name, &def) > 0) { while(parsepkgdata(file, pkg, &p, ep, &prefix, &name, &def) > 0) {
x = ilookup(name); x = ilookup(name);
if(x->prefix == nil) { if(x->prefix == nil) {
x->prefix = prefix; x->prefix = prefix;
x->def = strdup(def); x->def = estrdup(def);
x->file = file; x->file = file;
} else if(strcmp(x->prefix, prefix) != 0) { } else if(strcmp(x->prefix, prefix) != 0) {
fprint(2, "%s: conflicting definitions for %s\n", argv0, name); fprint(2, "%s: conflicting definitions for %s\n", argv0, name);
...@@ -244,7 +242,7 @@ expandpkg(char *t0, char *pkg) ...@@ -244,7 +242,7 @@ expandpkg(char *t0, char *pkg)
n++; n++;
if(n == 0) if(n == 0)
return strdup(t0); return estrdup(t0);
// use malloc, not mal, so that caller can free // use malloc, not mal, so that caller can free
w0 = malloc(strlen(t0) + strlen(pkg)*n); w0 = malloc(strlen(t0) + strlen(pkg)*n);
...@@ -429,7 +427,7 @@ loadcgo(char *file, char *pkg, char *p, int n) ...@@ -429,7 +427,7 @@ loadcgo(char *file, char *pkg, char *p, int n)
*next++ = '\0'; *next++ = '\0';
free(p0); free(p0);
p0 = strdup(p); // save for error message p0 = estrdup(p); // save for error message
nf = tokenize(p, f, nelem(f)); nf = tokenize(p, f, nelem(f));
if(strcmp(f[0], "cgo_import_dynamic") == 0) { if(strcmp(f[0], "cgo_import_dynamic") == 0) {
...@@ -487,9 +485,14 @@ loadcgo(char *file, char *pkg, char *p, int n) ...@@ -487,9 +485,14 @@ loadcgo(char *file, char *pkg, char *p, int n)
continue; 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) if(nf < 2 || nf > 3)
goto err; goto err;
local = f[1]; local = f[1];
...@@ -503,11 +506,15 @@ loadcgo(char *file, char *pkg, char *p, int n) ...@@ -503,11 +506,15 @@ loadcgo(char *file, char *pkg, char *p, int n)
fprint(2, "%s: symbol is both imported and exported: %s\n", argv0, local); fprint(2, "%s: symbol is both imported and exported: %s\n", argv0, local);
nerrors++; nerrors++;
} }
s->dynexport = 1;
if(strcmp(f[0], "cgo_export_static") == 0)
s->cgoexport |= CgoExportStatic;
else
s->cgoexport |= CgoExportDynamic;
if(s->dynimpname == nil) { if(s->dynimpname == nil) {
s->dynimpname = remote; s->dynimpname = remote;
if(ndynexp%32 == 0) if(ndynexp%32 == 0)
dynexp = realloc(dynexp, (ndynexp+32)*sizeof dynexp[0]); dynexp = erealloc(dynexp, (ndynexp+32)*sizeof dynexp[0]);
dynexp[ndynexp++] = s; dynexp[ndynexp++] = s;
} else if(strcmp(s->dynimpname, remote) != 0) { } 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); fprint(2, "%s: conflicting cgo_export directives: %s as %s and %s\n", argv0, s->name, s->dynimpname, remote);
...@@ -530,7 +537,7 @@ loadcgo(char *file, char *pkg, char *p, int n) ...@@ -530,7 +537,7 @@ loadcgo(char *file, char *pkg, char *p, int n)
return; return;
} }
free(interpreter); free(interpreter);
interpreter = strdup(f[1]); interpreter = estrdup(f[1]);
} }
continue; continue;
} }
...@@ -539,8 +546,8 @@ loadcgo(char *file, char *pkg, char *p, int n) ...@@ -539,8 +546,8 @@ loadcgo(char *file, char *pkg, char *p, int n)
if(nf != 2) if(nf != 2)
goto err; goto err;
if(nldflag%32 == 0) if(nldflag%32 == 0)
ldflag = realloc(ldflag, (nldflag+32)*sizeof ldflag[0]); ldflag = erealloc(ldflag, (nldflag+32)*sizeof ldflag[0]);
ldflag[nldflag++] = strdup(f[1]); ldflag[nldflag++] = estrdup(f[1]);
continue; continue;
} }
} }
...@@ -844,7 +851,7 @@ getpkg(char *path) ...@@ -844,7 +851,7 @@ getpkg(char *path)
if(strcmp(p->path, path) == 0) if(strcmp(p->path, path) == 0)
return p; return p;
p = mal(sizeof *p); p = mal(sizeof *p);
p->path = strdup(path); p->path = estrdup(path);
p->next = phash[h]; p->next = phash[h];
phash[h] = p; phash[h] = p;
p->all = pkgall; p->all = pkgall;
...@@ -868,7 +875,7 @@ imported(char *pkg, char *import) ...@@ -868,7 +875,7 @@ imported(char *pkg, char *import)
i->mimpby *= 2; i->mimpby *= 2;
if(i->mimpby == 0) if(i->mimpby == 0)
i->mimpby = 16; 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; i->impby[i->nimpby++] = p;
free(pkg); free(pkg);
......
...@@ -595,7 +595,7 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn) ...@@ -595,7 +595,7 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
s->sub = sect->sym->sub; s->sub = sect->sym->sub;
sect->sym->sub = s; sect->sym->sub = s;
s->type = sect->sym->type | (s->type&~SMASK) | SSUB; s->type = sect->sym->type | (s->type&~SMASK) | SSUB;
if(!s->dynexport) { if(!(s->cgoexport & CgoExportDynamic)) {
s->dynimplib = nil; // satisfy dynimport s->dynimplib = nil; // satisfy dynimport
s->dynimpname = nil; // satisfy dynimport s->dynimpname = nil; // satisfy dynimport
} }
......
...@@ -639,7 +639,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) ...@@ -639,7 +639,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
s->size = (sym+1)->value - sym->value; s->size = (sym+1)->value - sym->value;
else else
s->size = sect->addr + sect->size - sym->value; s->size = sect->addr + sect->size - sym->value;
if(!s->dynexport) { if(!(s->cgoexport & CgoExportDynamic)) {
s->dynimplib = nil; // satisfy dynimport s->dynimplib = nil; // satisfy dynimport
s->dynimpname = nil; // satisfy dynimport s->dynimpname = nil; // satisfy dynimport
} }
......
...@@ -44,6 +44,8 @@ int nlibdir = 0; ...@@ -44,6 +44,8 @@ int nlibdir = 0;
static int maxlibdir = 0; static int maxlibdir = 0;
static int cout = -1; static int cout = -1;
static void hostlinksetup(void);
char* goroot; char* goroot;
char* goarch; char* goarch;
char* goos; char* goos;
...@@ -59,11 +61,7 @@ Lflag(char *arg) ...@@ -59,11 +61,7 @@ Lflag(char *arg)
maxlibdir = 8; maxlibdir = 8;
else else
maxlibdir *= 2; maxlibdir *= 2;
p = realloc(libdir, maxlibdir * sizeof(*p)); p = erealloc(libdir, maxlibdir * sizeof(*p));
if (p == nil) {
print("too many -L's: %d\n", nlibdir);
usage();
}
libdir = p; libdir = p;
} }
libdir[nlibdir++] = arg; libdir[nlibdir++] = arg;
...@@ -95,7 +93,7 @@ libinit(void) ...@@ -95,7 +93,7 @@ libinit(void)
#endif #endif
cout = create(outfile, 1, 0775); cout = create(outfile, 1, 0775);
if(cout < 0) { if(cout < 0) {
diag("cannot create %s", outfile); diag("cannot create %s: %r", outfile);
errorexit(); errorexit();
} }
...@@ -242,7 +240,7 @@ addlibpath(char *srcref, char *objref, char *file, char *pkg) ...@@ -242,7 +240,7 @@ addlibpath(char *srcref, char *objref, char *file, char *pkg)
if(libraryp == nlibrary){ if(libraryp == nlibrary){
nlibrary = 50 + 2*libraryp; nlibrary = 50 + 2*libraryp;
library = realloc(library, sizeof library[0] * nlibrary); library = erealloc(library, sizeof library[0] * nlibrary);
} }
l = &library[libraryp++]; l = &library[libraryp++];
...@@ -288,7 +286,7 @@ loadinternal(char *name) ...@@ -288,7 +286,7 @@ loadinternal(char *name)
void void
loadlib(void) loadlib(void)
{ {
int i; int i, w, x;
loadinternal("runtime"); loadinternal("runtime");
if(thechar == '5') if(thechar == '5')
...@@ -303,6 +301,28 @@ loadlib(void) ...@@ -303,6 +301,28 @@ loadlib(void)
objfile(library[i].file, library[i].pkg); 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. // We've loaded all the code now.
// If there are no dynamic libraries needed, gcc disables dynamic linking. // 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) // Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
...@@ -375,7 +395,7 @@ objfile(char *file, char *pkg) ...@@ -375,7 +395,7 @@ objfile(char *file, char *pkg)
/* load it as a regular file */ /* load it as a regular file */
l = Bseek(f, 0L, 2); l = Bseek(f, 0L, 2);
Bseek(f, 0L, 0); Bseek(f, 0L, 0);
ldobj(f, pkg, l, file, FileObj); ldobj(f, pkg, l, file, file, FileObj);
Bterm(f); Bterm(f);
free(pkg); free(pkg);
return; return;
...@@ -434,7 +454,7 @@ objfile(char *file, char *pkg) ...@@ -434,7 +454,7 @@ objfile(char *file, char *pkg)
l--; l--;
snprint(pname, sizeof pname, "%s(%.*s)", file, utfnlen(arhdr.name, l), arhdr.name); snprint(pname, sizeof pname, "%s(%.*s)", file, utfnlen(arhdr.name, l), arhdr.name);
l = atolwhex(arhdr.size); l = atolwhex(arhdr.size);
ldobj(f, pkg, l, pname, ArchiveObj); ldobj(f, pkg, l, pname, file, ArchiveObj);
} }
out: out:
...@@ -442,8 +462,213 @@ out: ...@@ -442,8 +462,213 @@ out:
free(pkg); 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 void
ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence) 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, char *file, int whence)
{ {
char *line; char *line;
int n, c1, c2, c3, c4; int n, c1, c2, c3, c4;
...@@ -453,7 +678,7 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence) ...@@ -453,7 +678,7 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
eof = Boffset(f) + len; eof = Boffset(f) + len;
pn = strdup(pn); pn = estrdup(pn);
c1 = Bgetc(f); c1 = Bgetc(f);
c2 = Bgetc(f); c2 = Bgetc(f);
...@@ -466,18 +691,15 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence) ...@@ -466,18 +691,15 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
magic = c1<<24 | c2<<16 | c3<<8 | c4; magic = c1<<24 | c2<<16 | c3<<8 | c4;
if(magic == 0x7f454c46) { // \x7F E L F if(magic == 0x7f454c46) { // \x7F E L F
ldelf(f, pkg, len, pn); ldhostobj(ldelf, f, pkg, len, pn, file);
free(pn);
return; return;
} }
if((magic&~1) == 0xfeedface || (magic&~0x01000000) == 0xcefaedfe) { if((magic&~1) == 0xfeedface || (magic&~0x01000000) == 0xcefaedfe) {
ldmacho(f, pkg, len, pn); ldhostobj(ldmacho, f, pkg, len, pn, file);
free(pn);
return; return;
} }
if(c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86) { if(c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86) {
ldpe(f, pkg, len, pn); ldhostobj(ldpe, f, pkg, len, pn, file);
free(pn);
return; return;
} }
...@@ -524,7 +746,7 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence) ...@@ -524,7 +746,7 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
line[n] = '\0'; line[n] = '\0';
if(n-10 > strlen(t)) { if(n-10 > strlen(t)) {
if(theline == nil) if(theline == nil)
theline = strdup(line+10); theline = estrdup(line+10);
else if(strcmp(theline, line+10) != 0) { else if(strcmp(theline, line+10) != 0) {
line[n] = '\0'; line[n] = '\0';
diag("%s: object is [%s] expected [%s]", pn, line+10, theline); diag("%s: object is [%s] expected [%s]", pn, line+10, theline);
...@@ -1460,23 +1682,6 @@ Yconv(Fmt *fp) ...@@ -1460,23 +1682,6 @@ Yconv(Fmt *fp)
vlong coutpos; 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 void
cflush(void) cflush(void)
{ {
...@@ -1576,7 +1781,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) ...@@ -1576,7 +1781,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
put(s, s->name, 'T', s->value, s->size, s->version, 0); put(s, s->name, 'T', s->value, s->size, s->version, 0);
for(s=allsym; s!=S; s=s->allsym) { for(s=allsym; s!=S; s=s->allsym) {
if(s->hide) if(s->hide || (s->name[0] == '.' && s->version == 0))
continue; continue;
switch(s->type&SMASK) { switch(s->type&SMASK) {
case SCONST: case SCONST:
...@@ -1664,3 +1869,27 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) ...@@ -1664,3 +1869,27 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
Bprint(&bso, "symsize = %ud\n", symsize); Bprint(&bso, "symsize = %ud\n", symsize);
Bflush(&bso); 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;
}
...@@ -138,6 +138,7 @@ EXTERN char* outfile; ...@@ -138,6 +138,7 @@ EXTERN char* outfile;
EXTERN int32 nsymbol; EXTERN int32 nsymbol;
EXTERN char* thestring; EXTERN char* thestring;
EXTERN int ndynexp; EXTERN int ndynexp;
EXTERN Sym** dynexp;
EXTERN int nldflag; EXTERN int nldflag;
EXTERN char** ldflag; EXTERN char** ldflag;
EXTERN int havedynamic; EXTERN int havedynamic;
...@@ -149,6 +150,21 @@ EXTERN int flag_shared; ...@@ -149,6 +150,21 @@ EXTERN int flag_shared;
EXTERN char* tracksym; EXTERN char* tracksym;
EXTERN char* interpreter; 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 segtext;
EXTERN Segment segdata; EXTERN Segment segdata;
EXTERN Segment segsym; EXTERN Segment segsym;
...@@ -187,7 +203,7 @@ void adddynrel(Sym*, Reloc*); ...@@ -187,7 +203,7 @@ void adddynrel(Sym*, Reloc*);
void adddynrela(Sym*, Sym*, Reloc*); void adddynrela(Sym*, Sym*, Reloc*);
Sym* lookuprel(void); Sym* lookuprel(void);
void ldobj1(Biobuf *f, char*, int64 len, char *pn); 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 ldelf(Biobuf*, char*, int64, char*);
void ldmacho(Biobuf*, char*, int64, char*); void ldmacho(Biobuf*, char*, int64, char*);
void ldpe(Biobuf*, char*, int64, char*); void ldpe(Biobuf*, char*, int64, char*);
...@@ -242,6 +258,10 @@ void usage(void); ...@@ -242,6 +258,10 @@ void usage(void);
void setinterp(char*); void setinterp(char*);
Sym* listsort(Sym*, int(*cmp)(Sym*, Sym*), int); Sym* listsort(Sym*, int(*cmp)(Sym*, Sym*), int);
int valuecmp(Sym*, Sym*); int valuecmp(Sym*, Sym*);
void hostobjs(void);
void hostlink(void);
char* estrdup(char*);
void* erealloc(void*, long);
int pathchar(void); int pathchar(void);
void* mal(uint32); void* mal(uint32);
......
...@@ -56,11 +56,7 @@ newMachoLoad(uint32 type, uint32 ndata) ...@@ -56,11 +56,7 @@ newMachoLoad(uint32 type, uint32 ndata)
mload = 1; mload = 1;
else else
mload *= 2; mload *= 2;
load = realloc(load, mload*sizeof load[0]); load = erealloc(load, mload*sizeof load[0]);
if(load == nil) {
diag("out of memory");
errorexit();
}
} }
if(macho64 && (ndata & 1)) if(macho64 && (ndata & 1))
...@@ -286,13 +282,8 @@ machoadddynlib(char *lib) ...@@ -286,13 +282,8 @@ machoadddynlib(char *lib)
load_budget += 4096; load_budget += 4096;
} }
if(ndylib%32 == 0) { if(ndylib%32 == 0)
dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]); dylib = erealloc(dylib, (ndylib+32)*sizeof dylib[0]);
if(dylib == nil) {
diag("out of memory");
errorexit();
}
}
dylib[ndylib++] = lib; dylib[ndylib++] = lib;
} }
......
...@@ -195,7 +195,7 @@ initdynimport(void) ...@@ -195,7 +195,7 @@ initdynimport(void)
dr = nil; dr = nil;
m = nil; m = nil;
for(s = allsym; s != S; s = s->allsym) { for(s = allsym; s != S; s = s->allsym) {
if(!s->reachable || !s->dynimpname || s->dynexport) if(!s->reachable || !s->dynimpname || (s->cgoexport & CgoExportDynamic))
continue; continue;
for(d = dr; d != nil; d = d->next) { for(d = dr; d != nil; d = d->next) {
if(strcmp(d->name,s->dynimplib) == 0) { if(strcmp(d->name,s->dynimplib) == 0) {
...@@ -335,7 +335,7 @@ initdynexport(void) ...@@ -335,7 +335,7 @@ initdynexport(void)
nexport = 0; nexport = 0;
for(s = allsym; s != S; s = s->allsym) { for(s = allsym; s != S; s = s->allsym) {
if(!s->reachable || !s->dynimpname || !s->dynexport) if(!s->reachable || !s->dynimpname || !(s->cgoexport & CgoExportDynamic))
continue; continue;
if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) { if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) {
diag("pe dynexport table is full"); diag("pe dynexport table is full");
......
...@@ -121,7 +121,17 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) ...@@ -121,7 +121,17 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
// One pass for each binding: STB_LOCAL, STB_GLOBAL, // One pass for each binding: STB_LOCAL, STB_GLOBAL,
// maybe one day STB_WEAK. // 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) if(bind != elfbind)
return; return;
......
...@@ -12,8 +12,10 @@ ...@@ -12,8 +12,10 @@
// void crosscall2(void (*fn)(void *, int), void *, int); // void crosscall2(void (*fn)(void *, int), void *, int);
// //
// We need to export the symbol crosscall2 in order to support // We need to export the symbol crosscall2 in order to support
// callbacks from shared libraries. // callbacks from shared libraries. This applies regardless of
#pragma dynexport crosscall2 crosscall2 // linking mode.
#pragma cgo_export_static crosscall2
#pragma cgo_export_dynamic crosscall2
// Allocate memory. This allocates the requested number of bytes in // Allocate memory. This allocates the requested number of bytes in
// memory controlled by the Go runtime. The allocated memory will be // memory controlled by the Go runtime. The allocated memory will be
......
...@@ -280,3 +280,9 @@ runtime·cgounimpl(void) // called from (incomplete) assembly ...@@ -280,3 +280,9 @@ runtime·cgounimpl(void) // called from (incomplete) assembly
{ {
runtime·throw("runtime: cgo not implemented"); 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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment