obj7.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998
  1. // cmd/7l/noop.c, cmd/7l/obj.c, cmd/ld/pass.c from Vita Nuova.
  2. // https://code.google.com/p/ken-cc/source/browse/
  3. //
  4. // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
  5. // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
  6. // Portions Copyright © 1997-1999 Vita Nuova Limited
  7. // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
  8. // Portions Copyright © 2004,2006 Bruce Ellis
  9. // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
  10. // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
  11. // Portions Copyright © 2009 The Go Authors. All rights reserved.
  12. //
  13. // Permission is hereby granted, free of charge, to any person obtaining a copy
  14. // of this software and associated documentation files (the "Software"), to deal
  15. // in the Software without restriction, including without limitation the rights
  16. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  17. // copies of the Software, and to permit persons to whom the Software is
  18. // furnished to do so, subject to the following conditions:
  19. //
  20. // The above copyright notice and this permission notice shall be included in
  21. // all copies or substantial portions of the Software.
  22. //
  23. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  24. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  25. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  26. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  27. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  28. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  29. // THE SOFTWARE.
  30. package arm64
  31. import (
  32. "github.com/twitchyliquid64/golang-asm/obj"
  33. "github.com/twitchyliquid64/golang-asm/objabi"
  34. "github.com/twitchyliquid64/golang-asm/src"
  35. "github.com/twitchyliquid64/golang-asm/sys"
  36. "math"
  37. )
  38. var complements = []obj.As{
  39. AADD: ASUB,
  40. AADDW: ASUBW,
  41. ASUB: AADD,
  42. ASUBW: AADDW,
  43. ACMP: ACMN,
  44. ACMPW: ACMNW,
  45. ACMN: ACMP,
  46. ACMNW: ACMPW,
  47. }
  48. func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
  49. // MOV g_stackguard(g), R1
  50. p = obj.Appendp(p, c.newprog)
  51. p.As = AMOVD
  52. p.From.Type = obj.TYPE_MEM
  53. p.From.Reg = REGG
  54. p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
  55. if c.cursym.CFunc() {
  56. p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
  57. }
  58. p.To.Type = obj.TYPE_REG
  59. p.To.Reg = REG_R1
  60. // Mark the stack bound check and morestack call async nonpreemptible.
  61. // If we get preempted here, when resumed the preemption request is
  62. // cleared, but we'll still call morestack, which will double the stack
  63. // unnecessarily. See issue #35470.
  64. p = c.ctxt.StartUnsafePoint(p, c.newprog)
  65. q := (*obj.Prog)(nil)
  66. if framesize <= objabi.StackSmall {
  67. // small stack: SP < stackguard
  68. // MOV SP, R2
  69. // CMP stackguard, R2
  70. p = obj.Appendp(p, c.newprog)
  71. p.As = AMOVD
  72. p.From.Type = obj.TYPE_REG
  73. p.From.Reg = REGSP
  74. p.To.Type = obj.TYPE_REG
  75. p.To.Reg = REG_R2
  76. p = obj.Appendp(p, c.newprog)
  77. p.As = ACMP
  78. p.From.Type = obj.TYPE_REG
  79. p.From.Reg = REG_R1
  80. p.Reg = REG_R2
  81. } else if framesize <= objabi.StackBig {
  82. // large stack: SP-framesize < stackguard-StackSmall
  83. // SUB $(framesize-StackSmall), SP, R2
  84. // CMP stackguard, R2
  85. p = obj.Appendp(p, c.newprog)
  86. p.As = ASUB
  87. p.From.Type = obj.TYPE_CONST
  88. p.From.Offset = int64(framesize) - objabi.StackSmall
  89. p.Reg = REGSP
  90. p.To.Type = obj.TYPE_REG
  91. p.To.Reg = REG_R2
  92. p = obj.Appendp(p, c.newprog)
  93. p.As = ACMP
  94. p.From.Type = obj.TYPE_REG
  95. p.From.Reg = REG_R1
  96. p.Reg = REG_R2
  97. } else {
  98. // Such a large stack we need to protect against wraparound
  99. // if SP is close to zero.
  100. // SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall)
  101. // The +StackGuard on both sides is required to keep the left side positive:
  102. // SP is allowed to be slightly below stackguard. See stack.h.
  103. // CMP $StackPreempt, R1
  104. // BEQ label_of_call_to_morestack
  105. // ADD $StackGuard, SP, R2
  106. // SUB R1, R2
  107. // MOV $(framesize+(StackGuard-StackSmall)), R3
  108. // CMP R3, R2
  109. p = obj.Appendp(p, c.newprog)
  110. p.As = ACMP
  111. p.From.Type = obj.TYPE_CONST
  112. p.From.Offset = objabi.StackPreempt
  113. p.Reg = REG_R1
  114. p = obj.Appendp(p, c.newprog)
  115. q = p
  116. p.As = ABEQ
  117. p.To.Type = obj.TYPE_BRANCH
  118. p = obj.Appendp(p, c.newprog)
  119. p.As = AADD
  120. p.From.Type = obj.TYPE_CONST
  121. p.From.Offset = int64(objabi.StackGuard)
  122. p.Reg = REGSP
  123. p.To.Type = obj.TYPE_REG
  124. p.To.Reg = REG_R2
  125. p = obj.Appendp(p, c.newprog)
  126. p.As = ASUB
  127. p.From.Type = obj.TYPE_REG
  128. p.From.Reg = REG_R1
  129. p.To.Type = obj.TYPE_REG
  130. p.To.Reg = REG_R2
  131. p = obj.Appendp(p, c.newprog)
  132. p.As = AMOVD
  133. p.From.Type = obj.TYPE_CONST
  134. p.From.Offset = int64(framesize) + (int64(objabi.StackGuard) - objabi.StackSmall)
  135. p.To.Type = obj.TYPE_REG
  136. p.To.Reg = REG_R3
  137. p = obj.Appendp(p, c.newprog)
  138. p.As = ACMP
  139. p.From.Type = obj.TYPE_REG
  140. p.From.Reg = REG_R3
  141. p.Reg = REG_R2
  142. }
  143. // BLS do-morestack
  144. bls := obj.Appendp(p, c.newprog)
  145. bls.As = ABLS
  146. bls.To.Type = obj.TYPE_BRANCH
  147. end := c.ctxt.EndUnsafePoint(bls, c.newprog, -1)
  148. var last *obj.Prog
  149. for last = c.cursym.Func.Text; last.Link != nil; last = last.Link {
  150. }
  151. // Now we are at the end of the function, but logically
  152. // we are still in function prologue. We need to fix the
  153. // SP data and PCDATA.
  154. spfix := obj.Appendp(last, c.newprog)
  155. spfix.As = obj.ANOP
  156. spfix.Spadj = -framesize
  157. pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
  158. pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
  159. // MOV LR, R3
  160. movlr := obj.Appendp(pcdata, c.newprog)
  161. movlr.As = AMOVD
  162. movlr.From.Type = obj.TYPE_REG
  163. movlr.From.Reg = REGLINK
  164. movlr.To.Type = obj.TYPE_REG
  165. movlr.To.Reg = REG_R3
  166. if q != nil {
  167. q.To.SetTarget(movlr)
  168. }
  169. bls.To.SetTarget(movlr)
  170. debug := movlr
  171. if false {
  172. debug = obj.Appendp(debug, c.newprog)
  173. debug.As = AMOVD
  174. debug.From.Type = obj.TYPE_CONST
  175. debug.From.Offset = int64(framesize)
  176. debug.To.Type = obj.TYPE_REG
  177. debug.To.Reg = REGTMP
  178. }
  179. // BL runtime.morestack(SB)
  180. call := obj.Appendp(debug, c.newprog)
  181. call.As = ABL
  182. call.To.Type = obj.TYPE_BRANCH
  183. morestack := "runtime.morestack"
  184. switch {
  185. case c.cursym.CFunc():
  186. morestack = "runtime.morestackc"
  187. case !c.cursym.Func.Text.From.Sym.NeedCtxt():
  188. morestack = "runtime.morestack_noctxt"
  189. }
  190. call.To.Sym = c.ctxt.Lookup(morestack)
  191. pcdata = c.ctxt.EndUnsafePoint(call, c.newprog, -1)
  192. // B start
  193. jmp := obj.Appendp(pcdata, c.newprog)
  194. jmp.As = AB
  195. jmp.To.Type = obj.TYPE_BRANCH
  196. jmp.To.SetTarget(c.cursym.Func.Text.Link)
  197. jmp.Spadj = +framesize
  198. return end
  199. }
  200. func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
  201. c := ctxt7{ctxt: ctxt, newprog: newprog}
  202. p.From.Class = 0
  203. p.To.Class = 0
  204. // $0 results in C_ZCON, which matches both C_REG and various
  205. // C_xCON, however the C_REG cases in asmout don't expect a
  206. // constant, so they will use the register fields and assemble
  207. // a R0. To prevent that, rewrite $0 as ZR.
  208. if p.From.Type == obj.TYPE_CONST && p.From.Offset == 0 {
  209. p.From.Type = obj.TYPE_REG
  210. p.From.Reg = REGZERO
  211. }
  212. if p.To.Type == obj.TYPE_CONST && p.To.Offset == 0 {
  213. p.To.Type = obj.TYPE_REG
  214. p.To.Reg = REGZERO
  215. }
  216. // Rewrite BR/BL to symbol as TYPE_BRANCH.
  217. switch p.As {
  218. case AB,
  219. ABL,
  220. obj.ARET,
  221. obj.ADUFFZERO,
  222. obj.ADUFFCOPY:
  223. if p.To.Sym != nil {
  224. p.To.Type = obj.TYPE_BRANCH
  225. }
  226. break
  227. }
  228. // Rewrite float constants to values stored in memory.
  229. switch p.As {
  230. case AFMOVS:
  231. if p.From.Type == obj.TYPE_FCONST {
  232. f64 := p.From.Val.(float64)
  233. f32 := float32(f64)
  234. if c.chipfloat7(f64) > 0 {
  235. break
  236. }
  237. if math.Float32bits(f32) == 0 {
  238. p.From.Type = obj.TYPE_REG
  239. p.From.Reg = REGZERO
  240. break
  241. }
  242. p.From.Type = obj.TYPE_MEM
  243. p.From.Sym = c.ctxt.Float32Sym(f32)
  244. p.From.Name = obj.NAME_EXTERN
  245. p.From.Offset = 0
  246. }
  247. case AFMOVD:
  248. if p.From.Type == obj.TYPE_FCONST {
  249. f64 := p.From.Val.(float64)
  250. if c.chipfloat7(f64) > 0 {
  251. break
  252. }
  253. if math.Float64bits(f64) == 0 {
  254. p.From.Type = obj.TYPE_REG
  255. p.From.Reg = REGZERO
  256. break
  257. }
  258. p.From.Type = obj.TYPE_MEM
  259. p.From.Sym = c.ctxt.Float64Sym(f64)
  260. p.From.Name = obj.NAME_EXTERN
  261. p.From.Offset = 0
  262. }
  263. break
  264. }
  265. // Rewrite negative immediates as positive immediates with
  266. // complementary instruction.
  267. switch p.As {
  268. case AADD, ASUB, ACMP, ACMN:
  269. if p.From.Type == obj.TYPE_CONST && p.From.Offset < 0 && p.From.Offset != -1<<63 {
  270. p.From.Offset = -p.From.Offset
  271. p.As = complements[p.As]
  272. }
  273. case AADDW, ASUBW, ACMPW, ACMNW:
  274. if p.From.Type == obj.TYPE_CONST && p.From.Offset < 0 && int32(p.From.Offset) != -1<<31 {
  275. p.From.Offset = -p.From.Offset
  276. p.As = complements[p.As]
  277. }
  278. }
  279. // For 32-bit logical instruction with constant,
  280. // rewrite the high 32-bit to be a repetition of
  281. // the low 32-bit, so that the BITCON test can be
  282. // shared for both 32-bit and 64-bit. 32-bit ops
  283. // will zero the high 32-bit of the destination
  284. // register anyway.
  285. if isANDWop(p.As) && p.From.Type == obj.TYPE_CONST {
  286. v := p.From.Offset & 0xffffffff
  287. p.From.Offset = v | v<<32
  288. }
  289. if c.ctxt.Flag_dynlink {
  290. c.rewriteToUseGot(p)
  291. }
  292. }
  293. // Rewrite p, if necessary, to access global data via the global offset table.
  294. func (c *ctxt7) rewriteToUseGot(p *obj.Prog) {
  295. if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
  296. // ADUFFxxx $offset
  297. // becomes
  298. // MOVD runtime.duffxxx@GOT, REGTMP
  299. // ADD $offset, REGTMP
  300. // CALL REGTMP
  301. var sym *obj.LSym
  302. if p.As == obj.ADUFFZERO {
  303. sym = c.ctxt.Lookup("runtime.duffzero")
  304. } else {
  305. sym = c.ctxt.Lookup("runtime.duffcopy")
  306. }
  307. offset := p.To.Offset
  308. p.As = AMOVD
  309. p.From.Type = obj.TYPE_MEM
  310. p.From.Name = obj.NAME_GOTREF
  311. p.From.Sym = sym
  312. p.To.Type = obj.TYPE_REG
  313. p.To.Reg = REGTMP
  314. p.To.Name = obj.NAME_NONE
  315. p.To.Offset = 0
  316. p.To.Sym = nil
  317. p1 := obj.Appendp(p, c.newprog)
  318. p1.As = AADD
  319. p1.From.Type = obj.TYPE_CONST
  320. p1.From.Offset = offset
  321. p1.To.Type = obj.TYPE_REG
  322. p1.To.Reg = REGTMP
  323. p2 := obj.Appendp(p1, c.newprog)
  324. p2.As = obj.ACALL
  325. p2.To.Type = obj.TYPE_REG
  326. p2.To.Reg = REGTMP
  327. }
  328. // We only care about global data: NAME_EXTERN means a global
  329. // symbol in the Go sense, and p.Sym.Local is true for a few
  330. // internally defined symbols.
  331. if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
  332. // MOVD $sym, Rx becomes MOVD sym@GOT, Rx
  333. // MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx; ADD <off>, Rx
  334. if p.As != AMOVD {
  335. c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
  336. }
  337. if p.To.Type != obj.TYPE_REG {
  338. c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
  339. }
  340. p.From.Type = obj.TYPE_MEM
  341. p.From.Name = obj.NAME_GOTREF
  342. if p.From.Offset != 0 {
  343. q := obj.Appendp(p, c.newprog)
  344. q.As = AADD
  345. q.From.Type = obj.TYPE_CONST
  346. q.From.Offset = p.From.Offset
  347. q.To = p.To
  348. p.From.Offset = 0
  349. }
  350. }
  351. if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
  352. c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
  353. }
  354. var source *obj.Addr
  355. // MOVx sym, Ry becomes MOVD sym@GOT, REGTMP; MOVx (REGTMP), Ry
  356. // MOVx Ry, sym becomes MOVD sym@GOT, REGTMP; MOVD Ry, (REGTMP)
  357. // An addition may be inserted between the two MOVs if there is an offset.
  358. if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
  359. if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
  360. c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
  361. }
  362. source = &p.From
  363. } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
  364. source = &p.To
  365. } else {
  366. return
  367. }
  368. if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
  369. return
  370. }
  371. if source.Sym.Type == objabi.STLSBSS {
  372. return
  373. }
  374. if source.Type != obj.TYPE_MEM {
  375. c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
  376. }
  377. p1 := obj.Appendp(p, c.newprog)
  378. p2 := obj.Appendp(p1, c.newprog)
  379. p1.As = AMOVD
  380. p1.From.Type = obj.TYPE_MEM
  381. p1.From.Sym = source.Sym
  382. p1.From.Name = obj.NAME_GOTREF
  383. p1.To.Type = obj.TYPE_REG
  384. p1.To.Reg = REGTMP
  385. p2.As = p.As
  386. p2.From = p.From
  387. p2.To = p.To
  388. if p.From.Name == obj.NAME_EXTERN {
  389. p2.From.Reg = REGTMP
  390. p2.From.Name = obj.NAME_NONE
  391. p2.From.Sym = nil
  392. } else if p.To.Name == obj.NAME_EXTERN {
  393. p2.To.Reg = REGTMP
  394. p2.To.Name = obj.NAME_NONE
  395. p2.To.Sym = nil
  396. } else {
  397. return
  398. }
  399. obj.Nopout(p)
  400. }
  401. func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
  402. if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
  403. return
  404. }
  405. c := ctxt7{ctxt: ctxt, newprog: newprog, cursym: cursym}
  406. p := c.cursym.Func.Text
  407. textstksiz := p.To.Offset
  408. if textstksiz == -8 {
  409. // Historical way to mark NOFRAME.
  410. p.From.Sym.Set(obj.AttrNoFrame, true)
  411. textstksiz = 0
  412. }
  413. if textstksiz < 0 {
  414. c.ctxt.Diag("negative frame size %d - did you mean NOFRAME?", textstksiz)
  415. }
  416. if p.From.Sym.NoFrame() {
  417. if textstksiz != 0 {
  418. c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
  419. }
  420. }
  421. c.cursym.Func.Args = p.To.Val.(int32)
  422. c.cursym.Func.Locals = int32(textstksiz)
  423. /*
  424. * find leaf subroutines
  425. */
  426. for p := c.cursym.Func.Text; p != nil; p = p.Link {
  427. switch p.As {
  428. case obj.ATEXT:
  429. p.Mark |= LEAF
  430. case ABL,
  431. obj.ADUFFZERO,
  432. obj.ADUFFCOPY:
  433. c.cursym.Func.Text.Mark &^= LEAF
  434. }
  435. }
  436. var q *obj.Prog
  437. var q1 *obj.Prog
  438. var retjmp *obj.LSym
  439. for p := c.cursym.Func.Text; p != nil; p = p.Link {
  440. o := p.As
  441. switch o {
  442. case obj.ATEXT:
  443. c.cursym.Func.Text = p
  444. c.autosize = int32(textstksiz)
  445. if p.Mark&LEAF != 0 && c.autosize == 0 {
  446. // A leaf function with no locals has no frame.
  447. p.From.Sym.Set(obj.AttrNoFrame, true)
  448. }
  449. if !p.From.Sym.NoFrame() {
  450. // If there is a stack frame at all, it includes
  451. // space to save the LR.
  452. c.autosize += 8
  453. }
  454. if c.autosize != 0 {
  455. extrasize := int32(0)
  456. if c.autosize%16 == 8 {
  457. // Allocate extra 8 bytes on the frame top to save FP
  458. extrasize = 8
  459. } else if c.autosize&(16-1) == 0 {
  460. // Allocate extra 16 bytes to save FP for the old frame whose size is 8 mod 16
  461. extrasize = 16
  462. } else {
  463. c.ctxt.Diag("%v: unaligned frame size %d - must be 16 aligned", p, c.autosize-8)
  464. }
  465. c.autosize += extrasize
  466. c.cursym.Func.Locals += extrasize
  467. // low 32 bits for autosize
  468. // high 32 bits for extrasize
  469. p.To.Offset = int64(c.autosize) | int64(extrasize)<<32
  470. } else {
  471. // NOFRAME
  472. p.To.Offset = 0
  473. }
  474. if c.autosize == 0 && c.cursym.Func.Text.Mark&LEAF == 0 {
  475. if c.ctxt.Debugvlog {
  476. c.ctxt.Logf("save suppressed in: %s\n", c.cursym.Func.Text.From.Sym.Name)
  477. }
  478. c.cursym.Func.Text.Mark |= LEAF
  479. }
  480. if cursym.Func.Text.Mark&LEAF != 0 {
  481. cursym.Set(obj.AttrLeaf, true)
  482. if p.From.Sym.NoFrame() {
  483. break
  484. }
  485. }
  486. if !p.From.Sym.NoSplit() {
  487. p = c.stacksplit(p, c.autosize) // emit split check
  488. }
  489. var prologueEnd *obj.Prog
  490. aoffset := c.autosize
  491. if aoffset > 0xF0 {
  492. aoffset = 0xF0
  493. }
  494. // Frame is non-empty. Make sure to save link register, even if
  495. // it is a leaf function, so that traceback works.
  496. q = p
  497. if c.autosize > aoffset {
  498. // Frame size is too large for a MOVD.W instruction.
  499. // Store link register before decrementing SP, so if a signal comes
  500. // during the execution of the function prologue, the traceback
  501. // code will not see a half-updated stack frame.
  502. // This sequence is not async preemptible, as if we open a frame
  503. // at the current SP, it will clobber the saved LR.
  504. q = c.ctxt.StartUnsafePoint(q, c.newprog)
  505. q = obj.Appendp(q, c.newprog)
  506. q.Pos = p.Pos
  507. q.As = ASUB
  508. q.From.Type = obj.TYPE_CONST
  509. q.From.Offset = int64(c.autosize)
  510. q.Reg = REGSP
  511. q.To.Type = obj.TYPE_REG
  512. q.To.Reg = REGTMP
  513. prologueEnd = q
  514. q = obj.Appendp(q, c.newprog)
  515. q.Pos = p.Pos
  516. q.As = AMOVD
  517. q.From.Type = obj.TYPE_REG
  518. q.From.Reg = REGLINK
  519. q.To.Type = obj.TYPE_MEM
  520. q.To.Reg = REGTMP
  521. q1 = obj.Appendp(q, c.newprog)
  522. q1.Pos = p.Pos
  523. q1.As = AMOVD
  524. q1.From.Type = obj.TYPE_REG
  525. q1.From.Reg = REGTMP
  526. q1.To.Type = obj.TYPE_REG
  527. q1.To.Reg = REGSP
  528. q1.Spadj = c.autosize
  529. if c.ctxt.Headtype == objabi.Hdarwin {
  530. // iOS does not support SA_ONSTACK. We will run the signal handler
  531. // on the G stack. If we write below SP, it may be clobbered by
  532. // the signal handler. So we save LR after decrementing SP.
  533. q1 = obj.Appendp(q1, c.newprog)
  534. q1.Pos = p.Pos
  535. q1.As = AMOVD
  536. q1.From.Type = obj.TYPE_REG
  537. q1.From.Reg = REGLINK
  538. q1.To.Type = obj.TYPE_MEM
  539. q1.To.Reg = REGSP
  540. }
  541. q1 = c.ctxt.EndUnsafePoint(q1, c.newprog, -1)
  542. } else {
  543. // small frame, update SP and save LR in a single MOVD.W instruction
  544. q1 = obj.Appendp(q, c.newprog)
  545. q1.As = AMOVD
  546. q1.Pos = p.Pos
  547. q1.From.Type = obj.TYPE_REG
  548. q1.From.Reg = REGLINK
  549. q1.To.Type = obj.TYPE_MEM
  550. q1.Scond = C_XPRE
  551. q1.To.Offset = int64(-aoffset)
  552. q1.To.Reg = REGSP
  553. q1.Spadj = aoffset
  554. prologueEnd = q1
  555. }
  556. prologueEnd.Pos = prologueEnd.Pos.WithXlogue(src.PosPrologueEnd)
  557. if objabi.Framepointer_enabled {
  558. q1 = obj.Appendp(q1, c.newprog)
  559. q1.Pos = p.Pos
  560. q1.As = AMOVD
  561. q1.From.Type = obj.TYPE_REG
  562. q1.From.Reg = REGFP
  563. q1.To.Type = obj.TYPE_MEM
  564. q1.To.Reg = REGSP
  565. q1.To.Offset = -8
  566. q1 = obj.Appendp(q1, c.newprog)
  567. q1.Pos = p.Pos
  568. q1.As = ASUB
  569. q1.From.Type = obj.TYPE_CONST
  570. q1.From.Offset = 8
  571. q1.Reg = REGSP
  572. q1.To.Type = obj.TYPE_REG
  573. q1.To.Reg = REGFP
  574. }
  575. if c.cursym.Func.Text.From.Sym.Wrapper() {
  576. // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
  577. //
  578. // MOV g_panic(g), R1
  579. // CBNZ checkargp
  580. // end:
  581. // NOP
  582. // ... function body ...
  583. // checkargp:
  584. // MOV panic_argp(R1), R2
  585. // ADD $(autosize+8), RSP, R3
  586. // CMP R2, R3
  587. // BNE end
  588. // ADD $8, RSP, R4
  589. // MOVD R4, panic_argp(R1)
  590. // B end
  591. //
  592. // The NOP is needed to give the jumps somewhere to land.
  593. // It is a liblink NOP, not an ARM64 NOP: it encodes to 0 instruction bytes.
  594. q = q1
  595. // MOV g_panic(g), R1
  596. q = obj.Appendp(q, c.newprog)
  597. q.As = AMOVD
  598. q.From.Type = obj.TYPE_MEM
  599. q.From.Reg = REGG
  600. q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
  601. q.To.Type = obj.TYPE_REG
  602. q.To.Reg = REG_R1
  603. // CBNZ R1, checkargp
  604. cbnz := obj.Appendp(q, c.newprog)
  605. cbnz.As = ACBNZ
  606. cbnz.From.Type = obj.TYPE_REG
  607. cbnz.From.Reg = REG_R1
  608. cbnz.To.Type = obj.TYPE_BRANCH
  609. // Empty branch target at the top of the function body
  610. end := obj.Appendp(cbnz, c.newprog)
  611. end.As = obj.ANOP
  612. // find the end of the function
  613. var last *obj.Prog
  614. for last = end; last.Link != nil; last = last.Link {
  615. }
  616. // MOV panic_argp(R1), R2
  617. mov := obj.Appendp(last, c.newprog)
  618. mov.As = AMOVD
  619. mov.From.Type = obj.TYPE_MEM
  620. mov.From.Reg = REG_R1
  621. mov.From.Offset = 0 // Panic.argp
  622. mov.To.Type = obj.TYPE_REG
  623. mov.To.Reg = REG_R2
  624. // CBNZ branches to the MOV above
  625. cbnz.To.SetTarget(mov)
  626. // ADD $(autosize+8), SP, R3
  627. q = obj.Appendp(mov, c.newprog)
  628. q.As = AADD
  629. q.From.Type = obj.TYPE_CONST
  630. q.From.Offset = int64(c.autosize) + 8
  631. q.Reg = REGSP
  632. q.To.Type = obj.TYPE_REG
  633. q.To.Reg = REG_R3
  634. // CMP R2, R3
  635. q = obj.Appendp(q, c.newprog)
  636. q.As = ACMP
  637. q.From.Type = obj.TYPE_REG
  638. q.From.Reg = REG_R2
  639. q.Reg = REG_R3
  640. // BNE end
  641. q = obj.Appendp(q, c.newprog)
  642. q.As = ABNE
  643. q.To.Type = obj.TYPE_BRANCH
  644. q.To.SetTarget(end)
  645. // ADD $8, SP, R4
  646. q = obj.Appendp(q, c.newprog)
  647. q.As = AADD
  648. q.From.Type = obj.TYPE_CONST
  649. q.From.Offset = 8
  650. q.Reg = REGSP
  651. q.To.Type = obj.TYPE_REG
  652. q.To.Reg = REG_R4
  653. // MOV R4, panic_argp(R1)
  654. q = obj.Appendp(q, c.newprog)
  655. q.As = AMOVD
  656. q.From.Type = obj.TYPE_REG
  657. q.From.Reg = REG_R4
  658. q.To.Type = obj.TYPE_MEM
  659. q.To.Reg = REG_R1
  660. q.To.Offset = 0 // Panic.argp
  661. // B end
  662. q = obj.Appendp(q, c.newprog)
  663. q.As = AB
  664. q.To.Type = obj.TYPE_BRANCH
  665. q.To.SetTarget(end)
  666. }
  667. case obj.ARET:
  668. nocache(p)
  669. if p.From.Type == obj.TYPE_CONST {
  670. c.ctxt.Diag("using BECOME (%v) is not supported!", p)
  671. break
  672. }
  673. retjmp = p.To.Sym
  674. p.To = obj.Addr{}
  675. if c.cursym.Func.Text.Mark&LEAF != 0 {
  676. if c.autosize != 0 {
  677. p.As = AADD
  678. p.From.Type = obj.TYPE_CONST
  679. p.From.Offset = int64(c.autosize)
  680. p.To.Type = obj.TYPE_REG
  681. p.To.Reg = REGSP
  682. p.Spadj = -c.autosize
  683. if objabi.Framepointer_enabled {
  684. p = obj.Appendp(p, c.newprog)
  685. p.As = ASUB
  686. p.From.Type = obj.TYPE_CONST
  687. p.From.Offset = 8
  688. p.Reg = REGSP
  689. p.To.Type = obj.TYPE_REG
  690. p.To.Reg = REGFP
  691. }
  692. }
  693. } else {
  694. /* want write-back pre-indexed SP+autosize -> SP, loading REGLINK*/
  695. if objabi.Framepointer_enabled {
  696. p.As = AMOVD
  697. p.From.Type = obj.TYPE_MEM
  698. p.From.Reg = REGSP
  699. p.From.Offset = -8
  700. p.To.Type = obj.TYPE_REG
  701. p.To.Reg = REGFP
  702. p = obj.Appendp(p, c.newprog)
  703. }
  704. aoffset := c.autosize
  705. if aoffset <= 0xF0 {
  706. p.As = AMOVD
  707. p.From.Type = obj.TYPE_MEM
  708. p.Scond = C_XPOST
  709. p.From.Offset = int64(aoffset)
  710. p.From.Reg = REGSP
  711. p.To.Type = obj.TYPE_REG
  712. p.To.Reg = REGLINK
  713. p.Spadj = -aoffset
  714. } else {
  715. p.As = AMOVD
  716. p.From.Type = obj.TYPE_MEM
  717. p.From.Offset = 0
  718. p.From.Reg = REGSP
  719. p.To.Type = obj.TYPE_REG
  720. p.To.Reg = REGLINK
  721. q = newprog()
  722. q.As = AADD
  723. q.From.Type = obj.TYPE_CONST
  724. q.From.Offset = int64(aoffset)
  725. q.To.Type = obj.TYPE_REG
  726. q.To.Reg = REGSP
  727. q.Link = p.Link
  728. q.Spadj = int32(-q.From.Offset)
  729. q.Pos = p.Pos
  730. p.Link = q
  731. p = q
  732. }
  733. }
  734. if p.As != obj.ARET {
  735. q = newprog()
  736. q.Pos = p.Pos
  737. q.Link = p.Link
  738. p.Link = q
  739. p = q
  740. }
  741. if retjmp != nil { // retjmp
  742. p.As = AB
  743. p.To.Type = obj.TYPE_BRANCH
  744. p.To.Sym = retjmp
  745. p.Spadj = +c.autosize
  746. break
  747. }
  748. p.As = obj.ARET
  749. p.To.Type = obj.TYPE_MEM
  750. p.To.Offset = 0
  751. p.To.Reg = REGLINK
  752. p.Spadj = +c.autosize
  753. case AADD, ASUB:
  754. if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
  755. if p.As == AADD {
  756. p.Spadj = int32(-p.From.Offset)
  757. } else {
  758. p.Spadj = int32(+p.From.Offset)
  759. }
  760. }
  761. case obj.AGETCALLERPC:
  762. if cursym.Leaf() {
  763. /* MOVD LR, Rd */
  764. p.As = AMOVD
  765. p.From.Type = obj.TYPE_REG
  766. p.From.Reg = REGLINK
  767. } else {
  768. /* MOVD (RSP), Rd */
  769. p.As = AMOVD
  770. p.From.Type = obj.TYPE_MEM
  771. p.From.Reg = REGSP
  772. }
  773. case obj.ADUFFCOPY:
  774. if objabi.Framepointer_enabled {
  775. // ADR ret_addr, R27
  776. // STP (FP, R27), -24(SP)
  777. // SUB 24, SP, FP
  778. // DUFFCOPY
  779. // ret_addr:
  780. // SUB 8, SP, FP
  781. q1 := p
  782. // copy DUFFCOPY from q1 to q4
  783. q4 := obj.Appendp(p, c.newprog)
  784. q4.Pos = p.Pos
  785. q4.As = obj.ADUFFCOPY
  786. q4.To = p.To
  787. q1.As = AADR
  788. q1.From.Type = obj.TYPE_BRANCH
  789. q1.To.Type = obj.TYPE_REG
  790. q1.To.Reg = REG_R27
  791. q2 := obj.Appendp(q1, c.newprog)
  792. q2.Pos = p.Pos
  793. q2.As = ASTP
  794. q2.From.Type = obj.TYPE_REGREG
  795. q2.From.Reg = REGFP
  796. q2.From.Offset = int64(REG_R27)
  797. q2.To.Type = obj.TYPE_MEM
  798. q2.To.Reg = REGSP
  799. q2.To.Offset = -24
  800. // maintaine FP for DUFFCOPY
  801. q3 := obj.Appendp(q2, c.newprog)
  802. q3.Pos = p.Pos
  803. q3.As = ASUB
  804. q3.From.Type = obj.TYPE_CONST
  805. q3.From.Offset = 24
  806. q3.Reg = REGSP
  807. q3.To.Type = obj.TYPE_REG
  808. q3.To.Reg = REGFP
  809. q5 := obj.Appendp(q4, c.newprog)
  810. q5.Pos = p.Pos
  811. q5.As = ASUB
  812. q5.From.Type = obj.TYPE_CONST
  813. q5.From.Offset = 8
  814. q5.Reg = REGSP
  815. q5.To.Type = obj.TYPE_REG
  816. q5.To.Reg = REGFP
  817. q1.From.SetTarget(q5)
  818. p = q5
  819. }
  820. case obj.ADUFFZERO:
  821. if objabi.Framepointer_enabled {
  822. // ADR ret_addr, R27
  823. // STP (FP, R27), -24(SP)
  824. // SUB 24, SP, FP
  825. // DUFFZERO
  826. // ret_addr:
  827. // SUB 8, SP, FP
  828. q1 := p
  829. // copy DUFFZERO from q1 to q4
  830. q4 := obj.Appendp(p, c.newprog)
  831. q4.Pos = p.Pos
  832. q4.As = obj.ADUFFZERO
  833. q4.To = p.To
  834. q1.As = AADR
  835. q1.From.Type = obj.TYPE_BRANCH
  836. q1.To.Type = obj.TYPE_REG
  837. q1.To.Reg = REG_R27
  838. q2 := obj.Appendp(q1, c.newprog)
  839. q2.Pos = p.Pos
  840. q2.As = ASTP
  841. q2.From.Type = obj.TYPE_REGREG
  842. q2.From.Reg = REGFP
  843. q2.From.Offset = int64(REG_R27)
  844. q2.To.Type = obj.TYPE_MEM
  845. q2.To.Reg = REGSP
  846. q2.To.Offset = -24
  847. // maintaine FP for DUFFZERO
  848. q3 := obj.Appendp(q2, c.newprog)
  849. q3.Pos = p.Pos
  850. q3.As = ASUB
  851. q3.From.Type = obj.TYPE_CONST
  852. q3.From.Offset = 24
  853. q3.Reg = REGSP
  854. q3.To.Type = obj.TYPE_REG
  855. q3.To.Reg = REGFP
  856. q5 := obj.Appendp(q4, c.newprog)
  857. q5.Pos = p.Pos
  858. q5.As = ASUB
  859. q5.From.Type = obj.TYPE_CONST
  860. q5.From.Offset = 8
  861. q5.Reg = REGSP
  862. q5.To.Type = obj.TYPE_REG
  863. q5.To.Reg = REGFP
  864. q1.From.SetTarget(q5)
  865. p = q5
  866. }
  867. }
  868. }
  869. }
  870. func nocache(p *obj.Prog) {
  871. p.Optab = 0
  872. p.From.Class = 0
  873. p.To.Class = 0
  874. }
  875. var unaryDst = map[obj.As]bool{
  876. AWORD: true,
  877. ADWORD: true,
  878. ABL: true,
  879. AB: true,
  880. ACLREX: true,
  881. }
  882. var Linkarm64 = obj.LinkArch{
  883. Arch: sys.ArchARM64,
  884. Init: buildop,
  885. Preprocess: preprocess,
  886. Assemble: span7,
  887. Progedit: progedit,
  888. UnaryDst: unaryDst,
  889. DWARFRegisters: ARM64DWARFRegisters,
  890. }