| From c8f1e1c31cffa542b5546c8a2e2a1e972374f2a1 Mon Sep 17 00:00:00 2001 |
| From: Srdjan Petrovic <spetrovic@google.com> |
| 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 |
| --- |
| 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 | 4 ++-- |
| src/cmd/link/internal/ld/macho_combine_dwarf.go | 3 ++- |
| 6 files changed, 36 insertions(+), 17 deletions(-) |
| |
| diff --git a/misc/cgo/testcshared/test.bash b/misc/cgo/testcshared/test.bash |
| index 492d25e..4d3cbcc 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 8246dbb..c3fae86 100644 |
| --- a/src/cmd/dist/test.go |
| +++ b/src/cmd/dist/test.go |
| @@ -558,7 +558,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 07b4c30..0a18ec3 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 ba906fb..8bfc26b 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 3a8a881..6815347 100644 |
| --- a/src/cmd/link/internal/ld/macho.go |
| +++ b/src/cmd/link/internal/ld/macho.go |
| @@ -356,8 +356,8 @@ 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 |
| + if Linkmode == LinkExternal && sect.Rwx&1 == 0 { |
| + // Darwin external linker forbids absolute relocs in __TEXT, so if |
| // the section is not executable, put it in __DATA segment. |
| msect = newMachoSect(mseg, buf, "__DATA") |
| } else { |
| diff --git a/src/cmd/link/internal/ld/macho_combine_dwarf.go b/src/cmd/link/internal/ld/macho_combine_dwarf.go |
| index 9134373..b5a5a8d 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) |
| -- |
| 2.2.1 |
| |