diff options
author | Paul E. Murphy <murp@ibm.com> | 2022-03-22 11:52:02 -0500 |
---|---|---|
committer | Cherry Mui <cherryyz@google.com> | 2022-04-04 20:27:32 +0000 |
commit | 0bf8319883298dbeea81444cb704d8c0e9935bae (patch) | |
tree | ce7c3b2939b8d924cad5f4188dbeba5155397b28 | |
parent | 78b8b4a1760ce212c05edd14f52711936ee60930 (diff) | |
download | go-0bf8319883298dbeea81444cb704d8c0e9935bae.tar.gz go-0bf8319883298dbeea81444cb704d8c0e9935bae.zip |
[release-branch.go1.18] runtime: make static/dynamic startup detection work with musl on ppc64le
The glibc loader explicitly sets the first doubleword on the stack (R1)
to $0 to indicate it was dynamically loaded.
An ELFv2 ABI compliant loader will set R3/R4 to argc/argv when starting
the process, and R13 to TLS. musl is not compliant. Instead it passes
argc/argv like the kernel, but R3/R4 are in an undefined state and R13
is valid.
With the knowledge above, the startup code can be modified to
dynamically handle all three cases when linked internally.
Fixes #51874
Change-Id: I5de33862c161900d9161817388bbc13a65fdc69c
Reviewed-on: https://go-review.googlesource.com/c/go/+/394654
Reviewed-by: Cherry Mui <cherryyz@google.com>
Run-TryBot: Paul Murphy <murp@ibm.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Trust: Paul Murphy <murp@ibm.com>
Trust: Lynn Boger <laboger@linux.vnet.ibm.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/394794
Trust: Emmanuel Odeke <emmanuel@orijtech.com>
-rw-r--r-- | src/runtime/rt0_linux_ppc64le.s | 32 |
1 files changed, 21 insertions, 11 deletions
diff --git a/src/runtime/rt0_linux_ppc64le.s b/src/runtime/rt0_linux_ppc64le.s index 4f7c6e6c99..66f7e7b22a 100644 --- a/src/runtime/rt0_linux_ppc64le.s +++ b/src/runtime/rt0_linux_ppc64le.s @@ -147,25 +147,35 @@ TEXT _main<>(SB),NOSPLIT,$-8 // In a statically linked binary, the stack contains argc, // argv as argc string pointers followed by a NULL, envv as a // sequence of string pointers followed by a NULL, and auxv. - // There is no TLS base pointer. + // The TLS pointer should be initialized to 0. // - // In a dynamically linked binary, r3 contains argc, r4 - // contains argv, r5 contains envp, r6 contains auxv, and r13 + // In an ELFv2 compliant dynamically linked binary, R3 contains argc, + // R4 contains argv, R5 contains envp, R6 contains auxv, and R13 // contains the TLS pointer. // - // Figure out which case this is by looking at r4: if it's 0, - // we're statically linked; otherwise we're dynamically - // linked. - CMP R0, R4 - BNE dlink - - // Statically linked + // When loading via glibc, the first doubleword on the stack points + // to NULL a value. (that is *(uintptr)(R1) == 0). This is used to + // differentiate static vs dynamicly linked binaries. + // + // If loading with the musl loader, it doesn't follow the ELFv2 ABI. It + // passes argc/argv similar to the linux kernel, R13 (TLS) is + // initialized, and R3/R4 are undefined. + MOVD (R1), R12 + CMP R0, R12 + BEQ tls_and_argcv_in_reg + + // Arguments are passed via the stack (musl loader or a static binary) MOVD 0(R1), R3 // argc ADD $8, R1, R4 // argv + + // Did the TLS pointer get set? If so, don't change it (e.g musl). + CMP R0, R13 + BNE tls_and_argcv_in_reg + MOVD $runtimeĀ·m0+m_tls(SB), R13 // TLS ADD $0x7000, R13 -dlink: +tls_and_argcv_in_reg: BR main(SB) TEXT main(SB),NOSPLIT,$-8 |