Support three-argument instructions on x86-64.
Change-Id: I81c855cd4805d4a5016999669a0cb5261838f23a Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/35224 Commit-Queue: Adam Langley <agl@google.com> Reviewed-by: David Benjamin <davidben@google.com>
This commit is contained in:
parent
3390fd88d7
commit
1d1345377a
@ -801,6 +801,8 @@ const (
|
|||||||
// instrCombine merges the source and destination in some fashion, for example
|
// instrCombine merges the source and destination in some fashion, for example
|
||||||
// a 2-operand bitwise operation.
|
// a 2-operand bitwise operation.
|
||||||
instrCombine
|
instrCombine
|
||||||
|
// instrThreeArg merges two sources into a destination in some fashion.
|
||||||
|
instrThreeArg
|
||||||
instrOther
|
instrOther
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -831,6 +833,11 @@ func classifyInstruction(instr string, args []*node32) instructionType {
|
|||||||
return instrCombine
|
return instrCombine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "sarxq", "shlxq", "shrxq":
|
||||||
|
if len(args) == 3 {
|
||||||
|
return instrThreeArg
|
||||||
|
}
|
||||||
|
|
||||||
case "vpbroadcastq":
|
case "vpbroadcastq":
|
||||||
if len(args) == 2 {
|
if len(args) == 2 {
|
||||||
return instrTransformingMove
|
return instrTransformingMove
|
||||||
@ -878,10 +885,24 @@ func saveFlags(w stringWriter, redzoneCleared bool) wrapperFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveRegister(w stringWriter, avoidReg string) (wrapperFunc, string) {
|
func saveRegister(w stringWriter, avoidRegs []string) (wrapperFunc, string) {
|
||||||
reg := "%rax"
|
candidates := []string{"%rax", "%rbx", "%rcx", "%rdx"}
|
||||||
if reg == avoidReg {
|
|
||||||
reg = "%rbx"
|
var reg string
|
||||||
|
NextCandidate:
|
||||||
|
for _, candidate := range candidates {
|
||||||
|
for _, avoid := range avoidRegs {
|
||||||
|
if candidate == avoid {
|
||||||
|
continue NextCandidate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reg = candidate
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(reg) == 0 {
|
||||||
|
panic("too many excluded registers")
|
||||||
}
|
}
|
||||||
|
|
||||||
return func(k func()) {
|
return func(k func()) {
|
||||||
@ -918,6 +939,13 @@ func combineOp(w stringWriter, instructionName, source, dest string) wrapperFunc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func threeArgCombineOp(w stringWriter, instructionName, source1, source2, dest string) wrapperFunc {
|
||||||
|
return func(k func()) {
|
||||||
|
k()
|
||||||
|
w.WriteString("\t" + instructionName + " " + source1 + ", " + source2 + ", " + dest + "\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func isValidLEATarget(reg string) bool {
|
func isValidLEATarget(reg string) bool {
|
||||||
return !strings.HasPrefix(reg, "%xmm") && !strings.HasPrefix(reg, "%ymm") && !strings.HasPrefix(reg, "%zmm")
|
return !strings.HasPrefix(reg, "%xmm") && !strings.HasPrefix(reg, "%ymm") && !strings.HasPrefix(reg, "%zmm")
|
||||||
}
|
}
|
||||||
@ -1033,9 +1061,6 @@ Args:
|
|||||||
if len(offset) > 0 {
|
if len(offset) > 0 {
|
||||||
return nil, errors.New("loading from GOT with offset is unsupported")
|
return nil, errors.New("loading from GOT with offset is unsupported")
|
||||||
}
|
}
|
||||||
if i != 0 {
|
|
||||||
return nil, errors.New("GOT access must be source operand")
|
|
||||||
}
|
|
||||||
if !d.isRIPRelative(memRef) {
|
if !d.isRIPRelative(memRef) {
|
||||||
return nil, errors.New("GOT access must be IP-relative")
|
return nil, errors.New("GOT access must be IP-relative")
|
||||||
}
|
}
|
||||||
@ -1048,10 +1073,15 @@ Args:
|
|||||||
useGOT = true
|
useGOT = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
classification := classifyInstruction(instructionName, argNodes)
|
||||||
|
if classification != instrThreeArg && i != 0 {
|
||||||
|
return nil, errors.New("GOT access must be source operand")
|
||||||
|
}
|
||||||
|
|
||||||
// Reduce the instruction to movq symbol@GOTPCREL, targetReg.
|
// Reduce the instruction to movq symbol@GOTPCREL, targetReg.
|
||||||
var targetReg string
|
var targetReg string
|
||||||
var redzoneCleared bool
|
var redzoneCleared bool
|
||||||
switch classifyInstruction(instructionName, argNodes) {
|
switch classification {
|
||||||
case instrPush:
|
case instrPush:
|
||||||
wrappers = append(wrappers, push(d.output))
|
wrappers = append(wrappers, push(d.output))
|
||||||
targetReg = "%rax"
|
targetReg = "%rax"
|
||||||
@ -1073,12 +1103,36 @@ Args:
|
|||||||
if !isValidLEATarget(targetReg) {
|
if !isValidLEATarget(targetReg) {
|
||||||
return nil, fmt.Errorf("cannot handle combining instructions targeting non-general registers")
|
return nil, fmt.Errorf("cannot handle combining instructions targeting non-general registers")
|
||||||
}
|
}
|
||||||
saveRegWrapper, tempReg := saveRegister(d.output, targetReg)
|
saveRegWrapper, tempReg := saveRegister(d.output, []string{targetReg})
|
||||||
redzoneCleared = true
|
redzoneCleared = true
|
||||||
wrappers = append(wrappers, saveRegWrapper)
|
wrappers = append(wrappers, saveRegWrapper)
|
||||||
|
|
||||||
wrappers = append(wrappers, combineOp(d.output, instructionName, tempReg, targetReg))
|
wrappers = append(wrappers, combineOp(d.output, instructionName, tempReg, targetReg))
|
||||||
targetReg = tempReg
|
targetReg = tempReg
|
||||||
|
case instrThreeArg:
|
||||||
|
if n := len(argNodes); n != 3 {
|
||||||
|
return nil, fmt.Errorf("three-argument instruction has %d arguments", n)
|
||||||
|
}
|
||||||
|
if i != 0 && i != 1 {
|
||||||
|
return nil, errors.New("GOT access must be from soure operand")
|
||||||
|
}
|
||||||
|
targetReg = d.contents(argNodes[2])
|
||||||
|
|
||||||
|
otherSource := d.contents(argNodes[1])
|
||||||
|
if i == 1 {
|
||||||
|
otherSource = d.contents(argNodes[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
saveRegWrapper, tempReg := saveRegister(d.output, []string{targetReg, otherSource})
|
||||||
|
redzoneCleared = true
|
||||||
|
wrappers = append(wrappers, saveRegWrapper)
|
||||||
|
|
||||||
|
if i == 0 {
|
||||||
|
wrappers = append(wrappers, threeArgCombineOp(d.output, instructionName, tempReg, otherSource, targetReg))
|
||||||
|
} else {
|
||||||
|
wrappers = append(wrappers, threeArgCombineOp(d.output, instructionName, otherSource, tempReg, targetReg))
|
||||||
|
}
|
||||||
|
targetReg = tempReg
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("Cannot rewrite GOTPCREL reference for instruction %q", instructionName)
|
return nil, fmt.Errorf("Cannot rewrite GOTPCREL reference for instruction %q", instructionName)
|
||||||
}
|
}
|
||||||
@ -1087,7 +1141,7 @@ Args:
|
|||||||
// Sometimes the compiler will load from the GOT to an
|
// Sometimes the compiler will load from the GOT to an
|
||||||
// XMM register, which is not a valid target of an LEA
|
// XMM register, which is not a valid target of an LEA
|
||||||
// instruction.
|
// instruction.
|
||||||
saveRegWrapper, tempReg := saveRegister(d.output, "")
|
saveRegWrapper, tempReg := saveRegister(d.output, nil)
|
||||||
wrappers = append(wrappers, saveRegWrapper)
|
wrappers = append(wrappers, saveRegWrapper)
|
||||||
isAVX := strings.HasPrefix(instructionName, "v")
|
isAVX := strings.HasPrefix(instructionName, "v")
|
||||||
wrappers = append(wrappers, moveTo(d.output, targetReg, isAVX, tempReg))
|
wrappers = append(wrappers, moveTo(d.output, targetReg, isAVX, tempReg))
|
||||||
|
@ -48,6 +48,7 @@ var delocateTests = []delocateTest{
|
|||||||
{"x86_64-GOTRewrite", []string{"in.s"}, "out.s"},
|
{"x86_64-GOTRewrite", []string{"in.s"}, "out.s"},
|
||||||
{"x86_64-LabelRewrite", []string{"in1.s", "in2.s"}, "out.s"},
|
{"x86_64-LabelRewrite", []string{"in1.s", "in2.s"}, "out.s"},
|
||||||
{"x86_64-Sections", []string{"in.s"}, "out.s"},
|
{"x86_64-Sections", []string{"in.s"}, "out.s"},
|
||||||
|
{"x86_64-ThreeArg", []string{"in.s"}, "out.s"},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDelocate(t *testing.T) {
|
func TestDelocate(t *testing.T) {
|
||||||
|
14
util/fipstools/delocate/testdata/x86_64-ThreeArg/in.s
vendored
Normal file
14
util/fipstools/delocate/testdata/x86_64-ThreeArg/in.s
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
.type foo, @function
|
||||||
|
.globl foo
|
||||||
|
foo:
|
||||||
|
movq %rax, %rax
|
||||||
|
shrxq %rbx, kBoringSSLRSASqrtTwo@GOTPCREL(%rip), %rax
|
||||||
|
shrxq kBoringSSLRSASqrtTwo@GOTPCREL(%rip), %rbx, %rax
|
||||||
|
|
||||||
|
|
||||||
|
.type kBoringSSLRSASqrtTwo,@object # @kBoringSSLRSASqrtTwo
|
||||||
|
.section .rodata,"a",@progbits,unique,760
|
||||||
|
.globl kBoringSSLRSASqrtTwo
|
||||||
|
.p2align 4
|
||||||
|
kBoringSSLRSASqrtTwo:
|
||||||
|
.quad -2404814165548301886 # 0xdea06241f7aa81c2
|
114
util/fipstools/delocate/testdata/x86_64-ThreeArg/out.s
vendored
Normal file
114
util/fipstools/delocate/testdata/x86_64-ThreeArg/out.s
vendored
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
.text
|
||||||
|
.file 1 "inserted_by_delocate.c"
|
||||||
|
.loc 1 1 0
|
||||||
|
BORINGSSL_bcm_text_start:
|
||||||
|
.type foo, @function
|
||||||
|
.globl foo
|
||||||
|
.Lfoo_local_target:
|
||||||
|
foo:
|
||||||
|
movq %rax, %rax
|
||||||
|
# WAS shrxq %rbx, kBoringSSLRSASqrtTwo@GOTPCREL(%rip), %rax
|
||||||
|
leaq -128(%rsp), %rsp
|
||||||
|
pushq %rcx
|
||||||
|
leaq .LkBoringSSLRSASqrtTwo_local_target(%rip), %rcx
|
||||||
|
shrxq %rbx, %rcx, %rax
|
||||||
|
popq %rcx
|
||||||
|
leaq 128(%rsp), %rsp
|
||||||
|
# WAS shrxq kBoringSSLRSASqrtTwo@GOTPCREL(%rip), %rbx, %rax
|
||||||
|
leaq -128(%rsp), %rsp
|
||||||
|
pushq %rcx
|
||||||
|
leaq .LkBoringSSLRSASqrtTwo_local_target(%rip), %rcx
|
||||||
|
shrxq %rcx, %rbx, %rax
|
||||||
|
popq %rcx
|
||||||
|
leaq 128(%rsp), %rsp
|
||||||
|
|
||||||
|
|
||||||
|
.type kBoringSSLRSASqrtTwo,@object # @kBoringSSLRSASqrtTwo
|
||||||
|
# WAS .section .rodata,"a",@progbits,unique,760
|
||||||
|
.text
|
||||||
|
.globl kBoringSSLRSASqrtTwo
|
||||||
|
.p2align 4
|
||||||
|
.LkBoringSSLRSASqrtTwo_local_target:
|
||||||
|
kBoringSSLRSASqrtTwo:
|
||||||
|
.quad -2404814165548301886 # 0xdea06241f7aa81c2
|
||||||
|
.text
|
||||||
|
.loc 1 2 0
|
||||||
|
BORINGSSL_bcm_text_end:
|
||||||
|
.type OPENSSL_ia32cap_get, @function
|
||||||
|
.globl OPENSSL_ia32cap_get
|
||||||
|
.LOPENSSL_ia32cap_get_local_target:
|
||||||
|
OPENSSL_ia32cap_get:
|
||||||
|
leaq OPENSSL_ia32cap_P(%rip), %rax
|
||||||
|
ret
|
||||||
|
.extern OPENSSL_ia32cap_P
|
||||||
|
.type OPENSSL_ia32cap_addr_delta, @object
|
||||||
|
.size OPENSSL_ia32cap_addr_delta, 8
|
||||||
|
OPENSSL_ia32cap_addr_delta:
|
||||||
|
.quad OPENSSL_ia32cap_P-OPENSSL_ia32cap_addr_delta
|
||||||
|
.type BORINGSSL_bcm_text_hash, @object
|
||||||
|
.size BORINGSSL_bcm_text_hash, 64
|
||||||
|
BORINGSSL_bcm_text_hash:
|
||||||
|
.byte 0xae
|
||||||
|
.byte 0x2c
|
||||||
|
.byte 0xea
|
||||||
|
.byte 0x2a
|
||||||
|
.byte 0xbd
|
||||||
|
.byte 0xa6
|
||||||
|
.byte 0xf3
|
||||||
|
.byte 0xec
|
||||||
|
.byte 0x97
|
||||||
|
.byte 0x7f
|
||||||
|
.byte 0x9b
|
||||||
|
.byte 0xf6
|
||||||
|
.byte 0x94
|
||||||
|
.byte 0x9a
|
||||||
|
.byte 0xfc
|
||||||
|
.byte 0x83
|
||||||
|
.byte 0x68
|
||||||
|
.byte 0x27
|
||||||
|
.byte 0xcb
|
||||||
|
.byte 0xa0
|
||||||
|
.byte 0xa0
|
||||||
|
.byte 0x9f
|
||||||
|
.byte 0x6b
|
||||||
|
.byte 0x6f
|
||||||
|
.byte 0xde
|
||||||
|
.byte 0x52
|
||||||
|
.byte 0xcd
|
||||||
|
.byte 0xe2
|
||||||
|
.byte 0xcd
|
||||||
|
.byte 0xff
|
||||||
|
.byte 0x31
|
||||||
|
.byte 0x80
|
||||||
|
.byte 0xa2
|
||||||
|
.byte 0xd4
|
||||||
|
.byte 0xc3
|
||||||
|
.byte 0x66
|
||||||
|
.byte 0xf
|
||||||
|
.byte 0xc2
|
||||||
|
.byte 0x6a
|
||||||
|
.byte 0x7b
|
||||||
|
.byte 0xf4
|
||||||
|
.byte 0xbe
|
||||||
|
.byte 0x39
|
||||||
|
.byte 0xa2
|
||||||
|
.byte 0xd7
|
||||||
|
.byte 0x25
|
||||||
|
.byte 0xdb
|
||||||
|
.byte 0x21
|
||||||
|
.byte 0x98
|
||||||
|
.byte 0xe9
|
||||||
|
.byte 0xd5
|
||||||
|
.byte 0x53
|
||||||
|
.byte 0xbf
|
||||||
|
.byte 0x5c
|
||||||
|
.byte 0x32
|
||||||
|
.byte 0x6
|
||||||
|
.byte 0x83
|
||||||
|
.byte 0x34
|
||||||
|
.byte 0xc
|
||||||
|
.byte 0x65
|
||||||
|
.byte 0x89
|
||||||
|
.byte 0x52
|
||||||
|
.byte 0xbd
|
||||||
|
.byte 0x1f
|
Loading…
Reference in New Issue
Block a user