mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/link: don't export all symbols for ELF external linking
Since this may add a large number of --export-dynamic-symbol options, use a response file if the command line gets large. Fixes #53579 Change-Id: Ic226bf372bf1e177a3dae886d1c48f4ce3569c0e Reviewed-on: https://go-review.googlesource.com/c/go/+/414654 Reviewed-by: Michael Pratt <mpratt@google.com> Reviewed-by: Joedian Reid <joedian@golang.org> Run-TryBot: Ian Lance Taylor <iant@golang.org> Auto-Submit: Ian Lance Taylor <iant@golang.org> Reviewed-by: Than McIntosh <thanm@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
2bf0f54bbd
commit
1f29f39795
3 changed files with 129 additions and 17 deletions
|
|
@ -1605,7 +1605,13 @@ func (ctxt *Link) hostlink() {
|
||||||
|
|
||||||
// Force global symbols to be exported for dlopen, etc.
|
// Force global symbols to be exported for dlopen, etc.
|
||||||
if ctxt.IsELF {
|
if ctxt.IsELF {
|
||||||
argv = append(argv, "-rdynamic")
|
if ctxt.DynlinkingGo() || ctxt.BuildMode == BuildModeCShared || !linkerFlagSupported(ctxt.Arch, argv[0], altLinker, "-Wl,--export-dynamic-symbol=main") {
|
||||||
|
argv = append(argv, "-rdynamic")
|
||||||
|
} else {
|
||||||
|
ctxt.loader.ForAllCgoExportDynamic(func(s loader.Sym) {
|
||||||
|
argv = append(argv, "-Wl,--export-dynamic-symbol="+ctxt.loader.SymExtname(s))
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ctxt.HeadType == objabi.Haix {
|
if ctxt.HeadType == objabi.Haix {
|
||||||
fileName := xcoffCreateExportFile(ctxt)
|
fileName := xcoffCreateExportFile(ctxt)
|
||||||
|
|
@ -1748,7 +1754,7 @@ func (ctxt *Link) hostlink() {
|
||||||
// case used has specified "-fuse-ld=...".
|
// case used has specified "-fuse-ld=...".
|
||||||
extld := ctxt.extld()
|
extld := ctxt.extld()
|
||||||
name, args := extld[0], extld[1:]
|
name, args := extld[0], extld[1:]
|
||||||
args = append(args, flagExtldflags...)
|
args = append(args, trimLinkerArgv(flagExtldflags)...)
|
||||||
args = append(args, "-Wl,--version")
|
args = append(args, "-Wl,--version")
|
||||||
cmd := exec.Command(name, args...)
|
cmd := exec.Command(name, args...)
|
||||||
usingLLD := false
|
usingLLD := false
|
||||||
|
|
@ -1775,6 +1781,8 @@ func (ctxt *Link) hostlink() {
|
||||||
argv = append(argv, peimporteddlls()...)
|
argv = append(argv, peimporteddlls()...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
argv = ctxt.passLongArgsInResponseFile(argv, altLinker)
|
||||||
|
|
||||||
if ctxt.Debugvlog != 0 {
|
if ctxt.Debugvlog != 0 {
|
||||||
ctxt.Logf("host link:")
|
ctxt.Logf("host link:")
|
||||||
for _, v := range argv {
|
for _, v := range argv {
|
||||||
|
|
@ -1885,6 +1893,47 @@ func (ctxt *Link) hostlink() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// passLongArgsInResponseFile writes the arguments into a file if they
|
||||||
|
// are very long.
|
||||||
|
func (ctxt *Link) passLongArgsInResponseFile(argv []string, altLinker string) []string {
|
||||||
|
c := 0
|
||||||
|
for _, arg := range argv {
|
||||||
|
c += len(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c < sys.ExecArgLengthLimit {
|
||||||
|
return argv
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only use response files if they are supported.
|
||||||
|
response := filepath.Join(*flagTmpdir, "response")
|
||||||
|
if err := os.WriteFile(response, nil, 0644); err != nil {
|
||||||
|
log.Fatalf("failed while testing response file: %v", err)
|
||||||
|
}
|
||||||
|
if !linkerFlagSupported(ctxt.Arch, argv[0], altLinker, "@"+response) {
|
||||||
|
if ctxt.Debugvlog != 0 {
|
||||||
|
ctxt.Logf("not using response file because linker does not support one")
|
||||||
|
}
|
||||||
|
return argv
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
for _, arg := range argv[1:] {
|
||||||
|
// The external linker response file supports quoted strings.
|
||||||
|
fmt.Fprintf(&buf, "%q\n", arg)
|
||||||
|
}
|
||||||
|
if err := os.WriteFile(response, buf.Bytes(), 0644); err != nil {
|
||||||
|
log.Fatalf("failed while writing response file: %v", err)
|
||||||
|
}
|
||||||
|
if ctxt.Debugvlog != 0 {
|
||||||
|
ctxt.Logf("response file %s contents:\n%s", response, buf.Bytes())
|
||||||
|
}
|
||||||
|
return []string{
|
||||||
|
argv[0],
|
||||||
|
"@" + response,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var createTrivialCOnce sync.Once
|
var createTrivialCOnce sync.Once
|
||||||
|
|
||||||
func linkerFlagSupported(arch *sys.Arch, linker, altLinker, flag string) bool {
|
func linkerFlagSupported(arch *sys.Arch, linker, altLinker, flag string) bool {
|
||||||
|
|
@ -1895,6 +1944,28 @@ func linkerFlagSupported(arch *sys.Arch, linker, altLinker, flag string) bool {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
flags := hostlinkArchArgs(arch)
|
||||||
|
|
||||||
|
moreFlags := trimLinkerArgv(append(flagExtldflags, ldflag...))
|
||||||
|
flags = append(flags, moreFlags...)
|
||||||
|
|
||||||
|
if altLinker != "" {
|
||||||
|
flags = append(flags, "-fuse-ld="+altLinker)
|
||||||
|
}
|
||||||
|
flags = append(flags, flag, "trivial.c")
|
||||||
|
|
||||||
|
cmd := exec.Command(linker, flags...)
|
||||||
|
cmd.Dir = *flagTmpdir
|
||||||
|
cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
// GCC says "unrecognized command line option ‘-no-pie’"
|
||||||
|
// clang says "unknown argument: '-no-pie'"
|
||||||
|
return err == nil && !bytes.Contains(out, []byte("unrecognized")) && !bytes.Contains(out, []byte("unknown"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// trimLinkerArgv returns a new copy of argv that does not include flags
|
||||||
|
// that are not relevant for testing whether some linker option works.
|
||||||
|
func trimLinkerArgv(argv []string) []string {
|
||||||
flagsWithNextArgSkip := []string{
|
flagsWithNextArgSkip := []string{
|
||||||
"-F",
|
"-F",
|
||||||
"-l",
|
"-l",
|
||||||
|
|
@ -1921,10 +1992,10 @@ func linkerFlagSupported(arch *sys.Arch, linker, altLinker, flag string) bool {
|
||||||
"-target",
|
"-target",
|
||||||
}
|
}
|
||||||
|
|
||||||
flags := hostlinkArchArgs(arch)
|
var flags []string
|
||||||
keep := false
|
keep := false
|
||||||
skip := false
|
skip := false
|
||||||
for _, f := range append(flagExtldflags, ldflag...) {
|
for _, f := range argv {
|
||||||
if keep {
|
if keep {
|
||||||
flags = append(flags, f)
|
flags = append(flags, f)
|
||||||
keep = false
|
keep = false
|
||||||
|
|
@ -1945,19 +2016,7 @@ func linkerFlagSupported(arch *sys.Arch, linker, altLinker, flag string) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return flags
|
||||||
if altLinker != "" {
|
|
||||||
flags = append(flags, "-fuse-ld="+altLinker)
|
|
||||||
}
|
|
||||||
flags = append(flags, flag, "trivial.c")
|
|
||||||
|
|
||||||
cmd := exec.Command(linker, flags...)
|
|
||||||
cmd.Dir = *flagTmpdir
|
|
||||||
cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...)
|
|
||||||
out, err := cmd.CombinedOutput()
|
|
||||||
// GCC says "unrecognized command line option ‘-no-pie’"
|
|
||||||
// clang says "unknown argument: '-no-pie'"
|
|
||||||
return err == nil && !bytes.Contains(out, []byte("unrecognized")) && !bytes.Contains(out, []byte("unknown"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// hostlinkArchArgs returns arguments to pass to the external linker
|
// hostlinkArchArgs returns arguments to pass to the external linker
|
||||||
|
|
|
||||||
|
|
@ -1041,6 +1041,14 @@ func (l *Loader) SetAttrCgoExportDynamic(i Sym, v bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ForAllAttrCgoExportDynamic calls f for every symbol that has been
|
||||||
|
// marked with the "cgo_export_dynamic" compiler directive.
|
||||||
|
func (l *Loader) ForAllCgoExportDynamic(f func(Sym)) {
|
||||||
|
for s := range l.attrCgoExportDynamic {
|
||||||
|
f(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// AttrCgoExportStatic returns true for a symbol that has been
|
// AttrCgoExportStatic returns true for a symbol that has been
|
||||||
// specially marked via the "cgo_export_static" directive
|
// specially marked via the "cgo_export_static" directive
|
||||||
// written by cgo.
|
// written by cgo.
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"cmd/internal/sys"
|
||||||
)
|
)
|
||||||
|
|
||||||
var AuthorPaidByTheColumnInch struct {
|
var AuthorPaidByTheColumnInch struct {
|
||||||
|
|
@ -1150,3 +1152,46 @@ func TestUnlinkableObj(t *testing.T) {
|
||||||
t.Errorf("link failed: %v. output:\n%s", err, out)
|
t.Errorf("link failed: %v. output:\n%s", err, out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestResponseFile tests that creating a response file to pass to the
|
||||||
|
// external linker works correctly.
|
||||||
|
func TestResponseFile(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
testenv.MustHaveGoBuild(t)
|
||||||
|
|
||||||
|
// This test requires -linkmode=external. Currently all
|
||||||
|
// systems that support cgo support -linkmode=external.
|
||||||
|
testenv.MustHaveCGO(t)
|
||||||
|
|
||||||
|
tmpdir := t.TempDir()
|
||||||
|
|
||||||
|
src := filepath.Join(tmpdir, "x.go")
|
||||||
|
if err := os.WriteFile(src, []byte(`package main; import "C"; func main() {}`), 0666); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", "output", "x.go")
|
||||||
|
cmd.Dir = tmpdir
|
||||||
|
|
||||||
|
// Add enough arguments to push cmd/link into creating a response file.
|
||||||
|
var sb strings.Builder
|
||||||
|
sb.WriteString(`'-ldflags=all="-extldflags=`)
|
||||||
|
for i := 0; i < sys.ExecArgLengthLimit/len("-g"); i++ {
|
||||||
|
if i > 0 {
|
||||||
|
sb.WriteString(" ")
|
||||||
|
}
|
||||||
|
sb.WriteString("-g")
|
||||||
|
}
|
||||||
|
sb.WriteString(`"'`)
|
||||||
|
cmd = testenv.CleanCmdEnv(cmd)
|
||||||
|
cmd.Env = append(cmd.Env, "GOFLAGS="+sb.String())
|
||||||
|
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if len(out) > 0 {
|
||||||
|
t.Logf("%s", out)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue