abi_amd64.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /*
  2. * Copyright 2022 ByteDance Inc.
  3. *
  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
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  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.
  15. */
  16. package abi
  17. import (
  18. `fmt`
  19. `reflect`
  20. `unsafe`
  21. . `github.com/cloudwego/iasm/x86_64`
  22. )
  23. const (
  24. PtrSize = 8 // pointer size
  25. PtrAlign = 8 // pointer alignment
  26. )
  27. var iregOrderC = []Register{
  28. RDI,
  29. RSI,
  30. RDX,
  31. RCX,
  32. R8,
  33. R9,
  34. }
  35. var xregOrderC = []Register{
  36. XMM0,
  37. XMM1,
  38. XMM2,
  39. XMM3,
  40. XMM4,
  41. XMM5,
  42. XMM6,
  43. XMM7,
  44. }
  45. var (
  46. intType = reflect.TypeOf(0)
  47. ptrType = reflect.TypeOf(unsafe.Pointer(nil))
  48. )
  49. func (self *Frame) argv(i int) *MemoryOperand {
  50. return Ptr(RSP, int32(self.Prev() + self.desc.Args[i].Mem))
  51. }
  52. // spillv is used for growstack spill registers
  53. func (self *Frame) spillv(i int) *MemoryOperand {
  54. // remain one slot for caller return pc
  55. return Ptr(RSP, PtrSize + int32(self.desc.Args[i].Mem))
  56. }
  57. func (self *Frame) retv(i int) *MemoryOperand {
  58. return Ptr(RSP, int32(self.Prev() + self.desc.Rets[i].Mem))
  59. }
  60. func (self *Frame) resv(i int) *MemoryOperand {
  61. return Ptr(RSP, int32(self.Offs() - uint32((i+1) * PtrSize)))
  62. }
  63. func (self *Frame) emitGrowStack(p *Program, entry *Label) {
  64. // spill all register arguments
  65. for i, v := range self.desc.Args {
  66. if v.InRegister {
  67. if v.IsFloat == floatKind64 {
  68. p.MOVSD(v.Reg, self.spillv(i))
  69. } else if v.IsFloat == floatKind32 {
  70. p.MOVSS(v.Reg, self.spillv(i))
  71. }else {
  72. p.MOVQ(v.Reg, self.spillv(i))
  73. }
  74. }
  75. }
  76. // call runtime.morestack_noctxt
  77. p.MOVQ(F_morestack_noctxt, R12)
  78. p.CALLQ(R12)
  79. // load all register arguments
  80. for i, v := range self.desc.Args {
  81. if v.InRegister {
  82. if v.IsFloat == floatKind64 {
  83. p.MOVSD(self.spillv(i), v.Reg)
  84. } else if v.IsFloat == floatKind32 {
  85. p.MOVSS(self.spillv(i), v.Reg)
  86. }else {
  87. p.MOVQ(self.spillv(i), v.Reg)
  88. }
  89. }
  90. }
  91. // jump back to the function entry
  92. p.JMP(entry)
  93. }
  94. func (self *Frame) GrowStackTextSize() uint32 {
  95. p := DefaultArch.CreateProgram()
  96. // spill all register arguments
  97. for i, v := range self.desc.Args {
  98. if v.InRegister {
  99. if v.IsFloat == floatKind64 {
  100. p.MOVSD(v.Reg, self.spillv(i))
  101. } else if v.IsFloat == floatKind32 {
  102. p.MOVSS(v.Reg, self.spillv(i))
  103. }else {
  104. p.MOVQ(v.Reg, self.spillv(i))
  105. }
  106. }
  107. }
  108. // call runtime.morestack_noctxt
  109. p.MOVQ(F_morestack_noctxt, R12)
  110. p.CALLQ(R12)
  111. // load all register arguments
  112. for i, v := range self.desc.Args {
  113. if v.InRegister {
  114. if v.IsFloat == floatKind64 {
  115. p.MOVSD(self.spillv(i), v.Reg)
  116. } else if v.IsFloat == floatKind32 {
  117. p.MOVSS(self.spillv(i), v.Reg)
  118. } else {
  119. p.MOVQ(self.spillv(i), v.Reg)
  120. }
  121. }
  122. }
  123. // jump back to the function entry
  124. l := CreateLabel("")
  125. p.Link(l)
  126. p.JMP(l)
  127. return uint32(len(p.Assemble(0)))
  128. }
  129. func (self *Frame) emitPrologue(p *Program) {
  130. p.SUBQ(self.Size(), RSP)
  131. p.MOVQ(RBP, Ptr(RSP, int32(self.Offs())))
  132. p.LEAQ(Ptr(RSP, int32(self.Offs())), RBP)
  133. }
  134. func (self *Frame) emitEpilogue(p *Program) {
  135. p.MOVQ(Ptr(RSP, int32(self.Offs())), RBP)
  136. p.ADDQ(self.Size(), RSP)
  137. p.RET()
  138. }
  139. func (self *Frame) emitReserveRegs(p *Program) {
  140. // spill reserved registers
  141. for i, r := range ReservedRegs(self.ccall) {
  142. switch r.(type) {
  143. case Register64:
  144. p.MOVQ(r, self.resv(i))
  145. case XMMRegister:
  146. p.MOVSD(r, self.resv(i))
  147. default:
  148. panic(fmt.Sprintf("unsupported register type %t to reserve", r))
  149. }
  150. }
  151. }
  152. func (self *Frame) emitSpillPtrs(p *Program) {
  153. // spill pointer argument registers
  154. for i, r := range self.desc.Args {
  155. if r.InRegister && r.IsPointer {
  156. p.MOVQ(r.Reg, self.argv(i))
  157. }
  158. }
  159. }
  160. func (self *Frame) emitClearPtrs(p *Program) {
  161. // spill pointer argument registers
  162. for i, r := range self.desc.Args {
  163. if r.InRegister && r.IsPointer {
  164. p.MOVQ(int64(0), self.argv(i))
  165. }
  166. }
  167. }
  168. func (self *Frame) emitCallC(p *Program, addr uintptr) {
  169. p.MOVQ(addr, RAX)
  170. p.CALLQ(RAX)
  171. }
  172. type floatKind uint8
  173. const (
  174. notFloatKind floatKind = iota
  175. floatKind32
  176. floatKind64
  177. )
  178. type Parameter struct {
  179. InRegister bool
  180. IsPointer bool
  181. IsFloat floatKind
  182. Reg Register
  183. Mem uint32
  184. Type reflect.Type
  185. }
  186. func mkIReg(vt reflect.Type, reg Register64) (p Parameter) {
  187. p.Reg = reg
  188. p.Type = vt
  189. p.InRegister = true
  190. p.IsPointer = isPointer(vt)
  191. return
  192. }
  193. func isFloat(vt reflect.Type) floatKind {
  194. switch vt.Kind() {
  195. case reflect.Float32:
  196. return floatKind32
  197. case reflect.Float64:
  198. return floatKind64
  199. default:
  200. return notFloatKind
  201. }
  202. }
  203. func mkXReg(vt reflect.Type, reg XMMRegister) (p Parameter) {
  204. p.Reg = reg
  205. p.Type = vt
  206. p.InRegister = true
  207. p.IsFloat = isFloat(vt)
  208. return
  209. }
  210. func mkStack(vt reflect.Type, mem uint32) (p Parameter) {
  211. p.Mem = mem
  212. p.Type = vt
  213. p.InRegister = false
  214. p.IsPointer = isPointer(vt)
  215. p.IsFloat = isFloat(vt)
  216. return
  217. }
  218. func (self Parameter) String() string {
  219. if self.InRegister {
  220. return fmt.Sprintf("[%%%s, Pointer(%v), Float(%v)]", self.Reg, self.IsPointer, self.IsFloat)
  221. } else {
  222. return fmt.Sprintf("[%d(FP), Pointer(%v), Float(%v)]", self.Mem, self.IsPointer, self.IsFloat)
  223. }
  224. }
  225. func CallC(addr uintptr, fr Frame, maxStack uintptr) []byte {
  226. p := DefaultArch.CreateProgram()
  227. stack := CreateLabel("_stack_grow")
  228. entry := CreateLabel("_entry")
  229. p.Link(entry)
  230. fr.emitStackCheck(p, stack, maxStack)
  231. fr.emitPrologue(p)
  232. fr.emitReserveRegs(p)
  233. fr.emitSpillPtrs(p)
  234. fr.emitExchangeArgs(p)
  235. fr.emitCallC(p, addr)
  236. fr.emitExchangeRets(p)
  237. fr.emitRestoreRegs(p)
  238. fr.emitEpilogue(p)
  239. p.Link(stack)
  240. fr.emitGrowStack(p, entry)
  241. return p.Assemble(0)
  242. }
  243. func (self *Frame) emitDebug(p *Program) {
  244. p.INT(3)
  245. }