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: dies when using linkname on extern methods with -linkshared #22853

Closed
bryanpkc opened this issue Nov 22, 2017 · 11 comments
Closed

cmd/link: dies when using linkname on extern methods with -linkshared #22853

bryanpkc opened this issue Nov 22, 2017 · 11 comments
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@bryanpkc
Copy link
Contributor

Please answer these questions before submitting your issue. Thanks!

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

1.8, 1.9, tip

Does this issue reproduce with the latest release?

yes

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

linux amd64

What did you do?

go install -buildmode=shared std
git clone https://github.com/bryanpkc/shlibLinkname.git
cd shlibLinkname
make

What did you expect to see?

cd linkname1 && go install -buildmode=shared -linkshared
go run -linkshared linkname2.go
runtime error: linkname2

What did you see instead?

cd linkname1 && go install -buildmode=shared -linkshared
# /tmp/go-build657789550/b006/libgithub.com-bryanpkc-shlibLinkname-linkname1.so
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x10 pc=0x51022e]

goroutine 1 [running]:
cmd/link/internal/ld.relocsym(0xc42055e000, 0xc420599358)
        /home/bryanpkc/Sources/go/go/src/cmd/link/internal/ld/data.go:368 +0xe5e
cmd/link/internal/ld.(*Link).reloc(0xc42055e000)
        /home/bryanpkc/Sources/go/go/src/cmd/link/internal/ld/data.go:502 +0xbc
cmd/link/internal/ld.Main(0x6e5300, 0x10, 0x20, 0x1, 0x7, 0x10, 0x5f76e8, 0x1b, 0x5f4a92, 0x14, ...)
        /home/bryanpkc/Sources/go/go/src/cmd/link/internal/ld/main.go:222 +0xad2
main.main()
        /home/bryanpkc/Sources/go/go/src/cmd/link/main.go:62 +0x277
Makefile:2: recipe for target 'all' failed
make: *** [all] Error 2
@bryanpkc
Copy link
Contributor Author

bryanpkc commented Nov 22, 2017

This is similar to #16632 and #22566, but I think a new issue with a test case might help. In this test case, I am trying to use //go:linkname to get at a method defined in another shared library (libstd.so in this case). The receiver type (errorString in this case) is duplicated in my package. The compiled code would have worked, but the type data for the duplicated type contains (in the tfn field) a section-relative R_METHODOFF relocation to the external method. The actual address is not known at link time and not representable as a 32-bit section-relative offset, causing the linker to give up.

type."".errorString SRODATA size=80
        0x0000 10 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00  ................
        0x0010 25 34 58 05 07 08 08 18 00 00 00 00 00 00 00 00  %4X.............
        0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        0x0030 00 00 00 00 01 00 00 00 10 00 00 00 00 00 00 00  ................
        0x0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        rel 24+8 t=1 runtime.algarray+112
        rel 32+8 t=1 runtime.gcbits.01+0
        rel 40+4 t=5 type..namedata.*linkname1.errorString-+0
        rel 44+4 t=5 type.*"".errorString+0
        rel 48+4 t=5 type..importpath."".+0
        rel 64+4 t=5 type..namedata.Error.+0
        rel 68+4 t=24 type.func() string+0
        rel 72+4 t=24 "".(*errorString).Error+0
        rel 76+4 t=24 runtime.errorString.Error+0

Note that the ifn field is actually properly populated with an auto-generated wrapper method. My solution for this particular case is to generate call stubs (in cmd/link/intenral/amd64.gentext) for such methods. The call stub contains just one branch instruction with a PLT relocation to the external method. The address of the call stub would then be local to the text section and can be represented as an offset in the type data.

I also tested with //go:linkname on external functions and external global variables, but they do not cause any problem with the linker.

@gopherbot
Copy link

Change https://golang.org/cl/79635 mentions this issue: cmd/link: fix R_ADDROFF reloc to SDYNIMPORT syms

@gopherbot
Copy link

Change https://golang.org/cl/84496 mentions this issue: cmd/link: fix R_ADDROFF reloc to SDYNIMPORT syms

@bryanpkc
Copy link
Contributor Author

bryanpkc commented Jan 9, 2018

@ianlancetaylor Would you have time to comment on CL 79635?

@ianlancetaylor ianlancetaylor added the NeedsFix The path to resolution is known, but the work has not been done. label Mar 29, 2018
@ianlancetaylor ianlancetaylor added this to the Unplanned milestone Mar 29, 2018
@bryanpkc
Copy link
Contributor Author

bryanpkc commented Apr 1, 2018

@ianlancetaylor Could this be considered for 1.11? Do you see some problem with the proposed fix?

@ianlancetaylor
Copy link
Contributor

ianlancetaylor commented Apr 11, 2018

I have to admit that every time I look at this CL I bounce off it. If you wrote a feature request asking us to support using go:linkname to reference methods defined in a different shared library, I would probably vote to reject it. It locks us into a complexity that it's not clear that we need to support.

Can you expand on the use case here? We do not intend go:linkname to be a general purpose facility, and using go:linkname for a method rather than a function seems especially fragile.

@bryanpkc
Copy link
Contributor Author

Thanks Ian. I do understand your concern. Let me elaborate.

The reason for using go:linkname this way is that we are deploying mission-critical Go programs which cannot tolerate down time or restarts. We came up with a way to apply software updates dynamically through loading shared libraries, and the go:linkname directives are used in the patches to reduce/eliminate code duplication when we know that a desired function or method already exists in the original binary.

go:linkname already works for functions when linking both statically and dynamically, as well as for methods when linking statically. Building the same code (using go:linkname on methods) with the -linkshared option should work as the programmer would reasonably expect. The additional code to support this case is conceptually simple, and reuses the same well-tested approach for calling runtime.addmoduledata from libstd.so. I would consider the risk of this change to be fairly low.

Note that this CL allows the linker to fail more gracefully (instead of crashing) not only in the situation described in this issue, but also in the situation described in #16632.

@ianlancetaylor
Copy link
Contributor

The risk of the CL is low, but I'm much less clear on the risk of permitting go:linkname on methods. That seems to lock us into a specific naming scheme for methods that as far as I know we are not locked into today.

@bryanpkc
Copy link
Contributor Author

If your concern is that the compiler 's mangling scheme will be "locked in" by the //go:linkname directive, why can't we just adopt a toolchain-neutral way to refer to methods? The natural syntax for identifying methods uniquely at the language level (e.g. github.com/user/P.(*T).M) could be used in the directive, allowing the toolchain to map such a name to whatever mangled name is appropriate.

On the other hand, the current mangling scheme is already exposed/exploited in tools like gorename, so perhaps using it directly is not that big of a risk.

@ianlancetaylor
Copy link
Contributor

//go:linkname is already a horrible hack intended for special purpose use. You are suggesting making it more usable. That seems to me like a step in the wrong direction.

@bryanpkc
Copy link
Contributor Author

If we had to have a hack, it might as well be a robust hack. 😆 OK Ian, I guess I'll just have to think of something else for my use case.

@golang golang locked and limited conversation to collaborators Apr 23, 2019
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

3 participants