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: missing CGO symbols in .dynsym
on Go >= 1.21 on arm64
#62520
Comments
.dynsym
on Go >= 1.21 on arm64.dynsym
on Go >= 1.21 on arm64
Thanks for the report. Previously we dynamically export ~all symbols, which is too many and unnecessary for many of them. With that CL, we only export Go symbols that are dynamically exported to C. I think we probably should also export C symbols (that are not marked as static or hidden visibility) per C semantics. @ianlancetaylor what do you think? |
This is interesting. I don't think that behavior depends on the architecture. Maybe this could be due to different C toolchain versions? What C compiler and linker do you use for both architectures? |
Yes that may be the reason. Initially, I uncovered that new thing because in the PR to update to Go 1.21 for the project I'm working on cilium/tetragon#1344, we had only the Go test failing on arm64. See this run for example https://github.com/cilium/tetragon/actions/runs/6119884977/job/16610682208?pr=1344. The reason why it failed is because we load a uprobe at some point and a symbol that we previously used was missing only on the arm64 runners binaries. But those are GitHub-hosted runners for x86_64 and BuildJet self-hosted runners for arm64, so they might have different toolchains installed indeed (and I can't tell you exactly what's running on those without running workflows for that). I could however reproduce easily the issue to isolate the commit on my arm64 machine. |
The C linker doesn't export all symbols to the dynamic symbol table by default. I think that people who rely on this should be passing In general CL 414654 made the Go linker behave more like a C linker with regard to when dynamic symbols are exported. I think that is a good thing and I don't yet see a reason to change that. I agree that it is a change in behavior. |
So I just understood something new, my issue originally came from the fact that when compiling and running with Basically, when I do I'm not very familiar with how behaves |
|
ah yeah ok I see. I end up with a different behavior since I'm using the binary itself to hook a uprobe and then it can now fail since the symbol is now absent from |
Thanks. Is there anything still needed for this issue? Or we can close it? Thanks. |
Cool! I guess no regarding this response:
If the change of behavior is okay/better on your side, I just need to adapt and it won't be hard. I was just thinking that it might have been unexpected for the Go project and was interested in it. I was going to close it but I'll let you close it as not planned or completed, whatever you prefer. |
This seems to be true.
$ go env
gcc version 13.1.0 (Ubuntu 13.1.0-8ubuntu1~22.04) On my Linux/amd64 machine:
$go env
gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.2) I don't know if this is caused by the difference in GCC version, but this difference does exist. |
I guess this could use a little bit more effort to make sure behavior is the same with different architecture (and same everything, Go, gcc) and thus might be reopened if this is a real thing (on my side I still experience the architecture difference). |
I think this is conditioned on whether the C linker supports the |
On my Linux/amd64 machine, the C linker does not support the
On my Linux/arm64 machine, the C linker supports this option. |
Thanks. So this explains the difference. |
The GNU linker picked up the |
Go 1.21 broke dynamic symbol linking export, see more - golang/go#62520 - golang/go#62520 (comment) Signed-off-by: Mahe Tardy <mahe.tardy@gmail.com>
Go 1.21 broke dynamic symbol linking export, see more - golang/go#62520 - golang/go#62520 (comment) Signed-off-by: Mahe Tardy <mahe.tardy@gmail.com>
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
So the issue is a difference of behavior from Go 1.20 to Go 1.21 on arm64 (and not on amd64).
Let's make a minimal reproducing setup:
Put that in a file, for example main.go and
go build main
.Use a binary to read the symbols, for example
readelf -s main | grep symbol_test
, you can useless
as well to see:1.20.8
(and before), there is asymbol_test
in.dynsym
andsymbol_test
in.symtab
.1.21.0
and1.21.1
, there is only asymbol_test
in.symtab
, it was removed from.dynsym
.So I cloned Go and did a git bissect to see which commit was the culprit and found that it was 1f29f39 -> https://go-review.googlesource.com/c/go/+/414654. Unfortunately, I lack context and understanding of the Go codebase to understand why this changed the behavior like that on arm64 specifically and if this is unintended.
For context, I was using uprobes on a Go binary, and for a reason that is not entirely clear for now, the lib I was using to load the probe is only reading
.dynsym
.What did you expect to see?
I expected this behavior not to change, and especially not to change only on arm64 while amd64 is still behaving the same as in the past.
What did you see instead?
I saw that the symbol was missing in
.dynsym
using Go >= 1.21.The text was updated successfully, but these errors were encountered: