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: An incorrect address was generated when using the LD linker #47416

Closed
dangit815 opened this issue Jul 27, 2021 · 5 comments
Closed
Labels
FrozenDueToAge WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided.

Comments

@dangit815
Copy link

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

$ go version
go version go1.16.6 linux/arm64

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
[root@localhost bolt-case-1.16.6-ld]# go env
GO111MODULE="off"
GOARCH="arm64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/root/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/root/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/home/danny/go-1.16.6"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/home/danny/go-1.16.6/pkg/tool/linux_arm64"
GOVCS=""
GOVERSION="go1.16.6"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build1236999023=/tmp/go-build -gno-record-gcc-switches"

What did you do?

main.go

package main
  
import "fmt"

func main() {
    fmt.Println("Hello World!")
}

Build command:
go build -a -buildmode=pie -ldflags='-linkmode=external -extld=gcc -extldflags "-fPIE -pie -Wl,--emit-relocs"'

What did you expect to see?

I run objdump -r -D main, get this:
image

I run readelf -r main, get this:
image

The first 8 bytes of “runtime.buildVersion” object is the pointer to the string with golang version name. The pointers address (0x000db902) is invalid and fixed at runtime by the relocation on that address (0x190a00).
The address 0xdb0e1 is valid, pointing to the string and works fine at runtime.The same address (0xdb0e1) must be written in the runtime.buildVersion instead of garbage one.

What did you see instead?

The pointers address (0x000db902) is invalid, different from 0xdb0e1.

@cherrymui
Copy link
Member

cherrymui commented Jul 27, 2021

Could you explain why it must be written to the binary? If I understand your words correctly, it will be patched at run time by the dynamic linker anyway, so the program runs correctly?

Also, I'm don't know what do you mean by 0x000db902 is invalid. It looks like a valid address (pre-dynamic relocation) to me.

@cherrymui cherrymui added the WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. label Jul 27, 2021
@dangit815
Copy link
Author

dangit815 commented Jul 30, 2021

Yes, maybe my expression is not very clear and easy to misunderstand.
In my opinion, when using ld linker, the golang runtime library is still statically linked to the binary, some other dynamic library like libc.so is dynamically linked to binary. We can use ldd to see which dynamic libraries are linked by this binary:
image
So the pointers address on that address (0x190a00) should have been relocated to the correct address(0xdb0e1) in the binary at the time of linking(Link Time Relocation), not Load Time Relocation(at runtime).
I can show two correct examples.

  1. use golang internal linker
    go build -a -buildmode=pie main.go
    Run objdump -r -D, get this:
    image
    Run readelf -r, get this:
    image
    Obviously, the pointers address on that address (0x19ebe0) has been relocated to the correct address(0x000a0821) in the binary.
  2. use gold linker
    go build -a -buildmode=pie -ldflags='-linkmode=external -extld=gcc -extldflags "-fuse-ld=gold -fPIE -pie -Wl,--threads -Wl,--emit-relocs"'
    Run objdump -r -D, get this:
    image
    Run readelf -r, get this:
    image
    The pointers address on that address (0x190a00) has been relocated to the correct address(0x000db0c1) in the binary.

Thanks.

@cherrymui
Copy link
Member

As you use -buildmode=pie, this is a PIE binary, which means it will be relocated at load time and dynamic relocations will be applied (even the Go runtime is included in the binary "statically").

Also, as you mentioned, when using external linking the final bytes are actually written out by the external linker, not the Go linker. I'm not sure we have control with that. (Even we have, I'm not sure this is necessary, as the dynamic linker will overwrite it anyway.)

@dangit815
Copy link
Author

dangit815 commented Jul 31, 2021

Yes, you're right, I didn't consider this option -buildmode=pie before, my problem:)

So, do you think this is a bug of ld linker? Is it possible that it is related to the mechanism of go calling external linker?
If this is a bug in the ld linker, we may not be able to solve it on golang.

Thanks.

@cherrymui
Copy link
Member

So, do you think this is a bug of ld linker?

I don't think this is a bug. The generated program executes correctly (if I understand what you said correctly).

I think we can close this. Feel free to reopen if you disagree. Thanks.

@golang golang locked and limited conversation to collaborators Aug 2, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided.
Projects
None yet
Development

No branches or pull requests

3 participants