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, cmd/dist: wrong loader/interpreter used with cross-compiled toolchain for ppc64le #53813

Open
laboger opened this issue Jul 12, 2022 · 11 comments
Labels
compiler/runtime NeedsInvestigation
Milestone

Comments

@laboger
Copy link
Contributor

@laboger laboger commented Jul 12, 2022

What version of Go are you using (go version)?

$ go version
go version devel go1.19-4484c30f78 Wed

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
ppc64le

What did you do?

Built a cross toolchain on x86 host targeting ppc64le. By default CGO_ENABLED=0 for cross builds.
Moved the toolchain to a ppc64le machine. Many tests work fine except those that use -buildmode=pie. In those cases the test fails.

What did you expect to see?

Tests using -buildmode=pie work.

What did you see instead?

$ go build -buildmode=pie hello.go
$ ./hello
bash: ./hello: No such file or directory
$ file hello
hello: ELF 64-bit LSB shared object, 64-bit PowerPC or cisco 7500, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, with debug_info, not stripped

Same result if I set GO_LDSO=/libd64/ld64.so.2 before the go build command above.

If I set GO_LDSO=/lib64/ld64.so.2 when building the cross toolchain then it uses the correct path to the loader.

Also, if I build a cross compiled toolchain with a cross gcc on the build machine and set CGO_ENABLED=1, then the go binary is built dynamic but is unusable for the same reason.. With CGO_ENABLED=0, the go binary is static so doesn't have that problem.

@cherrymui
Copy link
Member

@cherrymui cherrymui commented Jul 12, 2022

Built a cross toolchain on x86 host targeting ppc64le. By default CGO_ENABLED=0 for cross builds.
Moved the toolchain to a ppc64le machine.

Could you show the commands you run for building and copying the toolchain? Is it just GOARCH=ppc64le ./make.bash then copying using scp or something? Or it is something else?

@mknyszek mknyszek added the NeedsInvestigation label Jul 12, 2022
@mknyszek mknyszek added this to the Go1.19 milestone Jul 12, 2022
@laboger
Copy link
Contributor Author

@laboger laboger commented Jul 12, 2022

I did GOOS=linux GOARCH=ppc64le ./make.bash on the x86 host.
I tarred it up and moved it over to my ppc64le machine, then untarred it.
After that I moved the go and gofmt binaries from go/bin/linux_ppc64le/ to go/bin so they were in the normal location.

@dmitshur dmitshur added the compiler/runtime label Jul 12, 2022
@cherrymui
Copy link
Member

@cherrymui cherrymui commented Jul 12, 2022

Thanks. During make.bash, cmd/dist writes defaultGO_LDSO in internal/buildcfg/zbootstrap.go ( https://cs.opensource.google/go/go/+/master:src/cmd/dist/buildruntime.go;l=69 ). And the linker picks up that value as the default dynamic linker path.

The linker already does not use defaultGO_LDSO when cross compiling at link time ( https://cs.opensource.google/go/go/+/master:src/cmd/link/internal/ld/elf.go;l=1771 ). But in this case the toolchain is cross-compiled but at link time the host and target are the same so it is not cross compiling (and there is no way for the linker to know it). So it still uses defaultGO_LDSO.

cmd/dist also writes in internal/buildcfg/zbootstrap.go defaultGOOS and defaultGOARCH. But they are just runtime.GOOS and runtime.GOARCH, i.e. the current host, so it doesn't help. Maybe cmd/dist could write a per-platform defaultGO_LDSO, so the linker can choose to use it only when targeting that platform.

cc @ianlancetaylor

@cherrymui cherrymui changed the title cmd/link: wrong loader/interpreter used with cross-compiled toolchain for ppc64le cmd/link, cmd/dist: wrong loader/interpreter used with cross-compiled toolchain for ppc64le Jul 12, 2022
@cherrymui cherrymui modified the milestones: Go1.19, Go1.20 Jul 12, 2022
@cherrymui
Copy link
Member

@cherrymui cherrymui commented Jul 12, 2022

This doesn't need to target Go 1.19. I think it needs more work to ship a cross-compiled binary release, and we're probably not going to do it for Go 1.19.

@laboger
Copy link
Contributor Author

@laboger laboger commented Jul 14, 2022

On a related note, I noticed this line in cmd/link/internal/ppc64/obj.go:

                Linuxdynld: "/lib64/ld64.so.1",

This is wrong for ppc64le, which is what the default should be since linux/ppc64 doesn't generate pie or dynamic binaries. It didn't seem worthy of its own issue since it has always been this way so this field must never be used, but it should still contain the correct string. It could be fixed along with the fix for this issue in Go 1.20. Probably when using the external linker the interpreter is set in a different way, and that's the way pies were generated up until @pmur s recent changes to the internal linker.

@cherrymui
Copy link
Member

@cherrymui cherrymui commented Jul 14, 2022

@laboger thanks. Yes, this should be fixed. Feel free to send a CL. What should it be?

This string is still used in some cases, for example, when cross compiling (not with a cross-compiled toolchain, but like GOARCH=ppc64le go build -buildmode=pie hello.go on a different architecture), or when GO_LDSO is not set.

@cherrymui
Copy link
Member

@cherrymui cherrymui commented Jul 14, 2022

The C cross toolchain on my machine uses /lib64/ld64.so.2. Maybe this is the correct value?

@laboger
Copy link
Contributor Author

@laboger laboger commented Jul 14, 2022

The C cross toolchain on my machine uses /lib64/ld64.so.2. Maybe this is the correct value?

Yes, it should be 2 since ppc64le is ELF v2. I can create a CL.

@gopherbot
Copy link

@gopherbot gopherbot commented Jul 14, 2022

Change https://go.dev/cl/417614 mentions this issue: cmd/link: use correct path for dynamic loader on ppc64le

@rsc
Copy link
Contributor

@rsc rsc commented Aug 2, 2022

Thanks for the CL for the default. I just ran into the GO_LDSO cross-compilation issue too, and I'm going to send a general fix for Go 1.20.

@rsc
Copy link
Contributor

@rsc rsc commented Aug 2, 2022

This issue is now a duplicate of either #54196 or #54197, depending on which way we fix the GO_LDSO problem (probably both ways).

gopherbot pushed a commit that referenced this issue Aug 5, 2022
The setting of the path for the dynamic loader when building for
linux/ppc64le ELF v2 was incorrectly set to the path for
PPC64 ELF v1. This has not caused issues in the common cases
because this string can be set based on the default GO_LDSO setting.
It does result in an incorrect value when cross compiling binaries
with -buildmode=pie.

Updates #53813

Change-Id: I84de1c97b42e0434760b76a57c5a05e055fbb730
Reviewed-on: https://go-review.googlesource.com/c/go/+/417614
Reviewed-by: Cherry Mui <cherryyz@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Run-TryBot: Lynn Boger <laboger@linux.vnet.ibm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime NeedsInvestigation
Projects
Status: Triage Backlog
Development

No branches or pull requests

6 participants