<#23653 Go 1.27: `go tool asm` is not passed `-std...
# github-notifications
q
#23653 Go 1.27: `go tool asm` is not passed `-std` for stdlib packages, breaking the from-source stdlib link on amd64 Issue created by michieltimmerman Summary With Go 1.27 on
[golang].go_search_paths
, any Pants goal that builds the Go standard library from source fails at the link step:
Copy code
ProcessExecutionFailure: Process 'Link Go binary: ./package_analyzer' failed with exit code 1.
stderr:
link: sync/atomic: invalid reference to internal/runtime/atomic.Load
package_analyzer
is Pants' own internal tool, so this takes down any goal that touches the Go backend — including
generate-lockfiles
for pure-Python resolves, if a
go_mod
target happens to be visible in the default build graph. This reproduces only on amd64 (see "Why arch matters" below), which is likely why it has gone unreported: Apple Silicon dev machines build cleanly. Root cause Go 1.27 made two coupled changes: 1.
cmd/asm
gained a
-std
flag
, and
cmd/go
passes it when assembling standard library packages. •
src/cmd/asm/internal/flags/flags.go
(go1.27.0):
Std = flag.Bool("std", false, "building standard library")
— absent in go1.26.0. •
src/cmd/go/internal/work/gc.go
(go1.27.0), in `asmArgs()`:
if p.Standard { args = append(args, "-std") }
— this block does not exist in go1.26.0. • Introduced by golang/go@`3a0f18376fb9` ("cmd/asm, cmd/go: pass -std to assembler for standard library packages", 2026-04-02). 2.
internal/runtime/atomic
switched its exports from
//go:linkname
to the new
//go:linknamestd
.
• New file
src/internal/runtime/atomic/linkname.go
(go1.27.0) carries
//go:linknamestd Load
,
Loadp
,
Load64
, … In go1.26.0 these were plain
//go:linkname
in
atomic_amd64.go
. • Introduced by golang/go@`4dde0f6c368f` ("all: use linknamestd for new linknames", 2026-05-20). The linker then treats the two differently —
src/cmd/link/internal/loader/loader.go
(go1.27.0): if osym.IsLinknameStd() { // It is pushed with linknamestd. Allow only pulls from the // standard library. if refpkg.Std() { return } } if osym.IsLinkname() { return } error()
refpkg.Std()
reads
ObjFlagStd
, which is set only when the referring object was produced with
-std
. The reference itself lives in assembly —
src/sync/atomic/asm.s
(byte-identical in 1.26 and 1.27):
Copy code
TEXT ·LoadUint32(SB),NOSPLIT,$0
	JMP	internal∕runtime∕atomic·Load(SB)
Pants passes
-std
to the compiler but never to the assembler.
src/python/pants/backend/go/util_rules/build_pkg.py
has
if request.is_stdlib: compile_args.append("-std")
, but
src/python/pants/backend/go/util_rules/assembly.py
— which builds both the
-gensymabis
and the assemble invocations via
_asm_args(...)
— contains no
-std
at all. So `sync/atomic`'s assembled object lacks
ObjFlagStd
,
refpkg.Std()
is false, and the link fails.
assembly.py
is byte-identical across
release_2.31.0
,
release_2.33.0
and
main
, so this is present on
main
today. Why arch matters • amd64:
internal/runtime/atomic.Load
is defined in Go (`atomic_amd64.go`:
func Load(ptr *uint32) uint32 { return *ptr }
), so its object comes from
go tool compile
, which Pants does pass
-std
to → the definer is std → the linker proceeds to the
refpkg.Std()
test, which the
-std
-less asm object fails → error. • arm64:
Load
is defined in assembly (`atomic_arm64.s`:
TEXT ·Load(SB),NOSPLIT,$0-12
).
checkLinkname
bails out early (
if !r.Std() { return }
) before reaching that test, so the build succeeds. Confirmed empirically: Pants 2.31.0 + Go 1.27.0 on darwin/arm64 builds the from-source stdlib and links
package_analyzer
with no error. Reproduction On linux/amd64, with Go 1.27.0: PANTS_GOLANG_GO_SEARCH_PATHS='["/path/to/go1.27.0/bin"]' \ pants --no-pantsd check <any go target> Expected: success. Actual:
link: sync/atomic: invalid reference to internal/runtime/atomic.Load
. Suggested fix Pass
-std
from
assembly.py
for stdlib packages, mirroring `build_pkg.py`'s
is_stdlib
handling — for both the
-gensymabis
and the assemble invocations. Older Go versions do not accept the flag, so it needs to be gated on the toolchain version. Note on 2.33.0 Pants 2.33.0's
[golang].use_prebuilt_stdlib_archives
(default
true
) hides this for the common case, because it delegates to a real
go install std
and
cmd/go
passes
-std
itself. I verified the harvest works for linux/amd64 with Go 1.27.0 (
GODEBUG=installgoroot=all go install -trimpath -pkgdir … std
→ 374 archives; linking a
sync/atomic
user against them succeeds). But per
stdlib_archives.py
the from-source path is still taken whenever coverage, the race detector, msan, asan, or custom
compiler_flags
are in play — so the underlying bug still bites in those configurations. pantsbuild/pants