mirror of https://github.com/golang/go.git
Merge branch 'golang:master' into master
This commit is contained in:
commit
090372e831
|
|
@ -0,0 +1,4 @@
|
|||
pkg testing, method (*B) Attr(string, string) #43936
|
||||
pkg testing, method (*F) Attr(string, string) #43936
|
||||
pkg testing, method (*T) Attr(string, string) #43936
|
||||
pkg testing, type TB interface, Attr(string, string) #43936
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
pkg runtime/trace, func NewFlightRecorder(FlightRecorderConfig) *FlightRecorder #63185
|
||||
pkg runtime/trace, method (*FlightRecorder) Enabled() bool #63185
|
||||
pkg runtime/trace, method (*FlightRecorder) Start() error #63185
|
||||
pkg runtime/trace, method (*FlightRecorder) Stop() #63185
|
||||
pkg runtime/trace, method (*FlightRecorder) WriteTo(io.Writer) (int64, error) #63185
|
||||
pkg runtime/trace, type FlightRecorder struct #63185
|
||||
pkg runtime/trace, type FlightRecorderConfig struct #63185
|
||||
pkg runtime/trace, type FlightRecorderConfig struct, MaxBytes uint64 #63185
|
||||
pkg runtime/trace, type FlightRecorderConfig struct, MinAge time.Duration #63185
|
||||
|
|
@ -1 +1 @@
|
|||
pkg sync, method (*WaitGroup) Go(func()) #63769
|
||||
pkg sync, method (*WaitGroup) Go(func()) #63796
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
pkg crypto/ecdsa, func ParseRawPrivateKey(elliptic.Curve, []uint8) (*PrivateKey, error) #63963
|
||||
pkg crypto/ecdsa, func ParseUncompressedPublicKey(elliptic.Curve, []uint8) (*PublicKey, error) #63963
|
||||
pkg crypto/ecdsa, method (*PrivateKey) Bytes() ([]uint8, error) #63963
|
||||
pkg crypto/ecdsa, method (*PublicKey) Bytes() ([]uint8, error) #63963
|
||||
|
|
@ -0,0 +1 @@
|
|||
pkg log/slog, func GroupAttrs(string, ...Attr) Attr #66365
|
||||
|
|
@ -3,6 +3,8 @@ pkg os, method (*Root) Chown(string, int, int) error #67002
|
|||
pkg os, method (*Root) Chtimes(string, time.Time, time.Time) error #67002
|
||||
pkg os, method (*Root) Lchown(string, int, int) error #67002
|
||||
pkg os, method (*Root) Link(string, string) error #67002
|
||||
pkg os, method (*Root) MkdirAll(string, fs.FileMode) error #67002
|
||||
pkg os, method (*Root) Readlink(string) (string, error) #67002
|
||||
pkg os, method (*Root) RemoveAll(string) error #67002
|
||||
pkg os, method (*Root) Rename(string, string) error #67002
|
||||
pkg os, method (*Root) Symlink(string, string) error #67002
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
pkg hash, type XOF interface { BlockSize, Read, Reset, Write } #69518
|
||||
pkg hash, type XOF interface, BlockSize() int #69518
|
||||
pkg hash, type XOF interface, Read([]uint8) (int, error) #69518
|
||||
pkg hash, type XOF interface, Reset() #69518
|
||||
pkg hash, type XOF interface, Write([]uint8) (int, error) #69518
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
pkg crypto/sha3, method (*SHA3) Clone() (hash.Cloner, error) #69521
|
||||
pkg hash, type Cloner interface { BlockSize, Clone, Reset, Size, Sum, Write } #69521
|
||||
pkg hash, type Cloner interface, BlockSize() int #69521
|
||||
pkg hash, type Cloner interface, Clone() (Cloner, error) #69521
|
||||
pkg hash, type Cloner interface, Reset() #69521
|
||||
pkg hash, type Cloner interface, Size() int #69521
|
||||
pkg hash, type Cloner interface, Sum([]uint8) []uint8 #69521
|
||||
pkg hash, type Cloner interface, Write([]uint8) (int, error) #69521
|
||||
pkg hash/maphash, method (*Hash) Clone() (hash.Cloner, error) #69521
|
||||
|
|
@ -0,0 +1 @@
|
|||
pkg crypto/tls, type Config struct, GetEncryptedClientHelloKeys func(*ClientHelloInfo) ([]EncryptedClientHelloKey, error) #71920
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
pkg os, method (*Root) ReadFile(string) ([]uint8, error) #73126
|
||||
pkg os, method (*Root) WriteFile(string, []uint8, fs.FileMode) error #73126
|
||||
|
|
@ -0,0 +1 @@
|
|||
pkg runtime, func SetDefaultGOMAXPROCS() #73193
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
pkg net/http, func NewCrossOriginProtection() *CrossOriginProtection #73626
|
||||
pkg net/http, method (*CrossOriginProtection) AddInsecureBypassPattern(string) #73626
|
||||
pkg net/http, method (*CrossOriginProtection) AddTrustedOrigin(string) error #73626
|
||||
pkg net/http, method (*CrossOriginProtection) Check(*Request) error #73626
|
||||
pkg net/http, method (*CrossOriginProtection) Handler(Handler) Handler #73626
|
||||
pkg net/http, method (*CrossOriginProtection) SetDenyHandler(Handler) #73626
|
||||
pkg net/http, type CrossOriginProtection struct #73626
|
||||
|
|
@ -169,6 +169,23 @@ Go command will follow symlinks to regular files embedding files.
|
|||
The default value `embedfollowsymlinks=0` does not allow following
|
||||
symlinks. `embedfollowsymlinks=1` will allow following symlinks.
|
||||
|
||||
Go 1.25 added a new `containermaxprocs` setting that controls whether the Go
|
||||
runtime will consider cgroup CPU limits when setting the default GOMAXPROCS.
|
||||
The default value `containermaxprocs=1` will use cgroup limits in addition to
|
||||
the total logical CPU count and CPU affinity. `containermaxprocs=0` will
|
||||
disable consideration of cgroup limits. This setting only affects Linux.
|
||||
|
||||
Go 1.25 added a new `updatemaxprocs` setting that controls whether the Go
|
||||
runtime will periodically update GOMAXPROCS for new CPU affinity or cgroup
|
||||
limits. The default value `updatemaxprocs=1` will enable periodic updates.
|
||||
`updatemaxprocs=0` will disable periodic updates.
|
||||
|
||||
Go 1.25 disabled SHA-1 signature algorithms in TLS 1.2 according to RFC 9155.
|
||||
The default can be reverted using the `tlssha1=1` setting.
|
||||
|
||||
Go 1.25 switched to SHA-256 to fill in missing SubjectKeyId in
|
||||
crypto/x509.CreateCertificate. The setting `x509sha256skid=0` reverts to SHA-1.
|
||||
|
||||
Go 1.25 corrected the semantics of contention reports for runtime-internal locks,
|
||||
and so removed the [`runtimecontentionstacks` setting](/pkg/runtime#hdr-Environment_Variable).
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,31 @@ This program will now print:
|
|||
|
||||
panic: PANIC [recovered, repanicked]
|
||||
|
||||
<!-- go.dev/issue/73193 -->
|
||||
|
||||
The default behavior of the `GOMAXPROCS` has changed. In prior versions of Go,
|
||||
`GOMAXPROCS` defaults to the number of logical CPUs available at startup
|
||||
([runtime.NumCPU]). Go 1.25 introduces two changes:
|
||||
|
||||
1. On Linux, the runtime considers the CPU bandwidth limit of the cgroup
|
||||
containing the process, if any. If the CPU bandwidth limit is lower than the
|
||||
number of logical CPUs available, `GOMAXPROCS` will default to the lower
|
||||
limit. In container runtime systems like Kubernetes, cgroup CPU bandwidth
|
||||
limits generally correspond to the "CPU limit" option. The Go runtime does
|
||||
not consider the "CPU requests" option.
|
||||
|
||||
2. On all OSes, the runtime periodically updates `GOMAXPROCS` if the number
|
||||
of logical CPUs available or the cgroup CPU bandwidth limit change.
|
||||
|
||||
Both of these behaviors are automatically disabled if `GOMAXPROCS` is set
|
||||
manually via the `GOMAXPROCS` environment variable or a call to
|
||||
[runtime.GOMAXPROCS]. They can also be disabled explicitly with the [GODEBUG
|
||||
settings](/doc/godebug) `containermaxprocs=0` and `updatemaxprocs=0`,
|
||||
respectively.
|
||||
|
||||
In order to support reading updated cgroup limits, the runtime will keep cached
|
||||
file descriptors for the cgroup files for the duration of the process lifetime.
|
||||
|
||||
<!-- go.dev/issue/71546 -->
|
||||
|
||||
On Linux systems with kernel support for anonymous VMA names
|
||||
|
|
|
|||
|
|
@ -38,6 +38,18 @@ successfully in Go 1.25. If this change is affecting your code, the solution is
|
|||
the non-nil error check earlier in your code, preferably immediately after
|
||||
the error-generating statement.
|
||||
|
||||
<!-- CLs 653856, 657937, 663795, 664299 -->
|
||||
|
||||
The compiler can now allocate the backing store for slices on the
|
||||
stack in more situations, which improves performance. This change has
|
||||
the potential to amplify the effects of incorrect
|
||||
[unsafe.Pointer](/pkg/unsafe#Pointer) usage, see for example [issue
|
||||
73199](/issue/73199). In order to track down these problems, the
|
||||
[bisect tool](https://pkg.go.dev/golang.org/x/tools/cmd/bisect) can be
|
||||
used to find the allocation causing trouble using the
|
||||
`-compile=variablemake` flag. All such new stack allocations can also
|
||||
be turned off using `-gcflags=all=-d=variablemakehash=n`.
|
||||
|
||||
## Assembler {#assembler}
|
||||
|
||||
## Linker {#linker}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
### New testing/synctest package
|
||||
|
||||
<!-- go.dev/issue/67434, go.dev/issue/73567 -->
|
||||
The new [testing/synctest](/pkg/testing/synctest) package
|
||||
provides support for testing concurrent code.
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
The new [ParseRawPrivateKey], [ParseUncompressedPublicKey], [PrivateKey.Bytes],
|
||||
and [PublicKey.Bytes] functions and methods implement low-level encodings,
|
||||
replacing the need to use crypto/elliptic or math/big functions and methods.
|
||||
|
|
@ -0,0 +1 @@
|
|||
The new [SHA3.Clone] method implements [hash.Cloner](/pkg/hash#Cloner).
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
The new [Config.GetEncryptedClientHelloKeys] callback can be used to set the
|
||||
[EncryptedClientHelloKey]s for a server to use when a client sends an Encrypted
|
||||
Client Hello extension.
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
SHA-1 signature algorithms are now disallowed in TLS 1.2 handshakes, per
|
||||
[RFC 9155](https://www.rfc-editor.org/rfc/rfc9155.html).
|
||||
They can be re-enabled with the `tlssha1=1` GODEBUG option.
|
||||
|
|
@ -0,0 +1 @@
|
|||
TLS servers now prefer the highest supported protocol version, even if it isn't the client's most preferred protocol version.
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
[CreateCertificate] now uses truncated SHA-256 to populate the `SubjectKeyId` if
|
||||
it is missing. The GODEBUG setting `x509sha256skid=0` reverts to SHA-1.
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
The new [XOF](/pkg/hash#XOF) interface can be implemented by "extendable output
|
||||
functions", which are hash functions with arbitrary or unlimited output length
|
||||
such as [SHAKE](https://pkg.go.dev/crypto/sha3#SHAKE).
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Hashes implementing the new [Cloner] interface can return a copy of their state.
|
||||
All standard library [Hash] implementations now implement [Cloner].
|
||||
|
|
@ -0,0 +1 @@
|
|||
The new [Hash.Clone] method implements [hash.Cloner](/pkg/hash#Cloner).
|
||||
|
|
@ -0,0 +1 @@
|
|||
[GroupAttrs] creates a group [Attr] from a slice of [Attr] values.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
The new [CrossOriginProtection] implements protections against [Cross-Site
|
||||
Request Forgery (CSRF)][] by rejecting non-safe cross-origin browser requests.
|
||||
It uses [modern browser Fetch metadata][Sec-Fetch-Site], doesn't require tokens
|
||||
or cookies, and supports origin-based and pattern-based bypasses.
|
||||
|
||||
[Sec-Fetch-Site]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-Fetch-Site
|
||||
[Cross-Site Request Forgery (CSRF)]: https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/CSRF
|
||||
|
|
@ -5,6 +5,10 @@ The [os.Root] type supports the following additional methods:
|
|||
* [os.Root.Chtimes]
|
||||
* [os.Root.Lchown]
|
||||
* [os.Root.Link]
|
||||
* [os.Root.MkdirAll]
|
||||
* [os.Root.ReadFile]
|
||||
* [os.Root.Readlink]
|
||||
* [os.Root.RemoveAll]
|
||||
* [os.Root.Rename]
|
||||
* [os.Root.Symlink]
|
||||
* [os.Root.WriteFile]
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
<!-- go.dev/issue/73126 is documented as part of 67002 -->
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
The new [SetDefaultGOMAXPROCS] function sets `GOMAXPROCS` to the runtime
|
||||
default value, as if the `GOMAXPROCS` environment variable is not set. This is
|
||||
useful for enabling the [new `GOMAXPROCS` default](#runtime) if it has been
|
||||
disabled by the `GOMAXPROCS` environment variable or a prior call to
|
||||
[GOMAXPROCS].
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<!-- go.dev/issue/63185 -->
|
||||
TODO The flight recorder has been added to the runtime/trace package.
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
The new methods [T.Attr], [B.Attr], and [F.Attr] emit an
|
||||
attribute to the test log. An attribute is an arbitrary
|
||||
key and value associated with a test.
|
||||
|
||||
For example, in a test named `TestAttr`,
|
||||
`t.Attr("key", "value")` emits:
|
||||
|
||||
```
|
||||
=== ATTR TestAttr key value
|
||||
```
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
<!--
|
||||
Output from relnote todo that was generated and reviewed on 2025-05-23, plus summary info from bug/CL: -->
|
||||
|
||||
<!-- TODO: CL 420114 has a RELNOTE comment without a suggested text (from RELNOTE comment in https://go.dev/cl/420114) -->
|
||||
all: implement plugin build mode for riscv64
|
||||
|
||||
<!-- TODO: CL 660996 has a RELNOTE comment without a suggested text (from RELNOTE comment in https://go.dev/cl/660996) -->
|
||||
cmd/link/internal/ld: introduce -funcalign=N option
|
||||
This patch adds linker option -funcalign=N that allows to set alignment
|
||||
for function entries.
|
||||
For \#72130.
|
||||
|
||||
<!-- TODO: accepted proposal https://go.dev/issue/32816 (from https://go.dev/cl/645155, https://go.dev/cl/645455, https://go.dev/cl/645955, https://go.dev/cl/646255, https://go.dev/cl/646455, https://go.dev/cl/646495, https://go.dev/cl/646655, https://go.dev/cl/646875, https://go.dev/cl/647298, https://go.dev/cl/647299, https://go.dev/cl/647736, https://go.dev/cl/648581, https://go.dev/cl/648715, https://go.dev/cl/648976, https://go.dev/cl/648995, https://go.dev/cl/649055, https://go.dev/cl/649056, https://go.dev/cl/649057, https://go.dev/cl/649456, https://go.dev/cl/649476, https://go.dev/cl/650755, https://go.dev/cl/651615, https://go.dev/cl/651617, https://go.dev/cl/651655, https://go.dev/cl/653436) -->
|
||||
cmd/fix: automate migrations for simple deprecations
|
||||
|
||||
<!-- TODO: accepted proposal https://go.dev/issue/34055 (from https://go.dev/cl/625577) -->
|
||||
cmd/go: allow serving module under the subdirectory of git repository
|
||||
cmd/go: add subdirectory support to go-import meta tag
|
||||
This CL adds ability to specify a subdirectory in the go-import meta tag.
|
||||
A go-import meta tag now will support:
|
||||
\<meta name="go-import" content="root-path vcs repo-url subdir">
|
||||
Fixes: \#34055
|
||||
|
||||
<!-- TODO: accepted proposal https://go.dev/issue/42965 (from https://go.dev/cl/643355, https://go.dev/cl/670656, https://go.dev/cl/670975, https://go.dev/cl/674076) -->
|
||||
cmd/go: add global ignore mechanism for Go tooling ecosystem
|
||||
|
||||
<!-- TODO: accepted proposal https://go.dev/issue/51430 (from https://go.dev/cl/644997, https://go.dev/cl/646355) -->
|
||||
cmd/cover: extend coverage testing to include applications
|
||||
|
||||
<!-- TODO: accepted proposal https://go.dev/issue/60905 (from https://go.dev/cl/645795) -->
|
||||
all: add GOARM64=v8.1 and so on
|
||||
runtime: check LSE support on ARM64 at runtime init
|
||||
Check presence of LSE support on ARM64 chip if we targeted it at compile
|
||||
time.
|
||||
Related to \#69124
|
||||
Updates \#60905
|
||||
Fixes \#71411
|
||||
|
||||
<!-- TODO: accepted proposal https://go.dev/issue/61476 (from https://go.dev/cl/633417) -->
|
||||
all: add GORISCV64 environment variable
|
||||
cmd/go: add rva23u64 as a valid value for GORISCV64
|
||||
The RVA23 profile was ratified on the 21st of October 2024.
|
||||
https://riscv.org/announcements/2024/10/risc-v-announces-ratification-of-the-rva23-profile-standard/
|
||||
Now that it's ratified we can add rva23u64 as a valid value for the
|
||||
GORISCV64 environment variable. This will allow the compiler and
|
||||
assembler to generate instructions made mandatory by the new profile
|
||||
without a runtime check. Examples of such instructions include those
|
||||
introduced by the Vector and Zicond extensions.
|
||||
Setting GORISCV64=rva23u64 defines the riscv64.rva20u64,
|
||||
riscv64.rva22u64 and riscv64.rva23u64 build tags, sets the internal
|
||||
variable buildcfg.GORISCV64 to 23 and defines the macros
|
||||
GORISCV64_rva23u64, hasV, hasZba, hasZbb, hasZbs, hasZfa, and
|
||||
hasZicond for use in assembly language code.
|
||||
Updates \#61476
|
||||
|
||||
<!-- TODO: accepted proposal https://go.dev/issue/61716 (from https://go.dev/cl/644475) -->
|
||||
math/rand/v2: revised API for math/rand
|
||||
rand: deprecate in favor of math/rand/v2
|
||||
For golang/go#61716
|
||||
Fixes golang/go#71373
|
||||
|
||||
<!-- TODO: accepted proposal https://go.dev/issue/64876 (from https://go.dev/cl/649435) -->
|
||||
cmd/go: enable GOCACHEPROG by default
|
||||
cmd/go/internal/cacheprog: drop Request.ObjectID
|
||||
ObjectID was a misnaming of OutputID from cacheprog's initial
|
||||
implementation. It was maintained for compatibility with existing
|
||||
cacheprog users in 1.24 but can be removed in 1.25.
|
||||
|
||||
<!-- TODO: accepted proposal https://go.dev/issue/68106 (from https://go.dev/cl/628175, https://go.dev/cl/674158, https://go.dev/cl/674436, https://go.dev/cl/674437, https://go.dev/cl/674555, https://go.dev/cl/674556, https://go.dev/cl/674575, https://go.dev/cl/675075, https://go.dev/cl/675076, https://go.dev/cl/675155, https://go.dev/cl/675235) -->
|
||||
cmd/go: doc -http should start a pkgsite instance and open a browser
|
||||
|
||||
<!-- TODO: accepted proposal https://go.dev/issue/69712 (from https://go.dev/cl/619955) -->
|
||||
cmd/go: -json flag for go version -m
|
||||
cmd/go: support -json flag in go version
|
||||
It supports features described in the issue:
|
||||
- add -json flag for 'go version -m' to print json encoding of
|
||||
runtime/debug.BuildSetting to standard output.
|
||||
- report an error when specifying -json flag without -m.
|
||||
- print build settings on seperated line for each binary
|
||||
Fixes \#69712
|
||||
|
||||
<!-- TODO: accepted proposal https://go.dev/issue/70123 (from https://go.dev/cl/657116) -->
|
||||
crypto: mechanism to enable FIPS mode
|
||||
|
||||
<!-- TODO: accepted proposal https://go.dev/issue/70128 (from https://go.dev/cl/645716, https://go.dev/cl/647455, https://go.dev/cl/651215, https://go.dev/cl/651256, https://go.dev/cl/652136, https://go.dev/cl/652215, https://go.dev/cl/653095, https://go.dev/cl/653139, https://go.dev/cl/653156, https://go.dev/cl/654395) -->
|
||||
spec: remove notion of core types
|
||||
|
||||
<!-- TODO: accepted proposal https://go.dev/issue/70200 (from https://go.dev/cl/674916) -->
|
||||
cmd/go: add fips140 module selection mechanism
|
||||
lib/fips140: set inprocess.txt to v1.0.0
|
||||
|
||||
<!-- TODO: accepted proposal https://go.dev/issue/70464 (from https://go.dev/cl/630137) -->
|
||||
testing: panic in AllocsPerRun during parallel test
|
||||
testing: panic in AllocsPerRun if parallel tests are running
|
||||
If other tests are running, AllocsPerRun's result will be inherently flaky.
|
||||
Saw this with CL 630136 and \#70327.
|
||||
Proposed in \#70464.
|
||||
Fixes \#70464.
|
||||
|
||||
<!-- TODO: accepted proposal https://go.dev/issue/71845 (from https://go.dev/cl/665796, https://go.dev/cl/666935) -->
|
||||
encoding/json/v2: add new JSON API behind a GOEXPERIMENT=jsonv2 guard
|
||||
|
||||
<!-- TODO: accepted proposal https://go.dev/issue/71867 (from https://go.dev/cl/666476, https://go.dev/cl/666755, https://go.dev/cl/673119, https://go.dev/cl/673696) -->
|
||||
cmd/go, cmd/distpack: build and run tools that are not necessary for builds as needed and don't include in binary distribution
|
||||
|
||||
<!-- Items that don't need to be mentioned in Go 1.25 release notes but are picked up by relnote todo
|
||||
|
||||
TODO: accepted proposal https://go.dev/issue/30999 (from https://go.dev/cl/671795)
|
||||
net: reject leading zeros in IP address parsers
|
||||
net: don't test with leading 0 in ipv4 addresses
|
||||
Updates \#30999
|
||||
Fixes \#73378
|
||||
|
||||
TODO: accepted proposal https://go.dev/issue/36532 (from https://go.dev/cl/647555)
|
||||
testing: reconsider adding Context method to testing.T
|
||||
database/sql: use t.Context in tests
|
||||
Replace "context.WithCancel(context.Background())" with "t.Context()".
|
||||
Updates \#36532
|
||||
|
||||
TODO: accepted proposal https://go.dev/issue/48429 (from https://go.dev/cl/648577)
|
||||
cmd/go: track tool dependencies in go.mod
|
||||
cmd/go: document -modfile and other flags for 'go tool'
|
||||
Mention -modfile, -C, -overlay, and -modcacherw in the 'go tool'
|
||||
documentation. We let a reference to 'go help build' give a pointer to
|
||||
more detailed information.
|
||||
The -modfile flag in particular is newly useful with the Go 1.24 support
|
||||
for user-defined tools with 'go tool'.
|
||||
Updates \#48429
|
||||
Updates \#33926
|
||||
Updates \#71663
|
||||
Fixes \#71502
|
||||
|
||||
TODO: accepted proposal https://go.dev/issue/51572 (from https://go.dev/cl/651996)
|
||||
cmd/go: add 'unix' build tag but not \*\_unix.go file support
|
||||
os, syscall: use unix build tag where appropriate
|
||||
These newly added files may use the unix build tag instead of explitly
|
||||
listing all unix-like GOOS values.
|
||||
For \#51572
|
||||
|
||||
TODO: accepted proposal https://go.dev/issue/53757 (from https://go.dev/cl/644575)
|
||||
x/sync/errgroup: propagate panics and Goexits through Wait
|
||||
errgroup: propagate panic and Goexit through Wait
|
||||
Recovered panic values are wrapped and saved in Group.
|
||||
Goexits are detected by a sentinel value set after the given function
|
||||
returns normally. Wait propagates the first instance of a panic or
|
||||
Goexit.
|
||||
According to the runtime.Goexit after the code will not be executed,
|
||||
with a bool, if f not call runtime.Goexit, is true,
|
||||
determine whether to propagate runtime.Goexit.
|
||||
Fixes golang/go#53757
|
||||
|
||||
TODO: accepted proposal https://go.dev/issue/54743 (from https://go.dev/cl/532415)
|
||||
ssh: add server side support for Diffie Hellman Group Exchange
|
||||
|
||||
TODO: accepted proposal https://go.dev/issue/57792 (from https://go.dev/cl/649716, https://go.dev/cl/651737)
|
||||
x/crypto/x509roots: new module
|
||||
|
||||
TODO: accepted proposal https://go.dev/issue/58523 (from https://go.dev/cl/538235)
|
||||
ssh: expose negotiated algorithms
|
||||
Fixes golang/go#58523
|
||||
Fixes golang/go#46638
|
||||
|
||||
TODO: accepted proposal https://go.dev/issue/61537 (from https://go.dev/cl/531935)
|
||||
ssh: export supported algorithms
|
||||
Fixes golang/go#61537
|
||||
|
||||
TODO: accepted proposal https://go.dev/issue/61901 (from https://go.dev/cl/647875)
|
||||
bytes, strings: add iterator forms of existing functions
|
||||
|
||||
TODO: accepted proposal https://go.dev/issue/61940 (from https://go.dev/cl/650235)
|
||||
all: fix links to Go wiki
|
||||
The Go wiki on GitHub has moved to go.dev in golang/go#61940.
|
||||
|
||||
TODO: accepted proposal https://go.dev/issue/64207 (from https://go.dev/cl/647015, https://go.dev/cl/652235)
|
||||
all: end support for macOS 10.15 in Go 1.23
|
||||
|
||||
TODO: accepted proposal https://go.dev/issue/67839 (from https://go.dev/cl/646535)
|
||||
x/sys/unix: access to ELF auxiliary vector
|
||||
runtime: adjust comments for auxv getAuxv
|
||||
github.com/cilium/ebpf no longer accesses getAuxv using linkname but now
|
||||
uses the golang.org/x/sys/unix.Auxv wrapper introduced in
|
||||
go.dev/cl/644295.
|
||||
Also adjust the list of users to include x/sys/unix.
|
||||
Updates \#67839
|
||||
Updates \#67401
|
||||
|
||||
TODO: accepted proposal https://go.dev/issue/68780 (from https://go.dev/cl/659835)
|
||||
x/term: support pluggable history
|
||||
term: support pluggable history
|
||||
Expose a new History interface that allows replacement of the default
|
||||
ring buffer to customize what gets added or not; as well as to allow
|
||||
saving/restoring history on either the default ringbuffer or a custom
|
||||
replacement.
|
||||
Fixes golang/go#68780
|
||||
|
||||
TODO: accepted proposal https://go.dev/issue/69095 (from https://go.dev/cl/649320, https://go.dev/cl/649321, https://go.dev/cl/649337, https://go.dev/cl/649376, https://go.dev/cl/649377, https://go.dev/cl/649378, https://go.dev/cl/649379, https://go.dev/cl/649380, https://go.dev/cl/649397, https://go.dev/cl/649398, https://go.dev/cl/649419, https://go.dev/cl/649497, https://go.dev/cl/649498, https://go.dev/cl/649618, https://go.dev/cl/649675, https://go.dev/cl/649676, https://go.dev/cl/649677, https://go.dev/cl/649695, https://go.dev/cl/649696, https://go.dev/cl/649697, https://go.dev/cl/649698, https://go.dev/cl/649715, https://go.dev/cl/649717, https://go.dev/cl/649718, https://go.dev/cl/649755, https://go.dev/cl/649775, https://go.dev/cl/649795, https://go.dev/cl/649815, https://go.dev/cl/649835, https://go.dev/cl/651336, https://go.dev/cl/651736, https://go.dev/cl/651737, https://go.dev/cl/658018)
|
||||
all, x/build/cmd/relui: automate go directive maintenance in golang.org/x repositories
|
||||
|
||||
TODO: accepted proposal https://go.dev/issue/70859 (from https://go.dev/cl/666056, https://go.dev/cl/670835, https://go.dev/cl/672015, https://go.dev/cl/672016, https://go.dev/cl/672017)
|
||||
x/tools/go/ast/inspector: add Cursor, to enable partial and multi-level traversals
|
||||
|
||||
-->
|
||||
|
|
@ -0,0 +1 @@
|
|||
v1.0.0
|
||||
|
|
@ -260,8 +260,11 @@ func (s *Scanner) setErr(err error) {
|
|||
}
|
||||
}
|
||||
|
||||
// Buffer sets the initial buffer to use when scanning
|
||||
// Buffer controls memory allocation by the Scanner.
|
||||
// It sets the initial buffer to use when scanning
|
||||
// and the maximum size of buffer that may be allocated during scanning.
|
||||
// The contents of the buffer are ignored.
|
||||
//
|
||||
// The maximum token size must be less than the larger of max and cap(buf).
|
||||
// If max <= cap(buf), [Scanner.Scan] will use this buffer only and do no allocation.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ func (e *escape) call(ks []hole, call ir.Node) {
|
|||
var fn *ir.Name
|
||||
switch call.Op() {
|
||||
case ir.OCALLFUNC:
|
||||
// TODO(thepudds): use an ir.ReassignOracle here.
|
||||
v := ir.StaticValue(call.Fun)
|
||||
fn = ir.StaticCalleeName(v)
|
||||
}
|
||||
|
|
@ -83,15 +84,19 @@ func (e *escape) call(ks []hole, call ir.Node) {
|
|||
argument(e.tagHole(ks, fn, param), arg)
|
||||
}
|
||||
|
||||
// hash/maphash.escapeForHash forces its argument to be on
|
||||
// the heap, if it contains a non-string pointer. We cannot
|
||||
// internal/abi.EscapeNonString forces its argument to be on
|
||||
// the heap, if it contains a non-string pointer.
|
||||
// This is used in hash/maphash.Comparable, where we cannot
|
||||
// hash pointers to local variables, as the address of the
|
||||
// local variable might change on stack growth.
|
||||
// Strings are okay as the hash depends on only the content,
|
||||
// not the pointer.
|
||||
// This is also used in unique.clone, to model the data flow
|
||||
// edge on the value with strings excluded, because strings
|
||||
// are cloned (by content).
|
||||
// The actual call we match is
|
||||
// hash/maphash.escapeForHash[go.shape.T](dict, go.shape.T)
|
||||
if fn != nil && fn.Sym().Pkg.Path == "hash/maphash" && strings.HasPrefix(fn.Sym().Name, "escapeForHash[") {
|
||||
// internal/abi.EscapeNonString[go.shape.T](dict, go.shape.T)
|
||||
if fn != nil && fn.Sym().Pkg.Path == "internal/abi" && strings.HasPrefix(fn.Sym().Name, "EscapeNonString[") {
|
||||
ps := fntype.Params()
|
||||
if len(ps) == 2 && ps[1].Type.IsShape() {
|
||||
if !hasNonStringPointers(ps[1].Type) {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ package escape
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"go/constant"
|
||||
"go/token"
|
||||
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/ir"
|
||||
|
|
@ -88,6 +90,7 @@ import (
|
|||
type batch struct {
|
||||
allLocs []*location
|
||||
closures []closure
|
||||
reassignOracles map[*ir.Func]*ir.ReassignOracle
|
||||
|
||||
heapLoc location
|
||||
mutatorLoc location
|
||||
|
|
@ -129,6 +132,7 @@ func Batch(fns []*ir.Func, recursive bool) {
|
|||
b.heapLoc.attrs = attrEscapes | attrPersists | attrMutates | attrCalls
|
||||
b.mutatorLoc.attrs = attrMutates
|
||||
b.calleeLoc.attrs = attrCalls
|
||||
b.reassignOracles = make(map[*ir.Func]*ir.ReassignOracle)
|
||||
|
||||
// Construct data-flow graph from syntax trees.
|
||||
for _, fn := range fns {
|
||||
|
|
@ -154,6 +158,11 @@ func Batch(fns []*ir.Func, recursive bool) {
|
|||
b.closures = nil
|
||||
|
||||
for _, loc := range b.allLocs {
|
||||
// Try to replace some non-constant expressions with literals.
|
||||
b.rewriteWithLiterals(loc.n, loc.curfn)
|
||||
|
||||
// Check if the node must be heap allocated for certain reasons
|
||||
// such as OMAKESLICE for a large slice.
|
||||
if why := HeapAllocReason(loc.n); why != "" {
|
||||
b.flow(b.heapHole().addr(loc.n, why), loc)
|
||||
}
|
||||
|
|
@ -515,3 +524,101 @@ func (b *batch) reportLeaks(pos src.XPos, name string, esc leaks, sig *types.Typ
|
|||
base.WarnfAt(pos, "%v does not escape, mutate, or call", name)
|
||||
}
|
||||
}
|
||||
|
||||
// rewriteWithLiterals attempts to replace certain non-constant expressions
|
||||
// within n with a literal if possible.
|
||||
func (b *batch) rewriteWithLiterals(n ir.Node, fn *ir.Func) {
|
||||
if n == nil || fn == nil {
|
||||
return
|
||||
}
|
||||
if n.Op() != ir.OMAKESLICE && n.Op() != ir.OCONVIFACE {
|
||||
return
|
||||
}
|
||||
if base.Flag.Cfg.CoverageInfo != nil {
|
||||
// Avoid altering coverage results.
|
||||
return
|
||||
}
|
||||
|
||||
// Look up a cached ReassignOracle for the function, lazily computing one if needed.
|
||||
ro := b.reassignOracle(fn)
|
||||
if ro == nil {
|
||||
base.Fatalf("no ReassignOracle for function %v with closure parent %v", fn, fn.ClosureParent)
|
||||
}
|
||||
|
||||
switch n.Op() {
|
||||
case ir.OMAKESLICE:
|
||||
// Check if we can replace a non-constant argument to make with
|
||||
// a literal to allow for this slice to be stack allocated if otherwise allowed.
|
||||
n := n.(*ir.MakeExpr)
|
||||
|
||||
r := &n.Cap
|
||||
if n.Cap == nil {
|
||||
r = &n.Len
|
||||
}
|
||||
|
||||
if s := ro.StaticValue(*r); s.Op() == ir.OLITERAL {
|
||||
lit, ok := s.(*ir.BasicLit)
|
||||
if !ok || lit.Val().Kind() != constant.Int {
|
||||
base.Fatalf("unexpected BasicLit Kind")
|
||||
}
|
||||
if constant.Compare(lit.Val(), token.GEQ, constant.MakeInt64(0)) {
|
||||
*r = lit
|
||||
}
|
||||
}
|
||||
case ir.OCONVIFACE:
|
||||
// Check if we can replace a non-constant expression in an interface conversion with
|
||||
// a literal to avoid heap allocating the underlying interface value.
|
||||
conv := n.(*ir.ConvExpr)
|
||||
if conv.X.Op() != ir.OLITERAL && !conv.X.Type().IsInterface() {
|
||||
v := ro.StaticValue(conv.X)
|
||||
if v != nil && v.Op() == ir.OLITERAL && ir.ValidTypeForConst(conv.X.Type(), v.Val()) {
|
||||
if base.Debug.EscapeDebug >= 3 {
|
||||
base.WarnfAt(n.Pos(), "rewriting OCONVIFACE value from %v (%v) to %v (%v)", conv.X, conv.X.Type(), v, v.Type())
|
||||
}
|
||||
v := v.(*ir.BasicLit)
|
||||
conv.X = ir.NewBasicLit(conv.X.Pos(), conv.X.Type(), v.Val())
|
||||
typecheck.Expr(conv)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// reassignOracle returns an initialized *ir.ReassignOracle for fn.
|
||||
// If fn is a closure, it returns the ReassignOracle for the ultimate parent.
|
||||
//
|
||||
// A new ReassignOracle is initialized lazily if needed, and the result
|
||||
// is cached to reduce duplicative work of preparing a ReassignOracle.
|
||||
func (b *batch) reassignOracle(fn *ir.Func) *ir.ReassignOracle {
|
||||
if ro, ok := b.reassignOracles[fn]; ok {
|
||||
return ro // Hit.
|
||||
}
|
||||
|
||||
// For closures, we want the ultimate parent's ReassignOracle,
|
||||
// so walk up the parent chain, if any.
|
||||
f := fn
|
||||
for f.ClosureParent != nil && !f.ClosureParent.IsPackageInit() {
|
||||
f = f.ClosureParent
|
||||
}
|
||||
|
||||
if f != fn {
|
||||
// We found a parent.
|
||||
ro := b.reassignOracles[f]
|
||||
if ro != nil {
|
||||
// Hit, via a parent. Before returning, store this ro for the original fn as well.
|
||||
b.reassignOracles[fn] = ro
|
||||
return ro
|
||||
}
|
||||
}
|
||||
|
||||
// Miss. We did not find a ReassignOracle for fn or a parent, so lazily create one.
|
||||
ro := &ir.ReassignOracle{}
|
||||
ro.Init(f)
|
||||
|
||||
// Cache the answer for the original fn.
|
||||
b.reassignOracles[fn] = ro
|
||||
if f != fn {
|
||||
// Cache for the parent as well.
|
||||
b.reassignOracles[f] = ro
|
||||
}
|
||||
return ro
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,35 +139,6 @@ func (l *location) leakTo(sink *location, derefs int) {
|
|||
l.paramEsc.AddHeap(derefs)
|
||||
}
|
||||
|
||||
// leakTo records that parameter l leaks to sink.
|
||||
func (b *batch) leakTo(l, sink *location, derefs int) {
|
||||
if (logopt.Enabled() || base.Flag.LowerM >= 2) && !l.hasAttr(attrEscapes) {
|
||||
if base.Flag.LowerM >= 2 {
|
||||
fmt.Printf("%s: parameter %v leaks to %s with derefs=%d:\n", base.FmtPos(l.n.Pos()), l.n, b.explainLoc(sink), derefs)
|
||||
}
|
||||
explanation := b.explainPath(sink, l)
|
||||
if logopt.Enabled() {
|
||||
var e_curfn *ir.Func // TODO(mdempsky): Fix.
|
||||
logopt.LogOpt(l.n.Pos(), "leak", "escape", ir.FuncName(e_curfn),
|
||||
fmt.Sprintf("parameter %v leaks to %s with derefs=%d", l.n, b.explainLoc(sink), derefs), explanation)
|
||||
}
|
||||
}
|
||||
|
||||
// If sink is a result parameter that doesn't escape (#44614)
|
||||
// and we can fit return bits into the escape analysis tag,
|
||||
// then record as a result leak.
|
||||
if !sink.hasAttr(attrEscapes) && sink.isName(ir.PPARAMOUT) && sink.curfn == l.curfn {
|
||||
if ri := sink.resultIndex - 1; ri < numEscResults {
|
||||
// Leak to result parameter.
|
||||
l.paramEsc.AddResult(ri, derefs)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, record as heap leak.
|
||||
l.paramEsc.AddHeap(derefs)
|
||||
}
|
||||
|
||||
func (l *location) isName(c ir.Class) bool {
|
||||
return l.n != nil && l.n.Op() == ir.ONAME && l.n.(*ir.Name).Class == c
|
||||
}
|
||||
|
|
@ -241,7 +212,7 @@ func (b *batch) flow(k hole, src *location) {
|
|||
if base.Flag.LowerM >= 2 || logopt.Enabled() {
|
||||
pos := base.FmtPos(src.n.Pos())
|
||||
if base.Flag.LowerM >= 2 {
|
||||
fmt.Printf("%s: %v escapes to heap:\n", pos, src.n)
|
||||
fmt.Printf("%s: %v escapes to heap in %v:\n", pos, src.n, ir.FuncName(src.curfn))
|
||||
}
|
||||
explanation := b.explainFlow(pos, dst, src, k.derefs, k.notes, []*logopt.LoggedOpt{})
|
||||
if logopt.Enabled() {
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ func (b *batch) walkOne(root *location, walkgen uint32, enqueue func(*location))
|
|||
if b.outlives(root, l) {
|
||||
if !l.hasAttr(attrEscapes) && (logopt.Enabled() || base.Flag.LowerM >= 2) {
|
||||
if base.Flag.LowerM >= 2 {
|
||||
fmt.Printf("%s: %v escapes to heap:\n", base.FmtPos(l.n.Pos()), l.n)
|
||||
fmt.Printf("%s: %v escapes to heap in %v:\n", base.FmtPos(l.n.Pos()), l.n, ir.FuncName(l.curfn))
|
||||
}
|
||||
explanation := b.explainPath(root, l)
|
||||
if logopt.Enabled() {
|
||||
|
|
@ -146,7 +146,7 @@ func (b *batch) walkOne(root *location, walkgen uint32, enqueue func(*location))
|
|||
if b.outlives(root, l) {
|
||||
if !l.hasAttr(attrEscapes) && (logopt.Enabled() || base.Flag.LowerM >= 2) {
|
||||
if base.Flag.LowerM >= 2 {
|
||||
fmt.Printf("%s: parameter %v leaks to %s with derefs=%d:\n", base.FmtPos(l.n.Pos()), l.n, b.explainLoc(root), derefs)
|
||||
fmt.Printf("%s: parameter %v leaks to %s for %v with derefs=%d:\n", base.FmtPos(l.n.Pos()), l.n, b.explainLoc(root), ir.FuncName(l.curfn), derefs)
|
||||
}
|
||||
explanation := b.explainPath(root, l)
|
||||
if logopt.Enabled() {
|
||||
|
|
@ -234,7 +234,7 @@ func (b *batch) explainFlow(pos string, dst, srcloc *location, derefs int, notes
|
|||
}
|
||||
print := base.Flag.LowerM >= 2
|
||||
|
||||
flow := fmt.Sprintf(" flow: %s = %s%v:", b.explainLoc(dst), ops, b.explainLoc(srcloc))
|
||||
flow := fmt.Sprintf(" flow: %s ← %s%v:", b.explainLoc(dst), ops, b.explainLoc(srcloc))
|
||||
if print {
|
||||
fmt.Printf("%s:%s\n", pos, flow)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,12 +5,9 @@
|
|||
package escape
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/typecheck"
|
||||
"cmd/compile/internal/types"
|
||||
"go/constant"
|
||||
"go/token"
|
||||
)
|
||||
|
||||
func isSliceSelfAssign(dst, src ir.Node) bool {
|
||||
|
|
@ -210,21 +207,9 @@ func HeapAllocReason(n ir.Node) string {
|
|||
if n.Op() == ir.OMAKESLICE {
|
||||
n := n.(*ir.MakeExpr)
|
||||
|
||||
r := &n.Cap
|
||||
r := n.Cap
|
||||
if n.Cap == nil {
|
||||
r = &n.Len
|
||||
}
|
||||
|
||||
// Try to determine static values of make() calls, to avoid allocating them on the heap.
|
||||
// We are doing this in escape analysis, so that it happens after inlining and devirtualization.
|
||||
if s := ir.StaticValue(*r); s.Op() == ir.OLITERAL {
|
||||
lit, ok := s.(*ir.BasicLit)
|
||||
if !ok || lit.Val().Kind() != constant.Int {
|
||||
base.Fatalf("unexpected BasicLit Kind")
|
||||
}
|
||||
if constant.Compare(lit.Val(), token.GEQ, constant.MakeInt64(0)) {
|
||||
*r = lit
|
||||
}
|
||||
r = n.Len
|
||||
}
|
||||
|
||||
elem := n.Type().Elem()
|
||||
|
|
@ -232,7 +217,7 @@ func HeapAllocReason(n ir.Node) string {
|
|||
// TODO: stack allocate these? See #65685.
|
||||
return "zero-sized element"
|
||||
}
|
||||
if !ir.IsSmallIntConst(*r) {
|
||||
if !ir.IsSmallIntConst(r) {
|
||||
// For non-constant sizes, we do a hybrid approach:
|
||||
//
|
||||
// if cap <= K {
|
||||
|
|
@ -249,7 +234,7 @@ func HeapAllocReason(n ir.Node) string {
|
|||
// Implementation is in ../walk/builtin.go:walkMakeSlice.
|
||||
return ""
|
||||
}
|
||||
if ir.Int64Val(*r) > ir.MaxImplicitStackVarSize/elem.Size() {
|
||||
if ir.Int64Val(r) > ir.MaxImplicitStackVarSize/elem.Size() {
|
||||
return "too large for stack"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -454,6 +454,11 @@ opSwitch:
|
|||
// generate code.
|
||||
cheap = true
|
||||
}
|
||||
if strings.HasPrefix(fn, "EscapeNonString[") {
|
||||
// internal/abi.EscapeNonString[T] is a compiler intrinsic
|
||||
// implemented in the escape analysis phase.
|
||||
cheap = true
|
||||
}
|
||||
case "internal/runtime/sys":
|
||||
switch fn {
|
||||
case "GetCallerPC", "GetCallerSP":
|
||||
|
|
@ -472,12 +477,6 @@ opSwitch:
|
|||
case "panicrangestate":
|
||||
cheap = true
|
||||
}
|
||||
case "hash/maphash":
|
||||
if strings.HasPrefix(fn, "escapeForHash[") {
|
||||
// hash/maphash.escapeForHash[T] is a compiler intrinsic
|
||||
// implemented in the escape analysis phase.
|
||||
cheap = true
|
||||
}
|
||||
}
|
||||
}
|
||||
// Special case for coverage counter updates; although
|
||||
|
|
@ -801,10 +800,10 @@ func inlineCallCheck(callerfn *ir.Func, call *ir.CallExpr) (bool, bool) {
|
|||
}
|
||||
}
|
||||
|
||||
// hash/maphash.escapeForHash[T] is a compiler intrinsic implemented
|
||||
// internal/abi.EscapeNonString[T] is a compiler intrinsic implemented
|
||||
// in the escape analysis phase.
|
||||
if fn := ir.StaticCalleeName(call.Fun); fn != nil && fn.Sym().Pkg.Path == "hash/maphash" &&
|
||||
strings.HasPrefix(fn.Sym().Name, "escapeForHash[") {
|
||||
if fn := ir.StaticCalleeName(call.Fun); fn != nil && fn.Sym().Pkg.Path == "internal/abi" &&
|
||||
strings.HasPrefix(fn.Sym().Name, "EscapeNonString[") {
|
||||
return false, true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ type symsStruct struct {
|
|||
Udiv *obj.LSym
|
||||
WriteBarrier *obj.LSym
|
||||
Zerobase *obj.LSym
|
||||
ZeroVal *obj.LSym
|
||||
ARM64HasATOMICS *obj.LSym
|
||||
ARMHasVFPv4 *obj.LSym
|
||||
Loong64HasLAMCAS *obj.LSym
|
||||
|
|
|
|||
|
|
@ -203,16 +203,16 @@ func s15a8(x *[15]int64) [15]int64 {
|
|||
// escape analysis explanation
|
||||
want(t, slogged, `{"range":{"start":{"line":7,"character":13},"end":{"line":7,"character":13}},"severity":3,"code":"leak","source":"go compiler","message":"parameter z leaks to ~r0 with derefs=0",`+
|
||||
`"relatedInformation":[`+
|
||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: y = z:"},`+
|
||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: y ← z:"},`+
|
||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y := z (assign-pair)"},`+
|
||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: ~r0 = y:"},`+
|
||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: ~r0 ← y:"},`+
|
||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+
|
||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y.b (dot of pointer)"},`+
|
||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+
|
||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from \u0026y.b (address-of)"},`+
|
||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":9},"end":{"line":4,"character":9}}},"message":"inlineLoc"},`+
|
||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from ~r0 = \u0026y.b (assign-pair)"},`+
|
||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: flow: ~r0 = ~r0:"},`+
|
||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: flow: ~r0 ← ~r0:"},`+
|
||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: from return ~r0 (return)"}]}`)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -165,6 +165,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
|||
ssa.OpLOONG64OR,
|
||||
ssa.OpLOONG64XOR,
|
||||
ssa.OpLOONG64NOR,
|
||||
ssa.OpLOONG64ANDN,
|
||||
ssa.OpLOONG64ORN,
|
||||
ssa.OpLOONG64SLL,
|
||||
ssa.OpLOONG64SLLV,
|
||||
ssa.OpLOONG64SRL,
|
||||
|
|
|
|||
|
|
@ -305,6 +305,7 @@ func ForCapture(fn *ir.Func) []VarAndLoop {
|
|||
as := ir.NewAssignStmt(x.Pos(), z, tz)
|
||||
as.Def = true
|
||||
as.SetTypecheck(1)
|
||||
z.Defn = as
|
||||
preBody.Append(as)
|
||||
dclFixups[z] = as
|
||||
|
||||
|
|
|
|||
|
|
@ -804,6 +804,9 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
|||
p := s.Prog(obj.AGETCALLERPC)
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
case ssa.OpMIPSLoweredPubBarrier:
|
||||
// SYNC
|
||||
s.Prog(v.Op.Asm())
|
||||
case ssa.OpClobber, ssa.OpClobberReg:
|
||||
// TODO: implement for clobberdead experiment. Nop is ok for now.
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -813,6 +813,9 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
|||
p := s.Prog(obj.AGETCALLERPC)
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
case ssa.OpMIPS64LoweredPubBarrier:
|
||||
// SYNC
|
||||
s.Prog(v.Op.Asm())
|
||||
case ssa.OpClobber, ssa.OpClobberReg:
|
||||
// TODO: implement for clobberdead experiment. Nop is ok for now.
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -49,6 +49,9 @@ type pkgReader struct {
|
|||
// but bitwise inverted so we can detect if we're missing the entry
|
||||
// or not.
|
||||
newindex []index
|
||||
|
||||
// indicates whether the data is reading during reshaping.
|
||||
reshaping bool
|
||||
}
|
||||
|
||||
func newPkgReader(pr pkgbits.PkgDecoder) *pkgReader {
|
||||
|
|
@ -116,6 +119,10 @@ type reader struct {
|
|||
// find parameters/results.
|
||||
funarghack bool
|
||||
|
||||
// reshaping is used during reading exprReshape code, preventing
|
||||
// the reader from shapifying the re-shaped type.
|
||||
reshaping bool
|
||||
|
||||
// methodSym is the name of method's name, if reading a method.
|
||||
// It's nil if reading a normal function or closure body.
|
||||
methodSym *types.Sym
|
||||
|
|
@ -762,7 +769,7 @@ func (pr *pkgReader) objIdxMayFail(idx index, implicits, explicits []*types.Type
|
|||
if hack {
|
||||
if sym.Def != nil {
|
||||
name = sym.Def.(*ir.Name)
|
||||
assert(name.Type() == typ)
|
||||
assert(types.IdenticalStrict(name.Type(), typ))
|
||||
return name, nil
|
||||
}
|
||||
sym.Def = name
|
||||
|
|
@ -1007,7 +1014,7 @@ func (pr *pkgReader) objDictIdx(sym *types.Sym, idx index, implicits, explicits
|
|||
// arguments.
|
||||
for i, targ := range dict.targs {
|
||||
basic := r.Bool()
|
||||
if dict.shaped {
|
||||
if dict.shaped && !pr.reshaping {
|
||||
dict.targs[i] = shapify(targ, basic)
|
||||
}
|
||||
}
|
||||
|
|
@ -2445,7 +2452,10 @@ func (r *reader) expr() (res ir.Node) {
|
|||
|
||||
case exprReshape:
|
||||
typ := r.typ()
|
||||
old := r.reshaping
|
||||
r.reshaping = true
|
||||
x := r.expr()
|
||||
r.reshaping = old
|
||||
|
||||
if types.IdenticalStrict(x.Type(), typ) {
|
||||
return x
|
||||
|
|
@ -2568,7 +2578,10 @@ func (r *reader) funcInst(pos src.XPos) (wrapperFn, baseFn, dictPtr ir.Node) {
|
|||
info := r.dict.subdicts[idx]
|
||||
explicits := r.p.typListIdx(info.explicits, r.dict)
|
||||
|
||||
old := r.p.reshaping
|
||||
r.p.reshaping = r.reshaping
|
||||
baseFn = r.p.objIdx(info.idx, implicits, explicits, true).(*ir.Name)
|
||||
r.p.reshaping = old
|
||||
|
||||
// TODO(mdempsky): Is there a more robust way to get the
|
||||
// dictionary pointer type here?
|
||||
|
|
|
|||
|
|
@ -782,6 +782,9 @@
|
|||
(AND x x) => x
|
||||
(OR x x) => x
|
||||
(XOR x x) => (MOVVconst [0])
|
||||
(ORN x (MOVVconst [-1])) => x
|
||||
(AND x (NORconst [0] y)) => (ANDN x y)
|
||||
(OR x (NORconst [0] y)) => (ORN x y)
|
||||
|
||||
// Fold negation into subtraction.
|
||||
(NEGV (SUBV x y)) => (SUBV y x)
|
||||
|
|
|
|||
|
|
@ -221,6 +221,8 @@ func init() {
|
|||
{name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64", typ: "UInt64"}, // arg0 ^ auxInt
|
||||
{name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true}, // ^(arg0 | arg1)
|
||||
{name: "NORconst", argLength: 1, reg: gp11, asm: "NOR", aux: "Int64"}, // ^(arg0 | auxInt)
|
||||
{name: "ANDN", argLength: 2, reg: gp21, asm: "ANDN"}, // arg0 & ^arg1
|
||||
{name: "ORN", argLength: 2, reg: gp21, asm: "ORN"}, // arg0 | ^arg1
|
||||
|
||||
{name: "FMADDF", argLength: 3, reg: fp31, asm: "FMADDF", commutative: true, typ: "Float32"}, // (arg0 * arg1) + arg2
|
||||
{name: "FMADDD", argLength: 3, reg: fp31, asm: "FMADDD", commutative: true, typ: "Float64"}, // (arg0 * arg1) + arg2
|
||||
|
|
|
|||
|
|
@ -420,6 +420,9 @@
|
|||
// Write barrier.
|
||||
(WB ...) => (LoweredWB ...)
|
||||
|
||||
// Publication barrier as intrinsic
|
||||
(PubBarrier ...) => (LoweredPubBarrier ...)
|
||||
|
||||
(PanicBounds [kind] x y mem) && boundsABI(kind) == 0 => (LoweredPanicBoundsA [kind] x y mem)
|
||||
(PanicBounds [kind] x y mem) && boundsABI(kind) == 1 => (LoweredPanicBoundsB [kind] x y mem)
|
||||
(PanicBounds [kind] x y mem) && boundsABI(kind) == 2 => (LoweredPanicBoundsC [kind] x y mem)
|
||||
|
|
|
|||
|
|
@ -476,6 +476,9 @@
|
|||
// Write barrier.
|
||||
(WB ...) => (LoweredWB ...)
|
||||
|
||||
// Publication barrier as intrinsic
|
||||
(PubBarrier ...) => (LoweredPubBarrier ...)
|
||||
|
||||
(PanicBounds [kind] x y mem) && boundsABI(kind) == 0 => (LoweredPanicBoundsA [kind] x y mem)
|
||||
(PanicBounds [kind] x y mem) && boundsABI(kind) == 1 => (LoweredPanicBoundsB [kind] x y mem)
|
||||
(PanicBounds [kind] x y mem) && boundsABI(kind) == 2 => (LoweredPanicBoundsC [kind] x y mem)
|
||||
|
|
|
|||
|
|
@ -466,6 +466,9 @@ func init() {
|
|||
// Returns a pointer to a write barrier buffer in R25.
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: (callerSave &^ gpg) | buildReg("R31"), outputs: []regMask{buildReg("R25")}}, clobberFlags: true, aux: "Int64"},
|
||||
|
||||
// Do data barrier. arg0=memorys
|
||||
{name: "LoweredPubBarrier", argLength: 1, asm: "SYNC", hasSideEffects: true},
|
||||
|
||||
// There are three of these functions so that they can have three different register inputs.
|
||||
// When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the
|
||||
// default registers to match so we don't need to copy registers around unnecessarily.
|
||||
|
|
|
|||
|
|
@ -408,6 +408,9 @@ func init() {
|
|||
// Returns a pointer to a write barrier buffer in R25.
|
||||
{name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: (callerSave &^ gpg) | buildReg("R31"), outputs: []regMask{buildReg("R25")}}, clobberFlags: true, aux: "Int64"},
|
||||
|
||||
// Do data barrier. arg0=memorys
|
||||
{name: "LoweredPubBarrier", argLength: 1, asm: "SYNC", hasSideEffects: true},
|
||||
|
||||
// There are three of these functions so that they can have three different register inputs.
|
||||
// When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the
|
||||
// default registers to match so we don't need to copy registers around unnecessarily.
|
||||
|
|
|
|||
|
|
@ -1188,6 +1188,8 @@
|
|||
// TODO: more of this
|
||||
(ADD x (NEG y)) => (SUB x y)
|
||||
(ADDW x (NEGW y)) => (SUBW x y)
|
||||
(SUB x (NEG y)) => (ADD x y)
|
||||
(SUBW x (NEGW y)) => (ADDW x y)
|
||||
(SUB x x) => (MOVDconst [0])
|
||||
(SUBW x x) => (MOVDconst [0])
|
||||
(AND x x) => x
|
||||
|
|
@ -1196,6 +1198,7 @@
|
|||
(ORW x x) => x
|
||||
(XOR x x) => (MOVDconst [0])
|
||||
(XORW x x) => (MOVDconst [0])
|
||||
(NEG (NEG x)) => x
|
||||
(NEG (ADDconst [c] (NEG x))) && c != -(1<<31) => (ADDconst [-c] x)
|
||||
(MOVBZreg (ANDWconst [m] x)) => (MOVWZreg (ANDWconst <typ.UInt32> [int32( uint8(m))] x))
|
||||
(MOVHZreg (ANDWconst [m] x)) => (MOVWZreg (ANDWconst <typ.UInt32> [int32(uint16(m))] x))
|
||||
|
|
|
|||
|
|
@ -2832,3 +2832,14 @@
|
|||
&& clobber(sbts)
|
||||
&& clobber(key)
|
||||
=> (StaticLECall {f} [argsize] typ_ map_ (StringMake <typ.String> ptr len) mem)
|
||||
|
||||
// Similarly to map lookups, also handle unique.Make for strings, which unique.Make will clone.
|
||||
(StaticLECall {f} [argsize] dict_ key:(SelectN [0] sbts:(StaticLECall {g} _ ptr len mem)) m:(SelectN [1] sbts))
|
||||
&& isSameCall(f, "unique.Make[go.shape.string]")
|
||||
&& isSameCall(g, "runtime.slicebytetostring")
|
||||
&& key.Uses == 1
|
||||
&& sbts.Uses == 2
|
||||
&& resetCopy(m, mem)
|
||||
&& clobber(sbts)
|
||||
&& clobber(key)
|
||||
=> (StaticLECall {f} [argsize] dict_ (StringMake <typ.String> ptr len) mem)
|
||||
|
|
|
|||
|
|
@ -581,7 +581,7 @@ func combineStores(root *Value) {
|
|||
mask := int64(1)<<(8*a[i].size) - 1
|
||||
s := 8 * (a[i].offset - a[0].offset)
|
||||
if root.Block.Func.Config.BigEndian {
|
||||
s = aTotalSize*8 - a[i].size - s
|
||||
s = (aTotalSize-a[i].size)*8 - s
|
||||
}
|
||||
c |= (a[i].store.Args[1].AuxInt & mask) << s
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1810,6 +1810,8 @@ const (
|
|||
OpLOONG64XORconst
|
||||
OpLOONG64NOR
|
||||
OpLOONG64NORconst
|
||||
OpLOONG64ANDN
|
||||
OpLOONG64ORN
|
||||
OpLOONG64FMADDF
|
||||
OpLOONG64FMADDD
|
||||
OpLOONG64FMSUBF
|
||||
|
|
@ -2074,6 +2076,7 @@ const (
|
|||
OpMIPSLoweredGetCallerSP
|
||||
OpMIPSLoweredGetCallerPC
|
||||
OpMIPSLoweredWB
|
||||
OpMIPSLoweredPubBarrier
|
||||
OpMIPSLoweredPanicBoundsA
|
||||
OpMIPSLoweredPanicBoundsB
|
||||
OpMIPSLoweredPanicBoundsC
|
||||
|
|
@ -2205,6 +2208,7 @@ const (
|
|||
OpMIPS64LoweredGetCallerSP
|
||||
OpMIPS64LoweredGetCallerPC
|
||||
OpMIPS64LoweredWB
|
||||
OpMIPS64LoweredPubBarrier
|
||||
OpMIPS64LoweredPanicBoundsA
|
||||
OpMIPS64LoweredPanicBoundsB
|
||||
OpMIPS64LoweredPanicBoundsC
|
||||
|
|
@ -24379,6 +24383,34 @@ var opcodeTable = [...]opInfo{
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ANDN",
|
||||
argLen: 2,
|
||||
asm: loong64.AANDN,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
|
||||
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ORN",
|
||||
argLen: 2,
|
||||
asm: loong64.AORN,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
|
||||
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "FMADDF",
|
||||
argLen: 3,
|
||||
|
|
@ -27959,6 +27991,13 @@ var opcodeTable = [...]opInfo{
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "LoweredPubBarrier",
|
||||
argLen: 1,
|
||||
hasSideEffects: true,
|
||||
asm: mips.ASYNC,
|
||||
reg: regInfo{},
|
||||
},
|
||||
{
|
||||
name: "LoweredPanicBoundsA",
|
||||
auxType: auxInt64,
|
||||
|
|
@ -29725,6 +29764,13 @@ var opcodeTable = [...]opInfo{
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "LoweredPubBarrier",
|
||||
argLen: 1,
|
||||
hasSideEffects: true,
|
||||
asm: mips.ASYNC,
|
||||
reg: regInfo{},
|
||||
},
|
||||
{
|
||||
name: "LoweredPanicBoundsA",
|
||||
auxType: auxInt64,
|
||||
|
|
|
|||
|
|
@ -436,6 +436,8 @@ func rewriteValueLOONG64(v *Value) bool {
|
|||
return rewriteValueLOONG64_OpLOONG64NORconst(v)
|
||||
case OpLOONG64OR:
|
||||
return rewriteValueLOONG64_OpLOONG64OR(v)
|
||||
case OpLOONG64ORN:
|
||||
return rewriteValueLOONG64_OpLOONG64ORN(v)
|
||||
case OpLOONG64ORconst:
|
||||
return rewriteValueLOONG64_OpLOONG64ORconst(v)
|
||||
case OpLOONG64REMV:
|
||||
|
|
@ -1926,6 +1928,21 @@ func rewriteValueLOONG64_OpLOONG64AND(v *Value) bool {
|
|||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (AND x (NORconst [0] y))
|
||||
// result: (ANDN x y)
|
||||
for {
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
if v_1.Op != OpLOONG64NORconst || auxIntToInt64(v_1.AuxInt) != 0 {
|
||||
continue
|
||||
}
|
||||
y := v_1.Args[0]
|
||||
v.reset(OpLOONG64ANDN)
|
||||
v.AddArg2(x, y)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueLOONG64_OpLOONG64ANDconst(v *Value) bool {
|
||||
|
|
@ -5583,6 +5600,36 @@ func rewriteValueLOONG64_OpLOONG64OR(v *Value) bool {
|
|||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (OR x (NORconst [0] y))
|
||||
// result: (ORN x y)
|
||||
for {
|
||||
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
|
||||
x := v_0
|
||||
if v_1.Op != OpLOONG64NORconst || auxIntToInt64(v_1.AuxInt) != 0 {
|
||||
continue
|
||||
}
|
||||
y := v_1.Args[0]
|
||||
v.reset(OpLOONG64ORN)
|
||||
v.AddArg2(x, y)
|
||||
return true
|
||||
}
|
||||
break
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueLOONG64_OpLOONG64ORN(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
// match: (ORN x (MOVVconst [-1]))
|
||||
// result: x
|
||||
for {
|
||||
x := v_0
|
||||
if v_1.Op != OpLOONG64MOVVconst || auxIntToInt64(v_1.AuxInt) != -1 {
|
||||
break
|
||||
}
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueLOONG64_OpLOONG64ORconst(v *Value) bool {
|
||||
|
|
|
|||
|
|
@ -450,6 +450,9 @@ func rewriteValueMIPS(v *Value) bool {
|
|||
return rewriteValueMIPS_OpPanicBounds(v)
|
||||
case OpPanicExtend:
|
||||
return rewriteValueMIPS_OpPanicExtend(v)
|
||||
case OpPubBarrier:
|
||||
v.Op = OpMIPSLoweredPubBarrier
|
||||
return true
|
||||
case OpRotateLeft16:
|
||||
return rewriteValueMIPS_OpRotateLeft16(v)
|
||||
case OpRotateLeft32:
|
||||
|
|
|
|||
|
|
@ -502,6 +502,9 @@ func rewriteValueMIPS64(v *Value) bool {
|
|||
return true
|
||||
case OpPanicBounds:
|
||||
return rewriteValueMIPS64_OpPanicBounds(v)
|
||||
case OpPubBarrier:
|
||||
v.Op = OpMIPS64LoweredPubBarrier
|
||||
return true
|
||||
case OpRotateLeft16:
|
||||
return rewriteValueMIPS64_OpRotateLeft16(v)
|
||||
case OpRotateLeft32:
|
||||
|
|
|
|||
|
|
@ -11292,6 +11292,16 @@ func rewriteValueS390X_OpS390XNEG(v *Value) bool {
|
|||
v.AuxInt = int64ToAuxInt(-c)
|
||||
return true
|
||||
}
|
||||
// match: (NEG (NEG x))
|
||||
// result: x
|
||||
for {
|
||||
if v_0.Op != OpS390XNEG {
|
||||
break
|
||||
}
|
||||
x := v_0.Args[0]
|
||||
v.copyOf(x)
|
||||
return true
|
||||
}
|
||||
// match: (NEG (ADDconst [c] (NEG x)))
|
||||
// cond: c != -(1<<31)
|
||||
// result: (ADDconst [-c] x)
|
||||
|
|
@ -13326,6 +13336,18 @@ func rewriteValueS390X_OpS390XSUB(v *Value) bool {
|
|||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
// match: (SUB x (NEG y))
|
||||
// result: (ADD x y)
|
||||
for {
|
||||
x := v_0
|
||||
if v_1.Op != OpS390XNEG {
|
||||
break
|
||||
}
|
||||
y := v_1.Args[0]
|
||||
v.reset(OpS390XADD)
|
||||
v.AddArg2(x, y)
|
||||
return true
|
||||
}
|
||||
// match: (SUB x x)
|
||||
// result: (MOVDconst [0])
|
||||
for {
|
||||
|
|
@ -13467,6 +13489,18 @@ func rewriteValueS390X_OpS390XSUBW(v *Value) bool {
|
|||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
// match: (SUBW x (NEGW y))
|
||||
// result: (ADDW x y)
|
||||
for {
|
||||
x := v_0
|
||||
if v_1.Op != OpS390XNEGW {
|
||||
break
|
||||
}
|
||||
y := v_1.Args[0]
|
||||
v.reset(OpS390XADDW)
|
||||
v.AddArg2(x, y)
|
||||
return true
|
||||
}
|
||||
// match: (SUBW x x)
|
||||
// result: (MOVDconst [0])
|
||||
for {
|
||||
|
|
|
|||
|
|
@ -30743,6 +30743,41 @@ func rewriteValuegeneric_OpStaticLECall(v *Value) bool {
|
|||
v.AddArg4(typ_, map_, v0, mem)
|
||||
return true
|
||||
}
|
||||
// match: (StaticLECall {f} [argsize] dict_ key:(SelectN [0] sbts:(StaticLECall {g} _ ptr len mem)) m:(SelectN [1] sbts))
|
||||
// cond: isSameCall(f, "unique.Make[go.shape.string]") && isSameCall(g, "runtime.slicebytetostring") && key.Uses == 1 && sbts.Uses == 2 && resetCopy(m, mem) && clobber(sbts) && clobber(key)
|
||||
// result: (StaticLECall {f} [argsize] dict_ (StringMake <typ.String> ptr len) mem)
|
||||
for {
|
||||
if len(v.Args) != 3 {
|
||||
break
|
||||
}
|
||||
argsize := auxIntToInt32(v.AuxInt)
|
||||
f := auxToCall(v.Aux)
|
||||
_ = v.Args[2]
|
||||
dict_ := v.Args[0]
|
||||
key := v.Args[1]
|
||||
if key.Op != OpSelectN || auxIntToInt64(key.AuxInt) != 0 {
|
||||
break
|
||||
}
|
||||
sbts := key.Args[0]
|
||||
if sbts.Op != OpStaticLECall || len(sbts.Args) != 4 {
|
||||
break
|
||||
}
|
||||
g := auxToCall(sbts.Aux)
|
||||
mem := sbts.Args[3]
|
||||
ptr := sbts.Args[1]
|
||||
len := sbts.Args[2]
|
||||
m := v.Args[2]
|
||||
if m.Op != OpSelectN || auxIntToInt64(m.AuxInt) != 1 || sbts != m.Args[0] || !(isSameCall(f, "unique.Make[go.shape.string]") && isSameCall(g, "runtime.slicebytetostring") && key.Uses == 1 && sbts.Uses == 2 && resetCopy(m, mem) && clobber(sbts) && clobber(key)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpStaticLECall)
|
||||
v.AuxInt = int32ToAuxInt(argsize)
|
||||
v.Aux = callToAux(f)
|
||||
v0 := b.NewValue0(v.Pos, OpStringMake, typ.String)
|
||||
v0.AddArg2(ptr, len)
|
||||
v.AddArg3(dict_, v0, mem)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValuegeneric_OpStore(v *Value) bool {
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ func initIntrinsics(cfg *intrinsicBuildConfig) {
|
|||
s.vars[memVar] = s.newValue1(ssa.OpPubBarrier, types.TypeMem, s.mem())
|
||||
return nil
|
||||
},
|
||||
sys.ARM64, sys.Loong64, sys.PPC64, sys.RISCV64)
|
||||
sys.ARM64, sys.Loong64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64)
|
||||
|
||||
/******** internal/runtime/sys ********/
|
||||
add("internal/runtime/sys", "GetCallerPC",
|
||||
|
|
|
|||
|
|
@ -554,6 +554,7 @@ var wantIntrinsics = map[testIntrinsicKey]struct{}{
|
|||
{"mips", "math/bits", "TrailingZeros64"}: struct{}{},
|
||||
{"mips", "math/bits", "TrailingZeros8"}: struct{}{},
|
||||
{"mips", "runtime", "KeepAlive"}: struct{}{},
|
||||
{"mips", "runtime", "publicationBarrier"}: struct{}{},
|
||||
{"mips", "runtime", "slicebytetostringtmp"}: struct{}{},
|
||||
{"mips", "sync", "runtime_LoadAcquintptr"}: struct{}{},
|
||||
{"mips", "sync", "runtime_StoreReluintptr"}: struct{}{},
|
||||
|
|
@ -631,6 +632,7 @@ var wantIntrinsics = map[testIntrinsicKey]struct{}{
|
|||
{"mips64", "math/bits", "Sub"}: struct{}{},
|
||||
{"mips64", "math/bits", "Sub64"}: struct{}{},
|
||||
{"mips64", "runtime", "KeepAlive"}: struct{}{},
|
||||
{"mips64", "runtime", "publicationBarrier"}: struct{}{},
|
||||
{"mips64", "runtime", "slicebytetostringtmp"}: struct{}{},
|
||||
{"mips64", "sync", "runtime_LoadAcquintptr"}: struct{}{},
|
||||
{"mips64", "sync", "runtime_StoreReluintptr"}: struct{}{},
|
||||
|
|
@ -718,6 +720,7 @@ var wantIntrinsics = map[testIntrinsicKey]struct{}{
|
|||
{"mips64le", "math/bits", "Sub"}: struct{}{},
|
||||
{"mips64le", "math/bits", "Sub64"}: struct{}{},
|
||||
{"mips64le", "runtime", "KeepAlive"}: struct{}{},
|
||||
{"mips64le", "runtime", "publicationBarrier"}: struct{}{},
|
||||
{"mips64le", "runtime", "slicebytetostringtmp"}: struct{}{},
|
||||
{"mips64le", "sync", "runtime_LoadAcquintptr"}: struct{}{},
|
||||
{"mips64le", "sync", "runtime_StoreReluintptr"}: struct{}{},
|
||||
|
|
@ -797,6 +800,7 @@ var wantIntrinsics = map[testIntrinsicKey]struct{}{
|
|||
{"mipsle", "math/bits", "TrailingZeros64"}: struct{}{},
|
||||
{"mipsle", "math/bits", "TrailingZeros8"}: struct{}{},
|
||||
{"mipsle", "runtime", "KeepAlive"}: struct{}{},
|
||||
{"mipsle", "runtime", "publicationBarrier"}: struct{}{},
|
||||
{"mipsle", "runtime", "slicebytetostringtmp"}: struct{}{},
|
||||
{"mipsle", "sync", "runtime_LoadAcquintptr"}: struct{}{},
|
||||
{"mipsle", "sync", "runtime_StoreReluintptr"}: struct{}{},
|
||||
|
|
|
|||
|
|
@ -166,6 +166,7 @@ func InitConfig() {
|
|||
ir.Syms.Udiv = typecheck.LookupRuntimeVar("udiv") // asm func with special ABI
|
||||
ir.Syms.WriteBarrier = typecheck.LookupRuntimeVar("writeBarrier") // struct { bool; ... }
|
||||
ir.Syms.Zerobase = typecheck.LookupRuntimeVar("zerobase")
|
||||
ir.Syms.ZeroVal = typecheck.LookupRuntimeVar("zeroVal")
|
||||
|
||||
if Arch.LinkArch.Family == sys.Wasm {
|
||||
BoundsCheckFunc[ssa.BoundsIndex] = typecheck.LookupRuntimeFunc("goPanicIndex")
|
||||
|
|
|
|||
|
|
@ -332,6 +332,7 @@ func TestStdFixed(t *testing.T) {
|
|||
"issue49814.go", // go/types does not have constraints on array size
|
||||
"issue56103.go", // anonymous interface cycles; will be a type checker error in 1.22
|
||||
"issue52697.go", // types2 does not have constraints on stack size
|
||||
"issue73309.go", // this test requires GODEBUG=gotypesalias=1
|
||||
|
||||
// These tests requires runtime/cgo.Incomplete, which is only available on some platforms.
|
||||
// However, types2 does not know about build constraints.
|
||||
|
|
|
|||
|
|
@ -175,6 +175,11 @@ func dataWord(conv *ir.ConvExpr, init *ir.Nodes) ir.Node {
|
|||
xe := ir.NewIndexExpr(base.Pos, staticuint64s, index)
|
||||
xe.SetBounded(true)
|
||||
value = xe
|
||||
case n.Op() == ir.OLINKSYMOFFSET && n.(*ir.LinksymOffsetExpr).Linksym == ir.Syms.ZeroVal && n.(*ir.LinksymOffsetExpr).Offset_ == 0:
|
||||
// n is using zeroVal, so we can use n directly.
|
||||
// (Note that n does not have a proper pos in this case, so using conv for the diagnostic instead.)
|
||||
diagnose("using global for zero value interface value", conv)
|
||||
value = n
|
||||
case n.Op() == ir.ONAME && n.(*ir.Name).Class == ir.PEXTERN && n.(*ir.Name).Readonly():
|
||||
// n is a readonly global; use it directly.
|
||||
diagnose("using global for interface value", n)
|
||||
|
|
|
|||
|
|
@ -594,8 +594,8 @@ func walkCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
|
|||
|
||||
if n.Op() == ir.OCALLFUNC {
|
||||
fn := ir.StaticCalleeName(n.Fun)
|
||||
if fn != nil && fn.Sym().Pkg.Path == "hash/maphash" && strings.HasPrefix(fn.Sym().Name, "escapeForHash[") {
|
||||
// hash/maphash.escapeForHash[T] is a compiler intrinsic
|
||||
if fn != nil && fn.Sym().Pkg.Path == "internal/abi" && strings.HasPrefix(fn.Sym().Name, "EscapeNonString[") {
|
||||
// internal/abi.EscapeNonString[T] is a compiler intrinsic
|
||||
// for the escape analysis to escape its argument based on
|
||||
// the type. The call itself is no-op. Just walk the
|
||||
// argument.
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ package walk
|
|||
import (
|
||||
"fmt"
|
||||
"go/constant"
|
||||
"internal/abi"
|
||||
"internal/buildcfg"
|
||||
|
||||
"cmd/compile/internal/base"
|
||||
|
|
@ -226,7 +227,8 @@ func (o *orderState) addrTemp(n ir.Node) ir.Node {
|
|||
// for the implicit conversion of "foo" to any, and we can't handle
|
||||
// the relocations in that temp.
|
||||
if n.Op() == ir.ONIL || (n.Op() == ir.OLITERAL && !base.Ctxt.IsFIPS()) {
|
||||
// TODO: expand this to all static composite literal nodes?
|
||||
// This is a basic literal or nil that we can store
|
||||
// directly in the read-only data section.
|
||||
n = typecheck.DefaultLit(n, nil)
|
||||
types.CalcSize(n.Type())
|
||||
vstat := readonlystaticname(n.Type())
|
||||
|
|
@ -239,6 +241,28 @@ func (o *orderState) addrTemp(n ir.Node) ir.Node {
|
|||
return vstat
|
||||
}
|
||||
|
||||
// Check now for a composite literal to possibly store in the read-only data section.
|
||||
v := staticValue(n)
|
||||
if v == nil {
|
||||
v = n
|
||||
}
|
||||
if (v.Op() == ir.OSTRUCTLIT || v.Op() == ir.OARRAYLIT) && !base.Ctxt.IsFIPS() {
|
||||
if ir.IsZero(v) && 0 < v.Type().Size() && v.Type().Size() <= abi.ZeroValSize {
|
||||
// This zero value can be represented by the read-only zeroVal.
|
||||
zeroVal := ir.NewLinksymExpr(v.Pos(), ir.Syms.ZeroVal, v.Type())
|
||||
vstat := typecheck.Expr(zeroVal).(*ir.LinksymOffsetExpr)
|
||||
return vstat
|
||||
}
|
||||
if isStaticCompositeLiteral(v) {
|
||||
// v can be directly represented in the read-only data section.
|
||||
lit := v.(*ir.CompLitExpr)
|
||||
vstat := readonlystaticname(lit.Type())
|
||||
fixedlit(inInitFunction, initKindStatic, lit, vstat, nil) // nil init
|
||||
vstat = typecheck.Expr(vstat).(*ir.Name)
|
||||
return vstat
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent taking the address of an SSA-able local variable (#63332).
|
||||
//
|
||||
// TODO(mdempsky): Note that OuterValue unwraps OCONVNOPs, but
|
||||
|
|
|
|||
|
|
@ -24,6 +24,13 @@ const tmpstringbufsize = 32
|
|||
|
||||
func Walk(fn *ir.Func) {
|
||||
ir.CurFunc = fn
|
||||
|
||||
// Set and then clear a package-level cache of static values for this fn.
|
||||
// (At some point, it might be worthwhile to have a walkState structure
|
||||
// that gets passed everywhere where things like this can go.)
|
||||
staticValues = findStaticValues(fn)
|
||||
defer func() { staticValues = nil }()
|
||||
|
||||
errorsBefore := base.Errors()
|
||||
order(fn)
|
||||
if base.Errors() > errorsBefore {
|
||||
|
|
@ -422,3 +429,43 @@ func ifaceData(pos src.XPos, n ir.Node, t *types.Type) ir.Node {
|
|||
ind.SetBounded(true)
|
||||
return ind
|
||||
}
|
||||
|
||||
// staticValue returns the earliest expression it can find that always
|
||||
// evaluates to n, with similar semantics to [ir.StaticValue].
|
||||
//
|
||||
// It only returns results for the ir.CurFunc being processed in [Walk],
|
||||
// including its closures, and uses a cache to reduce duplicative work.
|
||||
// It can return n or nil if it does not find an earlier expression.
|
||||
//
|
||||
// The current use case is reducing OCONVIFACE allocations, and hence
|
||||
// staticValue is currently only useful when given an *ir.ConvExpr.X as n.
|
||||
func staticValue(n ir.Node) ir.Node {
|
||||
if staticValues == nil {
|
||||
base.Fatalf("staticValues is nil. staticValue called outside of walk.Walk?")
|
||||
}
|
||||
return staticValues[n]
|
||||
}
|
||||
|
||||
// staticValues is a cache of static values for use by staticValue.
|
||||
var staticValues map[ir.Node]ir.Node
|
||||
|
||||
// findStaticValues returns a map of static values for fn.
|
||||
func findStaticValues(fn *ir.Func) map[ir.Node]ir.Node {
|
||||
// We can't use an ir.ReassignOracle or ir.StaticValue in the
|
||||
// middle of walk because they don't currently handle
|
||||
// transformed assignments (e.g., will complain about 'RHS == nil').
|
||||
// So we instead build this map to use in walk.
|
||||
ro := &ir.ReassignOracle{}
|
||||
ro.Init(fn)
|
||||
m := make(map[ir.Node]ir.Node)
|
||||
ir.Visit(fn, func(n ir.Node) {
|
||||
if n.Op() == ir.OCONVIFACE {
|
||||
x := n.(*ir.ConvExpr).X
|
||||
v := ro.StaticValue(x)
|
||||
if v != nil && v != x {
|
||||
m[x] = v
|
||||
}
|
||||
}
|
||||
})
|
||||
return m
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,8 +122,28 @@ func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) {
|
|||
}
|
||||
}
|
||||
if serveHTTP {
|
||||
// We want to run the logic below to determine a match for a symbol, method,
|
||||
// or field, but not actually print the documentation to the output.
|
||||
// Special case: if there are no arguments, try to go to an appropriate page
|
||||
// depending on whether we're in a module or workspace. The pkgsite homepage
|
||||
// is often not the most useful page.
|
||||
if len(flagSet.Args()) == 0 {
|
||||
mod, err := runCmd(append(os.Environ(), "GOWORK=off"), "go", "list", "-m")
|
||||
if err == nil && mod != "" && mod != "command-line-arguments" {
|
||||
// If there's a module, go to the module's doc page.
|
||||
return doPkgsite(mod)
|
||||
}
|
||||
gowork, err := runCmd(nil, "go", "env", "GOWORK")
|
||||
if err == nil && gowork != "" {
|
||||
// Outside a module, but in a workspace, go to the home page
|
||||
// with links to each of the modules' pages.
|
||||
return doPkgsite("")
|
||||
}
|
||||
// Outside a module or workspace, go to the documentation for the standard library.
|
||||
return doPkgsite("std")
|
||||
}
|
||||
|
||||
// If args are provided, we need to figure out which page to open on the pkgsite
|
||||
// instance. Run the logic below to determine a match for a symbol, method,
|
||||
// or field, but don't actually print the documentation to the output.
|
||||
writer = io.Discard
|
||||
}
|
||||
var paths []string
|
||||
|
|
@ -179,44 +199,42 @@ func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) {
|
|||
}
|
||||
if found {
|
||||
if serveHTTP {
|
||||
return doPkgsite(userPath, pkg, symbol, method)
|
||||
path, err := objectPath(userPath, pkg, symbol, method)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return doPkgsite(path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func listUserPath(userPath string) (string, error) {
|
||||
func runCmd(env []string, cmdline ...string) (string, error) {
|
||||
var stdout, stderr strings.Builder
|
||||
cmd := exec.Command("go", "list", userPath)
|
||||
cmd := exec.Command(cmdline[0], cmdline[1:]...)
|
||||
cmd.Env = env
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return "", fmt.Errorf("go doc: go list %s: %v\n%s\n", userPath, err, stderr.String())
|
||||
return "", fmt.Errorf("go doc: %s: %v\n%s\n", strings.Join(cmdline, " "), err, stderr.String())
|
||||
}
|
||||
return strings.TrimSpace(stdout.String()), nil
|
||||
}
|
||||
|
||||
func doPkgsite(userPath string, pkg *Package, symbol, method string) error {
|
||||
port, err := pickUnusedPort()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find port for documentation server: %v", err)
|
||||
}
|
||||
addr := fmt.Sprintf("localhost:%d", port)
|
||||
|
||||
// Assemble url to open on the browser, to point to documentation of
|
||||
// the requested object.
|
||||
importPath := pkg.build.ImportPath
|
||||
if importPath == "." {
|
||||
func objectPath(userPath string, pkg *Package, symbol, method string) (string, error) {
|
||||
var err error
|
||||
path := pkg.build.ImportPath
|
||||
if path == "." {
|
||||
// go/build couldn't determine the import path, probably
|
||||
// because this was a relative path into a module. Use
|
||||
// go list to get the import path.
|
||||
importPath, err = listUserPath(userPath)
|
||||
path, err = runCmd(nil, "go", "list", userPath)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
path := path.Join("http://"+addr, importPath)
|
||||
|
||||
object := symbol
|
||||
if symbol != "" && method != "" {
|
||||
object = symbol + "." + method
|
||||
|
|
@ -224,17 +242,38 @@ func doPkgsite(userPath string, pkg *Package, symbol, method string) error {
|
|||
if object != "" {
|
||||
path = path + "#" + object
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func doPkgsite(urlPath string) error {
|
||||
port, err := pickUnusedPort()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find port for documentation server: %v", err)
|
||||
}
|
||||
addr := fmt.Sprintf("localhost:%d", port)
|
||||
path := path.Join("http://"+addr, urlPath)
|
||||
|
||||
// Turn off the default signal handler for SIGINT (and SIGQUIT on Unix)
|
||||
// and instead wait for the child process to handle the signal and
|
||||
// exit before exiting ourselves.
|
||||
signal.Ignore(signalsToIgnore...)
|
||||
|
||||
// Prepend the local download cache to GOPROXY to get around deprecation checks.
|
||||
env := os.Environ()
|
||||
vars, err := runCmd(nil, "go", "env", "GOPROXY", "GOMODCACHE")
|
||||
fields := strings.Fields(vars)
|
||||
if err == nil && len(fields) == 2 {
|
||||
goproxy, gomodcache := fields[0], fields[1]
|
||||
goproxy = "file://" + filepath.Join(gomodcache, "cache", "download") + "," + goproxy
|
||||
env = append(env, "GOPROXY="+goproxy)
|
||||
}
|
||||
|
||||
const version = "v0.0.0-20250520201116-40659211760d"
|
||||
cmd := exec.Command("go", "run", "golang.org/x/pkgsite/cmd/internal/doc@"+version,
|
||||
"-gorepo", buildCtx.GOROOT,
|
||||
"-http", addr,
|
||||
"-open", path)
|
||||
cmd.Env = env
|
||||
cmd.Stdout = os.Stderr
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
|
|
|
|||
|
|
@ -191,20 +191,28 @@ func GetExitStatus() int {
|
|||
// connected to the go command's own stdout and stderr.
|
||||
// If the command fails, Run reports the error using Errorf.
|
||||
func Run(cmdargs ...any) {
|
||||
if err := RunErr(cmdargs...); err != nil {
|
||||
Errorf("%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Run runs the command, with stdout and stderr
|
||||
// connected to the go command's own stdout and stderr.
|
||||
// If the command fails, RunErr returns the error, which
|
||||
// may be an *exec.ExitError.
|
||||
func RunErr(cmdargs ...any) error {
|
||||
cmdline := str.StringList(cmdargs...)
|
||||
if cfg.BuildN || cfg.BuildX {
|
||||
fmt.Printf("%s\n", strings.Join(cmdline, " "))
|
||||
if cfg.BuildN {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
cmd := exec.Command(cmdline[0], cmdline[1:]...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
Errorf("%v", err)
|
||||
}
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
// RunStdin is like run but connects Stdin. It retries if it encounters an ETXTBSY.
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ import (
|
|||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cfg"
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
|
|
@ -131,5 +134,13 @@ Flags:
|
|||
}
|
||||
|
||||
func runDoc(ctx context.Context, cmd *base.Command, args []string) {
|
||||
base.Run(cfg.BuildToolexec, filepath.Join(cfg.GOROOTbin, "go"), "tool", "doc", args)
|
||||
base.StartSigHandlers()
|
||||
err := base.RunErr(cfg.BuildToolexec, filepath.Join(cfg.GOROOTbin, "go"), "tool", "doc", args)
|
||||
if err != nil {
|
||||
var ee *exec.ExitError
|
||||
if errors.As(err, &ee) {
|
||||
os.Exit(ee.ExitCode())
|
||||
}
|
||||
base.Error(err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -225,8 +225,6 @@ const (
|
|||
REGZERO = REG_R0 // set to zero
|
||||
REGLINK = REG_R1
|
||||
REGSP = REG_R3
|
||||
REGRET = REG_R20 // not use
|
||||
REGARG = -1 // -1 disables passing the first argument in register
|
||||
REGRT1 = REG_R20 // reserved for runtime, duffzero and duffcopy
|
||||
REGRT2 = REG_R21 // reserved for runtime, duffcopy
|
||||
REGCTXT = REG_R29 // context for closures
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ var runtimePkgs = []string{
|
|||
"runtime",
|
||||
|
||||
"internal/runtime/atomic",
|
||||
"internal/runtime/cgroup",
|
||||
"internal/runtime/exithook",
|
||||
"internal/runtime/gc",
|
||||
"internal/runtime/maps",
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ type event struct {
|
|||
Elapsed *float64 `json:",omitempty"`
|
||||
Output *textBytes `json:",omitempty"`
|
||||
FailedBuild string `json:",omitempty"`
|
||||
Key string `json:",omitempty"`
|
||||
Value string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// textBytes is a hack to get JSON to emit a []byte as a string
|
||||
|
|
@ -177,6 +179,7 @@ var (
|
|||
[]byte("=== PASS "),
|
||||
[]byte("=== FAIL "),
|
||||
[]byte("=== SKIP "),
|
||||
[]byte("=== ATTR "),
|
||||
}
|
||||
|
||||
reports = [][]byte{
|
||||
|
|
@ -333,6 +336,11 @@ func (c *Converter) handleInputLine(line []byte) {
|
|||
c.output.write(origLine)
|
||||
return
|
||||
}
|
||||
if action == "attr" {
|
||||
var rest string
|
||||
name, rest, _ = strings.Cut(name, " ")
|
||||
e.Key, e.Value, _ = strings.Cut(rest, " ")
|
||||
}
|
||||
// === update.
|
||||
// Finish any pending PASS/FAIL reports.
|
||||
c.needMarker = sawMarker
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
{"Action":"start"}
|
||||
{"Action":"run","Test":"TestAttr"}
|
||||
{"Action":"output","Test":"TestAttr","Output":"=== RUN TestAttr\n"}
|
||||
{"Action":"attr","Test":"TestAttr","Key":"key","Value":"value"}
|
||||
{"Action":"output","Test":"TestAttr","Output":"=== ATTR TestAttr key value\n"}
|
||||
{"Action":"run","Test":"TestAttr/sub"}
|
||||
{"Action":"output","Test":"TestAttr/sub","Output":"=== RUN TestAttr/sub\n"}
|
||||
{"Action":"attr","Test":"TestAttr/sub","Key":"key","Value":"value"}
|
||||
{"Action":"output","Test":"TestAttr/sub","Output":"=== ATTR TestAttr/sub key value\n"}
|
||||
{"Action":"output","Test":"TestAttr","Output":"--- PASS: TestAttr (0.00s)\n"}
|
||||
{"Action":"output","Test":"TestAttr/sub","Output":" --- PASS: TestAttr/sub (0.00s)\n"}
|
||||
{"Action":"pass","Test":"TestAttr/sub"}
|
||||
{"Action":"pass","Test":"TestAttr"}
|
||||
{"Action":"output","Output":"PASS\n"}
|
||||
{"Action":"pass"}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
=== RUN TestAttr
|
||||
=== ATTR TestAttr key value
|
||||
=== RUN TestAttr/sub
|
||||
=== ATTR TestAttr/sub key value
|
||||
--- PASS: TestAttr (0.00s)
|
||||
--- PASS: TestAttr/sub (0.00s)
|
||||
PASS
|
||||
|
|
@ -430,8 +430,10 @@ func (ctxt *Link) domacho() {
|
|||
// This must be fairly recent for Apple signing (go.dev/issue/30488).
|
||||
// Having too old a version here was also implicated in some problems
|
||||
// calling into macOS libraries (go.dev/issue/56784).
|
||||
// In general this can be the most recent supported macOS version.
|
||||
version = 11<<16 | 0<<8 | 0<<0 // 11.0.0
|
||||
// CL 460476 noted that in general this can be the most recent supported
|
||||
// macOS version, but we haven't tested if going higher than Go's oldest
|
||||
// supported macOS version could cause new problems.
|
||||
version = 12<<16 | 0<<8 | 0<<0 // 12.0.0
|
||||
}
|
||||
ml := newMachoLoad(ctxt.Arch, imacho.LC_BUILD_VERSION, 4)
|
||||
ml.data[0] = uint32(machoPlatform)
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ func TestIssue33979(t *testing.T) {
|
|||
testenv.MustHaveCGO(t)
|
||||
// N.B. go build below explictly doesn't pass through
|
||||
// -asan/-msan/-race, so we don't care about those.
|
||||
testenv.MustInternalLink(t, testenv.NoSpecialBuildTypes)
|
||||
testenv.MustInternalLink(t, testenv.SpecialBuildTypes{Cgo: true})
|
||||
|
||||
t.Parallel()
|
||||
|
||||
|
|
@ -397,8 +397,8 @@ func TestMachOBuildVersion(t *testing.T) {
|
|||
found := false
|
||||
checkMin := func(ver uint32) {
|
||||
major, minor, patch := (ver>>16)&0xff, (ver>>8)&0xff, (ver>>0)&0xff
|
||||
if major < 11 {
|
||||
t.Errorf("LC_BUILD_VERSION version %d.%d.%d < 11.0.0", major, minor, patch)
|
||||
if major < 12 {
|
||||
t.Errorf("LC_BUILD_VERSION version %d.%d.%d < 12.0.0", major, minor, patch)
|
||||
}
|
||||
}
|
||||
for _, cmd := range exem.Loads {
|
||||
|
|
|
|||
|
|
@ -5,13 +5,19 @@
|
|||
package crypto_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
|
@ -88,3 +94,50 @@ UjmopwKBgAqB2KYYMUqAOvYcBnEfLDmyZv9BTVNHbR2lKkMYqv5LlvDaBxVfilE0
|
|||
t.Errorf("VerifyPSS failed for MessageSigner signature: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisallowedAssemblyInstructions(t *testing.T) {
|
||||
// This test enforces the cryptography assembly policy rule that we do not
|
||||
// use BYTE or WORD instructions, since these instructions can obscure what
|
||||
// the assembly is actually doing. If we do not support specific
|
||||
// instructions in the assembler, we should not be using them until we do.
|
||||
//
|
||||
// Instead of using the output of the 'go tool asm' tool, we take the simple
|
||||
// approach and just search the text of .s files for usage of BYTE and WORD.
|
||||
// We do this because the assembler itself will sometimes insert WORD
|
||||
// instructions for things like function preambles etc.
|
||||
|
||||
boringSigPath := filepath.Join("internal", "boring", "sig")
|
||||
|
||||
matcher, err := regexp.Compile(`(^|;)\s(BYTE|WORD)\s`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := filepath.WalkDir(filepath.Join(testenv.GOROOT(t), "src/crypto"), func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if d.IsDir() || !strings.HasSuffix(path, ".s") {
|
||||
return nil
|
||||
}
|
||||
if strings.Contains(path, boringSigPath) {
|
||||
return nil
|
||||
}
|
||||
|
||||
f, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
i := 1
|
||||
for line := range bytes.Lines(f) {
|
||||
if matcher.Match(line) {
|
||||
t.Errorf("%s:%d assembly contains BYTE or WORD instruction (%q)", path, i, string(line))
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"crypto/internal/boring"
|
||||
"crypto/internal/boring/bbig"
|
||||
"crypto/internal/fips140/ecdsa"
|
||||
"crypto/internal/fips140/nistec"
|
||||
"crypto/internal/fips140cache"
|
||||
"crypto/internal/fips140hash"
|
||||
"crypto/internal/fips140only"
|
||||
|
|
@ -40,6 +41,18 @@ import (
|
|||
// PublicKey represents an ECDSA public key.
|
||||
type PublicKey struct {
|
||||
elliptic.Curve
|
||||
|
||||
// X, Y are the coordinates of the public key point.
|
||||
//
|
||||
// Modifying the raw coordinates can produce invalid keys, and may
|
||||
// invalidate internal optimizations; moreover, [big.Int] methods are not
|
||||
// suitable for operating on cryptographic values. To encode and decode
|
||||
// PublicKey values, use [PublicKey.Bytes] and [ParseUncompressedPublicKey]
|
||||
// or [x509.MarshalPKIXPublicKey] and [x509.ParsePKIXPublicKey]. For ECDH,
|
||||
// use [crypto/ecdh]. For lower-level elliptic curve operations, use a
|
||||
// third-party module like filippo.io/nistec.
|
||||
//
|
||||
// These fields will be deprecated in Go 1.26.
|
||||
X, Y *big.Int
|
||||
}
|
||||
|
||||
|
|
@ -78,9 +91,94 @@ func (pub *PublicKey) Equal(x crypto.PublicKey) bool {
|
|||
pub.Curve == xx.Curve
|
||||
}
|
||||
|
||||
// ParseUncompressedPublicKey parses a public key encoded as an uncompressed
|
||||
// point according to SEC 1, Version 2.0, Section 2.3.3 (also known as the X9.62
|
||||
// uncompressed format). It returns an error if the point is not in uncompressed
|
||||
// form, is not on the curve, or is the point at infinity.
|
||||
//
|
||||
// curve must be one of [elliptic.P224], [elliptic.P256], [elliptic.P384], or
|
||||
// [elliptic.P521], or ParseUncompressedPublicKey returns an error.
|
||||
//
|
||||
// ParseUncompressedPublicKey accepts the same format as
|
||||
// [ecdh.Curve.NewPublicKey] does for NIST curves, but returns a [PublicKey]
|
||||
// instead of an [ecdh.PublicKey].
|
||||
//
|
||||
// Note that public keys are more commonly encoded in DER (or PEM) format, which
|
||||
// can be parsed with [x509.ParsePKIXPublicKey] (and [encoding/pem]).
|
||||
func ParseUncompressedPublicKey(curve elliptic.Curve, data []byte) (*PublicKey, error) {
|
||||
if len(data) < 1 || data[0] != 4 {
|
||||
return nil, errors.New("ecdsa: invalid uncompressed public key")
|
||||
}
|
||||
switch curve {
|
||||
case elliptic.P224():
|
||||
return parseUncompressedPublicKey(ecdsa.P224(), curve, data)
|
||||
case elliptic.P256():
|
||||
return parseUncompressedPublicKey(ecdsa.P256(), curve, data)
|
||||
case elliptic.P384():
|
||||
return parseUncompressedPublicKey(ecdsa.P384(), curve, data)
|
||||
case elliptic.P521():
|
||||
return parseUncompressedPublicKey(ecdsa.P521(), curve, data)
|
||||
default:
|
||||
return nil, errors.New("ecdsa: curve not supported by ParseUncompressedPublicKey")
|
||||
}
|
||||
}
|
||||
|
||||
func parseUncompressedPublicKey[P ecdsa.Point[P]](c *ecdsa.Curve[P], curve elliptic.Curve, data []byte) (*PublicKey, error) {
|
||||
k, err := ecdsa.NewPublicKey(c, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return publicKeyFromFIPS(curve, k)
|
||||
}
|
||||
|
||||
// Bytes encodes the public key as an uncompressed point according to SEC 1,
|
||||
// Version 2.0, Section 2.3.3 (also known as the X9.62 uncompressed format).
|
||||
// It returns an error if the public key is invalid.
|
||||
//
|
||||
// PublicKey.Curve must be one of [elliptic.P224], [elliptic.P256],
|
||||
// [elliptic.P384], or [elliptic.P521], or Bytes returns an error.
|
||||
//
|
||||
// Bytes returns the same format as [ecdh.PublicKey.Bytes] does for NIST curves.
|
||||
//
|
||||
// Note that public keys are more commonly encoded in DER (or PEM) format, which
|
||||
// can be generated with [x509.MarshalPKIXPublicKey] (and [encoding/pem]).
|
||||
func (pub *PublicKey) Bytes() ([]byte, error) {
|
||||
switch pub.Curve {
|
||||
case elliptic.P224():
|
||||
return publicKeyBytes(ecdsa.P224(), pub)
|
||||
case elliptic.P256():
|
||||
return publicKeyBytes(ecdsa.P256(), pub)
|
||||
case elliptic.P384():
|
||||
return publicKeyBytes(ecdsa.P384(), pub)
|
||||
case elliptic.P521():
|
||||
return publicKeyBytes(ecdsa.P521(), pub)
|
||||
default:
|
||||
return nil, errors.New("ecdsa: curve not supported by PublicKey.Bytes")
|
||||
}
|
||||
}
|
||||
|
||||
func publicKeyBytes[P ecdsa.Point[P]](c *ecdsa.Curve[P], pub *PublicKey) ([]byte, error) {
|
||||
k, err := publicKeyToFIPS(c, pub)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return k.Bytes(), nil
|
||||
}
|
||||
|
||||
// PrivateKey represents an ECDSA private key.
|
||||
type PrivateKey struct {
|
||||
PublicKey
|
||||
|
||||
// D is the private scalar value.
|
||||
//
|
||||
// Modifying the raw value can produce invalid keys, and may
|
||||
// invalidate internal optimizations; moreover, [big.Int] methods are not
|
||||
// suitable for operating on cryptographic values. To encode and decode
|
||||
// PrivateKey values, use [PrivateKey.Bytes] and [ParseRawPrivateKey]
|
||||
// or [x509.MarshalPKCS8PrivateKey] and [x509.ParsePKCS8PrivateKey].
|
||||
// For ECDH, use [crypto/ecdh].
|
||||
//
|
||||
// This field will be deprecated in Go 1.26.
|
||||
D *big.Int
|
||||
}
|
||||
|
||||
|
|
@ -134,6 +232,82 @@ func bigIntEqual(a, b *big.Int) bool {
|
|||
return subtle.ConstantTimeCompare(a.Bytes(), b.Bytes()) == 1
|
||||
}
|
||||
|
||||
// ParseRawPrivateKey parses a private key encoded as a fixed-length big-endian
|
||||
// integer, according to SEC 1, Version 2.0, Section 2.3.6 (sometimes referred
|
||||
// to as the raw format). It returns an error if the value is not reduced modulo
|
||||
// the curve's order, or if it's zero.
|
||||
//
|
||||
// curve must be one of [elliptic.P224], [elliptic.P256], [elliptic.P384], or
|
||||
// [elliptic.P521], or ParseRawPrivateKey returns an error.
|
||||
//
|
||||
// ParseRawPrivateKey accepts the same format as [ecdh.Curve.NewPrivateKey] does
|
||||
// for NIST curves, but returns a [PrivateKey] instead of an [ecdh.PrivateKey].
|
||||
//
|
||||
// Note that private keys are more commonly encoded in ASN.1 or PKCS#8 format,
|
||||
// which can be parsed with [x509.ParseECPrivateKey] or
|
||||
// [x509.ParsePKCS8PrivateKey] (and [encoding/pem]).
|
||||
func ParseRawPrivateKey(curve elliptic.Curve, data []byte) (*PrivateKey, error) {
|
||||
switch curve {
|
||||
case elliptic.P224():
|
||||
return parseRawPrivateKey(ecdsa.P224(), nistec.NewP224Point, curve, data)
|
||||
case elliptic.P256():
|
||||
return parseRawPrivateKey(ecdsa.P256(), nistec.NewP256Point, curve, data)
|
||||
case elliptic.P384():
|
||||
return parseRawPrivateKey(ecdsa.P384(), nistec.NewP384Point, curve, data)
|
||||
case elliptic.P521():
|
||||
return parseRawPrivateKey(ecdsa.P521(), nistec.NewP521Point, curve, data)
|
||||
default:
|
||||
return nil, errors.New("ecdsa: curve not supported by ParseRawPrivateKey")
|
||||
}
|
||||
}
|
||||
|
||||
func parseRawPrivateKey[P ecdsa.Point[P]](c *ecdsa.Curve[P], newPoint func() P, curve elliptic.Curve, data []byte) (*PrivateKey, error) {
|
||||
q, err := newPoint().ScalarBaseMult(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
k, err := ecdsa.NewPrivateKey(c, data, q.Bytes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return privateKeyFromFIPS(curve, k)
|
||||
}
|
||||
|
||||
// Bytes encodes the private key as a fixed-length big-endian integer according
|
||||
// to SEC 1, Version 2.0, Section 2.3.6 (sometimes referred to as the raw
|
||||
// format). It returns an error if the private key is invalid.
|
||||
//
|
||||
// PrivateKey.Curve must be one of [elliptic.P224], [elliptic.P256],
|
||||
// [elliptic.P384], or [elliptic.P521], or Bytes returns an error.
|
||||
//
|
||||
// Bytes returns the same format as [ecdh.PrivateKey.Bytes] does for NIST curves.
|
||||
//
|
||||
// Note that private keys are more commonly encoded in ASN.1 or PKCS#8 format,
|
||||
// which can be generated with [x509.MarshalECPrivateKey] or
|
||||
// [x509.MarshalPKCS8PrivateKey] (and [encoding/pem]).
|
||||
func (priv *PrivateKey) Bytes() ([]byte, error) {
|
||||
switch priv.Curve {
|
||||
case elliptic.P224():
|
||||
return privateKeyBytes(ecdsa.P224(), priv)
|
||||
case elliptic.P256():
|
||||
return privateKeyBytes(ecdsa.P256(), priv)
|
||||
case elliptic.P384():
|
||||
return privateKeyBytes(ecdsa.P384(), priv)
|
||||
case elliptic.P521():
|
||||
return privateKeyBytes(ecdsa.P521(), priv)
|
||||
default:
|
||||
return nil, errors.New("ecdsa: curve not supported by PrivateKey.Bytes")
|
||||
}
|
||||
}
|
||||
|
||||
func privateKeyBytes[P ecdsa.Point[P]](c *ecdsa.Curve[P], priv *PrivateKey) ([]byte, error) {
|
||||
k, err := privateKeyToFIPS(c, priv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return k.Bytes(), nil
|
||||
}
|
||||
|
||||
// Sign signs a hash (which should be the result of hashing a larger message
|
||||
// with opts.HashFunc()) using the private key, priv. If the hash is longer than
|
||||
// the bit-length of the private key's curve order, the hash will be truncated
|
||||
|
|
|
|||
|
|
@ -546,6 +546,161 @@ func testRFC6979(t *testing.T, curve elliptic.Curve, D, X, Y, msg, r, s string)
|
|||
}
|
||||
}
|
||||
|
||||
func TestParseAndBytesRoundTrip(t *testing.T) {
|
||||
testAllCurves(t, testParseAndBytesRoundTrip)
|
||||
}
|
||||
|
||||
func testParseAndBytesRoundTrip(t *testing.T, curve elliptic.Curve) {
|
||||
if strings.HasSuffix(t.Name(), "/Generic") {
|
||||
t.Skip("these methods don't support generic curves")
|
||||
}
|
||||
priv, _ := GenerateKey(curve, rand.Reader)
|
||||
|
||||
b, err := priv.PublicKey.Bytes()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to serialize private key's public key: %v", err)
|
||||
}
|
||||
if b[0] != 4 {
|
||||
t.Fatalf("public key bytes doesn't start with 0x04 (uncompressed format)")
|
||||
}
|
||||
p, err := ParseUncompressedPublicKey(curve, b)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse private key's public key: %v", err)
|
||||
}
|
||||
if !priv.PublicKey.Equal(p) {
|
||||
t.Errorf("parsed private key's public key doesn't match original")
|
||||
}
|
||||
|
||||
bk, err := priv.Bytes()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to serialize private key: %v", err)
|
||||
}
|
||||
k, err := ParseRawPrivateKey(curve, bk)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse private key: %v", err)
|
||||
}
|
||||
if !priv.Equal(k) {
|
||||
t.Errorf("parsed private key doesn't match original")
|
||||
}
|
||||
|
||||
if curve != elliptic.P224() {
|
||||
privECDH, err := priv.ECDH()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to convert private key to ECDH: %v", err)
|
||||
}
|
||||
|
||||
pp, err := privECDH.Curve().NewPublicKey(b)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse with ECDH: %v", err)
|
||||
}
|
||||
if !privECDH.PublicKey().Equal(pp) {
|
||||
t.Errorf("parsed ECDH public key doesn't match original")
|
||||
}
|
||||
if !bytes.Equal(b, pp.Bytes()) {
|
||||
t.Errorf("encoded ECDH public key doesn't match Bytes")
|
||||
}
|
||||
|
||||
kk, err := privECDH.Curve().NewPrivateKey(bk)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse with ECDH: %v", err)
|
||||
}
|
||||
if !privECDH.Equal(kk) {
|
||||
t.Errorf("parsed ECDH private key doesn't match original")
|
||||
}
|
||||
if !bytes.Equal(bk, kk.Bytes()) {
|
||||
t.Errorf("encoded ECDH private key doesn't match Bytes")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidPublicKeys(t *testing.T) {
|
||||
testAllCurves(t, testInvalidPublicKeys)
|
||||
}
|
||||
|
||||
func testInvalidPublicKeys(t *testing.T, curve elliptic.Curve) {
|
||||
t.Run("Infinity", func(t *testing.T) {
|
||||
k := &PublicKey{Curve: curve, X: big.NewInt(0), Y: big.NewInt(0)}
|
||||
if _, err := k.Bytes(); err == nil {
|
||||
t.Errorf("PublicKey.Bytes accepted infinity")
|
||||
}
|
||||
|
||||
b := []byte{0}
|
||||
if _, err := ParseUncompressedPublicKey(curve, b); err == nil {
|
||||
t.Errorf("ParseUncompressedPublicKey accepted infinity")
|
||||
}
|
||||
b = make([]byte, 1+2*(curve.Params().BitSize+7)/8)
|
||||
b[0] = 4
|
||||
if _, err := ParseUncompressedPublicKey(curve, b); err == nil {
|
||||
t.Errorf("ParseUncompressedPublicKey accepted infinity")
|
||||
}
|
||||
})
|
||||
t.Run("NotOnCurve", func(t *testing.T) {
|
||||
k, _ := GenerateKey(curve, rand.Reader)
|
||||
k.X = k.X.Add(k.X, big.NewInt(1))
|
||||
if _, err := k.Bytes(); err == nil {
|
||||
t.Errorf("PublicKey.Bytes accepted not on curve")
|
||||
}
|
||||
|
||||
b := make([]byte, 1+2*(curve.Params().BitSize+7)/8)
|
||||
b[0] = 4
|
||||
k.X.FillBytes(b[1 : 1+len(b)/2])
|
||||
k.Y.FillBytes(b[1+len(b)/2:])
|
||||
if _, err := ParseUncompressedPublicKey(curve, b); err == nil {
|
||||
t.Errorf("ParseUncompressedPublicKey accepted not on curve")
|
||||
}
|
||||
})
|
||||
t.Run("Compressed", func(t *testing.T) {
|
||||
k, _ := GenerateKey(curve, rand.Reader)
|
||||
b := elliptic.MarshalCompressed(curve, k.X, k.Y)
|
||||
if _, err := ParseUncompressedPublicKey(curve, b); err == nil {
|
||||
t.Errorf("ParseUncompressedPublicKey accepted compressed key")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestInvalidPrivateKeys(t *testing.T) {
|
||||
testAllCurves(t, testInvalidPrivateKeys)
|
||||
}
|
||||
|
||||
func testInvalidPrivateKeys(t *testing.T, curve elliptic.Curve) {
|
||||
t.Run("Zero", func(t *testing.T) {
|
||||
k := &PrivateKey{PublicKey{curve, big.NewInt(0), big.NewInt(0)}, big.NewInt(0)}
|
||||
if _, err := k.Bytes(); err == nil {
|
||||
t.Errorf("PrivateKey.Bytes accepted zero key")
|
||||
}
|
||||
|
||||
b := make([]byte, (curve.Params().BitSize+7)/8)
|
||||
if _, err := ParseRawPrivateKey(curve, b); err == nil {
|
||||
t.Errorf("ParseRawPrivateKey accepted zero key")
|
||||
}
|
||||
})
|
||||
t.Run("Overflow", func(t *testing.T) {
|
||||
d := new(big.Int).Add(curve.Params().N, big.NewInt(5))
|
||||
x, y := curve.ScalarBaseMult(d.Bytes())
|
||||
k := &PrivateKey{PublicKey{curve, x, y}, d}
|
||||
if _, err := k.Bytes(); err == nil {
|
||||
t.Errorf("PrivateKey.Bytes accepted overflow key")
|
||||
}
|
||||
|
||||
b := make([]byte, (curve.Params().BitSize+7)/8)
|
||||
k.D.FillBytes(b)
|
||||
if _, err := ParseRawPrivateKey(curve, b); err == nil {
|
||||
t.Errorf("ParseRawPrivateKey accepted overflow key")
|
||||
}
|
||||
})
|
||||
t.Run("Length", func(t *testing.T) {
|
||||
b := []byte{1, 2, 3}
|
||||
if _, err := ParseRawPrivateKey(curve, b); err == nil {
|
||||
t.Errorf("ParseRawPrivateKey accepted short key")
|
||||
}
|
||||
|
||||
b = append(b, make([]byte, (curve.Params().BitSize+7)/8)...)
|
||||
if _, err := ParseRawPrivateKey(curve, b); err == nil {
|
||||
t.Errorf("ParseRawPrivateKey accepted long key")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func benchmarkAllCurves(b *testing.B, f func(*testing.B, elliptic.Curve)) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
|
|
|||
|
|
@ -7,11 +7,8 @@ package fips140
|
|||
import (
|
||||
"crypto/internal/fips140"
|
||||
"crypto/internal/fips140/check"
|
||||
"internal/godebug"
|
||||
)
|
||||
|
||||
var fips140GODEBUG = godebug.New("fips140")
|
||||
|
||||
// Enabled reports whether the cryptography libraries are operating in FIPS
|
||||
// 140-3 mode.
|
||||
//
|
||||
|
|
@ -21,11 +18,6 @@ var fips140GODEBUG = godebug.New("fips140")
|
|||
//
|
||||
// This can't be changed after the program has started.
|
||||
func Enabled() bool {
|
||||
godebug := fips140GODEBUG.Value()
|
||||
currentlyEnabled := godebug == "on" || godebug == "only" || godebug == "debug"
|
||||
if currentlyEnabled != fips140.Enabled {
|
||||
panic("crypto/fips140: GODEBUG setting changed after program start")
|
||||
}
|
||||
if fips140.Enabled && !check.Verified {
|
||||
panic("crypto/fips140: FIPS 140-3 mode enabled, but integrity check didn't pass")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package fips140
|
||||
|
||||
import (
|
||||
"internal/godebug"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestImmutableGODEBUG(t *testing.T) {
|
||||
defer func(v string) { os.Setenv("GODEBUG", v) }(os.Getenv("GODEBUG"))
|
||||
|
||||
fips140Enabled := Enabled()
|
||||
fips140Setting := godebug.New("fips140")
|
||||
fips140SettingValue := fips140Setting.Value()
|
||||
|
||||
os.Setenv("GODEBUG", "fips140=off")
|
||||
if Enabled() != fips140Enabled {
|
||||
t.Errorf("Enabled() changed after setting GODEBUG=fips140=off")
|
||||
}
|
||||
if fips140Setting.Value() != fips140SettingValue {
|
||||
t.Errorf("fips140Setting.Value() changed after setting GODEBUG=fips140=off")
|
||||
}
|
||||
|
||||
os.Setenv("GODEBUG", "fips140=on")
|
||||
if Enabled() != fips140Enabled {
|
||||
t.Errorf("Enabled() changed after setting GODEBUG=fips140=on")
|
||||
}
|
||||
if fips140Setting.Value() != fips140SettingValue {
|
||||
t.Errorf("fips140Setting.Value() changed after setting GODEBUG=fips140=on")
|
||||
}
|
||||
|
||||
os.Setenv("GODEBUG", "fips140=")
|
||||
if Enabled() != fips140Enabled {
|
||||
t.Errorf("Enabled() changed after setting GODEBUG=fips140=")
|
||||
}
|
||||
if fips140Setting.Value() != fips140SettingValue {
|
||||
t.Errorf("fips140Setting.Value() changed after setting GODEBUG=fips140=")
|
||||
}
|
||||
|
||||
os.Setenv("GODEBUG", "")
|
||||
if Enabled() != fips140Enabled {
|
||||
t.Errorf("Enabled() changed after setting GODEBUG=")
|
||||
}
|
||||
if fips140Setting.Value() != fips140SettingValue {
|
||||
t.Errorf("fips140Setting.Value() changed after setting GODEBUG=")
|
||||
}
|
||||
}
|
||||
|
|
@ -632,6 +632,18 @@ func TestHMACHash(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestExtraMethods(t *testing.T) {
|
||||
h := New(sha256.New, []byte("key"))
|
||||
cryptotest.NoExtraMethods(t, maybeCloner(h))
|
||||
}
|
||||
|
||||
func maybeCloner(h hash.Hash) any {
|
||||
if c, ok := h.(hash.Cloner); ok {
|
||||
return &c
|
||||
}
|
||||
return &h
|
||||
}
|
||||
|
||||
func BenchmarkHMACSHA256_1K(b *testing.B) {
|
||||
key := make([]byte, 32)
|
||||
buf := make([]byte, 1024)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
package cryptotest
|
||||
|
||||
import (
|
||||
"crypto/internal/boring"
|
||||
"crypto/internal/fips140"
|
||||
"hash"
|
||||
"internal/testhash"
|
||||
"io"
|
||||
|
|
@ -18,6 +20,10 @@ type MakeHash func() hash.Hash
|
|||
// TestHash performs a set of tests on hash.Hash implementations, checking the
|
||||
// documented requirements of Write, Sum, Reset, Size, and BlockSize.
|
||||
func TestHash(t *testing.T, mh MakeHash) {
|
||||
if boring.Enabled || fips140.Version() == "v1.0" {
|
||||
testhash.TestHashWithoutClone(t, testhash.MakeHash(mh))
|
||||
return
|
||||
}
|
||||
testhash.TestHash(t, testhash.MakeHash(mh))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ package cryptotest
|
|||
import (
|
||||
"crypto/internal/boring"
|
||||
"crypto/internal/impl"
|
||||
"internal/goarch"
|
||||
"internal/goos"
|
||||
"internal/testenv"
|
||||
"testing"
|
||||
|
|
@ -35,15 +36,14 @@ func TestAllImplementations(t *testing.T, pkg string, f func(t *testing.T)) {
|
|||
t.Run(name, f)
|
||||
} else {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
// Report an error if we're on Linux CI (assumed to be the most
|
||||
// consistent) and the builder can't test this implementation.
|
||||
if testenv.Builder() != "" && goos.GOOS == "linux" {
|
||||
// Report an error if we're on the most capable builder for the
|
||||
// architecture and the builder can't test this implementation.
|
||||
flagship := goos.GOOS == "linux" && goarch.GOARCH != "arm64" ||
|
||||
goos.GOOS == "darwin" && goarch.GOARCH == "arm64"
|
||||
if testenv.Builder() != "" && flagship {
|
||||
if name == "SHA-NI" {
|
||||
t.Skip("known issue, see golang.org/issue/69592")
|
||||
}
|
||||
if name == "Armv8.2" {
|
||||
t.Skip("known issue, see golang.org/issue/69593")
|
||||
}
|
||||
t.Error("builder doesn't support CPU features needed to test this implementation")
|
||||
} else {
|
||||
t.Skip("implementation not supported")
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import (
|
|||
"crypto/internal/fips140/drbg"
|
||||
"crypto/internal/fips140/nistec"
|
||||
"errors"
|
||||
"hash"
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
|
@ -271,7 +272,7 @@ type Signature struct {
|
|||
// the hash function H) using the private key, priv. If the hash is longer than
|
||||
// the bit-length of the private key's curve order, the hash will be truncated
|
||||
// to that length.
|
||||
func Sign[P Point[P], H fips140.Hash](c *Curve[P], h func() H, priv *PrivateKey, rand io.Reader, hash []byte) (*Signature, error) {
|
||||
func Sign[P Point[P], H hash.Hash](c *Curve[P], h func() H, priv *PrivateKey, rand io.Reader, hash []byte) (*Signature, error) {
|
||||
if priv.pub.curve != c.curve {
|
||||
return nil, errors.New("ecdsa: private key does not match curve")
|
||||
}
|
||||
|
|
@ -304,7 +305,7 @@ func Sign[P Point[P], H fips140.Hash](c *Curve[P], h func() H, priv *PrivateKey,
|
|||
// hash is longer than the bit-length of the private key's curve order, the hash
|
||||
// will be truncated to that length. This applies Deterministic ECDSA as
|
||||
// specified in FIPS 186-5 and RFC 6979.
|
||||
func SignDeterministic[P Point[P], H fips140.Hash](c *Curve[P], h func() H, priv *PrivateKey, hash []byte) (*Signature, error) {
|
||||
func SignDeterministic[P Point[P], H hash.Hash](c *Curve[P], h func() H, priv *PrivateKey, hash []byte) (*Signature, error) {
|
||||
if priv.pub.curve != c.curve {
|
||||
return nil, errors.New("ecdsa: private key does not match curve")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"bytes"
|
||||
"crypto/internal/fips140"
|
||||
"crypto/internal/fips140/hmac"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// hmacDRBG is an SP 800-90A Rev. 1 HMAC_DRBG.
|
||||
|
|
@ -48,7 +49,7 @@ type personalizationString interface {
|
|||
isPersonalizationString()
|
||||
}
|
||||
|
||||
func newDRBG[H fips140.Hash](hash func() H, entropy, nonce []byte, s personalizationString) *hmacDRBG {
|
||||
func newDRBG[H hash.Hash](hash func() H, entropy, nonce []byte, s personalizationString) *hmacDRBG {
|
||||
// HMAC_DRBG_Instantiate_algorithm, per Section 10.1.2.3.
|
||||
fips140.RecordApproved()
|
||||
|
||||
|
|
@ -121,7 +122,7 @@ func newDRBG[H fips140.Hash](hash func() H, entropy, nonce []byte, s personaliza
|
|||
//
|
||||
// This should only be used for ACVP testing. hmacDRBG is not intended to be
|
||||
// used directly.
|
||||
func TestingOnlyNewDRBG(hash func() fips140.Hash, entropy, nonce []byte, s []byte) *hmacDRBG {
|
||||
func TestingOnlyNewDRBG(hash func() hash.Hash, entropy, nonce []byte, s []byte) *hmacDRBG {
|
||||
return newDRBG(hash, entropy, nonce, plainPersonalizationString(s))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ package fips140
|
|||
import (
|
||||
"crypto/internal/fips140deps/godebug"
|
||||
"errors"
|
||||
"hash"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
|
|
@ -69,3 +70,9 @@ func Version() string {
|
|||
// moved to a different file.
|
||||
return "latest" //mkzip:version
|
||||
}
|
||||
|
||||
// Hash is a legacy compatibility alias for hash.Hash.
|
||||
//
|
||||
// It's only here because [crypto/internal/fips140/ecdsa.TestingOnlyNewDRBG]
|
||||
// takes a "func() fips140.Hash" in v1.0.0, instead of being generic.
|
||||
type Hash = hash.Hash
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package fips140
|
||||
|
||||
import "io"
|
||||
|
||||
// Hash is the common interface implemented by all hash functions. It is a copy
|
||||
// of [hash.Hash] from the standard library, to avoid depending on security
|
||||
// definitions from outside of the module.
|
||||
type Hash interface {
|
||||
// Write (via the embedded io.Writer interface) adds more data to the
|
||||
// running hash. It never returns an error.
|
||||
io.Writer
|
||||
|
||||
// Sum appends the current hash to b and returns the resulting slice.
|
||||
// It does not change the underlying hash state.
|
||||
Sum(b []byte) []byte
|
||||
|
||||
// Reset resets the Hash to its initial state.
|
||||
Reset()
|
||||
|
||||
// Size returns the number of bytes Sum will return.
|
||||
Size() int
|
||||
|
||||
// BlockSize returns the hash's underlying block size.
|
||||
// The Write method must be able to accept any amount
|
||||
// of data, but it may operate more efficiently if all writes
|
||||
// are a multiple of the block size.
|
||||
BlockSize() int
|
||||
}
|
||||
|
|
@ -7,9 +7,10 @@ package hkdf
|
|||
import (
|
||||
"crypto/internal/fips140"
|
||||
"crypto/internal/fips140/hmac"
|
||||
"hash"
|
||||
)
|
||||
|
||||
func Extract[H fips140.Hash](h func() H, secret, salt []byte) []byte {
|
||||
func Extract[H hash.Hash](h func() H, secret, salt []byte) []byte {
|
||||
if len(secret) < 112/8 {
|
||||
fips140.RecordNonApproved()
|
||||
}
|
||||
|
|
@ -23,7 +24,7 @@ func Extract[H fips140.Hash](h func() H, secret, salt []byte) []byte {
|
|||
return extractor.Sum(nil)
|
||||
}
|
||||
|
||||
func Expand[H fips140.Hash](h func() H, pseudorandomKey []byte, info string, keyLen int) []byte {
|
||||
func Expand[H hash.Hash](h func() H, pseudorandomKey []byte, info string, keyLen int) []byte {
|
||||
out := make([]byte, 0, keyLen)
|
||||
expander := hmac.New(h, pseudorandomKey)
|
||||
hmac.MarkAsUsedInKDF(expander)
|
||||
|
|
@ -50,7 +51,7 @@ func Expand[H fips140.Hash](h func() H, pseudorandomKey []byte, info string, key
|
|||
return out
|
||||
}
|
||||
|
||||
func Key[H fips140.Hash](h func() H, secret, salt []byte, info string, keyLen int) []byte {
|
||||
func Key[H hash.Hash](h func() H, secret, salt []byte, info string, keyLen int) []byte {
|
||||
prk := Extract(h, secret, salt)
|
||||
return Expand(h, prk, info, keyLen)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import (
|
|||
"crypto/internal/fips140/sha256"
|
||||
"crypto/internal/fips140/sha3"
|
||||
"crypto/internal/fips140/sha512"
|
||||
"errors"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// key is zero padded to the block size of the hash function
|
||||
|
|
@ -28,8 +30,9 @@ type marshalable interface {
|
|||
}
|
||||
|
||||
type HMAC struct {
|
||||
// opad and ipad may share underlying storage with HMAC clones.
|
||||
opad, ipad []byte
|
||||
outer, inner fips140.Hash
|
||||
outer, inner hash.Hash
|
||||
|
||||
// If marshaled is true, then opad and ipad do not contain a padded
|
||||
// copy of the key, but rather the marshaled state of outer/inner after
|
||||
|
|
@ -127,8 +130,32 @@ func (h *HMAC) Reset() {
|
|||
h.marshaled = true
|
||||
}
|
||||
|
||||
// New returns a new HMAC hash using the given [fips140.Hash] type and key.
|
||||
func New[H fips140.Hash](h func() H, key []byte) *HMAC {
|
||||
// Clone implements [hash.Cloner] if the underlying hash does.
|
||||
// Otherwise, it returns [errors.ErrUnsupported].
|
||||
func (h *HMAC) Clone() (hash.Cloner, error) {
|
||||
r := *h
|
||||
ic, ok := h.inner.(hash.Cloner)
|
||||
if !ok {
|
||||
return nil, errors.ErrUnsupported
|
||||
}
|
||||
oc, ok := h.outer.(hash.Cloner)
|
||||
if !ok {
|
||||
return nil, errors.ErrUnsupported
|
||||
}
|
||||
var err error
|
||||
r.inner, err = ic.Clone()
|
||||
if err != nil {
|
||||
return nil, errors.ErrUnsupported
|
||||
}
|
||||
r.outer, err = oc.Clone()
|
||||
if err != nil {
|
||||
return nil, errors.ErrUnsupported
|
||||
}
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
// New returns a new HMAC hash using the given [hash.Hash] type and key.
|
||||
func New[H hash.Hash](h func() H, key []byte) *HMAC {
|
||||
hm := &HMAC{keyLen: len(key)}
|
||||
hm.outer = h()
|
||||
hm.inner = h()
|
||||
|
|
|
|||
|
|
@ -7,11 +7,6 @@
|
|||
#include "textflag.h"
|
||||
#include "go_asm.h"
|
||||
|
||||
DATA p256ordK0<>+0x00(SB)/4, $0xee00bc4f
|
||||
DATA p256ord<>+0x00(SB)/8, $0xffffffff00000000
|
||||
DATA p256ord<>+0x08(SB)/8, $0xffffffffffffffff
|
||||
DATA p256ord<>+0x10(SB)/8, $0xbce6faada7179e84
|
||||
DATA p256ord<>+0x18(SB)/8, $0xf3b9cac2fc632551
|
||||
DATA p256<>+0x00(SB)/8, $0xffffffff00000001 // P256
|
||||
DATA p256<>+0x08(SB)/8, $0x0000000000000000 // P256
|
||||
DATA p256<>+0x10(SB)/8, $0x00000000ffffffff // P256
|
||||
|
|
@ -44,8 +39,6 @@ DATA p256mul<>+0x80(SB)/8, $0x00000000fffffffe // (1*2^256)%P256
|
|||
DATA p256mul<>+0x88(SB)/8, $0xffffffffffffffff // (1*2^256)%P256
|
||||
DATA p256mul<>+0x90(SB)/8, $0xffffffff00000000 // (1*2^256)%P256
|
||||
DATA p256mul<>+0x98(SB)/8, $0x0000000000000001 // (1*2^256)%P256
|
||||
GLOBL p256ordK0<>(SB), 8, $4
|
||||
GLOBL p256ord<>(SB), 8, $32
|
||||
GLOBL p256<>(SB), 8, $96
|
||||
GLOBL p256mul<>(SB), 8, $160
|
||||
|
||||
|
|
@ -500,392 +493,6 @@ loop_select:
|
|||
#undef SEL2
|
||||
#undef CPOOL
|
||||
|
||||
// ---------------------------------------
|
||||
|
||||
// func p256OrdMul(res, in1, in2 *p256OrdElement)
|
||||
#define res_ptr R1
|
||||
#define x_ptr R2
|
||||
#define y_ptr R3
|
||||
#define X0 V0
|
||||
#define X1 V1
|
||||
#define Y0 V2
|
||||
#define Y1 V3
|
||||
#define M0 V4
|
||||
#define M1 V5
|
||||
#define T0 V6
|
||||
#define T1 V7
|
||||
#define T2 V8
|
||||
#define YDIG V9
|
||||
|
||||
#define ADD1 V16
|
||||
#define ADD1H V17
|
||||
#define ADD2 V18
|
||||
#define ADD2H V19
|
||||
#define RED1 V20
|
||||
#define RED1H V21
|
||||
#define RED2 V22
|
||||
#define RED2H V23
|
||||
#define CAR1 V24
|
||||
#define CAR1M V25
|
||||
|
||||
#define MK0 V30
|
||||
#define K0 V31
|
||||
TEXT ·p256OrdMul<>(SB), NOSPLIT, $0
|
||||
MOVD res+0(FP), res_ptr
|
||||
MOVD in1+8(FP), x_ptr
|
||||
MOVD in2+16(FP), y_ptr
|
||||
|
||||
VZERO T2
|
||||
MOVD $p256ordK0<>+0x00(SB), R4
|
||||
|
||||
// VLEF $3, 0(R4), K0
|
||||
WORD $0xE7F40000
|
||||
BYTE $0x38
|
||||
BYTE $0x03
|
||||
MOVD $p256ord<>+0x00(SB), R4
|
||||
VL 16(R4), M0
|
||||
VL 0(R4), M1
|
||||
|
||||
VL (0*16)(x_ptr), X0
|
||||
VPDI $0x4, X0, X0, X0
|
||||
VL (1*16)(x_ptr), X1
|
||||
VPDI $0x4, X1, X1, X1
|
||||
VL (0*16)(y_ptr), Y0
|
||||
VPDI $0x4, Y0, Y0, Y0
|
||||
VL (1*16)(y_ptr), Y1
|
||||
VPDI $0x4, Y1, Y1, Y1
|
||||
|
||||
// ---------------------------------------------------------------------------/
|
||||
VREPF $3, Y0, YDIG
|
||||
VMLF X0, YDIG, ADD1
|
||||
VMLF ADD1, K0, MK0
|
||||
VREPF $3, MK0, MK0
|
||||
|
||||
VMLF X1, YDIG, ADD2
|
||||
VMLHF X0, YDIG, ADD1H
|
||||
VMLHF X1, YDIG, ADD2H
|
||||
|
||||
VMALF M0, MK0, ADD1, RED1
|
||||
VMALHF M0, MK0, ADD1, RED1H
|
||||
VMALF M1, MK0, ADD2, RED2
|
||||
VMALHF M1, MK0, ADD2, RED2H
|
||||
|
||||
VSLDB $12, RED2, RED1, RED1
|
||||
VSLDB $12, T2, RED2, RED2
|
||||
|
||||
VACCQ RED1, ADD1H, CAR1
|
||||
VAQ RED1, ADD1H, T0
|
||||
VACCQ RED1H, T0, CAR1M
|
||||
VAQ RED1H, T0, T0
|
||||
|
||||
// << ready for next MK0
|
||||
|
||||
VACQ RED2, ADD2H, CAR1, T1
|
||||
VACCCQ RED2, ADD2H, CAR1, CAR1
|
||||
VACCCQ RED2H, T1, CAR1M, T2
|
||||
VACQ RED2H, T1, CAR1M, T1
|
||||
VAQ CAR1, T2, T2
|
||||
|
||||
// ---------------------------------------------------
|
||||
/* *
|
||||
* ---+--------+--------+
|
||||
* T2| T1 | T0 |
|
||||
* ---+--------+--------+
|
||||
* *(add)*
|
||||
* +--------+--------+
|
||||
* | X1 | X0 |
|
||||
* +--------+--------+
|
||||
* *(mul)*
|
||||
* +--------+--------+
|
||||
* | YDIG | YDIG |
|
||||
* +--------+--------+
|
||||
* *(add)*
|
||||
* +--------+--------+
|
||||
* | M1 | M0 |
|
||||
* +--------+--------+
|
||||
* *(mul)*
|
||||
* +--------+--------+
|
||||
* | MK0 | MK0 |
|
||||
* +--------+--------+
|
||||
*
|
||||
* ---------------------
|
||||
*
|
||||
* +--------+--------+
|
||||
* | ADD2 | ADD1 |
|
||||
* +--------+--------+
|
||||
* +--------+--------+
|
||||
* | ADD2H | ADD1H |
|
||||
* +--------+--------+
|
||||
* +--------+--------+
|
||||
* | RED2 | RED1 |
|
||||
* +--------+--------+
|
||||
* +--------+--------+
|
||||
* | RED2H | RED1H |
|
||||
* +--------+--------+
|
||||
*/
|
||||
VREPF $2, Y0, YDIG
|
||||
VMALF X0, YDIG, T0, ADD1
|
||||
VMLF ADD1, K0, MK0
|
||||
VREPF $3, MK0, MK0
|
||||
|
||||
VMALF X1, YDIG, T1, ADD2
|
||||
VMALHF X0, YDIG, T0, ADD1H
|
||||
VMALHF X1, YDIG, T1, ADD2H
|
||||
|
||||
VMALF M0, MK0, ADD1, RED1
|
||||
VMALHF M0, MK0, ADD1, RED1H
|
||||
VMALF M1, MK0, ADD2, RED2
|
||||
VMALHF M1, MK0, ADD2, RED2H
|
||||
|
||||
VSLDB $12, RED2, RED1, RED1
|
||||
VSLDB $12, T2, RED2, RED2
|
||||
|
||||
VACCQ RED1, ADD1H, CAR1
|
||||
VAQ RED1, ADD1H, T0
|
||||
VACCQ RED1H, T0, CAR1M
|
||||
VAQ RED1H, T0, T0
|
||||
|
||||
// << ready for next MK0
|
||||
|
||||
VACQ RED2, ADD2H, CAR1, T1
|
||||
VACCCQ RED2, ADD2H, CAR1, CAR1
|
||||
VACCCQ RED2H, T1, CAR1M, T2
|
||||
VACQ RED2H, T1, CAR1M, T1
|
||||
VAQ CAR1, T2, T2
|
||||
|
||||
// ---------------------------------------------------
|
||||
VREPF $1, Y0, YDIG
|
||||
VMALF X0, YDIG, T0, ADD1
|
||||
VMLF ADD1, K0, MK0
|
||||
VREPF $3, MK0, MK0
|
||||
|
||||
VMALF X1, YDIG, T1, ADD2
|
||||
VMALHF X0, YDIG, T0, ADD1H
|
||||
VMALHF X1, YDIG, T1, ADD2H
|
||||
|
||||
VMALF M0, MK0, ADD1, RED1
|
||||
VMALHF M0, MK0, ADD1, RED1H
|
||||
VMALF M1, MK0, ADD2, RED2
|
||||
VMALHF M1, MK0, ADD2, RED2H
|
||||
|
||||
VSLDB $12, RED2, RED1, RED1
|
||||
VSLDB $12, T2, RED2, RED2
|
||||
|
||||
VACCQ RED1, ADD1H, CAR1
|
||||
VAQ RED1, ADD1H, T0
|
||||
VACCQ RED1H, T0, CAR1M
|
||||
VAQ RED1H, T0, T0
|
||||
|
||||
// << ready for next MK0
|
||||
|
||||
VACQ RED2, ADD2H, CAR1, T1
|
||||
VACCCQ RED2, ADD2H, CAR1, CAR1
|
||||
VACCCQ RED2H, T1, CAR1M, T2
|
||||
VACQ RED2H, T1, CAR1M, T1
|
||||
VAQ CAR1, T2, T2
|
||||
|
||||
// ---------------------------------------------------
|
||||
VREPF $0, Y0, YDIG
|
||||
VMALF X0, YDIG, T0, ADD1
|
||||
VMLF ADD1, K0, MK0
|
||||
VREPF $3, MK0, MK0
|
||||
|
||||
VMALF X1, YDIG, T1, ADD2
|
||||
VMALHF X0, YDIG, T0, ADD1H
|
||||
VMALHF X1, YDIG, T1, ADD2H
|
||||
|
||||
VMALF M0, MK0, ADD1, RED1
|
||||
VMALHF M0, MK0, ADD1, RED1H
|
||||
VMALF M1, MK0, ADD2, RED2
|
||||
VMALHF M1, MK0, ADD2, RED2H
|
||||
|
||||
VSLDB $12, RED2, RED1, RED1
|
||||
VSLDB $12, T2, RED2, RED2
|
||||
|
||||
VACCQ RED1, ADD1H, CAR1
|
||||
VAQ RED1, ADD1H, T0
|
||||
VACCQ RED1H, T0, CAR1M
|
||||
VAQ RED1H, T0, T0
|
||||
|
||||
// << ready for next MK0
|
||||
|
||||
VACQ RED2, ADD2H, CAR1, T1
|
||||
VACCCQ RED2, ADD2H, CAR1, CAR1
|
||||
VACCCQ RED2H, T1, CAR1M, T2
|
||||
VACQ RED2H, T1, CAR1M, T1
|
||||
VAQ CAR1, T2, T2
|
||||
|
||||
// ---------------------------------------------------
|
||||
VREPF $3, Y1, YDIG
|
||||
VMALF X0, YDIG, T0, ADD1
|
||||
VMLF ADD1, K0, MK0
|
||||
VREPF $3, MK0, MK0
|
||||
|
||||
VMALF X1, YDIG, T1, ADD2
|
||||
VMALHF X0, YDIG, T0, ADD1H
|
||||
VMALHF X1, YDIG, T1, ADD2H
|
||||
|
||||
VMALF M0, MK0, ADD1, RED1
|
||||
VMALHF M0, MK0, ADD1, RED1H
|
||||
VMALF M1, MK0, ADD2, RED2
|
||||
VMALHF M1, MK0, ADD2, RED2H
|
||||
|
||||
VSLDB $12, RED2, RED1, RED1
|
||||
VSLDB $12, T2, RED2, RED2
|
||||
|
||||
VACCQ RED1, ADD1H, CAR1
|
||||
VAQ RED1, ADD1H, T0
|
||||
VACCQ RED1H, T0, CAR1M
|
||||
VAQ RED1H, T0, T0
|
||||
|
||||
// << ready for next MK0
|
||||
|
||||
VACQ RED2, ADD2H, CAR1, T1
|
||||
VACCCQ RED2, ADD2H, CAR1, CAR1
|
||||
VACCCQ RED2H, T1, CAR1M, T2
|
||||
VACQ RED2H, T1, CAR1M, T1
|
||||
VAQ CAR1, T2, T2
|
||||
|
||||
// ---------------------------------------------------
|
||||
VREPF $2, Y1, YDIG
|
||||
VMALF X0, YDIG, T0, ADD1
|
||||
VMLF ADD1, K0, MK0
|
||||
VREPF $3, MK0, MK0
|
||||
|
||||
VMALF X1, YDIG, T1, ADD2
|
||||
VMALHF X0, YDIG, T0, ADD1H
|
||||
VMALHF X1, YDIG, T1, ADD2H
|
||||
|
||||
VMALF M0, MK0, ADD1, RED1
|
||||
VMALHF M0, MK0, ADD1, RED1H
|
||||
VMALF M1, MK0, ADD2, RED2
|
||||
VMALHF M1, MK0, ADD2, RED2H
|
||||
|
||||
VSLDB $12, RED2, RED1, RED1
|
||||
VSLDB $12, T2, RED2, RED2
|
||||
|
||||
VACCQ RED1, ADD1H, CAR1
|
||||
VAQ RED1, ADD1H, T0
|
||||
VACCQ RED1H, T0, CAR1M
|
||||
VAQ RED1H, T0, T0
|
||||
|
||||
// << ready for next MK0
|
||||
|
||||
VACQ RED2, ADD2H, CAR1, T1
|
||||
VACCCQ RED2, ADD2H, CAR1, CAR1
|
||||
VACCCQ RED2H, T1, CAR1M, T2
|
||||
VACQ RED2H, T1, CAR1M, T1
|
||||
VAQ CAR1, T2, T2
|
||||
|
||||
// ---------------------------------------------------
|
||||
VREPF $1, Y1, YDIG
|
||||
VMALF X0, YDIG, T0, ADD1
|
||||
VMLF ADD1, K0, MK0
|
||||
VREPF $3, MK0, MK0
|
||||
|
||||
VMALF X1, YDIG, T1, ADD2
|
||||
VMALHF X0, YDIG, T0, ADD1H
|
||||
VMALHF X1, YDIG, T1, ADD2H
|
||||
|
||||
VMALF M0, MK0, ADD1, RED1
|
||||
VMALHF M0, MK0, ADD1, RED1H
|
||||
VMALF M1, MK0, ADD2, RED2
|
||||
VMALHF M1, MK0, ADD2, RED2H
|
||||
|
||||
VSLDB $12, RED2, RED1, RED1
|
||||
VSLDB $12, T2, RED2, RED2
|
||||
|
||||
VACCQ RED1, ADD1H, CAR1
|
||||
VAQ RED1, ADD1H, T0
|
||||
VACCQ RED1H, T0, CAR1M
|
||||
VAQ RED1H, T0, T0
|
||||
|
||||
// << ready for next MK0
|
||||
|
||||
VACQ RED2, ADD2H, CAR1, T1
|
||||
VACCCQ RED2, ADD2H, CAR1, CAR1
|
||||
VACCCQ RED2H, T1, CAR1M, T2
|
||||
VACQ RED2H, T1, CAR1M, T1
|
||||
VAQ CAR1, T2, T2
|
||||
|
||||
// ---------------------------------------------------
|
||||
VREPF $0, Y1, YDIG
|
||||
VMALF X0, YDIG, T0, ADD1
|
||||
VMLF ADD1, K0, MK0
|
||||
VREPF $3, MK0, MK0
|
||||
|
||||
VMALF X1, YDIG, T1, ADD2
|
||||
VMALHF X0, YDIG, T0, ADD1H
|
||||
VMALHF X1, YDIG, T1, ADD2H
|
||||
|
||||
VMALF M0, MK0, ADD1, RED1
|
||||
VMALHF M0, MK0, ADD1, RED1H
|
||||
VMALF M1, MK0, ADD2, RED2
|
||||
VMALHF M1, MK0, ADD2, RED2H
|
||||
|
||||
VSLDB $12, RED2, RED1, RED1
|
||||
VSLDB $12, T2, RED2, RED2
|
||||
|
||||
VACCQ RED1, ADD1H, CAR1
|
||||
VAQ RED1, ADD1H, T0
|
||||
VACCQ RED1H, T0, CAR1M
|
||||
VAQ RED1H, T0, T0
|
||||
|
||||
// << ready for next MK0
|
||||
|
||||
VACQ RED2, ADD2H, CAR1, T1
|
||||
VACCCQ RED2, ADD2H, CAR1, CAR1
|
||||
VACCCQ RED2H, T1, CAR1M, T2
|
||||
VACQ RED2H, T1, CAR1M, T1
|
||||
VAQ CAR1, T2, T2
|
||||
|
||||
// ---------------------------------------------------
|
||||
|
||||
VZERO RED1
|
||||
VSCBIQ M0, T0, CAR1
|
||||
VSQ M0, T0, ADD1
|
||||
VSBCBIQ T1, M1, CAR1, CAR1M
|
||||
VSBIQ T1, M1, CAR1, ADD2
|
||||
VSBIQ T2, RED1, CAR1M, T2
|
||||
|
||||
// what output to use, ADD2||ADD1 or T1||T0?
|
||||
VSEL T0, ADD1, T2, T0
|
||||
VSEL T1, ADD2, T2, T1
|
||||
|
||||
VPDI $0x4, T0, T0, T0
|
||||
VST T0, (0*16)(res_ptr)
|
||||
VPDI $0x4, T1, T1, T1
|
||||
VST T1, (1*16)(res_ptr)
|
||||
RET
|
||||
|
||||
#undef res_ptr
|
||||
#undef x_ptr
|
||||
#undef y_ptr
|
||||
#undef X0
|
||||
#undef X1
|
||||
#undef Y0
|
||||
#undef Y1
|
||||
#undef M0
|
||||
#undef M1
|
||||
#undef T0
|
||||
#undef T1
|
||||
#undef T2
|
||||
#undef YDIG
|
||||
|
||||
#undef ADD1
|
||||
#undef ADD1H
|
||||
#undef ADD2
|
||||
#undef ADD2H
|
||||
#undef RED1
|
||||
#undef RED1H
|
||||
#undef RED2
|
||||
#undef RED2H
|
||||
#undef CAR1
|
||||
#undef CAR1M
|
||||
|
||||
#undef MK0
|
||||
#undef K0
|
||||
|
||||
// ---------------------------------------
|
||||
// p256MulInternal
|
||||
// V0-V3,V30,V31 - Not Modified
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"crypto/internal/fips140"
|
||||
"crypto/internal/fips140/hmac"
|
||||
"errors"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// divRoundUp divides x+y-1 by y, rounding up if the result is not whole.
|
||||
|
|
@ -19,7 +20,7 @@ func divRoundUp(x, y int) int {
|
|||
return int((int64(x) + int64(y) - 1) / int64(y))
|
||||
}
|
||||
|
||||
func Key[Hash fips140.Hash](h func() Hash, password string, salt []byte, iter, keyLength int) ([]byte, error) {
|
||||
func Key[Hash hash.Hash](h func() Hash, password string, salt []byte, iter, keyLength int) ([]byte, error) {
|
||||
setServiceIndicator(salt, keyLength)
|
||||
|
||||
if keyLength <= 0 {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import (
|
|||
"crypto/internal/fips140/sha512"
|
||||
"crypto/internal/fips140/subtle"
|
||||
"errors"
|
||||
"hash"
|
||||
"io"
|
||||
)
|
||||
|
||||
|
|
@ -48,7 +49,7 @@ func incCounter(c *[4]byte) {
|
|||
|
||||
// mgf1XOR XORs the bytes in out with a mask generated using the MGF1 function
|
||||
// specified in PKCS #1 v2.1.
|
||||
func mgf1XOR(out []byte, hash fips140.Hash, seed []byte) {
|
||||
func mgf1XOR(out []byte, hash hash.Hash, seed []byte) {
|
||||
var counter [4]byte
|
||||
var digest []byte
|
||||
|
||||
|
|
@ -67,7 +68,7 @@ func mgf1XOR(out []byte, hash fips140.Hash, seed []byte) {
|
|||
}
|
||||
}
|
||||
|
||||
func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash fips140.Hash) ([]byte, error) {
|
||||
func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash hash.Hash) ([]byte, error) {
|
||||
// See RFC 8017, Section 9.1.1.
|
||||
|
||||
hLen := hash.Size()
|
||||
|
|
@ -144,7 +145,7 @@ func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash fips140.Hash) ([]
|
|||
|
||||
const pssSaltLengthAutodetect = -1
|
||||
|
||||
func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash fips140.Hash) error {
|
||||
func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash hash.Hash) error {
|
||||
// See RFC 8017, Section 9.1.2.
|
||||
|
||||
hLen := hash.Size()
|
||||
|
|
@ -250,7 +251,7 @@ func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash fips140.Hash) error
|
|||
|
||||
// PSSMaxSaltLength returns the maximum salt length for a given public key and
|
||||
// hash function.
|
||||
func PSSMaxSaltLength(pub *PublicKey, hash fips140.Hash) (int, error) {
|
||||
func PSSMaxSaltLength(pub *PublicKey, hash hash.Hash) (int, error) {
|
||||
saltLength := (pub.N.BitLen()-1+7)/8 - 2 - hash.Size()
|
||||
if saltLength < 0 {
|
||||
return 0, ErrMessageTooLong
|
||||
|
|
@ -264,7 +265,7 @@ func PSSMaxSaltLength(pub *PublicKey, hash fips140.Hash) (int, error) {
|
|||
}
|
||||
|
||||
// SignPSS calculates the signature of hashed using RSASSA-PSS.
|
||||
func SignPSS(rand io.Reader, priv *PrivateKey, hash fips140.Hash, hashed []byte, saltLength int) ([]byte, error) {
|
||||
func SignPSS(rand io.Reader, priv *PrivateKey, hash hash.Hash, hashed []byte, saltLength int) ([]byte, error) {
|
||||
fipsSelfTest()
|
||||
fips140.RecordApproved()
|
||||
checkApprovedHash(hash)
|
||||
|
|
@ -311,19 +312,19 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash fips140.Hash, hashed []byte,
|
|||
}
|
||||
|
||||
// VerifyPSS verifies sig with RSASSA-PSS automatically detecting the salt length.
|
||||
func VerifyPSS(pub *PublicKey, hash fips140.Hash, digest []byte, sig []byte) error {
|
||||
func VerifyPSS(pub *PublicKey, hash hash.Hash, digest []byte, sig []byte) error {
|
||||
return verifyPSS(pub, hash, digest, sig, pssSaltLengthAutodetect)
|
||||
}
|
||||
|
||||
// VerifyPSS verifies sig with RSASSA-PSS and an expected salt length.
|
||||
func VerifyPSSWithSaltLength(pub *PublicKey, hash fips140.Hash, digest []byte, sig []byte, saltLength int) error {
|
||||
func VerifyPSSWithSaltLength(pub *PublicKey, hash hash.Hash, digest []byte, sig []byte, saltLength int) error {
|
||||
if saltLength < 0 {
|
||||
return errors.New("crypto/rsa: salt length cannot be negative")
|
||||
}
|
||||
return verifyPSS(pub, hash, digest, sig, saltLength)
|
||||
}
|
||||
|
||||
func verifyPSS(pub *PublicKey, hash fips140.Hash, digest []byte, sig []byte, saltLength int) error {
|
||||
func verifyPSS(pub *PublicKey, hash hash.Hash, digest []byte, sig []byte, saltLength int) error {
|
||||
fipsSelfTest()
|
||||
fips140.RecordApproved()
|
||||
checkApprovedHash(hash)
|
||||
|
|
@ -359,7 +360,7 @@ func verifyPSS(pub *PublicKey, hash fips140.Hash, digest []byte, sig []byte, sal
|
|||
return emsaPSSVerify(digest, em, emBits, saltLength, hash)
|
||||
}
|
||||
|
||||
func checkApprovedHash(hash fips140.Hash) {
|
||||
func checkApprovedHash(hash hash.Hash) {
|
||||
switch hash.(type) {
|
||||
case *sha256.Digest, *sha512.Digest, *sha3.Digest:
|
||||
default:
|
||||
|
|
@ -368,7 +369,7 @@ func checkApprovedHash(hash fips140.Hash) {
|
|||
}
|
||||
|
||||
// EncryptOAEP encrypts the given message with RSAES-OAEP.
|
||||
func EncryptOAEP(hash, mgfHash fips140.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) ([]byte, error) {
|
||||
func EncryptOAEP(hash, mgfHash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) ([]byte, error) {
|
||||
// Note that while we don't commit to deterministic execution with respect
|
||||
// to the random stream, we also don't apply MaybeReadByte, so per Hyrum's
|
||||
// Law it's probably relied upon by some. It's a tolerable promise because a
|
||||
|
|
@ -411,7 +412,7 @@ func EncryptOAEP(hash, mgfHash fips140.Hash, random io.Reader, pub *PublicKey, m
|
|||
}
|
||||
|
||||
// DecryptOAEP decrypts ciphertext using RSAES-OAEP.
|
||||
func DecryptOAEP(hash, mgfHash fips140.Hash, priv *PrivateKey, ciphertext []byte, label []byte) ([]byte, error) {
|
||||
func DecryptOAEP(hash, mgfHash hash.Hash, priv *PrivateKey, ciphertext []byte, label []byte) ([]byte, error) {
|
||||
fipsSelfTest()
|
||||
fips140.RecordApproved()
|
||||
checkApprovedHash(hash)
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@ import (
|
|||
"os"
|
||||
|
||||
. "github.com/mmcloughlin/avo/build"
|
||||
. "github.com/mmcloughlin/avo/operand"
|
||||
. "github.com/mmcloughlin/avo/reg"
|
||||
)
|
||||
|
||||
//go:generate go run . -out ../sha256block_amd64.s
|
||||
|
|
@ -61,203 +59,11 @@ func main() {
|
|||
|
||||
Package("crypto/internal/fips140/sha256")
|
||||
ConstraintExpr("!purego")
|
||||
blockAMD64()
|
||||
blockAVX2()
|
||||
blockSHANI()
|
||||
Generate()
|
||||
}
|
||||
|
||||
// Wt = Mt; for 0 <= t <= 15
|
||||
func msgSchedule0(index int) {
|
||||
MOVL(Mem{Base: SI}.Offset(index*4), EAX)
|
||||
BSWAPL(EAX)
|
||||
MOVL(EAX, Mem{Base: BP}.Offset(index*4))
|
||||
}
|
||||
|
||||
// Wt = SIGMA1(Wt-2) + Wt-7 + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
|
||||
//
|
||||
// SIGMA0(x) = ROTR(7,x) XOR ROTR(18,x) XOR SHR(3,x)
|
||||
// SIGMA1(x) = ROTR(17,x) XOR ROTR(19,x) XOR SHR(10,x)
|
||||
func msgSchedule1(index int) {
|
||||
MOVL(Mem{Base: BP}.Offset((index-2)*4), EAX)
|
||||
MOVL(EAX, ECX)
|
||||
RORL(Imm(17), EAX)
|
||||
MOVL(ECX, EDX)
|
||||
RORL(Imm(19), ECX)
|
||||
SHRL(Imm(10), EDX)
|
||||
MOVL(Mem{Base: BP}.Offset((index-15)*4), EBX)
|
||||
XORL(ECX, EAX)
|
||||
MOVL(EBX, ECX)
|
||||
XORL(EDX, EAX)
|
||||
RORL(Imm(7), EBX)
|
||||
MOVL(ECX, EDX)
|
||||
SHRL(Imm(3), EDX)
|
||||
RORL(Imm(18), ECX)
|
||||
ADDL(Mem{Base: BP}.Offset((index-7)*4), EAX)
|
||||
XORL(ECX, EBX)
|
||||
XORL(EDX, EBX)
|
||||
ADDL(Mem{Base: BP}.Offset((index-16)*4), EBX)
|
||||
ADDL(EBX, EAX)
|
||||
MOVL(EAX, Mem{Base: BP}.Offset((index)*4))
|
||||
}
|
||||
|
||||
// Calculate T1 in AX - uses AX, CX and DX registers.
|
||||
// h is also used as an accumulator. Wt is passed in AX.
|
||||
//
|
||||
// T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + Kt + Wt
|
||||
// BIGSIGMA1(x) = ROTR(6,x) XOR ROTR(11,x) XOR ROTR(25,x)
|
||||
// Ch(x, y, z) = (x AND y) XOR (NOT x AND z)
|
||||
func sha256T1(konst uint32, e, f, g, h GPPhysical) {
|
||||
ADDL(EAX, h)
|
||||
MOVL(e, EAX)
|
||||
ADDL(U32(konst), h)
|
||||
MOVL(e, ECX)
|
||||
RORL(U8(6), EAX)
|
||||
MOVL(e, EDX)
|
||||
RORL(U8(11), ECX)
|
||||
XORL(ECX, EAX)
|
||||
MOVL(e, ECX)
|
||||
RORL(U8(25), EDX)
|
||||
ANDL(f, ECX)
|
||||
XORL(EAX, EDX)
|
||||
MOVL(e, EAX)
|
||||
NOTL(EAX)
|
||||
ADDL(EDX, h)
|
||||
ANDL(g, EAX)
|
||||
XORL(ECX, EAX)
|
||||
ADDL(h, EAX)
|
||||
}
|
||||
|
||||
// Calculate T2 in BX - uses BX, CX, DX and DI registers.
|
||||
//
|
||||
// T2 = BIGSIGMA0(a) + Maj(a, b, c)
|
||||
// BIGSIGMA0(x) = ROTR(2,x) XOR ROTR(13,x) XOR ROTR(22,x)
|
||||
// Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z)
|
||||
func sha256T2(a, b, c GPPhysical) {
|
||||
MOVL(a, EDI)
|
||||
MOVL(c, EBX)
|
||||
RORL(U8(2), EDI)
|
||||
MOVL(a, EDX)
|
||||
ANDL(b, EBX)
|
||||
RORL(U8(13), EDX)
|
||||
MOVL(a, ECX)
|
||||
ANDL(c, ECX)
|
||||
XORL(EDX, EDI)
|
||||
XORL(ECX, EBX)
|
||||
MOVL(a, EDX)
|
||||
MOVL(b, ECX)
|
||||
RORL(U8(22), EDX)
|
||||
ANDL(a, ECX)
|
||||
XORL(ECX, EBX)
|
||||
XORL(EDX, EDI)
|
||||
ADDL(EDI, EBX)
|
||||
}
|
||||
|
||||
// Calculate T1 and T2, then e = d + T1 and a = T1 + T2.
|
||||
// The values for e and a are stored in d and h, ready for rotation.
|
||||
func sha256Round(index int, konst uint32, a, b, c, d, e, f, g, h GPPhysical) {
|
||||
sha256T1(konst, e, f, g, h)
|
||||
sha256T2(a, b, c)
|
||||
MOVL(EBX, h)
|
||||
ADDL(EAX, d)
|
||||
ADDL(EAX, h)
|
||||
}
|
||||
|
||||
func sha256Round0(index int, konst uint32, a, b, c, d, e, f, g, h GPPhysical) {
|
||||
msgSchedule0(index)
|
||||
sha256Round(index, konst, a, b, c, d, e, f, g, h)
|
||||
}
|
||||
|
||||
func sha256Round1(index int, konst uint32, a, b, c, d, e, f, g, h GPPhysical) {
|
||||
msgSchedule1(index)
|
||||
sha256Round(index, konst, a, b, c, d, e, f, g, h)
|
||||
}
|
||||
|
||||
func blockAMD64() {
|
||||
Implement("blockAMD64")
|
||||
AllocLocal(256 + 8)
|
||||
|
||||
Load(Param("p").Base(), RSI)
|
||||
Load(Param("p").Len(), RDX)
|
||||
SHRQ(Imm(6), RDX)
|
||||
SHLQ(Imm(6), RDX)
|
||||
|
||||
// Return if p is empty
|
||||
LEAQ(Mem{Base: RSI, Index: RDX, Scale: 1}, RDI)
|
||||
MOVQ(RDI, Mem{Base: SP}.Offset(256))
|
||||
CMPQ(RSI, RDI)
|
||||
JEQ(LabelRef("end"))
|
||||
|
||||
BP := Mem{Base: BP}
|
||||
Load(Param("dig"), RBP)
|
||||
MOVL(BP.Offset(0*4), R8L) // a = H0
|
||||
MOVL(BP.Offset(1*4), R9L) // b = H1
|
||||
MOVL(BP.Offset(2*4), R10L) // c = H2
|
||||
MOVL(BP.Offset(3*4), R11L) // d = H3
|
||||
MOVL(BP.Offset(4*4), R12L) // e = H4
|
||||
MOVL(BP.Offset(5*4), R13L) // f = H5
|
||||
MOVL(BP.Offset(6*4), R14L) // g = H6
|
||||
MOVL(BP.Offset(7*4), R15L) // h = H7
|
||||
|
||||
loop()
|
||||
end()
|
||||
}
|
||||
|
||||
func rotateRight(slice *[]GPPhysical) []GPPhysical {
|
||||
n := len(*slice)
|
||||
new := make([]GPPhysical, n)
|
||||
for i, reg := range *slice {
|
||||
new[(i+1)%n] = reg
|
||||
}
|
||||
return new
|
||||
}
|
||||
|
||||
func loop() {
|
||||
Label("loop")
|
||||
MOVQ(RSP, RBP)
|
||||
|
||||
regs := []GPPhysical{R8L, R9L, R10L, R11L, R12L, R13L, R14L, R15L}
|
||||
n := len(_K)
|
||||
|
||||
for i := 0; i < 16; i++ {
|
||||
sha256Round0(i, _K[i], regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7])
|
||||
regs = rotateRight(®s)
|
||||
}
|
||||
|
||||
for i := 16; i < n; i++ {
|
||||
sha256Round1(i, _K[i], regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7])
|
||||
regs = rotateRight(®s)
|
||||
}
|
||||
|
||||
Load(Param("dig"), RBP)
|
||||
BP := Mem{Base: BP}
|
||||
ADDL(BP.Offset(0*4), R8L) // H0 = a + H0
|
||||
MOVL(R8L, BP.Offset(0*4))
|
||||
ADDL(BP.Offset(1*4), R9L) // H1 = b + H1
|
||||
MOVL(R9L, BP.Offset(1*4))
|
||||
ADDL(BP.Offset(2*4), R10L) // H2 = c + H2
|
||||
MOVL(R10L, BP.Offset(2*4))
|
||||
ADDL(BP.Offset(3*4), R11L) // H3 = d + H3
|
||||
MOVL(R11L, BP.Offset(3*4))
|
||||
ADDL(BP.Offset(4*4), R12L) // H4 = e + H4
|
||||
MOVL(R12L, BP.Offset(4*4))
|
||||
ADDL(BP.Offset(5*4), R13L) // H5 = f + H5
|
||||
MOVL(R13L, BP.Offset(5*4))
|
||||
ADDL(BP.Offset(6*4), R14L) // H6 = g + H6
|
||||
MOVL(R14L, BP.Offset(6*4))
|
||||
ADDL(BP.Offset(7*4), R15L) // H7 = h + H7
|
||||
MOVL(R15L, BP.Offset(7*4))
|
||||
|
||||
ADDQ(Imm(64), RSI)
|
||||
CMPQ(RSI, Mem{Base: SP}.Offset(256))
|
||||
JB(LabelRef("loop"))
|
||||
}
|
||||
|
||||
func end() {
|
||||
Label("end")
|
||||
RET()
|
||||
}
|
||||
|
||||
var _K = []uint32{
|
||||
0x428a2f98,
|
||||
0x71374491,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue