Skip to content

Commit

Permalink
runtime: make static/dynamic startup detection work with musl on ppc64le
Browse files Browse the repository at this point in the history
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 #51787

Change-Id: I5de33862c161900d9161817388bbc13a65fdc69c
Reviewed-on: https://go-review.googlesource.com/c/go/+/394654
Reviewed-by: Cherry Mui <[email protected]>
Run-TryBot: Paul Murphy <[email protected]>
TryBot-Result: Gopher Robot <[email protected]>
Trust: Paul Murphy <[email protected]>
Trust: Lynn Boger <[email protected]>
  • Loading branch information
pmur committed Mar 22, 2022
1 parent 817d6ea commit 9461679
Showing 1 changed file with 21 additions and 11 deletions.
32 changes: 21 additions & 11 deletions src/runtime/rt0_linux_ppc64le.s
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 9461679

Please sign in to comment.