Suppose there is an internal package that provides a method as follows.
This method is used internally, it has no export properties, so it can’t be
imported by other external packages, so since this is the case, is there any way to call this method outside the package? The answer is yes, except that this hack blocks at least 80% of Gopher’s knowledge, and it is
1. go:linkname Basics
go:linkname, it is necessary to understand the internal package
internal, which is unique to Golang. go 1.4 “Internal” Packages were added in Go 1.14.
An import of a path containing the element “internal” is disallowed if the importing code is outside the tree rooted at the parent of the “internal” directory.
The simple understanding is that this particular
internal package can only be imported by a specific external package.
/a/b/c/internal/d/e/fcan only be imported by
/a/b/c, not by
$GOROOT/src/pkg/internal/xxx, can only be imported by
$GOROOT/src/pkg/net/http/internalcan only be imported by
$GOPATH/src/mypkg/internal/foocan only be imported by
How can I directly reference the
internal.print method without violating this principle?
//go:linkname directive instructs the compiler to use
importpath.name as the object file symbolic name of a variable or function declared as
localname in the source code. Since this directive can break the type system and package modularity, it is only enabled in files that have
unsafe imported. As follows.
This completes the process of
go:linkname pointing the method implementation to an unexported method implementation of an external package. In simple terms, this means that
go:linkname [local] [target] binds the specific implementation
target to the current
local method. When run directly, it prompts a
missing body error. This is because
go build adds the
-complete parameter to check for completeness, and apparently this
xxx.s file to the calling directory. Finally the whole file directory is as follows.
The output after running is as follows.
2. go:linkname advanced 1: random numbers
math.Rand are pseudo-random number generators. But the difference is that
runtime.fastrand is in the context of the current goroutine. Therefore, it does not require locking during frequent calls, so its performance is much better than that of `math. Here are the performance tests of both.
The performance data obtained from benchmarking shows that
math/rand in terms of performance.
3. go:linkname Advanced 2: Timestamp
runtime.nanotime1() both get timestamps, but
time.Now() has underlying calls to runtime.walltime1 and runtime.nanotime to get the timestamp and program runtime respectively. And the latter only needs to get the timestamp separately. Therefore, in some scenarios, such as statistical time consumption, then you can directly get better performance with
nanotime1(). The following is the benchmarking code.
As you can see,
time.Now() in terms of performance.
With an understanding of how
go:linkname works, we can optimize our code for specific scenarios and improve performance bottlenecks. When reading the golang source code, you can also see a lot of
go:linkname directives, understanding this directive helps us better understand the underlying logic of golang code.