diff --git a/asm/arm64_goroot_test.go b/asm/arm64_goroot_test.go index 610f126..c4da846 100644 --- a/asm/arm64_goroot_test.go +++ b/asm/arm64_goroot_test.go @@ -55,17 +55,11 @@ var gorootARM64Packages = []string{ // not silently dropped: the gaps are findings, and closing one is a matter // of removing its entry and watching the file pin itself. var gorootARM64GapFiles = map[string]string{ - "runtime/asm_arm64.s": "the unparenthesised NOSPLIT|NOFRAME flag list is not recognised, so the prologue and guard shapes diverge", - "runtime/sys_linux_arm64.s": "the unparenthesised NOSPLIT|NOFRAME flag list is not recognised, so the prologue and guard shapes diverge (cgoSigtramp, clone)", - "runtime/tls_arm64.s": "a branch distance diverges: an earlier statement's expansion is sized differently", - "crypto/internal/fips140/aes/aes_arm64.s": "a tested immediate bit in a TBZ diverges", - "crypto/internal/fips140/aes/gcm/gcm_arm64.s": "an ADD immediate's value diverges mid-function", - "crypto/internal/fips140/nistec/p256_asm_arm64.s": "a branch distance and a logical-immediate lowering diverge", - "runtime/memclr_arm64.s": "a branch distance diverges: an earlier statement's expansion is sized differently", - "runtime/preempt_arm64.s": "the prologue shape for the function's frame diverges at the first word", - "runtime/race_arm64.s": "the flag list and prologue shape diverge at the first words", - "runtime/rt0_linux_arm64.s": "the #ifdef GOOS selection diverges: gasm keeps a word the toolchain drops", - "internal/runtime/syscall/linux/asm_linux_arm64.s": "a branch distance diverges: an earlier statement's expansion is sized differently", + "runtime/asm_arm64.s": "the unparenthesised NOSPLIT|NOFRAME flag list is not recognised, so the prologue and guard shapes diverge", + "runtime/sys_linux_arm64.s": "the unparenthesised NOSPLIT|NOFRAME flag list is not recognised, so the prologue and guard shapes diverge (cgoSigtramp, clone)", + "runtime/preempt_arm64.s": "the unparenthesised NOSPLIT|NOFRAME flag list is not recognised, so the prologue and guard shapes diverge (asyncPreempt)", + "runtime/race_arm64.s": "the unparenthesised NOSPLIT|NOFRAME flag list is not recognised, so the prologue shape diverges (racecallbackthunk)", + "runtime/rt0_linux_arm64.s": "the #ifdef GOOS selection diverges: gasm keeps a word the toolchain drops", } // gorootOtherGOOS matches the file names of the ports the linux build never @@ -152,22 +146,30 @@ func TestGOROOTARM64Parity(t *testing.T) { if oout, err := cmd.CombinedOutput(); err != nil { t.Fatalf("go tool asm %s: %v\n%s", base, err, oout) } - gt := oracleFuncText(t, mustRead(t, objPath)) - byLocal := gt + byLocal := oracleFuncText(t, mustRead(t, objPath)) + // The object's symdef order is the source order, gasm's + // function list too, so same-named functions pair up in + // definition order: a file-local kernel beside its + // package-level twin (runtime·racefuncenter and + // racefuncenter<>) carries the plain name twice in the + // object and the reader cannot see the locality. + seen := map[string]int{} for _, fn := range img.Funcs { gasmCode := maskCode(append([]byte(nil), img.Code[fn.Offset:fn.Offset+fn.Size]...), fn.Relocs) - goCode, ok := byLocal[fn.Name] - if !ok { + bodies := byLocal[fn.Name] + idx := seen[fn.Name] + seen[fn.Name] = idx + 1 + if idx >= len(bodies) { keys := make([]string, 0, len(byLocal)) for name := range byLocal { keys = append(keys, name) } t.Errorf("%s: not in the oracle output (%d functions: %s)", - fn.Name, len(gt), strings.Join(keys, ", ")) + fn.Name, len(byLocal), strings.Join(keys, ", ")) continue } - goCode = maskCode(append([]byte(nil), goCode...), fn.Relocs) + goCode := maskCode(append([]byte(nil), bodies[idx]...), fn.Relocs) cmpLen := min(len(goCode), len(gasmCode)) if !bytes.Equal(gasmCode[:cmpLen], goCode[:cmpLen]) { for w := 0; w < cmpLen/4; w++ { @@ -202,13 +204,16 @@ func TestGOROOTARM64Parity(t *testing.T) { // non-package and the hashed (file-local) definitions both, keyed by the // local name: GOROOT keeps several kernels file-local (cmpbody<>, // encryptBlockAsm<>), and those ride the hashed definition blocks the -// non-package reader never sees. -func oracleFuncText(t *testing.T, obj []byte) map[string][]byte { +// non-package reader never sees. The value is the functions' bodies in +// symdef order: a file-local kernel beside its package-level twin carries +// the same plain name twice (the object reader cannot see the locality), +// and the encoder pairs them up in definition order. +func oracleFuncText(t *testing.T, obj []byte) map[string][][]byte { t.Helper() v := openGoobj(t, obj) data := v.blk(blkData) didx := v.blk(blkDataIdx) - out := make(map[string][]byte) + out := make(map[string][][]byte) di := 0 for _, bi := range []int{blkSymdef, blkHashed64def, blkHasheddef, blkNonpkgdef} { for _, s := range v.syms(bi) { @@ -221,7 +226,7 @@ func oracleFuncText(t *testing.T, obj []byte) map[string][]byte { if _, after, ok := strings.Cut(name, "."); ok { name = after } - out[name] = data[off : int(off)+int(s.size)] + out[name] = append(out[name], data[off:int(off)+int(s.size)]) } } di++