From cc6554f750ccaf63bcdcc478b2a60d71ca76d342 Mon Sep 17 00:00:00 2001 From: Srdjan Petrovic Date: Tue, 16 Jun 2015 10:07:45 -0700 Subject: [PATCH] cmd/link/internal/ld, cmd/go: -buildmode=c-shared support for darwin/amd64 All of the heavy-lifting was done by minux@, with his external-linking support for darwin/arm64: golang.org/cl/8781 Change-Id: I7c9fbc19246f418c065c92fb2c13c00026ff0f82 Reviewed-on: https://go-review.googlesource.com/11127 Run-TryBot: Srdjan Petrovic TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- misc/cgo/testcshared/test.bash | 29 ++++++++++++------- src/cmd/dist/test.go | 2 +- src/cmd/go/build.go | 1 + src/cmd/link/internal/ld/lib.go | 14 +++++++-- src/cmd/link/internal/ld/macho.go | 7 +++-- .../link/internal/ld/macho_combine_dwarf.go | 3 +- 6 files changed, 38 insertions(+), 18 deletions(-) diff --git a/misc/cgo/testcshared/test.bash b/misc/cgo/testcshared/test.bash index 492d25e1342..4d3cbccc748 100755 --- a/misc/cgo/testcshared/test.bash +++ b/misc/cgo/testcshared/test.bash @@ -20,7 +20,7 @@ goarch=$(go env GOARCH) # Directory where cgo headers and outputs will be installed. # The installation directory format varies depending on the platform. installdir=pkg/${goos}_${goarch}_testcshared_shared -if [ "${goos}/${goarch}" == "android/arm" ]; then +if [ "${goos}/${goarch}" == "android/arm" ] || [ "${goos}/${goarch}" == "darwin/amd64" ]; then installdir=pkg/${goos}_${goarch}_testcshared fi @@ -70,15 +70,20 @@ rm -rf pkg suffix="-installsuffix testcshared" +libext="so" +if [ "$goos" == "darwin" ]; then + libext="dylib" +fi + # Create the header files. GOPATH=$(pwd) go install -buildmode=c-shared $suffix libgo -GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo.so src/libgo/libgo.go -binpush libgo.so +GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo.$libext src/libgo/libgo.go +binpush libgo.$libext # test0: exported symbols in shared lib are accessible. # TODO(iant): using _shared here shouldn't really be necessary. -$(go env CC) $(go env GOGCCFLAGS) -I ${installdir} -o testp main0.c libgo.so +$(go env CC) $(go env GOGCCFLAGS) -I ${installdir} -o testp main0.c libgo.$libext binpush testp output=$(run LD_LIBRARY_PATH=. ./testp) @@ -87,19 +92,23 @@ if [ "$output" != "PASS" ]; then exit 1 fi -# test1: .so can be dynamically loaded and exported symbols are accessible. +# test1: shared library can be dynamically loaded and exported symbols are accessible. $(go env CC) $(go env GOGCCFLAGS) -o testp main1.c -ldl binpush testp -output=$(run ./testp ./libgo.so) +output=$(run ./testp ./libgo.$libext) if [ "$output" != "PASS" ]; then echo "FAIL test1 got ${output}" exit 1 fi -# test2: tests libgo2.so which does not export any functions. -GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo2.so src/libgo2/libgo2.go -binpush libgo2.so -$(go env CC) $(go env GOGCCFLAGS) -o testp2 main2.c -Wl,--no-as-needed libgo2.so +# test2: tests libgo2 which does not export any functions. +GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo2.$libext src/libgo2/libgo2.go +binpush libgo2.$libext +linkflags="-Wl,--no-as-needed" +if [ "$goos" == "darwin" ]; then + linkflags="" +fi +$(go env CC) $(go env GOGCCFLAGS) -o testp2 main2.c $linkflags libgo2.$libext binpush testp2 output=$(run LD_LIBRARY_PATH=. ./testp2) if [ "$output" != "PASS" ]; then diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 6f1b43cfced..802631dbf98 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -571,7 +571,7 @@ func (t *tester) supportedBuildmode(mode string) bool { case "c-shared": // TODO(hyangah): add linux-386. switch pair { - case "linux-amd64", "android-arm": + case "linux-amd64", "darwin-amd64", "android-arm": return true } return false diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index 49893de0ed9..a9f9b588721 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -334,6 +334,7 @@ func buildModeInit() { codegenArg = "-shared" case "linux/arm": buildAsmflags = append(buildAsmflags, "-shared") + case "darwin/amd64": case "android/arm": default: fatalf("-buildmode=c-shared not supported on %s\n", platform) diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index faa5fc9fd68..ac28439d968 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -926,7 +926,7 @@ func hostlink() { } if HEADTYPE == obj.Hdarwin { - argv = append(argv, "-Wl,-no_pie,-pagezero_size,4000000,-headerpad,1144") + argv = append(argv, "-Wl,-no_pie,-headerpad,1144") } if HEADTYPE == obj.Hopenbsd { argv = append(argv, "-Wl,-nopie") @@ -944,9 +944,17 @@ func hostlink() { } switch Buildmode { + case BuildmodeExe: + if HEADTYPE == obj.Hdarwin { + argv = append(argv, "-Wl,-pagezero_size,4000000") + } case BuildmodeCShared: - argv = append(argv, "-Wl,-Bsymbolic") - argv = append(argv, "-shared") + if HEADTYPE == obj.Hdarwin { + argv = append(argv, "-dynamiclib") + } else { + argv = append(argv, "-Wl,-Bsymbolic") + argv = append(argv, "-shared") + } case BuildmodeShared: // TODO(mwhudson): unless you do this, dynamic relocations fill // out the findfunctab table and for some reason shared libraries diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go index 3a8a881d97b..1f14db744fc 100644 --- a/src/cmd/link/internal/ld/macho.go +++ b/src/cmd/link/internal/ld/macho.go @@ -356,9 +356,10 @@ func machoshbits(mseg *MachoSeg, sect *Section, segname string) { buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1) var msect *MachoSect - if Thearch.Thechar == '7' && sect.Rwx&1 == 0 { - // darwin/arm64 forbids absolute relocs in __TEXT, so if - // the section is not executable, put it in __DATA segment. + if sect.Rwx&1 == 0 && (Thearch.Thechar == '7' || (Thearch.Thechar == '6' && Buildmode == BuildmodeCShared)) { + // Darwin external linker on arm64 and on amd64 in c-shared buildmode + // complains about absolute relocs in __TEXT, so if the section is not + // executable, put it in __DATA segment. msect = newMachoSect(mseg, buf, "__DATA") } else { msect = newMachoSect(mseg, buf, segname) diff --git a/src/cmd/link/internal/ld/macho_combine_dwarf.go b/src/cmd/link/internal/ld/macho_combine_dwarf.go index 9134373a524..b5a5a8d4290 100644 --- a/src/cmd/link/internal/ld/macho_combine_dwarf.go +++ b/src/cmd/link/internal/ld/macho_combine_dwarf.go @@ -22,6 +22,7 @@ var machHeader *macho.FileHeader var mappedHeader []byte const ( + LC_ID_DYLIB = 0xd LC_LOAD_DYLINKER = 0xe LC_PREBOUND_DYLIB = 0x10 LC_LOAD_WEAK_DYLIB = 0x18 @@ -246,7 +247,7 @@ func machoCombineDwarf(inexe, dsym, outexe string) error { err = machoUpdateLoadCommand(reader, &linkEditDataCmd{}, "DataOff") case LC_ENCRYPTION_INFO, LC_ENCRYPTION_INFO_64: err = machoUpdateLoadCommand(reader, &encryptionInfoCmd{}, "CryptOff") - case macho.LoadCmdDylib, macho.LoadCmdThread, macho.LoadCmdUnixThread, LC_PREBOUND_DYLIB, LC_UUID, LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_SOURCE_VERSION, LC_MAIN, LC_LOAD_DYLINKER, LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_RPATH: + case macho.LoadCmdDylib, macho.LoadCmdThread, macho.LoadCmdUnixThread, LC_PREBOUND_DYLIB, LC_UUID, LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_SOURCE_VERSION, LC_MAIN, LC_LOAD_DYLINKER, LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_RPATH, LC_ID_DYLIB: // Nothing to update default: err = fmt.Errorf("Unknown load command 0x%x (%s)\n", int(cmd.Cmd), cmd.Cmd)