case ld.R_TLS:
if r.Siz == 4 {
- if ld.Flag_shared != 0 {
+ if ld.Buildmode == ld.BuildmodeCShared {
ld.Thearch.Lput(ld.R_ARM_TLS_IE32 | uint32(elfsym)<<8)
} else {
ld.Thearch.Lput(ld.R_ARM_TLS_LE32 | uint32(elfsym)<<8)
case ld.R_TLS:
if r.Siz == 4 {
- if ld.Flag_shared != 0 {
+ if ld.Buildmode == ld.BuildmodeCShared {
ld.Thearch.Vput(ld.R_X86_64_GOTTPOFF | uint64(elfsym)<<32)
} else {
ld.Thearch.Vput(ld.R_X86_64_TPOFF32 | uint64(elfsym)<<32)
ld.Linkmode = ld.LinkInternal
}
- if ld.Flag_shared != 0 {
+ if ld.Buildmode == ld.BuildmodeCShared {
ld.Linkmode = ld.LinkExternal
}
}
// Create a new entry in the .init_array section that points to the
// library initializer function.
- if Flag_shared != 0 && s.Name == INITENTRY {
+ if Buildmode == BuildmodeCShared && s.Name == INITENTRY {
addinitarrdata(s)
}
}
sect.Length = uint64(datsize) - sect.Vaddr
/* shared library initializer */
- if Flag_shared != 0 {
+ if Buildmode == BuildmodeCShared {
sect := addsection(&Segdata, ".init_array", 06)
sect.Align = maxalign(s, SINITARR)
datsize = Rnd(datsize, int64(sect.Align))
Addstring(shstrtab, ".note.GNU-stack")
}
- if Flag_shared != 0 {
+ if Buildmode == BuildmodeCShared {
Addstring(shstrtab, ".init_array")
switch Thearch.Thechar {
case '6', '7', '9':
local = expandpkg(local, pkg)
s = Linklookup(Ctxt, local, 0)
- if Flag_shared != 0 && s == Linklookup(Ctxt, "main", 0) {
+ if Buildmode == BuildmodeCShared && s == Linklookup(Ctxt, "main", 0) {
continue
}
import (
"bytes"
"cmd/internal/obj"
+ "errors"
"fmt"
"io/ioutil"
"log"
elfglobalsymndx int
flag_installsuffix string
flag_race int
- Flag_shared int
+ Buildmode BuildMode
tracksym string
interpreter string
tmpdir string
Ctxt.Libdir = append(Ctxt.Libdir, arg)
}
+// A BuildMode indicates the sort of object we are building:
+// "exe": build a main package and everything it imports into an executable.
+// "c-shared": build a main package, plus all packages that it imports, into a
+// single C shared library. The only callable symbols will be those functions
+// marked as exported.
+type BuildMode uint8
+
+const (
+ BuildmodeExe BuildMode = iota
+ BuildmodeCShared
+)
+
+func (mode *BuildMode) Set(s string) error {
+ switch s {
+ default:
+ return errors.New("invalid mode")
+ case "exe":
+ *mode = BuildmodeExe
+ case "c-shared":
+ goarch := obj.Getgoarch()
+ if goarch != "amd64" && goarch != "arm" {
+ return fmt.Errorf("not supported on %s", goarch)
+ }
+ *mode = BuildmodeCShared
+ }
+ return nil
+}
+
+func (mode *BuildMode) String() string {
+ switch *mode {
+ case BuildmodeExe:
+ return "exe"
+ case BuildmodeCShared:
+ return "c-shared"
+ }
+ return fmt.Sprintf("BuildMode(%d)", uint8(*mode))
+}
+
/*
* Unix doesn't like it when we write to a running (or, sometimes,
* recently run) binary, so remove the output file before writing it.
coutbuf = *Binitw(f)
if INITENTRY == "" {
- if Flag_shared == 0 {
- INITENTRY = fmt.Sprintf("_rt0_%s_%s", goarch, goos)
- } else {
+ switch Buildmode {
+ case BuildmodeCShared:
INITENTRY = fmt.Sprintf("_rt0_%s_%s_lib", goarch, goos)
+ case BuildmodeExe:
+ INITENTRY = fmt.Sprintf("_rt0_%s_%s", goarch, goos)
+ default:
+ Diag("unknown INITENTRY for buildmode %v", Buildmode)
}
}
}
func loadlib() {
- if Flag_shared != 0 {
+ if Buildmode == BuildmodeCShared {
s := Linklookup(Ctxt, "runtime.islibrary", 0)
s.Dupok = 1
Adduint8(Ctxt, s, 1)
// binaries, so leave it enabled on OS X (Mach-O) binaries.
// Also leave it enabled on Solaris which doesn't support
// statically linked binaries.
- if Flag_shared == 0 && havedynamic == 0 && HEADTYPE != Hdarwin && HEADTYPE != Hsolaris {
+ if Buildmode == BuildmodeExe && havedynamic == 0 && HEADTYPE != Hdarwin && HEADTYPE != Hsolaris {
Debug['d'] = 1
}
argv = append(argv, "-Wl,--rosegment")
}
- if Flag_shared != 0 {
+ if Buildmode == BuildmodeCShared {
argv = append(argv, "-Wl,-Bsymbolic")
argv = append(argv, "-shared")
}
obj.Flagfn1("X", "name value: define string data", addstrdata1)
obj.Flagcount("Z", "clear stack frame on entry", &Debug['Z'])
obj.Flagcount("a", "disassemble output", &Debug['a'])
+ flag.Var(&Buildmode, "buildmode", "build mode to use")
obj.Flagcount("c", "dump call graph", &Debug['c'])
obj.Flagcount("d", "disable dynamic executable", &Debug['d'])
obj.Flagstr("extld", "ld: linker to run in external mode", &extld)
obj.Flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath)
obj.Flagcount("race", "enable race detector", &flag_race)
obj.Flagcount("s", "disable symbol table", &Debug['s'])
+ var flagShared int
if Thearch.Thechar == '5' || Thearch.Thechar == '6' {
- obj.Flagcount("shared", "generate shared object (implies -linkmode external)", &Flag_shared)
+ obj.Flagcount("shared", "generate shared object (implies -linkmode external)", &flagShared)
}
obj.Flagstr("tmpdir", "dir: leave temporary files in this directory", &tmpdir)
obj.Flagcount("u", "reject unsafe packages", &Debug['u'])
startProfile()
Ctxt.Bso = &Bso
Ctxt.Debugvlog = int32(Debug['v'])
+ if flagShared != 0 {
+ if Buildmode == BuildmodeExe {
+ Buildmode = BuildmodeCShared
+ } else if Buildmode != BuildmodeCShared {
+ Diag("-shared and -buildmode=%s are incompatible\n", Buildmode.String())
+ Errorexit()
+ }
+ }
if flag.NArg() != 1 {
usage()