@@ -1605,7 +1605,13 @@ func (ctxt *Link) hostlink() {
1605
1605
1606
1606
// Force global symbols to be exported for dlopen, etc.
1607
1607
if ctxt .IsELF {
1608
- argv = append (argv , "-rdynamic" )
1608
+ if ctxt .DynlinkingGo () || ctxt .BuildMode == BuildModeCShared || ! linkerFlagSupported (ctxt .Arch , argv [0 ], altLinker , "-Wl,--export-dynamic-symbol=main" ) {
1609
+ argv = append (argv , "-rdynamic" )
1610
+ } else {
1611
+ ctxt .loader .ForAllCgoExportDynamic (func (s loader.Sym ) {
1612
+ argv = append (argv , "-Wl,--export-dynamic-symbol=" + ctxt .loader .SymExtname (s ))
1613
+ })
1614
+ }
1609
1615
}
1610
1616
if ctxt .HeadType == objabi .Haix {
1611
1617
fileName := xcoffCreateExportFile (ctxt )
@@ -1748,7 +1754,7 @@ func (ctxt *Link) hostlink() {
1748
1754
// case used has specified "-fuse-ld=...".
1749
1755
extld := ctxt .extld ()
1750
1756
name , args := extld [0 ], extld [1 :]
1751
- args = append (args , flagExtldflags ... )
1757
+ args = append (args , trimLinkerArgv ( flagExtldflags ) ... )
1752
1758
args = append (args , "-Wl,--version" )
1753
1759
cmd := exec .Command (name , args ... )
1754
1760
usingLLD := false
@@ -1775,6 +1781,8 @@ func (ctxt *Link) hostlink() {
1775
1781
argv = append (argv , peimporteddlls ()... )
1776
1782
}
1777
1783
1784
+ argv = ctxt .passLongArgsInResponseFile (argv , altLinker )
1785
+
1778
1786
if ctxt .Debugvlog != 0 {
1779
1787
ctxt .Logf ("host link:" )
1780
1788
for _ , v := range argv {
@@ -1885,6 +1893,47 @@ func (ctxt *Link) hostlink() {
1885
1893
}
1886
1894
}
1887
1895
1896
+ // passLongArgsInResponseFile writes the arguments into a file if they
1897
+ // are very long.
1898
+ func (ctxt * Link ) passLongArgsInResponseFile (argv []string , altLinker string ) []string {
1899
+ c := 0
1900
+ for _ , arg := range argv {
1901
+ c += len (arg )
1902
+ }
1903
+
1904
+ if c < sys .ExecArgLengthLimit {
1905
+ return argv
1906
+ }
1907
+
1908
+ // Only use response files if they are supported.
1909
+ response := filepath .Join (* flagTmpdir , "response" )
1910
+ if err := os .WriteFile (response , nil , 0644 ); err != nil {
1911
+ log .Fatalf ("failed while testing response file: %v" , err )
1912
+ }
1913
+ if ! linkerFlagSupported (ctxt .Arch , argv [0 ], altLinker , "@" + response ) {
1914
+ if ctxt .Debugvlog != 0 {
1915
+ ctxt .Logf ("not using response file because linker does not support one" )
1916
+ }
1917
+ return argv
1918
+ }
1919
+
1920
+ var buf bytes.Buffer
1921
+ for _ , arg := range argv [1 :] {
1922
+ // The external linker response file supports quoted strings.
1923
+ fmt .Fprintf (& buf , "%q\n " , arg )
1924
+ }
1925
+ if err := os .WriteFile (response , buf .Bytes (), 0644 ); err != nil {
1926
+ log .Fatalf ("failed while writing response file: %v" , err )
1927
+ }
1928
+ if ctxt .Debugvlog != 0 {
1929
+ ctxt .Logf ("response file %s contents:\n %s" , response , buf .Bytes ())
1930
+ }
1931
+ return []string {
1932
+ argv [0 ],
1933
+ "@" + response ,
1934
+ }
1935
+ }
1936
+
1888
1937
var createTrivialCOnce sync.Once
1889
1938
1890
1939
func linkerFlagSupported (arch * sys.Arch , linker , altLinker , flag string ) bool {
@@ -1895,6 +1944,28 @@ func linkerFlagSupported(arch *sys.Arch, linker, altLinker, flag string) bool {
1895
1944
}
1896
1945
})
1897
1946
1947
+ flags := hostlinkArchArgs (arch )
1948
+
1949
+ moreFlags := trimLinkerArgv (append (flagExtldflags , ldflag ... ))
1950
+ flags = append (flags , moreFlags ... )
1951
+
1952
+ if altLinker != "" {
1953
+ flags = append (flags , "-fuse-ld=" + altLinker )
1954
+ }
1955
+ flags = append (flags , flag , "trivial.c" )
1956
+
1957
+ cmd := exec .Command (linker , flags ... )
1958
+ cmd .Dir = * flagTmpdir
1959
+ cmd .Env = append ([]string {"LC_ALL=C" }, os .Environ ()... )
1960
+ out , err := cmd .CombinedOutput ()
1961
+ // GCC says "unrecognized command line option ‘-no-pie’"
1962
+ // clang says "unknown argument: '-no-pie'"
1963
+ return err == nil && ! bytes .Contains (out , []byte ("unrecognized" )) && ! bytes .Contains (out , []byte ("unknown" ))
1964
+ }
1965
+
1966
+ // trimLinkerArgv returns a new copy of argv that does not include flags
1967
+ // that are not relevant for testing whether some linker option works.
1968
+ func trimLinkerArgv (argv []string ) []string {
1898
1969
flagsWithNextArgSkip := []string {
1899
1970
"-F" ,
1900
1971
"-l" ,
@@ -1921,10 +1992,10 @@ func linkerFlagSupported(arch *sys.Arch, linker, altLinker, flag string) bool {
1921
1992
"-target" ,
1922
1993
}
1923
1994
1924
- flags := hostlinkArchArgs ( arch )
1995
+ var flags [] string
1925
1996
keep := false
1926
1997
skip := false
1927
- for _ , f := range append ( flagExtldflags , ldflag ... ) {
1998
+ for _ , f := range argv {
1928
1999
if keep {
1929
2000
flags = append (flags , f )
1930
2001
keep = false
@@ -1945,19 +2016,7 @@ func linkerFlagSupported(arch *sys.Arch, linker, altLinker, flag string) bool {
1945
2016
}
1946
2017
}
1947
2018
}
1948
-
1949
- if altLinker != "" {
1950
- flags = append (flags , "-fuse-ld=" + altLinker )
1951
- }
1952
- flags = append (flags , flag , "trivial.c" )
1953
-
1954
- cmd := exec .Command (linker , flags ... )
1955
- cmd .Dir = * flagTmpdir
1956
- cmd .Env = append ([]string {"LC_ALL=C" }, os .Environ ()... )
1957
- out , err := cmd .CombinedOutput ()
1958
- // GCC says "unrecognized command line option ‘-no-pie’"
1959
- // clang says "unknown argument: '-no-pie'"
1960
- return err == nil && ! bytes .Contains (out , []byte ("unrecognized" )) && ! bytes .Contains (out , []byte ("unknown" ))
2019
+ return flags
1961
2020
}
1962
2021
1963
2022
// hostlinkArchArgs returns arguments to pass to the external linker
0 commit comments