fix(asm): encode amd64 frame adjustments above 127 bytes with imm32
This commit is contained in:
+8
-6
@@ -22,6 +22,11 @@ import (
|
|||||||
// FP/SP frame-relative operands, and local-label jumps. SB (global symbol)
|
// FP/SP frame-relative operands, and local-label jumps. SB (global symbol)
|
||||||
// operands require relocations and are not yet supported; the SIMD (VEX/AVX2)
|
// operands require relocations and are not yet supported; the SIMD (VEX/AVX2)
|
||||||
// integer and shuffle/extract/permute/move set is in.
|
// integer and shuffle/extract/permute/move set is in.
|
||||||
|
//
|
||||||
|
// Like the other architectures, the stack-growth guard (the morestack check
|
||||||
|
// in the prologue and the call back into the runtime in the epilogue) is not
|
||||||
|
// emitted: the bytes match go tool asm only for NOSPLIT functions or
|
||||||
|
// zero-frame leaves, where the toolchain emits no guard either.
|
||||||
func Assemble(t *ast.Text) ([]byte, map[string]int, error) {
|
func Assemble(t *ast.Text) ([]byte, map[string]int, error) {
|
||||||
code, _, labels, _, _, err := assemble(t, nil)
|
code, _, labels, _, _, err := assemble(t, nil)
|
||||||
return code, labels, err
|
return code, labels, err
|
||||||
@@ -31,7 +36,7 @@ func Assemble(t *ast.Text) ([]byte, map[string]int, error) {
|
|||||||
// the set of static symbols a GLOBL in the same file defines. A nil link
|
// the set of static symbols a GLOBL in the same file defines. A nil link
|
||||||
// rejects SB operands outright (single-function assembly cannot resolve
|
// rejects SB operands outright (single-function assembly cannot resolve
|
||||||
// them). When allowExternal is set, a reference to a symbol no GLOBL in the
|
// them). When allowExternal is set, a reference to a symbol no GLOBL in the
|
||||||
// file defines is recorded as an external relocation instead of failing —
|
// file defines is recorded as an external relocation instead of failing
|
||||||
// the object-file emitters resolve it at link time.
|
// the object-file emitters resolve it at link time.
|
||||||
type linkInfo struct {
|
type linkInfo struct {
|
||||||
symbols map[string]bool
|
symbols map[string]bool
|
||||||
@@ -258,14 +263,11 @@ func epilogueBytes(size int) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func subSP(size int) []byte { // SUBQ $size, SP
|
func subSP(size int) []byte { // SUBQ $size, SP
|
||||||
|
// imm8 holds -128..127; anything larger takes the imm32 form, exactly as
|
||||||
|
// the Go assembler encodes it (verified for 8, 128, 200 and 255).
|
||||||
if size >= -128 && size <= 127 {
|
if size >= -128 && size <= 127 {
|
||||||
return []byte{0x48, 0x83, 0xEC, byte(int8(size))}
|
return []byte{0x48, 0x83, 0xEC, byte(int8(size))}
|
||||||
}
|
}
|
||||||
// 128..255 do not fit SUB's unsigned imm8, but the Go assembler
|
|
||||||
// switches to ADDQ $-size, SP whose sign-extended imm8 does.
|
|
||||||
if size >= -255 && size <= 255 {
|
|
||||||
return []byte{0x48, 0x83, 0xC4, byte(int8(-size))}
|
|
||||||
}
|
|
||||||
return append([]byte{0x48, 0x81, 0xEC}, le32(int64(size))...)
|
return append([]byte{0x48, 0x81, 0xEC}, le32(int64(size))...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package asm
|
package asm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -351,3 +352,26 @@ TEXT ·pf(SB), NOSPLIT, $0
|
|||||||
t.Errorf("PREFETCHT0 bytes: got %s, want 0f 18 0b", hex)
|
t.Errorf("PREFETCHT0 bytes: got %s, want 0f 18 0b", hex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestSubSPEncodings pins the prologue SUB against the bytes go tool asm
|
||||||
|
// emits for SUBQ $size, SP: imm8 for -128..127, the imm32 form for anything
|
||||||
|
// larger. The intermediate 129..255 range used to encode an ADD with a
|
||||||
|
// truncated immediate, moving SP the wrong way.
|
||||||
|
func TestSubSPEncodings(t *testing.T) {
|
||||||
|
for _, tt := range []struct {
|
||||||
|
size int
|
||||||
|
want []byte
|
||||||
|
}{
|
||||||
|
{8, []byte{0x48, 0x83, 0xEC, 0x08}},
|
||||||
|
{127, []byte{0x48, 0x83, 0xEC, 0x7F}},
|
||||||
|
{128, []byte{0x48, 0x81, 0xEC, 0x80, 0x00, 0x00, 0x00}},
|
||||||
|
{200, []byte{0x48, 0x81, 0xEC, 0xC8, 0x00, 0x00, 0x00}},
|
||||||
|
{255, []byte{0x48, 0x81, 0xEC, 0xFF, 0x00, 0x00, 0x00}},
|
||||||
|
{4096, []byte{0x48, 0x81, 0xEC, 0x00, 0x10, 0x00, 0x00}},
|
||||||
|
} {
|
||||||
|
got := subSP(tt.size)
|
||||||
|
if !bytes.Equal(got, tt.want) {
|
||||||
|
t.Errorf("subSP(%d) = %x, want %x", tt.size, got, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user