]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/ld: host linking support for linux/amd64
authorRuss Cox <rsc@golang.org>
Thu, 7 Mar 2013 14:19:02 +0000 (09:19 -0500)
committerRuss Cox <rsc@golang.org>
Thu, 7 Mar 2013 14:19:02 +0000 (09:19 -0500)
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

21 files changed:
src/cmd/5l/asm.c
src/cmd/5l/l.h
src/cmd/5l/obj.c
src/cmd/6l/asm.c
src/cmd/6l/l.h
src/cmd/6l/obj.c
src/cmd/8l/asm.c
src/cmd/8l/l.h
src/cmd/8l/obj.c
src/cmd/ld/data.c
src/cmd/ld/dwarf.c
src/cmd/ld/go.c
src/cmd/ld/ldelf.c
src/cmd/ld/ldmacho.c
src/cmd/ld/lib.c
src/cmd/ld/lib.h
src/cmd/ld/macho.c
src/cmd/ld/pe.c
src/cmd/ld/symtab.c
src/pkg/runtime/cgo/callbacks.c
src/pkg/runtime/cgocall.c

index 04f2a9c6cb0b8eec74a5a544e74ce12ac15f4544..097b74e31bbae30b0f4e17bfc8d362f90caf1fee 100644 (file)
@@ -125,7 +125,7 @@ adddynrel(Sym *s, Reloc *r)
        // 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);
@@ -138,7 +138,7 @@ adddynrel(Sym *s, Reloc *r)
                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);
@@ -149,7 +149,7 @@ adddynrel(Sym *s, Reloc *r)
                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);
@@ -171,7 +171,7 @@ adddynrel(Sym *s, Reloc *r)
 
        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);
@@ -184,7 +184,7 @@ adddynrel(Sym *s, Reloc *r)
                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;
@@ -201,7 +201,7 @@ adddynrel(Sym *s, Reloc *r)
        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);
@@ -210,7 +210,7 @@ adddynrel(Sym *s, Reloc *r)
        }
        
        // 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) {
@@ -464,7 +464,7 @@ adddynsym(Sym *s)
 
                /* 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;
@@ -472,7 +472,7 @@ adddynsym(Sym *s)
                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) {
index 62dd8947f06a19757627637170835fd190d3b0ec..059e269a91d0b0418f3470622d155a1cf95a9114 100644 (file)
@@ -137,7 +137,7 @@ struct      Sym
        short   version;
        uchar   dupok;
        uchar   reachable;
-       uchar   dynexport;
+       uchar   cgoexport;
        uchar   leaf;
        int32   dynid;
        int32   plt;
index 6aa7fdd69bf648f5ea102c014418d9d5ef80b573..58ac77052d9d1a0523cff2e4faefadaf4673a744 100644 (file)
@@ -82,6 +82,7 @@ main(int argc, char *argv[])
        INITRND = -1;
        INITENTRY = 0;
        LIBINITENTRY = 0;
+       linkmode = LinkInternal; // TODO: LinkAuto once everything works.
        nuxiinit();
        
        p = getgoarm();
@@ -126,6 +127,7 @@ main(int argc, char *argv[])
        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);
 
@@ -268,6 +270,7 @@ main(int argc, char *argv[])
        reloc();
        asmb();
        undef();
+       hostlink();
 
        if(debug['c'])
                print("ARM size = %d\n", armsize);
index 5fb75ba4d003160b948109f75db04d1af197a23d..627e10af0a2ba06f7530f65ba6a165ac1f39c2e3 100644 (file)
@@ -131,7 +131,7 @@ adddynrel(Sym *s, Reloc *r)
 
        // 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);
@@ -142,7 +142,7 @@ adddynrel(Sym *s, Reloc *r)
        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;
@@ -150,7 +150,7 @@ adddynrel(Sym *s, Reloc *r)
                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
@@ -171,7 +171,7 @@ adddynrel(Sym *s, Reloc *r)
                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;
@@ -182,12 +182,12 @@ adddynrel(Sym *s, Reloc *r)
        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;
@@ -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_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) {
@@ -219,7 +219,7 @@ adddynrel(Sym *s, Reloc *r)
                }
                // 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;
@@ -229,7 +229,7 @@ adddynrel(Sym *s, Reloc *r)
        }
        
        // 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) {
@@ -470,7 +470,7 @@ adddynsym(Sym *s)
                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;
@@ -480,7 +480,7 @@ adddynsym(Sym *s)
                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) {
@@ -510,7 +510,7 @@ adddynsym(Sym *s)
                /* 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));
                }
index ffb8a45522e41d0fd9f68aea1c6cfb7b9e0c1e25..22fb23b1b70f04e0f581f34f97fc51e9594cfe2a 100644 (file)
@@ -144,7 +144,7 @@ struct      Sym
        short   version;
        uchar   dupok;
        uchar   reachable;
-       uchar   dynexport;
+       uchar   cgoexport;
        uchar   special;
        uchar   stkcheck;
        uchar   hide;
index 10e4a986019eb13849e3e84c31a199d74f7a06f7..6ced8be7fd665082811ceb868e07287c9d053fc6 100644 (file)
@@ -83,6 +83,7 @@ main(int argc, char *argv[])
        INITRND = -1;
        INITENTRY = 0;
        LIBINITENTRY = 0;
+       linkmode = LinkInternal; // TODO: LinkAuto once everything works.
        nuxiinit();
 
        flagcount("1", "use alternate profiling code", &debug['1']);
@@ -122,6 +123,10 @@ main(int argc, char *argv[])
        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();
@@ -282,6 +287,7 @@ main(int argc, char *argv[])
        reloc();
        asmb();
        undef();
+       hostlink();
        if(debug['v']) {
                Bprint(&bso, "%5.2f cpu time\n", cputime());
                Bprint(&bso, "%d symbols\n", nsymbol);
index a00174c3681261f5b4144614fa15d57e15629e9b..3563c0849f3b8b503ba2fd7ce4cde8a578d1c51b 100644 (file)
@@ -128,7 +128,7 @@ adddynrel(Sym *s, Reloc *r)
 
        // 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);
@@ -139,7 +139,7 @@ adddynrel(Sym *s, Reloc *r)
        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;
@@ -147,7 +147,7 @@ adddynrel(Sym *s, Reloc *r)
                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) {
@@ -175,19 +175,19 @@ adddynrel(Sym *s, Reloc *r)
                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;
@@ -198,7 +198,7 @@ adddynrel(Sym *s, Reloc *r)
                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) {
@@ -217,7 +217,7 @@ adddynrel(Sym *s, Reloc *r)
        }
        
        // 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) {
@@ -461,7 +461,7 @@ adddynsym(Sym *s)
        
                /* 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;
@@ -469,7 +469,7 @@ adddynsym(Sym *s)
                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) {
index f88f058e35f4569c01e5fd844c75445c636730d1..f6b164d9e40484273afdcf92d14d6e576e764d6b 100644 (file)
@@ -126,7 +126,7 @@ struct      Sym
        short   version;
        uchar   dupok;
        uchar   reachable;
-       uchar   dynexport;
+       uchar   cgoexport;
        uchar   special;
        uchar   stkcheck;
        uchar   hide;
index dcb8390b97979d8a4b07f95d2ad385af7d999011..f06bc5d9dc996464453a9cb70995fa8712ddc021 100644 (file)
@@ -90,6 +90,7 @@ main(int argc, char *argv[])
        INITRND = -1;
        INITENTRY = 0;
        LIBINITENTRY = 0;
+       linkmode = LinkInternal; // TODO: LinkAuto once everything works.
        nuxiinit();
 
        flagcount("1", "use alternate profiling code", &debug['1']);
@@ -125,6 +126,7 @@ main(int argc, char *argv[])
        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);
 
@@ -308,6 +310,8 @@ main(int argc, char *argv[])
        reloc();
        asmb();
        undef();
+       hostlink();
+
        if(debug['v']) {
                Bprint(&bso, "%5.2f cpu time\n", cputime());
                Bprint(&bso, "%d symbols\n", nsymbol);
index 6c6b1be433582178477adaaaae960180efbfd78f..b344abd9b0794b954b05fd95b3338821e8295c1d 100644 (file)
@@ -135,11 +135,7 @@ addrel(Sym *s)
                        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++];
@@ -300,7 +296,7 @@ dynrelocsym(Sym *s)
        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);
@@ -342,11 +338,7 @@ symgrow(Sym *s, int32 siz)
                        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;
index d6a357e4982c5abf45be3db62e7988dd2d97d3ec..949752994b185cbe8a2a2dc007f3c7f8d91e4206 100644 (file)
@@ -1260,7 +1260,7 @@ dwarfaddfrag(int n, char *frag)
        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]));
        }
 
@@ -1342,7 +1342,7 @@ addhistfile(char *zentry)
 
        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>";
@@ -1412,7 +1412,7 @@ checknesting(void)
                includestacksize += 1;
                includestacksize <<= 2;
 //             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)
                        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);
index 2b6fdd6b5ebc1a4e8ccdf175dde79d5fb3117f42..403b800b9bc8f8f927e091d847f33a05695fee10 100644 (file)
@@ -59,7 +59,7 @@ ilookup(char *name)
                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++;
@@ -71,8 +71,6 @@ static void loadcgo(char*, char*, char*, int);
 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)
 {
@@ -205,14 +203,14 @@ loadpkgdata(char *file, char *pkg, char *data, int len)
        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);
@@ -244,7 +242,7 @@ expandpkg(char *t0, char *pkg)
                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);
@@ -429,7 +427,7 @@ loadcgo(char *file, char *pkg, char *p, int 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) {
@@ -487,9 +485,14 @@ loadcgo(char *file, char *pkg, char *p, int n)
                        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];
@@ -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);
                                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);
@@ -530,7 +537,7 @@ loadcgo(char *file, char *pkg, char *p, int n)
                                        return;
                                }
                                free(interpreter);
-                               interpreter = strdup(f[1]);
+                               interpreter = estrdup(f[1]);
                        }
                        continue;
                }
@@ -539,8 +546,8 @@ loadcgo(char *file, char *pkg, char *p, int n)
                        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;
                }
        }
@@ -844,7 +851,7 @@ getpkg(char *path)
                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;
@@ -868,7 +875,7 @@ imported(char *pkg, char *import)
                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);
index 2bbf4f83e356b7d0ee5d689c20cafebb1d40a10f..750dff4e6010a5b656402548750f6a89b1d4d5dd 100644 (file)
@@ -595,7 +595,7 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
                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
                }
index 41852f17c67280f4335242fe1c0099150ac19c3e..2509be471c3372fd6bc3215153ed62586119acc6 100644 (file)
@@ -639,7 +639,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
                        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
                }
index 26fa4f2ac7adedb31629550ca5a0f16534f689c5..db6b7761b7badba07675dea8cc3557c23798bd15 100644 (file)
@@ -44,6 +44,8 @@ int   nlibdir = 0;
 static int     maxlibdir = 0;
 static int     cout = -1;
 
+static void    hostlinksetup(void);
+
 char*  goroot;
 char*  goarch;
 char*  goos;
@@ -59,11 +61,7 @@ Lflag(char *arg)
                        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;
@@ -95,7 +93,7 @@ libinit(void)
 #endif
        cout = create(outfile, 1, 0775);
        if(cout < 0) {
-               diag("cannot create %s", outfile);
+               diag("cannot create %s: %r", outfile);
                errorexit();
        }
 
@@ -242,7 +240,7 @@ addlibpath(char *srcref, char *objref, char *file, char *pkg)
 
        if(libraryp == nlibrary){
                nlibrary = 50 + 2*libraryp;
-               library = realloc(library, sizeof library[0] * nlibrary);
+               library = erealloc(library, sizeof library[0] * nlibrary);
        }
 
        l = &library[libraryp++];
@@ -288,7 +286,7 @@ loadinternal(char *name)
 void
 loadlib(void)
 {
-       int i;
+       int i, w, x;
 
        loadinternal("runtime");
        if(thechar == '5')
@@ -303,6 +301,28 @@ loadlib(void)
                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)
@@ -375,7 +395,7 @@ objfile(char *file, char *pkg)
                /* 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;
@@ -434,7 +454,7 @@ objfile(char *file, char *pkg)
                        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:
@@ -442,8 +462,213 @@ 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;
@@ -453,7 +678,7 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
 
        eof = Boffset(f) + len;
 
-       pn = strdup(pn);
+       pn = estrdup(pn);
 
        c1 = Bgetc(f);
        c2 = Bgetc(f);
@@ -466,18 +691,15 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
 
        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;
        }
 
@@ -524,7 +746,7 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
        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);
@@ -1460,23 +1682,6 @@ Yconv(Fmt *fp)
 
 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)
 {
@@ -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);
 
        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:
@@ -1664,3 +1869,27 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
                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;
+}
index 25fe45675e23ba39d59c0f200e3dce23b3b95b04..0b7e48c8a2816ad068b7c12252c0eb190eb1c8fe 100644 (file)
@@ -138,6 +138,7 @@ EXTERN      char*   outfile;
 EXTERN int32   nsymbol;
 EXTERN char*   thestring;
 EXTERN int     ndynexp;
+EXTERN Sym**   dynexp;
 EXTERN int     nldflag;
 EXTERN char**  ldflag;
 EXTERN int     havedynamic;
@@ -149,6 +150,21 @@ EXTERN     int flag_shared;
 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;
@@ -187,7 +203,7 @@ void        adddynrel(Sym*, Reloc*);
 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*);
@@ -242,6 +258,10 @@ void       usage(void);
 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);
index 6781c25a43d5703e526336f39a6c23368142e614..75be9d940233c5806bd8676162d0118435cc0240 100644 (file)
@@ -56,11 +56,7 @@ newMachoLoad(uint32 type, uint32 ndata)
                        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))
@@ -286,13 +282,8 @@ machoadddynlib(char *lib)
                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;
 }
 
index f2903ba0f922d46790ad9343c6a3cfc31aa36dac..85f622dbc016f2d6b52321be2a0b3c3aefc5c454 100644 (file)
@@ -195,7 +195,7 @@ initdynimport(void)
        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) {
@@ -335,7 +335,7 @@ initdynexport(void)
        
        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");
index 89a594872e88136bb20b0c6c557d8f8295f88a8e..d8b8b932893d6d441a531bebdac50bda1f209e3b 100644 (file)
@@ -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,
        // 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;
 
index 51bd529ecb43dc3e508f5660c5d071092a138e02..19f6115a665b6ea0614570bbf28326b1b379e66d 100644 (file)
 //   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
index 590bf9b672417b14a43060f16271efb4e2292bc3..3ed1243aacc84e43670307d8db06254029ad4704 100644 (file)
@@ -280,3 +280,9 @@ runtime·cgounimpl(void)    // called from (incomplete) assembly
 {
        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