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: ppc64le internal linking does not handle TOC correctly #15409

Open
ianlancetaylor opened this Issue Apr 22, 2016 · 3 comments

Comments

Projects
None yet
3 participants
@ianlancetaylor
Contributor

ianlancetaylor commented Apr 22, 2016

The tests in misc/cgo/test fail with -linkmode=internal on ppc64le. From https://build.golang.org/log/a5a334010e62ae540ec0ec4916a8615cae0472d7:

fatal error: unexpected signal during runtime execution
[signal 0xb code=0x1 addr=0x0 pc=0x0]

runtime stack:
runtime.throw(0x20095a, 0x2a)
    /tmp/workdir/go/src/runtime/panic.go:566 +0x8c fp=0x3fffe2aaac68 sp=0x3fffe2aaac38
runtime.sigpanic()
    /tmp/workdir/go/src/runtime/sigpanic_unix.go:12 +0x64 fp=0x3fffe2aaacd0 sp=0x3fffe2aaac68
invalid spdelta _cgo_wait_runtime_init_done 0x176870 0x1768a0 0x0 -1
invalid spdelta _cgo_wait_runtime_init_done 0x176870 0x1768a0 0x0 -1
_cgo_wait_runtime_init_done()
    ?:0 +0x30 fp=0x3fffe2aaacef sp=0x3fffe2aaacf0

goroutine 1 [syscall, locked to thread]:
runtime.cgocall(0x173b80, 0xc820045e60, 0xc800000000)
    /tmp/workdir/go/src/runtime/cgocall.go:130 +0x170 fp=0xc820045e00 sp=0xc820045db0
_/tmp/workdir/go/misc/cgo/test._Cfunc_lockOSThreadC()
    ??:0 +0x40 fp=0xc820045e40 sp=0xc820045e00
_/tmp/workdir/go/misc/cgo/test.init.1()
    /tmp/workdir/go/misc/cgo/test/issue3775.go:23 +0x24 fp=0xc820045e60 sp=0xc820045e40
_/tmp/workdir/go/misc/cgo/test.init()
    _/tmp/workdir/go/misc/cgo/test/_test/_obj_test/_cgo_import.go:53 +0x470 fp=0xc820045ef8 sp=0xc820045e60
main.init()
    _/tmp/workdir/go/misc/cgo/test/_test/_testmain.go:192 +0x88 fp=0xc820045f18 sp=0xc820045ef8
runtime.main()
    /tmp/workdir/go/src/runtime/proc.go:177 +0x2d4 fp=0xc820045f80 sp=0xc820045f18
runtime.goexit()
    /tmp/workdir/go/src/runtime/asm_ppc64x.s:1090 +0x4 fp=0xc820045f80 sp=0xc820045f80

goroutine 17 [syscall, locked to thread]:
runtime.goexit()
    /tmp/workdir/go/src/runtime/asm_ppc64x.s:1090 +0x4 fp=0xc820034fb0 sp=0xc820034fb0

goroutine 2 [force gc (idle)]:
runtime.gopark(0x20e9f8, 0x2e9890, 0x1fa910, 0xf, 0x14, 0x1)
    /tmp/workdir/go/src/runtime/proc.go:264 +0x19c fp=0xc820020708 sp=0xc8200206c8
runtime.goparkunlock(0x2e9890, 0x1fa910, 0xf, 0xc820000114, 0x1)
    /tmp/workdir/go/src/runtime/proc.go:270 +0x58 fp=0xc820020758 sp=0xc820020708
runtime.forcegchelper()
    /tmp/workdir/go/src/runtime/proc.go:229 +0xdc fp=0xc8200207a0 sp=0xc820020758
runtime.goexit()
    /tmp/workdir/go/src/runtime/asm_ppc64x.s:1090 +0x4 fp=0xc8200207a0 sp=0xc8200207a0
created by runtime.init.4
    /tmp/workdir/go/src/runtime/proc.go:218 +0x38

goroutine 3 [GC sweep wait]:
runtime.gopark(0x20e9f8, 0x2e9a60, 0x1fa13f, 0xd, 0x32e14, 0x1)
    /tmp/workdir/go/src/runtime/proc.go:264 +0x19c fp=0xc820020ef8 sp=0xc820020eb8
runtime.goparkunlock(0x2e9a60, 0x1fa13f, 0xd, 0x14, 0x1)
    /tmp/workdir/go/src/runtime/proc.go:270 +0x58 fp=0xc820020f48 sp=0xc820020ef8
runtime.bgsweep(0xc820052000)
    /tmp/workdir/go/src/runtime/mgcsweep.go:63 +0xbc fp=0xc820020f98 sp=0xc820020f48
runtime.goexit()
    /tmp/workdir/go/src/runtime/asm_ppc64x.s:1090 +0x4 fp=0xc820020f98 sp=0xc820020f98
created by runtime.gcenable
    /tmp/workdir/go/src/runtime/mgc.go:195 +0x5c

goroutine 18 [finalizer wait]:
runtime.gopark(0x20e9f8, 0x304988, 0x1fa545, 0xe, 0x14, 0x1)
    /tmp/workdir/go/src/runtime/proc.go:264 +0x19c fp=0xc82001c6c8 sp=0xc82001c688
runtime.goparkunlock(0x304988, 0x1fa545, 0xe, 0x14, 0x1)
    /tmp/workdir/go/src/runtime/proc.go:270 +0x58 fp=0xc82001c718 sp=0xc82001c6c8
runtime.runfinq()
    /tmp/workdir/go/src/runtime/mfinal.go:158 +0xc0 fp=0xc82001c7a0 sp=0xc82001c718
runtime.goexit()
    /tmp/workdir/go/src/runtime/asm_ppc64x.s:1090 +0x4 fp=0xc82001c7a0 sp=0xc82001c7a0
created by runtime.createfing
    /tmp/workdir/go/src/runtime/mfinal.go:139 +0x84

goroutine 19 [syscall]:
runtime.notetsleepg(0x304c00, 0xffffffffffffffff, 0x1)
    /tmp/workdir/go/src/runtime/lock_futex.go:205 +0x60 fp=0xc82001cf00 sp=0xc82001cec0
os/signal.signal_recv(0x0)
    /tmp/workdir/go/src/runtime/sigqueue.go:116 +0x270 fp=0xc82001cf50 sp=0xc82001cf00
os/signal.loop()
    /tmp/workdir/go/src/os/signal/signal_unix.go:22 +0x24 fp=0xc82001cfa0 sp=0xc82001cf50
runtime.goexit()
    /tmp/workdir/go/src/runtime/asm_ppc64x.s:1090 +0x4 fp=0xc82001cfa0 sp=0xc82001cfa0
created by os/signal.init.1
    /tmp/workdir/go/src/os/signal/signal_unix.go:28 +0x44
exit status 2
FAIL    _/tmp/workdir/go/misc/cgo/test  0.009s

I believe that the problem is this: the PPC ELF v2 ABI requires that every function start with a small prologue that computes the TOC pointer in r2 from the function address in r12. This computation is two instructions; in normal PPC assembler it looks like this:

0: addis 2,12,.TOC.-0b@ha
addi 2,2,.TOC.-0b@l

The symbol .TOC. is not defined in an object file, and is magically defined by the linker. The linker must arrange that every function in the same module (shared library or executable) compute the same value for r2.

The problem is that cmd/link is using a different value for .TOC. for functions defined in different object files. I haven't sorted it all out, but cmd/link seems to use a different .TOC. symbol for each object file, and to give them different values. This may be correct for the ELF v1 ABI; I'm not sure. It's not correct for the ELF v2 ABI used on PPC64le.

@ianlancetaylor ianlancetaylor added this to the Unplanned milestone Apr 22, 2016

@gopherbot

This comment has been minimized.

gopherbot commented Apr 22, 2016

CL https://golang.org/cl/22379 mentions this issue.

gopherbot pushed a commit that referenced this issue Apr 22, 2016

cmd/dist: skip misc/cgo/test with internal linking on ppc64le
CL 22372 changed ppc64le to use normal cgo initialization on ppc64le.
Doing this uncovered a cmd/link error using internal linking.
Opened issue 15409 for the problem.  This CL disables the test.

Update #15409.

Change-Id: Ia1bb6b874c1b5a4df1a0436c8841c145142c30f7
Reviewed-on: https://go-review.googlesource.com/22379
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
@mwhudson

This comment has been minimized.

Contributor

mwhudson commented Apr 23, 2016

FWIW I think if we fix this we could always generate ELFv2-style PIC for
ppc64 in the compiler. Also I don't think we have cgo for ELFv1 at all,
internally or externally linked, so that can't be the excuse for this :-)
On 23/04/2016 6:00 am, "GopherBot" notifications@github.com wrote:

CL https://golang.org/cl/22379 mentions this issue.


You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub
#15409 (comment)

@mwhudson

This comment has been minimized.

Contributor

mwhudson commented Oct 28, 2017

Actually, according the the ABI it is not invalid to have multiple TOCs in a module:

The link editor may create multiple TOCs. In such a case, the constituent .got, .toc, .sdata, and .sbss
sections are conceptually repeated as necessary, with each TOC typically using a TOC pointer value
of its base plus 0x8000. Any constituent section of type SHT_NOBITS in any TOC but the last is
converted to type SHT_PROGBITS filled with zeros.

I think this is what the code is trying to do. It doesn't handle .sdata or .sbss sections at all, but I get the impression they are not present with default compiler options?

However:

When multiple TOCs are present, linking must take care to save, initialize, and restore TOC pointers
within a single module when calling from one function to a second function using a different TOC
pointer value. Many of the same issues associated with a cross-module call apply also to calls within
a module but using different TOC pointers.

I guess this is where things are going wrong. I don't entirely get how we end up with calls between functions using different TOC pointer values though.

It still seems likely to me that moving to a model with a single TOC would make life easier overall.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment