obj9.go 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278
  1. // cmd/9l/noop.c, cmd/9l/pass.c, cmd/9l/span.c from Vita Nuova.
  2. //
  3. // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
  4. // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
  5. // Portions Copyright © 1997-1999 Vita Nuova Limited
  6. // Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
  7. // Portions Copyright © 2004,2006 Bruce Ellis
  8. // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
  9. // Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
  10. // Portions Copyright © 2009 The Go Authors. All rights reserved.
  11. //
  12. // Permission is hereby granted, free of charge, to any person obtaining a copy
  13. // of this software and associated documentation files (the "Software"), to deal
  14. // in the Software without restriction, including without limitation the rights
  15. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  16. // copies of the Software, and to permit persons to whom the Software is
  17. // furnished to do so, subject to the following conditions:
  18. //
  19. // The above copyright notice and this permission notice shall be included in
  20. // all copies or substantial portions of the Software.
  21. //
  22. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  23. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  24. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  25. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  26. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  27. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  28. // THE SOFTWARE.
  29. package ppc64
  30. import (
  31. "github.com/twitchyliquid64/golang-asm/obj"
  32. "github.com/twitchyliquid64/golang-asm/objabi"
  33. "github.com/twitchyliquid64/golang-asm/sys"
  34. )
  35. func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
  36. p.From.Class = 0
  37. p.To.Class = 0
  38. c := ctxt9{ctxt: ctxt, newprog: newprog}
  39. // Rewrite BR/BL to symbol as TYPE_BRANCH.
  40. switch p.As {
  41. case ABR,
  42. ABL,
  43. obj.ARET,
  44. obj.ADUFFZERO,
  45. obj.ADUFFCOPY:
  46. if p.To.Sym != nil {
  47. p.To.Type = obj.TYPE_BRANCH
  48. }
  49. }
  50. // Rewrite float constants to values stored in memory.
  51. switch p.As {
  52. case AFMOVS:
  53. if p.From.Type == obj.TYPE_FCONST {
  54. f32 := float32(p.From.Val.(float64))
  55. p.From.Type = obj.TYPE_MEM
  56. p.From.Sym = ctxt.Float32Sym(f32)
  57. p.From.Name = obj.NAME_EXTERN
  58. p.From.Offset = 0
  59. }
  60. case AFMOVD:
  61. if p.From.Type == obj.TYPE_FCONST {
  62. f64 := p.From.Val.(float64)
  63. // Constant not needed in memory for float +/- 0
  64. if f64 != 0 {
  65. p.From.Type = obj.TYPE_MEM
  66. p.From.Sym = ctxt.Float64Sym(f64)
  67. p.From.Name = obj.NAME_EXTERN
  68. p.From.Offset = 0
  69. }
  70. }
  71. // Put >32-bit constants in memory and load them
  72. case AMOVD:
  73. if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == 0 && int64(int32(p.From.Offset)) != p.From.Offset {
  74. p.From.Type = obj.TYPE_MEM
  75. p.From.Sym = ctxt.Int64Sym(p.From.Offset)
  76. p.From.Name = obj.NAME_EXTERN
  77. p.From.Offset = 0
  78. }
  79. }
  80. // Rewrite SUB constants into ADD.
  81. switch p.As {
  82. case ASUBC:
  83. if p.From.Type == obj.TYPE_CONST {
  84. p.From.Offset = -p.From.Offset
  85. p.As = AADDC
  86. }
  87. case ASUBCCC:
  88. if p.From.Type == obj.TYPE_CONST {
  89. p.From.Offset = -p.From.Offset
  90. p.As = AADDCCC
  91. }
  92. case ASUB:
  93. if p.From.Type == obj.TYPE_CONST {
  94. p.From.Offset = -p.From.Offset
  95. p.As = AADD
  96. }
  97. }
  98. if c.ctxt.Headtype == objabi.Haix {
  99. c.rewriteToUseTOC(p)
  100. } else if c.ctxt.Flag_dynlink {
  101. c.rewriteToUseGot(p)
  102. }
  103. }
  104. // Rewrite p, if necessary, to access a symbol using its TOC anchor.
  105. // This code is for AIX only.
  106. func (c *ctxt9) rewriteToUseTOC(p *obj.Prog) {
  107. if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
  108. return
  109. }
  110. if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
  111. // ADUFFZERO/ADUFFCOPY is considered as an ABL except in dynamic
  112. // link where it should be an indirect call.
  113. if !c.ctxt.Flag_dynlink {
  114. return
  115. }
  116. // ADUFFxxx $offset
  117. // becomes
  118. // MOVD runtime.duffxxx@TOC, R12
  119. // ADD $offset, R12
  120. // MOVD R12, LR
  121. // BL (LR)
  122. var sym *obj.LSym
  123. if p.As == obj.ADUFFZERO {
  124. sym = c.ctxt.Lookup("runtime.duffzero")
  125. } else {
  126. sym = c.ctxt.Lookup("runtime.duffcopy")
  127. }
  128. // Retrieve or create the TOC anchor.
  129. symtoc := c.ctxt.LookupInit("TOC."+sym.Name, func(s *obj.LSym) {
  130. s.Type = objabi.SDATA
  131. s.Set(obj.AttrDuplicateOK, true)
  132. s.Set(obj.AttrStatic, true)
  133. c.ctxt.Data = append(c.ctxt.Data, s)
  134. s.WriteAddr(c.ctxt, 0, 8, sym, 0)
  135. })
  136. offset := p.To.Offset
  137. p.As = AMOVD
  138. p.From.Type = obj.TYPE_MEM
  139. p.From.Name = obj.NAME_TOCREF
  140. p.From.Sym = symtoc
  141. p.To.Type = obj.TYPE_REG
  142. p.To.Reg = REG_R12
  143. p.To.Name = obj.NAME_NONE
  144. p.To.Offset = 0
  145. p.To.Sym = nil
  146. p1 := obj.Appendp(p, c.newprog)
  147. p1.As = AADD
  148. p1.From.Type = obj.TYPE_CONST
  149. p1.From.Offset = offset
  150. p1.To.Type = obj.TYPE_REG
  151. p1.To.Reg = REG_R12
  152. p2 := obj.Appendp(p1, c.newprog)
  153. p2.As = AMOVD
  154. p2.From.Type = obj.TYPE_REG
  155. p2.From.Reg = REG_R12
  156. p2.To.Type = obj.TYPE_REG
  157. p2.To.Reg = REG_LR
  158. p3 := obj.Appendp(p2, c.newprog)
  159. p3.As = obj.ACALL
  160. p3.To.Type = obj.TYPE_REG
  161. p3.To.Reg = REG_LR
  162. }
  163. var source *obj.Addr
  164. if p.From.Name == obj.NAME_EXTERN || p.From.Name == obj.NAME_STATIC {
  165. if p.From.Type == obj.TYPE_ADDR {
  166. if p.As == ADWORD {
  167. // ADWORD $sym doesn't need TOC anchor
  168. return
  169. }
  170. if p.As != AMOVD {
  171. c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v", p)
  172. return
  173. }
  174. if p.To.Type != obj.TYPE_REG {
  175. c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v", p)
  176. return
  177. }
  178. } else if p.From.Type != obj.TYPE_MEM {
  179. c.ctxt.Diag("do not know how to handle %v without TYPE_MEM", p)
  180. return
  181. }
  182. source = &p.From
  183. } else if p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC {
  184. if p.To.Type != obj.TYPE_MEM {
  185. c.ctxt.Diag("do not know how to handle %v without TYPE_MEM", p)
  186. return
  187. }
  188. if source != nil {
  189. c.ctxt.Diag("cannot handle symbols on both sides in %v", p)
  190. return
  191. }
  192. source = &p.To
  193. } else {
  194. return
  195. }
  196. if source.Sym == nil {
  197. c.ctxt.Diag("do not know how to handle nil symbol in %v", p)
  198. return
  199. }
  200. if source.Sym.Type == objabi.STLSBSS {
  201. return
  202. }
  203. // Retrieve or create the TOC anchor.
  204. symtoc := c.ctxt.LookupInit("TOC."+source.Sym.Name, func(s *obj.LSym) {
  205. s.Type = objabi.SDATA
  206. s.Set(obj.AttrDuplicateOK, true)
  207. s.Set(obj.AttrStatic, true)
  208. c.ctxt.Data = append(c.ctxt.Data, s)
  209. s.WriteAddr(c.ctxt, 0, 8, source.Sym, 0)
  210. })
  211. if source.Type == obj.TYPE_ADDR {
  212. // MOVD $sym, Rx becomes MOVD symtoc, Rx
  213. // MOVD $sym+<off>, Rx becomes MOVD symtoc, Rx; ADD <off>, Rx
  214. p.From.Type = obj.TYPE_MEM
  215. p.From.Sym = symtoc
  216. p.From.Name = obj.NAME_TOCREF
  217. if p.From.Offset != 0 {
  218. q := obj.Appendp(p, c.newprog)
  219. q.As = AADD
  220. q.From.Type = obj.TYPE_CONST
  221. q.From.Offset = p.From.Offset
  222. p.From.Offset = 0
  223. q.To = p.To
  224. }
  225. return
  226. }
  227. // MOVx sym, Ry becomes MOVD symtoc, REGTMP; MOVx (REGTMP), Ry
  228. // MOVx Ry, sym becomes MOVD symtoc, REGTMP; MOVx Ry, (REGTMP)
  229. // An addition may be inserted between the two MOVs if there is an offset.
  230. q := obj.Appendp(p, c.newprog)
  231. q.As = AMOVD
  232. q.From.Type = obj.TYPE_MEM
  233. q.From.Sym = symtoc
  234. q.From.Name = obj.NAME_TOCREF
  235. q.To.Type = obj.TYPE_REG
  236. q.To.Reg = REGTMP
  237. q = obj.Appendp(q, c.newprog)
  238. q.As = p.As
  239. q.From = p.From
  240. q.To = p.To
  241. if p.From.Name != obj.NAME_NONE {
  242. q.From.Type = obj.TYPE_MEM
  243. q.From.Reg = REGTMP
  244. q.From.Name = obj.NAME_NONE
  245. q.From.Sym = nil
  246. } else if p.To.Name != obj.NAME_NONE {
  247. q.To.Type = obj.TYPE_MEM
  248. q.To.Reg = REGTMP
  249. q.To.Name = obj.NAME_NONE
  250. q.To.Sym = nil
  251. } else {
  252. c.ctxt.Diag("unreachable case in rewriteToUseTOC with %v", p)
  253. }
  254. obj.Nopout(p)
  255. }
  256. // Rewrite p, if necessary, to access global data via the global offset table.
  257. func (c *ctxt9) rewriteToUseGot(p *obj.Prog) {
  258. if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
  259. // ADUFFxxx $offset
  260. // becomes
  261. // MOVD runtime.duffxxx@GOT, R12
  262. // ADD $offset, R12
  263. // MOVD R12, LR
  264. // BL (LR)
  265. var sym *obj.LSym
  266. if p.As == obj.ADUFFZERO {
  267. sym = c.ctxt.Lookup("runtime.duffzero")
  268. } else {
  269. sym = c.ctxt.Lookup("runtime.duffcopy")
  270. }
  271. offset := p.To.Offset
  272. p.As = AMOVD
  273. p.From.Type = obj.TYPE_MEM
  274. p.From.Name = obj.NAME_GOTREF
  275. p.From.Sym = sym
  276. p.To.Type = obj.TYPE_REG
  277. p.To.Reg = REG_R12
  278. p.To.Name = obj.NAME_NONE
  279. p.To.Offset = 0
  280. p.To.Sym = nil
  281. p1 := obj.Appendp(p, c.newprog)
  282. p1.As = AADD
  283. p1.From.Type = obj.TYPE_CONST
  284. p1.From.Offset = offset
  285. p1.To.Type = obj.TYPE_REG
  286. p1.To.Reg = REG_R12
  287. p2 := obj.Appendp(p1, c.newprog)
  288. p2.As = AMOVD
  289. p2.From.Type = obj.TYPE_REG
  290. p2.From.Reg = REG_R12
  291. p2.To.Type = obj.TYPE_REG
  292. p2.To.Reg = REG_LR
  293. p3 := obj.Appendp(p2, c.newprog)
  294. p3.As = obj.ACALL
  295. p3.To.Type = obj.TYPE_REG
  296. p3.To.Reg = REG_LR
  297. }
  298. // We only care about global data: NAME_EXTERN means a global
  299. // symbol in the Go sense, and p.Sym.Local is true for a few
  300. // internally defined symbols.
  301. if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
  302. // MOVD $sym, Rx becomes MOVD sym@GOT, Rx
  303. // MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx; ADD <off>, Rx
  304. if p.As != AMOVD {
  305. c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
  306. }
  307. if p.To.Type != obj.TYPE_REG {
  308. c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
  309. }
  310. p.From.Type = obj.TYPE_MEM
  311. p.From.Name = obj.NAME_GOTREF
  312. if p.From.Offset != 0 {
  313. q := obj.Appendp(p, c.newprog)
  314. q.As = AADD
  315. q.From.Type = obj.TYPE_CONST
  316. q.From.Offset = p.From.Offset
  317. q.To = p.To
  318. p.From.Offset = 0
  319. }
  320. }
  321. if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
  322. c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
  323. }
  324. var source *obj.Addr
  325. // MOVx sym, Ry becomes MOVD sym@GOT, REGTMP; MOVx (REGTMP), Ry
  326. // MOVx Ry, sym becomes MOVD sym@GOT, REGTMP; MOVx Ry, (REGTMP)
  327. // An addition may be inserted between the two MOVs if there is an offset.
  328. if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
  329. if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
  330. c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
  331. }
  332. source = &p.From
  333. } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
  334. source = &p.To
  335. } else {
  336. return
  337. }
  338. if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
  339. return
  340. }
  341. if source.Sym.Type == objabi.STLSBSS {
  342. return
  343. }
  344. if source.Type != obj.TYPE_MEM {
  345. c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
  346. }
  347. p1 := obj.Appendp(p, c.newprog)
  348. p2 := obj.Appendp(p1, c.newprog)
  349. p1.As = AMOVD
  350. p1.From.Type = obj.TYPE_MEM
  351. p1.From.Sym = source.Sym
  352. p1.From.Name = obj.NAME_GOTREF
  353. p1.To.Type = obj.TYPE_REG
  354. p1.To.Reg = REGTMP
  355. p2.As = p.As
  356. p2.From = p.From
  357. p2.To = p.To
  358. if p.From.Name == obj.NAME_EXTERN {
  359. p2.From.Reg = REGTMP
  360. p2.From.Name = obj.NAME_NONE
  361. p2.From.Sym = nil
  362. } else if p.To.Name == obj.NAME_EXTERN {
  363. p2.To.Reg = REGTMP
  364. p2.To.Name = obj.NAME_NONE
  365. p2.To.Sym = nil
  366. } else {
  367. return
  368. }
  369. obj.Nopout(p)
  370. }
  371. func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
  372. // TODO(minux): add morestack short-cuts with small fixed frame-size.
  373. if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
  374. return
  375. }
  376. c := ctxt9{ctxt: ctxt, cursym: cursym, newprog: newprog}
  377. p := c.cursym.Func.Text
  378. textstksiz := p.To.Offset
  379. if textstksiz == -8 {
  380. // Compatibility hack.
  381. p.From.Sym.Set(obj.AttrNoFrame, true)
  382. textstksiz = 0
  383. }
  384. if textstksiz%8 != 0 {
  385. c.ctxt.Diag("frame size %d not a multiple of 8", textstksiz)
  386. }
  387. if p.From.Sym.NoFrame() {
  388. if textstksiz != 0 {
  389. c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
  390. }
  391. }
  392. c.cursym.Func.Args = p.To.Val.(int32)
  393. c.cursym.Func.Locals = int32(textstksiz)
  394. /*
  395. * find leaf subroutines
  396. * expand RET
  397. * expand BECOME pseudo
  398. */
  399. var q *obj.Prog
  400. var q1 *obj.Prog
  401. for p := c.cursym.Func.Text; p != nil; p = p.Link {
  402. switch p.As {
  403. /* too hard, just leave alone */
  404. case obj.ATEXT:
  405. q = p
  406. p.Mark |= LABEL | LEAF | SYNC
  407. if p.Link != nil {
  408. p.Link.Mark |= LABEL
  409. }
  410. case ANOR:
  411. q = p
  412. if p.To.Type == obj.TYPE_REG {
  413. if p.To.Reg == REGZERO {
  414. p.Mark |= LABEL | SYNC
  415. }
  416. }
  417. case ALWAR,
  418. ALBAR,
  419. ASTBCCC,
  420. ASTWCCC,
  421. AECIWX,
  422. AECOWX,
  423. AEIEIO,
  424. AICBI,
  425. AISYNC,
  426. ATLBIE,
  427. ATLBIEL,
  428. ASLBIA,
  429. ASLBIE,
  430. ASLBMFEE,
  431. ASLBMFEV,
  432. ASLBMTE,
  433. ADCBF,
  434. ADCBI,
  435. ADCBST,
  436. ADCBT,
  437. ADCBTST,
  438. ADCBZ,
  439. ASYNC,
  440. ATLBSYNC,
  441. APTESYNC,
  442. ALWSYNC,
  443. ATW,
  444. AWORD,
  445. ARFI,
  446. ARFCI,
  447. ARFID,
  448. AHRFID:
  449. q = p
  450. p.Mark |= LABEL | SYNC
  451. continue
  452. case AMOVW, AMOVWZ, AMOVD:
  453. q = p
  454. if p.From.Reg >= REG_SPECIAL || p.To.Reg >= REG_SPECIAL {
  455. p.Mark |= LABEL | SYNC
  456. }
  457. continue
  458. case AFABS,
  459. AFABSCC,
  460. AFADD,
  461. AFADDCC,
  462. AFCTIW,
  463. AFCTIWCC,
  464. AFCTIWZ,
  465. AFCTIWZCC,
  466. AFDIV,
  467. AFDIVCC,
  468. AFMADD,
  469. AFMADDCC,
  470. AFMOVD,
  471. AFMOVDU,
  472. /* case AFMOVDS: */
  473. AFMOVS,
  474. AFMOVSU,
  475. /* case AFMOVSD: */
  476. AFMSUB,
  477. AFMSUBCC,
  478. AFMUL,
  479. AFMULCC,
  480. AFNABS,
  481. AFNABSCC,
  482. AFNEG,
  483. AFNEGCC,
  484. AFNMADD,
  485. AFNMADDCC,
  486. AFNMSUB,
  487. AFNMSUBCC,
  488. AFRSP,
  489. AFRSPCC,
  490. AFSUB,
  491. AFSUBCC:
  492. q = p
  493. p.Mark |= FLOAT
  494. continue
  495. case ABL,
  496. ABCL,
  497. obj.ADUFFZERO,
  498. obj.ADUFFCOPY:
  499. c.cursym.Func.Text.Mark &^= LEAF
  500. fallthrough
  501. case ABC,
  502. ABEQ,
  503. ABGE,
  504. ABGT,
  505. ABLE,
  506. ABLT,
  507. ABNE,
  508. ABR,
  509. ABVC,
  510. ABVS:
  511. p.Mark |= BRANCH
  512. q = p
  513. q1 = p.To.Target()
  514. if q1 != nil {
  515. // NOPs are not removed due to #40689.
  516. if q1.Mark&LEAF == 0 {
  517. q1.Mark |= LABEL
  518. }
  519. } else {
  520. p.Mark |= LABEL
  521. }
  522. q1 = p.Link
  523. if q1 != nil {
  524. q1.Mark |= LABEL
  525. }
  526. continue
  527. case AFCMPO, AFCMPU:
  528. q = p
  529. p.Mark |= FCMP | FLOAT
  530. continue
  531. case obj.ARET:
  532. q = p
  533. if p.Link != nil {
  534. p.Link.Mark |= LABEL
  535. }
  536. continue
  537. case obj.ANOP:
  538. // NOPs are not removed due to
  539. // #40689
  540. continue
  541. default:
  542. q = p
  543. continue
  544. }
  545. }
  546. autosize := int32(0)
  547. var p1 *obj.Prog
  548. var p2 *obj.Prog
  549. for p := c.cursym.Func.Text; p != nil; p = p.Link {
  550. o := p.As
  551. switch o {
  552. case obj.ATEXT:
  553. autosize = int32(textstksiz)
  554. if p.Mark&LEAF != 0 && autosize == 0 {
  555. // A leaf function with no locals has no frame.
  556. p.From.Sym.Set(obj.AttrNoFrame, true)
  557. }
  558. if !p.From.Sym.NoFrame() {
  559. // If there is a stack frame at all, it includes
  560. // space to save the LR.
  561. autosize += int32(c.ctxt.FixedFrameSize())
  562. }
  563. if p.Mark&LEAF != 0 && autosize < objabi.StackSmall {
  564. // A leaf function with a small stack can be marked
  565. // NOSPLIT, avoiding a stack check.
  566. p.From.Sym.Set(obj.AttrNoSplit, true)
  567. }
  568. p.To.Offset = int64(autosize)
  569. q = p
  570. if c.ctxt.Flag_shared && c.cursym.Name != "runtime.duffzero" && c.cursym.Name != "runtime.duffcopy" {
  571. // When compiling Go into PIC, all functions must start
  572. // with instructions to load the TOC pointer into r2:
  573. //
  574. // addis r2, r12, .TOC.-func@ha
  575. // addi r2, r2, .TOC.-func@l+4
  576. //
  577. // We could probably skip this prologue in some situations
  578. // but it's a bit subtle. However, it is both safe and
  579. // necessary to leave the prologue off duffzero and
  580. // duffcopy as we rely on being able to jump to a specific
  581. // instruction offset for them.
  582. //
  583. // These are AWORDS because there is no (afaict) way to
  584. // generate the addis instruction except as part of the
  585. // load of a large constant, and in that case there is no
  586. // way to use r12 as the source.
  587. //
  588. // Note that the same condition is tested in
  589. // putelfsym in cmd/link/internal/ld/symtab.go
  590. // where we set the st_other field to indicate
  591. // the presence of these instructions.
  592. q = obj.Appendp(q, c.newprog)
  593. q.As = AWORD
  594. q.Pos = p.Pos
  595. q.From.Type = obj.TYPE_CONST
  596. q.From.Offset = 0x3c4c0000
  597. q = obj.Appendp(q, c.newprog)
  598. q.As = AWORD
  599. q.Pos = p.Pos
  600. q.From.Type = obj.TYPE_CONST
  601. q.From.Offset = 0x38420000
  602. rel := obj.Addrel(c.cursym)
  603. rel.Off = 0
  604. rel.Siz = 8
  605. rel.Sym = c.ctxt.Lookup(".TOC.")
  606. rel.Type = objabi.R_ADDRPOWER_PCREL
  607. }
  608. if !c.cursym.Func.Text.From.Sym.NoSplit() {
  609. q = c.stacksplit(q, autosize) // emit split check
  610. }
  611. // Special handling of the racecall thunk. Assume that its asm code will
  612. // save the link register and update the stack, since that code is
  613. // called directly from C/C++ and can't clobber REGTMP (R31).
  614. if autosize != 0 && c.cursym.Name != "runtime.racecallbackthunk" {
  615. // Save the link register and update the SP. MOVDU is used unless
  616. // the frame size is too large. The link register must be saved
  617. // even for non-empty leaf functions so that traceback works.
  618. if autosize >= -BIG && autosize <= BIG {
  619. // Use MOVDU to adjust R1 when saving R31, if autosize is small.
  620. q = obj.Appendp(q, c.newprog)
  621. q.As = AMOVD
  622. q.Pos = p.Pos
  623. q.From.Type = obj.TYPE_REG
  624. q.From.Reg = REG_LR
  625. q.To.Type = obj.TYPE_REG
  626. q.To.Reg = REGTMP
  627. q = obj.Appendp(q, c.newprog)
  628. q.As = AMOVDU
  629. q.Pos = p.Pos
  630. q.From.Type = obj.TYPE_REG
  631. q.From.Reg = REGTMP
  632. q.To.Type = obj.TYPE_MEM
  633. q.To.Offset = int64(-autosize)
  634. q.To.Reg = REGSP
  635. q.Spadj = autosize
  636. } else {
  637. // Frame size is too large for a MOVDU instruction.
  638. // Store link register before decrementing SP, so if a signal comes
  639. // during the execution of the function prologue, the traceback
  640. // code will not see a half-updated stack frame.
  641. // This sequence is not async preemptible, as if we open a frame
  642. // at the current SP, it will clobber the saved LR.
  643. q = obj.Appendp(q, c.newprog)
  644. q.As = AMOVD
  645. q.Pos = p.Pos
  646. q.From.Type = obj.TYPE_REG
  647. q.From.Reg = REG_LR
  648. q.To.Type = obj.TYPE_REG
  649. q.To.Reg = REG_R29 // REGTMP may be used to synthesize large offset in the next instruction
  650. q = c.ctxt.StartUnsafePoint(q, c.newprog)
  651. q = obj.Appendp(q, c.newprog)
  652. q.As = AMOVD
  653. q.Pos = p.Pos
  654. q.From.Type = obj.TYPE_REG
  655. q.From.Reg = REG_R29
  656. q.To.Type = obj.TYPE_MEM
  657. q.To.Offset = int64(-autosize)
  658. q.To.Reg = REGSP
  659. q = obj.Appendp(q, c.newprog)
  660. q.As = AADD
  661. q.Pos = p.Pos
  662. q.From.Type = obj.TYPE_CONST
  663. q.From.Offset = int64(-autosize)
  664. q.To.Type = obj.TYPE_REG
  665. q.To.Reg = REGSP
  666. q.Spadj = +autosize
  667. q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
  668. }
  669. } else if c.cursym.Func.Text.Mark&LEAF == 0 {
  670. // A very few functions that do not return to their caller
  671. // (e.g. gogo) are not identified as leaves but still have
  672. // no frame.
  673. c.cursym.Func.Text.Mark |= LEAF
  674. }
  675. if c.cursym.Func.Text.Mark&LEAF != 0 {
  676. c.cursym.Set(obj.AttrLeaf, true)
  677. break
  678. }
  679. if c.ctxt.Flag_shared {
  680. q = obj.Appendp(q, c.newprog)
  681. q.As = AMOVD
  682. q.Pos = p.Pos
  683. q.From.Type = obj.TYPE_REG
  684. q.From.Reg = REG_R2
  685. q.To.Type = obj.TYPE_MEM
  686. q.To.Reg = REGSP
  687. q.To.Offset = 24
  688. }
  689. if c.cursym.Func.Text.From.Sym.Wrapper() {
  690. // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
  691. //
  692. // MOVD g_panic(g), R3
  693. // CMP R0, R3
  694. // BEQ end
  695. // MOVD panic_argp(R3), R4
  696. // ADD $(autosize+8), R1, R5
  697. // CMP R4, R5
  698. // BNE end
  699. // ADD $8, R1, R6
  700. // MOVD R6, panic_argp(R3)
  701. // end:
  702. // NOP
  703. //
  704. // The NOP is needed to give the jumps somewhere to land.
  705. // It is a liblink NOP, not a ppc64 NOP: it encodes to 0 instruction bytes.
  706. q = obj.Appendp(q, c.newprog)
  707. q.As = AMOVD
  708. q.From.Type = obj.TYPE_MEM
  709. q.From.Reg = REGG
  710. q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
  711. q.To.Type = obj.TYPE_REG
  712. q.To.Reg = REG_R3
  713. q = obj.Appendp(q, c.newprog)
  714. q.As = ACMP
  715. q.From.Type = obj.TYPE_REG
  716. q.From.Reg = REG_R0
  717. q.To.Type = obj.TYPE_REG
  718. q.To.Reg = REG_R3
  719. q = obj.Appendp(q, c.newprog)
  720. q.As = ABEQ
  721. q.To.Type = obj.TYPE_BRANCH
  722. p1 = q
  723. q = obj.Appendp(q, c.newprog)
  724. q.As = AMOVD
  725. q.From.Type = obj.TYPE_MEM
  726. q.From.Reg = REG_R3
  727. q.From.Offset = 0 // Panic.argp
  728. q.To.Type = obj.TYPE_REG
  729. q.To.Reg = REG_R4
  730. q = obj.Appendp(q, c.newprog)
  731. q.As = AADD
  732. q.From.Type = obj.TYPE_CONST
  733. q.From.Offset = int64(autosize) + c.ctxt.FixedFrameSize()
  734. q.Reg = REGSP
  735. q.To.Type = obj.TYPE_REG
  736. q.To.Reg = REG_R5
  737. q = obj.Appendp(q, c.newprog)
  738. q.As = ACMP
  739. q.From.Type = obj.TYPE_REG
  740. q.From.Reg = REG_R4
  741. q.To.Type = obj.TYPE_REG
  742. q.To.Reg = REG_R5
  743. q = obj.Appendp(q, c.newprog)
  744. q.As = ABNE
  745. q.To.Type = obj.TYPE_BRANCH
  746. p2 = q
  747. q = obj.Appendp(q, c.newprog)
  748. q.As = AADD
  749. q.From.Type = obj.TYPE_CONST
  750. q.From.Offset = c.ctxt.FixedFrameSize()
  751. q.Reg = REGSP
  752. q.To.Type = obj.TYPE_REG
  753. q.To.Reg = REG_R6
  754. q = obj.Appendp(q, c.newprog)
  755. q.As = AMOVD
  756. q.From.Type = obj.TYPE_REG
  757. q.From.Reg = REG_R6
  758. q.To.Type = obj.TYPE_MEM
  759. q.To.Reg = REG_R3
  760. q.To.Offset = 0 // Panic.argp
  761. q = obj.Appendp(q, c.newprog)
  762. q.As = obj.ANOP
  763. p1.To.SetTarget(q)
  764. p2.To.SetTarget(q)
  765. }
  766. case obj.ARET:
  767. if p.From.Type == obj.TYPE_CONST {
  768. c.ctxt.Diag("using BECOME (%v) is not supported!", p)
  769. break
  770. }
  771. retTarget := p.To.Sym
  772. if c.cursym.Func.Text.Mark&LEAF != 0 {
  773. if autosize == 0 || c.cursym.Name == "runtime.racecallbackthunk" {
  774. p.As = ABR
  775. p.From = obj.Addr{}
  776. if retTarget == nil {
  777. p.To.Type = obj.TYPE_REG
  778. p.To.Reg = REG_LR
  779. } else {
  780. p.To.Type = obj.TYPE_BRANCH
  781. p.To.Sym = retTarget
  782. }
  783. p.Mark |= BRANCH
  784. break
  785. }
  786. p.As = AADD
  787. p.From.Type = obj.TYPE_CONST
  788. p.From.Offset = int64(autosize)
  789. p.To.Type = obj.TYPE_REG
  790. p.To.Reg = REGSP
  791. p.Spadj = -autosize
  792. q = c.newprog()
  793. q.As = ABR
  794. q.Pos = p.Pos
  795. q.To.Type = obj.TYPE_REG
  796. q.To.Reg = REG_LR
  797. q.Mark |= BRANCH
  798. q.Spadj = +autosize
  799. q.Link = p.Link
  800. p.Link = q
  801. break
  802. }
  803. p.As = AMOVD
  804. p.From.Type = obj.TYPE_MEM
  805. p.From.Offset = 0
  806. p.From.Reg = REGSP
  807. p.To.Type = obj.TYPE_REG
  808. p.To.Reg = REGTMP
  809. q = c.newprog()
  810. q.As = AMOVD
  811. q.Pos = p.Pos
  812. q.From.Type = obj.TYPE_REG
  813. q.From.Reg = REGTMP
  814. q.To.Type = obj.TYPE_REG
  815. q.To.Reg = REG_LR
  816. q.Link = p.Link
  817. p.Link = q
  818. p = q
  819. if false {
  820. // Debug bad returns
  821. q = c.newprog()
  822. q.As = AMOVD
  823. q.Pos = p.Pos
  824. q.From.Type = obj.TYPE_MEM
  825. q.From.Offset = 0
  826. q.From.Reg = REGTMP
  827. q.To.Type = obj.TYPE_REG
  828. q.To.Reg = REGTMP
  829. q.Link = p.Link
  830. p.Link = q
  831. p = q
  832. }
  833. prev := p
  834. if autosize != 0 && c.cursym.Name != "runtime.racecallbackthunk" {
  835. q = c.newprog()
  836. q.As = AADD
  837. q.Pos = p.Pos
  838. q.From.Type = obj.TYPE_CONST
  839. q.From.Offset = int64(autosize)
  840. q.To.Type = obj.TYPE_REG
  841. q.To.Reg = REGSP
  842. q.Spadj = -autosize
  843. q.Link = p.Link
  844. prev.Link = q
  845. prev = q
  846. }
  847. q1 = c.newprog()
  848. q1.As = ABR
  849. q1.Pos = p.Pos
  850. if retTarget == nil {
  851. q1.To.Type = obj.TYPE_REG
  852. q1.To.Reg = REG_LR
  853. } else {
  854. q1.To.Type = obj.TYPE_BRANCH
  855. q1.To.Sym = retTarget
  856. }
  857. q1.Mark |= BRANCH
  858. q1.Spadj = +autosize
  859. q1.Link = q.Link
  860. prev.Link = q1
  861. case AADD:
  862. if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
  863. p.Spadj = int32(-p.From.Offset)
  864. }
  865. case AMOVDU:
  866. if p.To.Type == obj.TYPE_MEM && p.To.Reg == REGSP {
  867. p.Spadj = int32(-p.To.Offset)
  868. }
  869. if p.From.Type == obj.TYPE_MEM && p.From.Reg == REGSP {
  870. p.Spadj = int32(-p.From.Offset)
  871. }
  872. case obj.AGETCALLERPC:
  873. if cursym.Leaf() {
  874. /* MOVD LR, Rd */
  875. p.As = AMOVD
  876. p.From.Type = obj.TYPE_REG
  877. p.From.Reg = REG_LR
  878. } else {
  879. /* MOVD (RSP), Rd */
  880. p.As = AMOVD
  881. p.From.Type = obj.TYPE_MEM
  882. p.From.Reg = REGSP
  883. }
  884. }
  885. }
  886. }
  887. /*
  888. // instruction scheduling
  889. if(debug['Q'] == 0)
  890. return;
  891. curtext = nil;
  892. q = nil; // p - 1
  893. q1 = firstp; // top of block
  894. o = 0; // count of instructions
  895. for(p = firstp; p != nil; p = p1) {
  896. p1 = p->link;
  897. o++;
  898. if(p->mark & NOSCHED){
  899. if(q1 != p){
  900. sched(q1, q);
  901. }
  902. for(; p != nil; p = p->link){
  903. if(!(p->mark & NOSCHED))
  904. break;
  905. q = p;
  906. }
  907. p1 = p;
  908. q1 = p;
  909. o = 0;
  910. continue;
  911. }
  912. if(p->mark & (LABEL|SYNC)) {
  913. if(q1 != p)
  914. sched(q1, q);
  915. q1 = p;
  916. o = 1;
  917. }
  918. if(p->mark & (BRANCH|SYNC)) {
  919. sched(q1, p);
  920. q1 = p1;
  921. o = 0;
  922. }
  923. if(o >= NSCHED) {
  924. sched(q1, p);
  925. q1 = p1;
  926. o = 0;
  927. }
  928. q = p;
  929. }
  930. */
  931. func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
  932. p0 := p // save entry point, but skipping the two instructions setting R2 in shared mode
  933. // MOVD g_stackguard(g), R3
  934. p = obj.Appendp(p, c.newprog)
  935. p.As = AMOVD
  936. p.From.Type = obj.TYPE_MEM
  937. p.From.Reg = REGG
  938. p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
  939. if c.cursym.CFunc() {
  940. p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
  941. }
  942. p.To.Type = obj.TYPE_REG
  943. p.To.Reg = REG_R3
  944. // Mark the stack bound check and morestack call async nonpreemptible.
  945. // If we get preempted here, when resumed the preemption request is
  946. // cleared, but we'll still call morestack, which will double the stack
  947. // unnecessarily. See issue #35470.
  948. p = c.ctxt.StartUnsafePoint(p, c.newprog)
  949. var q *obj.Prog
  950. if framesize <= objabi.StackSmall {
  951. // small stack: SP < stackguard
  952. // CMP stackguard, SP
  953. p = obj.Appendp(p, c.newprog)
  954. p.As = ACMPU
  955. p.From.Type = obj.TYPE_REG
  956. p.From.Reg = REG_R3
  957. p.To.Type = obj.TYPE_REG
  958. p.To.Reg = REGSP
  959. } else if framesize <= objabi.StackBig {
  960. // large stack: SP-framesize < stackguard-StackSmall
  961. // ADD $-(framesize-StackSmall), SP, R4
  962. // CMP stackguard, R4
  963. p = obj.Appendp(p, c.newprog)
  964. p.As = AADD
  965. p.From.Type = obj.TYPE_CONST
  966. p.From.Offset = -(int64(framesize) - objabi.StackSmall)
  967. p.Reg = REGSP
  968. p.To.Type = obj.TYPE_REG
  969. p.To.Reg = REG_R4
  970. p = obj.Appendp(p, c.newprog)
  971. p.As = ACMPU
  972. p.From.Type = obj.TYPE_REG
  973. p.From.Reg = REG_R3
  974. p.To.Type = obj.TYPE_REG
  975. p.To.Reg = REG_R4
  976. } else {
  977. // Such a large stack we need to protect against wraparound.
  978. // If SP is close to zero:
  979. // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
  980. // The +StackGuard on both sides is required to keep the left side positive:
  981. // SP is allowed to be slightly below stackguard. See stack.h.
  982. //
  983. // Preemption sets stackguard to StackPreempt, a very large value.
  984. // That breaks the math above, so we have to check for that explicitly.
  985. // // stackguard is R3
  986. // CMP R3, $StackPreempt
  987. // BEQ label-of-call-to-morestack
  988. // ADD $StackGuard, SP, R4
  989. // SUB R3, R4
  990. // MOVD $(framesize+(StackGuard-StackSmall)), R31
  991. // CMPU R31, R4
  992. p = obj.Appendp(p, c.newprog)
  993. p.As = ACMP
  994. p.From.Type = obj.TYPE_REG
  995. p.From.Reg = REG_R3
  996. p.To.Type = obj.TYPE_CONST
  997. p.To.Offset = objabi.StackPreempt
  998. p = obj.Appendp(p, c.newprog)
  999. q = p
  1000. p.As = ABEQ
  1001. p.To.Type = obj.TYPE_BRANCH
  1002. p = obj.Appendp(p, c.newprog)
  1003. p.As = AADD
  1004. p.From.Type = obj.TYPE_CONST
  1005. p.From.Offset = int64(objabi.StackGuard)
  1006. p.Reg = REGSP
  1007. p.To.Type = obj.TYPE_REG
  1008. p.To.Reg = REG_R4
  1009. p = obj.Appendp(p, c.newprog)
  1010. p.As = ASUB
  1011. p.From.Type = obj.TYPE_REG
  1012. p.From.Reg = REG_R3
  1013. p.To.Type = obj.TYPE_REG
  1014. p.To.Reg = REG_R4
  1015. p = obj.Appendp(p, c.newprog)
  1016. p.As = AMOVD
  1017. p.From.Type = obj.TYPE_CONST
  1018. p.From.Offset = int64(framesize) + int64(objabi.StackGuard) - objabi.StackSmall
  1019. p.To.Type = obj.TYPE_REG
  1020. p.To.Reg = REGTMP
  1021. p = obj.Appendp(p, c.newprog)
  1022. p.As = ACMPU
  1023. p.From.Type = obj.TYPE_REG
  1024. p.From.Reg = REGTMP
  1025. p.To.Type = obj.TYPE_REG
  1026. p.To.Reg = REG_R4
  1027. }
  1028. // q1: BLT done
  1029. p = obj.Appendp(p, c.newprog)
  1030. q1 := p
  1031. p.As = ABLT
  1032. p.To.Type = obj.TYPE_BRANCH
  1033. // MOVD LR, R5
  1034. p = obj.Appendp(p, c.newprog)
  1035. p.As = AMOVD
  1036. p.From.Type = obj.TYPE_REG
  1037. p.From.Reg = REG_LR
  1038. p.To.Type = obj.TYPE_REG
  1039. p.To.Reg = REG_R5
  1040. if q != nil {
  1041. q.To.SetTarget(p)
  1042. }
  1043. p = c.ctxt.EmitEntryStackMap(c.cursym, p, c.newprog)
  1044. var morestacksym *obj.LSym
  1045. if c.cursym.CFunc() {
  1046. morestacksym = c.ctxt.Lookup("runtime.morestackc")
  1047. } else if !c.cursym.Func.Text.From.Sym.NeedCtxt() {
  1048. morestacksym = c.ctxt.Lookup("runtime.morestack_noctxt")
  1049. } else {
  1050. morestacksym = c.ctxt.Lookup("runtime.morestack")
  1051. }
  1052. if c.ctxt.Flag_shared {
  1053. // In PPC64 PIC code, R2 is used as TOC pointer derived from R12
  1054. // which is the address of function entry point when entering
  1055. // the function. We need to preserve R2 across call to morestack.
  1056. // Fortunately, in shared mode, 8(SP) and 16(SP) are reserved in
  1057. // the caller's frame, but not used (0(SP) is caller's saved LR,
  1058. // 24(SP) is caller's saved R2). Use 8(SP) to save this function's R2.
  1059. // MOVD R12, 8(SP)
  1060. p = obj.Appendp(p, c.newprog)
  1061. p.As = AMOVD
  1062. p.From.Type = obj.TYPE_REG
  1063. p.From.Reg = REG_R2
  1064. p.To.Type = obj.TYPE_MEM
  1065. p.To.Reg = REGSP
  1066. p.To.Offset = 8
  1067. }
  1068. if c.ctxt.Flag_dynlink {
  1069. // Avoid calling morestack via a PLT when dynamically linking. The
  1070. // PLT stubs generated by the system linker on ppc64le when "std r2,
  1071. // 24(r1)" to save the TOC pointer in their callers stack
  1072. // frame. Unfortunately (and necessarily) morestack is called before
  1073. // the function that calls it sets up its frame and so the PLT ends
  1074. // up smashing the saved TOC pointer for its caller's caller.
  1075. //
  1076. // According to the ABI documentation there is a mechanism to avoid
  1077. // the TOC save that the PLT stub does (put a R_PPC64_TOCSAVE
  1078. // relocation on the nop after the call to morestack) but at the time
  1079. // of writing it is not supported at all by gold and my attempt to
  1080. // use it with ld.bfd caused an internal linker error. So this hack
  1081. // seems preferable.
  1082. // MOVD $runtime.morestack(SB), R12
  1083. p = obj.Appendp(p, c.newprog)
  1084. p.As = AMOVD
  1085. p.From.Type = obj.TYPE_MEM
  1086. p.From.Sym = morestacksym
  1087. p.From.Name = obj.NAME_GOTREF
  1088. p.To.Type = obj.TYPE_REG
  1089. p.To.Reg = REG_R12
  1090. // MOVD R12, LR
  1091. p = obj.Appendp(p, c.newprog)
  1092. p.As = AMOVD
  1093. p.From.Type = obj.TYPE_REG
  1094. p.From.Reg = REG_R12
  1095. p.To.Type = obj.TYPE_REG
  1096. p.To.Reg = REG_LR
  1097. // BL LR
  1098. p = obj.Appendp(p, c.newprog)
  1099. p.As = obj.ACALL
  1100. p.To.Type = obj.TYPE_REG
  1101. p.To.Reg = REG_LR
  1102. } else {
  1103. // BL runtime.morestack(SB)
  1104. p = obj.Appendp(p, c.newprog)
  1105. p.As = ABL
  1106. p.To.Type = obj.TYPE_BRANCH
  1107. p.To.Sym = morestacksym
  1108. }
  1109. if c.ctxt.Flag_shared {
  1110. // MOVD 8(SP), R2
  1111. p = obj.Appendp(p, c.newprog)
  1112. p.As = AMOVD
  1113. p.From.Type = obj.TYPE_MEM
  1114. p.From.Reg = REGSP
  1115. p.From.Offset = 8
  1116. p.To.Type = obj.TYPE_REG
  1117. p.To.Reg = REG_R2
  1118. }
  1119. p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
  1120. // BR start
  1121. p = obj.Appendp(p, c.newprog)
  1122. p.As = ABR
  1123. p.To.Type = obj.TYPE_BRANCH
  1124. p.To.SetTarget(p0.Link)
  1125. // placeholder for q1's jump target
  1126. p = obj.Appendp(p, c.newprog)
  1127. p.As = obj.ANOP // zero-width place holder
  1128. q1.To.SetTarget(p)
  1129. return p
  1130. }
  1131. var Linkppc64 = obj.LinkArch{
  1132. Arch: sys.ArchPPC64,
  1133. Init: buildop,
  1134. Preprocess: preprocess,
  1135. Assemble: span9,
  1136. Progedit: progedit,
  1137. DWARFRegisters: PPC64DWARFRegisters,
  1138. }
  1139. var Linkppc64le = obj.LinkArch{
  1140. Arch: sys.ArchPPC64LE,
  1141. Init: buildop,
  1142. Preprocess: preprocess,
  1143. Assemble: span9,
  1144. Progedit: progedit,
  1145. DWARFRegisters: PPC64DWARFRegisters,
  1146. }