Go

What is //go:linkname, and what changed about it in Go 1.23?

Question 442HardGo 1.22 to 1.25

//go:linkname localname importpath.name tells the compiler to use importpath.name as the object-file symbol for localname. It needs import _ "unsafe". It comes in two forms:

  • Push: the package that defines the symbol marks it with a linkname, which exports it on purpose (the runtime does this for sync, time and reflect).
  • Pull: a package declares a function without a body and links it to another package's unexported symbol. This is how many libraries reached into runtime internals such as runtime.nanotime or runtime.fastrand.
package fastclock

import _ "unsafe" // required for //go:linkname

//go:linkname nanotime runtime.nanotime
func nanotime() int64   // allowed: runtime explicitly keeps this symbol linkable

// Pulling a standard-library internal that is NOT marked as linkable
// is rejected by the linker since Go 1.23.
// Escape hatch (not for production):  go build -ldflags=-checklinkname=0

Go 1.23 change: the linker now rejects pull-only linknames to standard-library internals unless the defining package marks the symbol with a push linkname. Widely used symbols (the "hall of shame" of popular modules that depend on them) were marked to keep existing code working, but new internals are off limits.

What interviewers want: linkname bypasses the type system and the compatibility promise. The symbol can change signature or disappear in any release and break your build or, worse, corrupt memory. Prefer public APIs, for example math/rand/v2 instead of fastrand, or time.Now(), which already uses a monotonic clock.

More on Modules, Packages & Tooling

All 36 Modules, Packages & Tooling questions