2
* Copyright 2022 ByteDance Inc.
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
24
. `github.com/chenzhuoyu/iasm/x86_64`
28
PtrSize = 8 // pointer size
29
PtrAlign = 8 // pointer alignment
32
var iregOrderC = []Register{
41
var xregOrderC = []Register{
53
intType = reflect.TypeOf(0)
54
ptrType = reflect.TypeOf(unsafe.Pointer(nil))
57
func (self *Frame) argv(i int) *MemoryOperand {
58
return Ptr(RSP, int32(self.Prev() + self.desc.Args[i].Mem))
61
// spillv is used for growstack spill registers
62
func (self *Frame) spillv(i int) *MemoryOperand {
63
// remain one slot for caller return pc
64
return Ptr(RSP, PtrSize + int32(self.desc.Args[i].Mem))
67
func (self *Frame) retv(i int) *MemoryOperand {
68
return Ptr(RSP, int32(self.Prev() + self.desc.Rets[i].Mem))
71
func (self *Frame) resv(i int) *MemoryOperand {
72
return Ptr(RSP, int32(self.Offs() - uint32((i+1) * PtrSize)))
75
func (self *Frame) emitGrowStack(p *Program, entry *Label) {
76
// spill all register arguments
77
for i, v := range self.desc.Args {
79
if v.IsFloat == floatKind64 {
80
p.MOVSD(v.Reg, self.spillv(i))
81
} else if v.IsFloat == floatKind32 {
82
p.MOVSS(v.Reg, self.spillv(i))
84
p.MOVQ(v.Reg, self.spillv(i))
89
// call runtime.morestack_noctxt
90
p.MOVQ(F_morestack_noctxt, R12)
92
// load all register arguments
93
for i, v := range self.desc.Args {
95
if v.IsFloat == floatKind64 {
96
p.MOVSD(self.spillv(i), v.Reg)
97
} else if v.IsFloat == floatKind32 {
98
p.MOVSS(self.spillv(i), v.Reg)
100
p.MOVQ(self.spillv(i), v.Reg)
105
// jump back to the function entry
109
func (self *Frame) GrowStackTextSize() uint32 {
110
p := DefaultArch.CreateProgram()
111
// spill all register arguments
112
for i, v := range self.desc.Args {
114
if v.IsFloat == floatKind64 {
115
p.MOVSD(v.Reg, self.spillv(i))
116
} else if v.IsFloat == floatKind32 {
117
p.MOVSS(v.Reg, self.spillv(i))
119
p.MOVQ(v.Reg, self.spillv(i))
124
// call runtime.morestack_noctxt
125
p.MOVQ(F_morestack_noctxt, R12)
127
// load all register arguments
128
for i, v := range self.desc.Args {
130
if v.IsFloat == floatKind64 {
131
p.MOVSD(self.spillv(i), v.Reg)
132
} else if v.IsFloat == floatKind32 {
133
p.MOVSS(self.spillv(i), v.Reg)
135
p.MOVQ(self.spillv(i), v.Reg)
140
// jump back to the function entry
145
return uint32(len(p.Assemble(0)))
148
func (self *Frame) emitPrologue(p *Program) {
149
p.SUBQ(self.Size(), RSP)
150
p.MOVQ(RBP, Ptr(RSP, int32(self.Offs())))
151
p.LEAQ(Ptr(RSP, int32(self.Offs())), RBP)
154
func (self *Frame) emitEpilogue(p *Program) {
155
p.MOVQ(Ptr(RSP, int32(self.Offs())), RBP)
156
p.ADDQ(self.Size(), RSP)
160
func (self *Frame) emitReserveRegs(p *Program) {
161
// spill reserved registers
162
for i, r := range ReservedRegs(self.ccall) {
165
p.MOVQ(r, self.resv(i))
167
p.MOVSD(r, self.resv(i))
169
panic(fmt.Sprintf("unsupported register type %t to reserve", r))
174
func (self *Frame) emitSpillPtrs(p *Program) {
175
// spill pointer argument registers
176
for i, r := range self.desc.Args {
177
if r.InRegister && r.IsPointer {
178
p.MOVQ(r.Reg, self.argv(i))
183
func (self *Frame) emitClearPtrs(p *Program) {
184
// spill pointer argument registers
185
for i, r := range self.desc.Args {
186
if r.InRegister && r.IsPointer {
187
p.MOVQ(int64(0), self.argv(i))
192
func (self *Frame) emitCallC(p *Program, addr uintptr) {
200
notFloatKind floatKind = iota
205
type Parameter struct {
214
func mkIReg(vt reflect.Type, reg Register64) (p Parameter) {
218
p.IsPointer = isPointer(vt)
222
func isFloat(vt reflect.Type) floatKind {
224
case reflect.Float32:
226
case reflect.Float64:
233
func mkXReg(vt reflect.Type, reg XMMRegister) (p Parameter) {
237
p.IsFloat = isFloat(vt)
241
func mkStack(vt reflect.Type, mem uint32) (p Parameter) {
245
p.IsPointer = isPointer(vt)
246
p.IsFloat = isFloat(vt)
250
func (self Parameter) String() string {
252
return fmt.Sprintf("[%%%s, Pointer(%v), Float(%v)]", self.Reg, self.IsPointer, self.IsFloat)
254
return fmt.Sprintf("[%d(FP), Pointer(%v), Float(%v)]", self.Mem, self.IsPointer, self.IsFloat)
258
func CallC(addr uintptr, fr Frame, maxStack uintptr) []byte {
259
p := DefaultArch.CreateProgram()
261
stack := CreateLabel("_stack_grow")
262
entry := CreateLabel("_entry")
264
fr.emitStackCheck(p, stack, maxStack)
266
fr.emitReserveRegs(p)
268
fr.emitExchangeArgs(p)
269
fr.emitCallC(p, addr)
270
fr.emitExchangeRets(p)
271
fr.emitRestoreRegs(p)
274
fr.emitGrowStack(p, entry)
280
func (self *Frame) emitDebug(p *Program) {