Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/link: external linking does not link dynamic libraries without cgo #42459

Closed
FiloSottile opened this issue Nov 9, 2020 · 15 comments
Closed
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@FiloSottile
Copy link
Contributor

https://golang.org/cl/232397 removes the cgo implementation from crypto/x509, which was preserved just for test purposes.

In doing so it seems to have broken external linking.

$ godev test crypto/x509 -ldflags=-linkmode=external
# crypto/x509.test
/Users/valsorda/go/pkg/tool/darwin_amd64/link: running clang failed: exit status 1
Undefined symbols for architecture x86_64:
  "_CFArrayGetCount", referenced from:
      _crypto/x509/internal/macos.x509_CFArrayGetCount_trampoline in go.o
  "_CFArrayGetValueAtIndex", referenced from:
      _crypto/x509/internal/macos.x509_CFArrayGetValueAtIndex_trampoline in go.o
  "_CFDataGetBytePtr", referenced from:
      _crypto/x509/internal/macos.x509_CFDataGetBytePtr_trampoline in go.o
  "_CFDataGetLength", referenced from:
      _crypto/x509/internal/macos.x509_CFDataGetLength_trampoline in go.o
  "_CFDictionaryGetValueIfPresent", referenced from:
      _crypto/x509/internal/macos.x509_CFDictionaryGetValueIfPresent_trampoline in go.o
  "_CFEqual", referenced from:
      _crypto/x509/internal/macos.x509_CFEqual_trampoline in go.o
  "_CFNumberGetValue", referenced from:
      _crypto/x509/internal/macos.x509_CFNumberGetValue_trampoline in go.o
  "_CFRelease", referenced from:
      _crypto/x509/internal/macos.x509_CFRelease_trampoline in go.o
  "_CFStringCreateWithBytes", referenced from:
      _crypto/x509/internal/macos.x509_CFStringCreateWithBytes_trampoline in go.o
  "_SecItemExport", referenced from:
      _crypto/x509/internal/macos.x509_SecItemExport_trampoline in go.o
  "_SecPolicyCopyProperties", referenced from:
      _crypto/x509/internal/macos.x509_SecPolicyCopyProperties_trampoline in go.o
  "_SecTrustSettingsCopyCertificates", referenced from:
      _crypto/x509/internal/macos.x509_SecTrustSettingsCopyCertificates_trampoline in go.o
  "_SecTrustSettingsCopyTrustSettings", referenced from:
      _crypto/x509/internal/macos.x509_SecTrustSettingsCopyTrustSettings_trampoline in go.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

https://storage.googleapis.com/go-build-log/14984eec/darwin-amd64-10_14_b0e9ceb1.log

I suppose the build was relying on the #cgo LDFLAGS: -framework CoreFoundation -framework Security line from the cgo file to bring in the dynamic libraries, even if it was not cgo to use them, as they were used via go:cgo_import_dynamic.

See also https://golang.org/cl/248333. /cc @cherrymui @thanm @randall77

@cherrymui
Copy link
Member

Thanks for reporting. I can reproduce on the current tip with $ CGO_ENABLED=0 go test -c -ldflags=-linkmode=external crypto/x509.

I agree it is related to the LDFLAGS. One way is that you could add

//go:cgo_ldflag "-framework"
//go:cgo_ldflag "CoreFoundation"
//go:cgo_ldflag "-framework"
//go:cgo_ldflag "Security"

to one of the non-cgo files (e.g. crypto/x509/internal/macos/corefoundation.go). (You have to do one flag a line, sorry.)

cc @ianlancetaylor about using cgo_ldflag in non-cgo-generated files. (It is still limited to the standard library by the compiler.)

@cagedmantis cagedmantis added the NeedsFix The path to resolution is known, but the work has not been done. label Nov 9, 2020
@cagedmantis cagedmantis added this to the Backlog milestone Nov 9, 2020
@FiloSottile
Copy link
Contributor Author

FiloSottile commented Nov 9, 2020 via email

@cherrymui
Copy link
Member

I don't know there is anyway for the linker to add those flags automatically in general. (Another possibility is to pass them in the command line, as -extldflags, but I assume this is not what you wanted.)

From cgo_import_dynamic pragmas the linker knows the libraries' paths, but it doesn't know the framework. In internal linking mode we just emit LC_LOAD_DYLIB with the libraries directly. Maybe we could hardcode a list of frameworks in the linker. But I'm not sure this is any better than adding pragmas in the source code.

Ideas welcome :)

@ianlancetaylor
Copy link
Member

If we're going to use //go:cgo_ldflag in crypto/x509, we should update the comment in cmd/compile/internal/gc, which only mentions the runtime and syscall packages.

@enuoCM
Copy link

enuoCM commented Mar 10, 2021

If we're going to use //go:cgo_ldflag in crypto/x509, we should update the comment in cmd/compile/internal/gc, which only mentions the runtime and syscall packages.

@iamoryanmoshe Can you explain how to update it? Update following code in noder.go? Thanks.

// For security, we disallow //go:cgo_* directives other
// than cgo_import_dynamic outside cgo-generated files.
// Exception: they are allowed in the standard library, for runtime and syscall.
if !isCgoGeneratedFile(pos) && !compiling_std {
    p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//%s only allowed in cgo-generated code", text)})
}

@zchee
Copy link
Contributor

zchee commented Aug 10, 2021

@FiloSottile @cherrymui Still repro? I can't so I think related $CC when ./make.bash. what you used $CC?

@tcastelly
Copy link

Hello @zchee

I don't know if it can help you, but I have the same problem when I try to call a cgo lib with a call to "crypto/x509".
https://github.com/shenron/x509-go-ffi

@cherrymui
Copy link
Member

If you build a c-archive, when you link it into the final executable, try passing -framework CoreFoundation -framework Security flags to the C linker.

Since the final linking step is not controlled by the Go toolchain, unfortunately I don't think there is anything we could do to help.

@cherrymui
Copy link
Member

cherrymui commented Aug 10, 2021

@zchee the original issue is fixed. The fix was not elegant but unfortunately I couldn't think of a better way. Closing. Thanks.

@dkasianov
Copy link

dkasianov commented Aug 20, 2021

If you build a c-archive, when you link it into the final executable, try passing -framework CoreFoundation -framework Security flags to the C linker.

Since the final linking step is not controlled by the Go toolchain, unfortunately I don't think there is anything we could do to help.

I try to build but get an error that no such directory Security

I used cmake target_link_options which makes -framework CoreFoundation -framework Security to become -framework CoreFoundation Security that makes that silly error. Solution is:

target_link_options(target_name BEFORE PRIVATE "SHELL:-framework Security")
target_link_options(target_name BEFORE PRIVATE "SHELL:-framework CoreFoundation")

@t0rr3sp3dr0
Copy link
Contributor

Is this really fixed? I'm still able to reproduce the problem with Go 1.17.2 darwin/amd64.

CGO_ENABLED=0 go test -c -ldflags=-d crypto/x509
# crypto/x509.test
/usr/local/Cellar/go/1.17.2/libexec/pkg/tool/darwin_amd64/link: /usr/local/Cellar/go/1.17.2/libexec/pkg/darwin_amd64/runtime.a(_go_.o): cannot use dynamic imports with -d flag
/usr/local/Cellar/go/1.17.2/libexec/pkg/tool/darwin_amd64/link: /usr/local/Cellar/go/1.17.2/libexec/pkg/darwin_amd64/syscall.a(_go_.o): cannot use dynamic imports with -d flag
/usr/local/Cellar/go/1.17.2/libexec/pkg/tool/darwin_amd64/link: /usr/local/Cellar/go/1.17.2/libexec/pkg/darwin_amd64/internal/syscall/unix.a(_go_.o): cannot use dynamic imports with -d flag
/usr/local/Cellar/go/1.17.2/libexec/pkg/tool/darwin_amd64/link: /usr/local/Cellar/go/1.17.2/libexec/pkg/darwin_amd64/crypto/x509/internal/macos.a(_go_.o): cannot use dynamic imports with -d flag
crypto/x509/internal/macos.x509_CFArrayGetCount_trampoline: relocation target x509_CFArrayGetCount not defined
crypto/x509/internal/macos.x509_CFArrayGetValueAtIndex_trampoline: relocation target x509_CFArrayGetValueAtIndex not defined
crypto/x509/internal/macos.x509_CFDataGetBytePtr_trampoline: relocation target x509_CFDataGetBytePtr not defined
crypto/x509/internal/macos.x509_CFDataGetLength_trampoline: relocation target x509_CFDataGetLength not defined
crypto/x509/internal/macos.x509_CFStringCreateWithBytes_trampoline: relocation target x509_CFStringCreateWithBytes not defined
crypto/x509/internal/macos.x509_CFRelease_trampoline: relocation target x509_CFRelease not defined
crypto/x509/internal/macos.x509_CFDictionaryGetValueIfPresent_trampoline: relocation target x509_CFDictionaryGetValueIfPresent not defined
crypto/x509/internal/macos.x509_CFNumberGetValue_trampoline: relocation target x509_CFNumberGetValue not defined
crypto/x509/internal/macos.x509_CFEqual_trampoline: relocation target x509_CFEqual not defined
crypto/x509/internal/macos.x509_SecTrustSettingsCopyCertificates_trampoline: relocation target x509_SecTrustSettingsCopyCertificates not defined
crypto/x509/internal/macos.x509_SecItemExport_trampoline: relocation target x509_SecItemExport not defined
crypto/x509/internal/macos.x509_SecTrustSettingsCopyTrustSettings_trampoline: relocation target x509_SecTrustSettingsCopyTrustSettings not defined
crypto/x509/internal/macos.x509_SecPolicyCopyProperties_trampoline: relocation target x509_SecPolicyCopyProperties not defined
runtime.exit_trampoline: relocation target libc_exit not defined
runtime.open_trampoline: relocation target libc_open not defined
runtime.close_trampoline: relocation target libc_close not defined
runtime.read_trampoline: relocation target libc_read not defined
/usr/local/Cellar/go/1.17.2/libexec/pkg/tool/darwin_amd64/link: too many errors
unexpected fault address 0xbd97438
fatal error: fault
unexpected fault address 0xbe8e028
fatal error: fault

@cherrymui
Copy link
Member

cherrymui commented Nov 18, 2021

@t0rr3sp3dr0 why do you pass the -d flag? This issue is not about the -d flag and it is expected that the -d flag won't work here.

@t0rr3sp3dr0
Copy link
Contributor

t0rr3sp3dr0 commented Nov 18, 2021

We have a service written in Go and it is statically built so it can run on any environment. Previously we were only building for Linux and that still works, but I tried to compile it on a Mac and found this problem.

I know we don't have true static binaries on Mac, but shouldn't builtin packages of Go support this flag instead of causing a linking error? If that's unsupported on macOS, shouldn’t the flag be NOP or give the user a warning?

@cherrymui
Copy link
Member

Thanks. Yeah, we could make it a better and clearer error, or no-op.

@gopherbot
Copy link
Contributor

Change https://golang.org/cl/365658 mentions this issue: cmd/link: exit early when -d is used on libc platforms

gopherbot pushed a commit that referenced this issue Nov 20, 2021
On platforms where we use libc for syscalls, we dynamically link
with libc and therefore dynamic linking cannot be disabled. Exit
early when -d is specified.

Update #42459.

Change-Id: I05abfe111df723b5ee512ceafef734e3804dd0a8
Reviewed-on: https://go-review.googlesource.com/c/go/+/365658
Trust: Cherry Mui <[email protected]>
Run-TryBot: Cherry Mui <[email protected]>
TryBot-Result: Go Bot <[email protected]>
Reviewed-by: Than McIntosh <[email protected]>
@golang golang locked and limited conversation to collaborators Nov 19, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

No branches or pull requests

10 participants