obj6.go 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261
  1. // Inferno utils/6l/pass.c
  2. // https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/pass.c
  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 x86
  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. "strings"
  38. )
  39. func CanUse1InsnTLS(ctxt *obj.Link) bool {
  40. if isAndroid {
  41. // Android uses a global variable for the tls offset.
  42. return false
  43. }
  44. if ctxt.Arch.Family == sys.I386 {
  45. switch ctxt.Headtype {
  46. case objabi.Hlinux,
  47. objabi.Hplan9,
  48. objabi.Hwindows:
  49. return false
  50. }
  51. return true
  52. }
  53. switch ctxt.Headtype {
  54. case objabi.Hplan9, objabi.Hwindows:
  55. return false
  56. case objabi.Hlinux, objabi.Hfreebsd:
  57. return !ctxt.Flag_shared
  58. }
  59. return true
  60. }
  61. func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
  62. // Thread-local storage references use the TLS pseudo-register.
  63. // As a register, TLS refers to the thread-local storage base, and it
  64. // can only be loaded into another register:
  65. //
  66. // MOVQ TLS, AX
  67. //
  68. // An offset from the thread-local storage base is written off(reg)(TLS*1).
  69. // Semantically it is off(reg), but the (TLS*1) annotation marks this as
  70. // indexing from the loaded TLS base. This emits a relocation so that
  71. // if the linker needs to adjust the offset, it can. For example:
  72. //
  73. // MOVQ TLS, AX
  74. // MOVQ 0(AX)(TLS*1), CX // load g into CX
  75. //
  76. // On systems that support direct access to the TLS memory, this
  77. // pair of instructions can be reduced to a direct TLS memory reference:
  78. //
  79. // MOVQ 0(TLS), CX // load g into CX
  80. //
  81. // The 2-instruction and 1-instruction forms correspond to the two code
  82. // sequences for loading a TLS variable in the local exec model given in "ELF
  83. // Handling For Thread-Local Storage".
  84. //
  85. // We apply this rewrite on systems that support the 1-instruction form.
  86. // The decision is made using only the operating system and the -shared flag,
  87. // not the link mode. If some link modes on a particular operating system
  88. // require the 2-instruction form, then all builds for that operating system
  89. // will use the 2-instruction form, so that the link mode decision can be
  90. // delayed to link time.
  91. //
  92. // In this way, all supported systems use identical instructions to
  93. // access TLS, and they are rewritten appropriately first here in
  94. // liblink and then finally using relocations in the linker.
  95. //
  96. // When -shared is passed, we leave the code in the 2-instruction form but
  97. // assemble (and relocate) them in different ways to generate the initial
  98. // exec code sequence. It's a bit of a fluke that this is possible without
  99. // rewriting the instructions more comprehensively, and it only does because
  100. // we only support a single TLS variable (g).
  101. if CanUse1InsnTLS(ctxt) {
  102. // Reduce 2-instruction sequence to 1-instruction sequence.
  103. // Sequences like
  104. // MOVQ TLS, BX
  105. // ... off(BX)(TLS*1) ...
  106. // become
  107. // NOP
  108. // ... off(TLS) ...
  109. //
  110. // TODO(rsc): Remove the Hsolaris special case. It exists only to
  111. // guarantee we are producing byte-identical binaries as before this code.
  112. // But it should be unnecessary.
  113. if (p.As == AMOVQ || p.As == AMOVL) && p.From.Type == obj.TYPE_REG && p.From.Reg == REG_TLS && p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 && ctxt.Headtype != objabi.Hsolaris {
  114. obj.Nopout(p)
  115. }
  116. if p.From.Type == obj.TYPE_MEM && p.From.Index == REG_TLS && REG_AX <= p.From.Reg && p.From.Reg <= REG_R15 {
  117. p.From.Reg = REG_TLS
  118. p.From.Scale = 0
  119. p.From.Index = REG_NONE
  120. }
  121. if p.To.Type == obj.TYPE_MEM && p.To.Index == REG_TLS && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 {
  122. p.To.Reg = REG_TLS
  123. p.To.Scale = 0
  124. p.To.Index = REG_NONE
  125. }
  126. } else {
  127. // load_g_cx, below, always inserts the 1-instruction sequence. Rewrite it
  128. // as the 2-instruction sequence if necessary.
  129. // MOVQ 0(TLS), BX
  130. // becomes
  131. // MOVQ TLS, BX
  132. // MOVQ 0(BX)(TLS*1), BX
  133. if (p.As == AMOVQ || p.As == AMOVL) && p.From.Type == obj.TYPE_MEM && p.From.Reg == REG_TLS && p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 {
  134. q := obj.Appendp(p, newprog)
  135. q.As = p.As
  136. q.From = p.From
  137. q.From.Type = obj.TYPE_MEM
  138. q.From.Reg = p.To.Reg
  139. q.From.Index = REG_TLS
  140. q.From.Scale = 2 // TODO: use 1
  141. q.To = p.To
  142. p.From.Type = obj.TYPE_REG
  143. p.From.Reg = REG_TLS
  144. p.From.Index = REG_NONE
  145. p.From.Offset = 0
  146. }
  147. }
  148. // Android uses a tls offset determined at runtime. Rewrite
  149. // MOVQ TLS, BX
  150. // to
  151. // MOVQ runtime.tls_g(SB), BX
  152. if isAndroid && (p.As == AMOVQ || p.As == AMOVL) && p.From.Type == obj.TYPE_REG && p.From.Reg == REG_TLS && p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 {
  153. p.From.Type = obj.TYPE_MEM
  154. p.From.Name = obj.NAME_EXTERN
  155. p.From.Reg = REG_NONE
  156. p.From.Sym = ctxt.Lookup("runtime.tls_g")
  157. p.From.Index = REG_NONE
  158. }
  159. // TODO: Remove.
  160. if ctxt.Headtype == objabi.Hwindows && ctxt.Arch.Family == sys.AMD64 || ctxt.Headtype == objabi.Hplan9 {
  161. if p.From.Scale == 1 && p.From.Index == REG_TLS {
  162. p.From.Scale = 2
  163. }
  164. if p.To.Scale == 1 && p.To.Index == REG_TLS {
  165. p.To.Scale = 2
  166. }
  167. }
  168. // Rewrite 0 to $0 in 3rd argument to CMPPS etc.
  169. // That's what the tables expect.
  170. switch p.As {
  171. case ACMPPD, ACMPPS, ACMPSD, ACMPSS:
  172. if p.To.Type == obj.TYPE_MEM && p.To.Name == obj.NAME_NONE && p.To.Reg == REG_NONE && p.To.Index == REG_NONE && p.To.Sym == nil {
  173. p.To.Type = obj.TYPE_CONST
  174. }
  175. }
  176. // Rewrite CALL/JMP/RET to symbol as TYPE_BRANCH.
  177. switch p.As {
  178. case obj.ACALL, obj.AJMP, obj.ARET:
  179. if p.To.Type == obj.TYPE_MEM && (p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC) && p.To.Sym != nil {
  180. p.To.Type = obj.TYPE_BRANCH
  181. }
  182. }
  183. // Rewrite MOVL/MOVQ $XXX(FP/SP) as LEAL/LEAQ.
  184. if p.From.Type == obj.TYPE_ADDR && (ctxt.Arch.Family == sys.AMD64 || p.From.Name != obj.NAME_EXTERN && p.From.Name != obj.NAME_STATIC) {
  185. switch p.As {
  186. case AMOVL:
  187. p.As = ALEAL
  188. p.From.Type = obj.TYPE_MEM
  189. case AMOVQ:
  190. p.As = ALEAQ
  191. p.From.Type = obj.TYPE_MEM
  192. }
  193. }
  194. // Rewrite float constants to values stored in memory.
  195. switch p.As {
  196. // Convert AMOVSS $(0), Xx to AXORPS Xx, Xx
  197. case AMOVSS:
  198. if p.From.Type == obj.TYPE_FCONST {
  199. // f == 0 can't be used here due to -0, so use Float64bits
  200. if f := p.From.Val.(float64); math.Float64bits(f) == 0 {
  201. if p.To.Type == obj.TYPE_REG && REG_X0 <= p.To.Reg && p.To.Reg <= REG_X15 {
  202. p.As = AXORPS
  203. p.From = p.To
  204. break
  205. }
  206. }
  207. }
  208. fallthrough
  209. case AFMOVF,
  210. AFADDF,
  211. AFSUBF,
  212. AFSUBRF,
  213. AFMULF,
  214. AFDIVF,
  215. AFDIVRF,
  216. AFCOMF,
  217. AFCOMFP,
  218. AADDSS,
  219. ASUBSS,
  220. AMULSS,
  221. ADIVSS,
  222. ACOMISS,
  223. AUCOMISS:
  224. if p.From.Type == obj.TYPE_FCONST {
  225. f32 := float32(p.From.Val.(float64))
  226. p.From.Type = obj.TYPE_MEM
  227. p.From.Name = obj.NAME_EXTERN
  228. p.From.Sym = ctxt.Float32Sym(f32)
  229. p.From.Offset = 0
  230. }
  231. case AMOVSD:
  232. // Convert AMOVSD $(0), Xx to AXORPS Xx, Xx
  233. if p.From.Type == obj.TYPE_FCONST {
  234. // f == 0 can't be used here due to -0, so use Float64bits
  235. if f := p.From.Val.(float64); math.Float64bits(f) == 0 {
  236. if p.To.Type == obj.TYPE_REG && REG_X0 <= p.To.Reg && p.To.Reg <= REG_X15 {
  237. p.As = AXORPS
  238. p.From = p.To
  239. break
  240. }
  241. }
  242. }
  243. fallthrough
  244. case AFMOVD,
  245. AFADDD,
  246. AFSUBD,
  247. AFSUBRD,
  248. AFMULD,
  249. AFDIVD,
  250. AFDIVRD,
  251. AFCOMD,
  252. AFCOMDP,
  253. AADDSD,
  254. ASUBSD,
  255. AMULSD,
  256. ADIVSD,
  257. ACOMISD,
  258. AUCOMISD:
  259. if p.From.Type == obj.TYPE_FCONST {
  260. f64 := p.From.Val.(float64)
  261. p.From.Type = obj.TYPE_MEM
  262. p.From.Name = obj.NAME_EXTERN
  263. p.From.Sym = ctxt.Float64Sym(f64)
  264. p.From.Offset = 0
  265. }
  266. }
  267. if ctxt.Flag_dynlink {
  268. rewriteToUseGot(ctxt, p, newprog)
  269. }
  270. if ctxt.Flag_shared && ctxt.Arch.Family == sys.I386 {
  271. rewriteToPcrel(ctxt, p, newprog)
  272. }
  273. }
  274. // Rewrite p, if necessary, to access global data via the global offset table.
  275. func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
  276. var lea, mov obj.As
  277. var reg int16
  278. if ctxt.Arch.Family == sys.AMD64 {
  279. lea = ALEAQ
  280. mov = AMOVQ
  281. reg = REG_R15
  282. } else {
  283. lea = ALEAL
  284. mov = AMOVL
  285. reg = REG_CX
  286. if p.As == ALEAL && p.To.Reg != p.From.Reg && p.To.Reg != p.From.Index {
  287. // Special case: clobber the destination register with
  288. // the PC so we don't have to clobber CX.
  289. // The SSA backend depends on CX not being clobbered across LEAL.
  290. // See cmd/compile/internal/ssa/gen/386.rules (search for Flag_shared).
  291. reg = p.To.Reg
  292. }
  293. }
  294. if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
  295. // ADUFFxxx $offset
  296. // becomes
  297. // $MOV runtime.duffxxx@GOT, $reg
  298. // $LEA $offset($reg), $reg
  299. // CALL $reg
  300. // (we use LEAx rather than ADDx because ADDx clobbers
  301. // flags and duffzero on 386 does not otherwise do so).
  302. var sym *obj.LSym
  303. if p.As == obj.ADUFFZERO {
  304. sym = ctxt.Lookup("runtime.duffzero")
  305. } else {
  306. sym = ctxt.Lookup("runtime.duffcopy")
  307. }
  308. offset := p.To.Offset
  309. p.As = mov
  310. p.From.Type = obj.TYPE_MEM
  311. p.From.Name = obj.NAME_GOTREF
  312. p.From.Sym = sym
  313. p.To.Type = obj.TYPE_REG
  314. p.To.Reg = reg
  315. p.To.Offset = 0
  316. p.To.Sym = nil
  317. p1 := obj.Appendp(p, newprog)
  318. p1.As = lea
  319. p1.From.Type = obj.TYPE_MEM
  320. p1.From.Offset = offset
  321. p1.From.Reg = reg
  322. p1.To.Type = obj.TYPE_REG
  323. p1.To.Reg = reg
  324. p2 := obj.Appendp(p1, newprog)
  325. p2.As = obj.ACALL
  326. p2.To.Type = obj.TYPE_REG
  327. p2.To.Reg = reg
  328. }
  329. // We only care about global data: NAME_EXTERN means a global
  330. // symbol in the Go sense, and p.Sym.Local is true for a few
  331. // internally defined symbols.
  332. if p.As == lea && p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
  333. // $LEA sym, Rx becomes $MOV $sym, Rx which will be rewritten below
  334. p.As = mov
  335. p.From.Type = obj.TYPE_ADDR
  336. }
  337. if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
  338. // $MOV $sym, Rx becomes $MOV sym@GOT, Rx
  339. // $MOV $sym+<off>, Rx becomes $MOV sym@GOT, Rx; $LEA <off>(Rx), Rx
  340. // On 386 only, more complicated things like PUSHL $sym become $MOV sym@GOT, CX; PUSHL CX
  341. cmplxdest := false
  342. pAs := p.As
  343. var dest obj.Addr
  344. if p.To.Type != obj.TYPE_REG || pAs != mov {
  345. if ctxt.Arch.Family == sys.AMD64 {
  346. ctxt.Diag("do not know how to handle LEA-type insn to non-register in %v with -dynlink", p)
  347. }
  348. cmplxdest = true
  349. dest = p.To
  350. p.As = mov
  351. p.To.Type = obj.TYPE_REG
  352. p.To.Reg = reg
  353. p.To.Sym = nil
  354. p.To.Name = obj.NAME_NONE
  355. }
  356. p.From.Type = obj.TYPE_MEM
  357. p.From.Name = obj.NAME_GOTREF
  358. q := p
  359. if p.From.Offset != 0 {
  360. q = obj.Appendp(p, newprog)
  361. q.As = lea
  362. q.From.Type = obj.TYPE_MEM
  363. q.From.Reg = p.To.Reg
  364. q.From.Offset = p.From.Offset
  365. q.To = p.To
  366. p.From.Offset = 0
  367. }
  368. if cmplxdest {
  369. q = obj.Appendp(q, newprog)
  370. q.As = pAs
  371. q.To = dest
  372. q.From.Type = obj.TYPE_REG
  373. q.From.Reg = reg
  374. }
  375. }
  376. if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
  377. ctxt.Diag("don't know how to handle %v with -dynlink", p)
  378. }
  379. var source *obj.Addr
  380. // MOVx sym, Ry becomes $MOV sym@GOT, R15; MOVx (R15), Ry
  381. // MOVx Ry, sym becomes $MOV sym@GOT, R15; MOVx Ry, (R15)
  382. // An addition may be inserted between the two MOVs if there is an offset.
  383. if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
  384. if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
  385. ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
  386. }
  387. source = &p.From
  388. } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
  389. source = &p.To
  390. } else {
  391. return
  392. }
  393. if p.As == obj.ACALL {
  394. // When dynlinking on 386, almost any call might end up being a call
  395. // to a PLT, so make sure the GOT pointer is loaded into BX.
  396. // RegTo2 is set on the replacement call insn to stop it being
  397. // processed when it is in turn passed to progedit.
  398. //
  399. // We disable open-coded defers in buildssa() on 386 ONLY with shared
  400. // libraries because of this extra code added before deferreturn calls.
  401. if ctxt.Arch.Family == sys.AMD64 || (p.To.Sym != nil && p.To.Sym.Local()) || p.RegTo2 != 0 {
  402. return
  403. }
  404. p1 := obj.Appendp(p, newprog)
  405. p2 := obj.Appendp(p1, newprog)
  406. p1.As = ALEAL
  407. p1.From.Type = obj.TYPE_MEM
  408. p1.From.Name = obj.NAME_STATIC
  409. p1.From.Sym = ctxt.Lookup("_GLOBAL_OFFSET_TABLE_")
  410. p1.To.Type = obj.TYPE_REG
  411. p1.To.Reg = REG_BX
  412. p2.As = p.As
  413. p2.Scond = p.Scond
  414. p2.From = p.From
  415. if p.RestArgs != nil {
  416. p2.RestArgs = append(p2.RestArgs, p.RestArgs...)
  417. }
  418. p2.Reg = p.Reg
  419. p2.To = p.To
  420. // p.To.Type was set to TYPE_BRANCH above, but that makes checkaddr
  421. // in ../pass.go complain, so set it back to TYPE_MEM here, until p2
  422. // itself gets passed to progedit.
  423. p2.To.Type = obj.TYPE_MEM
  424. p2.RegTo2 = 1
  425. obj.Nopout(p)
  426. return
  427. }
  428. if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ARET || p.As == obj.AJMP {
  429. return
  430. }
  431. if source.Type != obj.TYPE_MEM {
  432. ctxt.Diag("don't know how to handle %v with -dynlink", p)
  433. }
  434. p1 := obj.Appendp(p, newprog)
  435. p2 := obj.Appendp(p1, newprog)
  436. p1.As = mov
  437. p1.From.Type = obj.TYPE_MEM
  438. p1.From.Sym = source.Sym
  439. p1.From.Name = obj.NAME_GOTREF
  440. p1.To.Type = obj.TYPE_REG
  441. p1.To.Reg = reg
  442. p2.As = p.As
  443. p2.From = p.From
  444. p2.To = p.To
  445. if p.From.Name == obj.NAME_EXTERN {
  446. p2.From.Reg = reg
  447. p2.From.Name = obj.NAME_NONE
  448. p2.From.Sym = nil
  449. } else if p.To.Name == obj.NAME_EXTERN {
  450. p2.To.Reg = reg
  451. p2.To.Name = obj.NAME_NONE
  452. p2.To.Sym = nil
  453. } else {
  454. return
  455. }
  456. obj.Nopout(p)
  457. }
  458. func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
  459. // RegTo2 is set on the instructions we insert here so they don't get
  460. // processed twice.
  461. if p.RegTo2 != 0 {
  462. return
  463. }
  464. if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
  465. return
  466. }
  467. // Any Prog (aside from the above special cases) with an Addr with Name ==
  468. // NAME_EXTERN, NAME_STATIC or NAME_GOTREF has a CALL __x86.get_pc_thunk.XX
  469. // inserted before it.
  470. isName := func(a *obj.Addr) bool {
  471. if a.Sym == nil || (a.Type != obj.TYPE_MEM && a.Type != obj.TYPE_ADDR) || a.Reg != 0 {
  472. return false
  473. }
  474. if a.Sym.Type == objabi.STLSBSS {
  475. return false
  476. }
  477. return a.Name == obj.NAME_EXTERN || a.Name == obj.NAME_STATIC || a.Name == obj.NAME_GOTREF
  478. }
  479. if isName(&p.From) && p.From.Type == obj.TYPE_ADDR {
  480. // Handle things like "MOVL $sym, (SP)" or "PUSHL $sym" by rewriting
  481. // to "MOVL $sym, CX; MOVL CX, (SP)" or "MOVL $sym, CX; PUSHL CX"
  482. // respectively.
  483. if p.To.Type != obj.TYPE_REG {
  484. q := obj.Appendp(p, newprog)
  485. q.As = p.As
  486. q.From.Type = obj.TYPE_REG
  487. q.From.Reg = REG_CX
  488. q.To = p.To
  489. p.As = AMOVL
  490. p.To.Type = obj.TYPE_REG
  491. p.To.Reg = REG_CX
  492. p.To.Sym = nil
  493. p.To.Name = obj.NAME_NONE
  494. }
  495. }
  496. if !isName(&p.From) && !isName(&p.To) && (p.GetFrom3() == nil || !isName(p.GetFrom3())) {
  497. return
  498. }
  499. var dst int16 = REG_CX
  500. if (p.As == ALEAL || p.As == AMOVL) && p.To.Reg != p.From.Reg && p.To.Reg != p.From.Index {
  501. dst = p.To.Reg
  502. // Why? See the comment near the top of rewriteToUseGot above.
  503. // AMOVLs might be introduced by the GOT rewrites.
  504. }
  505. q := obj.Appendp(p, newprog)
  506. q.RegTo2 = 1
  507. r := obj.Appendp(q, newprog)
  508. r.RegTo2 = 1
  509. q.As = obj.ACALL
  510. thunkname := "__x86.get_pc_thunk." + strings.ToLower(rconv(int(dst)))
  511. q.To.Sym = ctxt.LookupInit(thunkname, func(s *obj.LSym) { s.Set(obj.AttrLocal, true) })
  512. q.To.Type = obj.TYPE_MEM
  513. q.To.Name = obj.NAME_EXTERN
  514. r.As = p.As
  515. r.Scond = p.Scond
  516. r.From = p.From
  517. r.RestArgs = p.RestArgs
  518. r.Reg = p.Reg
  519. r.To = p.To
  520. if isName(&p.From) {
  521. r.From.Reg = dst
  522. }
  523. if isName(&p.To) {
  524. r.To.Reg = dst
  525. }
  526. if p.GetFrom3() != nil && isName(p.GetFrom3()) {
  527. r.GetFrom3().Reg = dst
  528. }
  529. obj.Nopout(p)
  530. }
  531. func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
  532. if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
  533. return
  534. }
  535. p := cursym.Func.Text
  536. autoffset := int32(p.To.Offset)
  537. if autoffset < 0 {
  538. autoffset = 0
  539. }
  540. hasCall := false
  541. for q := p; q != nil; q = q.Link {
  542. if q.As == obj.ACALL || q.As == obj.ADUFFCOPY || q.As == obj.ADUFFZERO {
  543. hasCall = true
  544. break
  545. }
  546. }
  547. var bpsize int
  548. if ctxt.Arch.Family == sys.AMD64 &&
  549. !p.From.Sym.NoFrame() && // (1) below
  550. !(autoffset == 0 && p.From.Sym.NoSplit()) && // (2) below
  551. !(autoffset == 0 && !hasCall) { // (3) below
  552. // Make room to save a base pointer.
  553. // There are 2 cases we must avoid:
  554. // 1) If noframe is set (which we do for functions which tail call).
  555. // 2) Scary runtime internals which would be all messed up by frame pointers.
  556. // We detect these using a heuristic: frameless nosplit functions.
  557. // TODO: Maybe someday we label them all with NOFRAME and get rid of this heuristic.
  558. // For performance, we also want to avoid:
  559. // 3) Frameless leaf functions
  560. bpsize = ctxt.Arch.PtrSize
  561. autoffset += int32(bpsize)
  562. p.To.Offset += int64(bpsize)
  563. } else {
  564. bpsize = 0
  565. }
  566. textarg := int64(p.To.Val.(int32))
  567. cursym.Func.Args = int32(textarg)
  568. cursym.Func.Locals = int32(p.To.Offset)
  569. // TODO(rsc): Remove.
  570. if ctxt.Arch.Family == sys.I386 && cursym.Func.Locals < 0 {
  571. cursym.Func.Locals = 0
  572. }
  573. // TODO(rsc): Remove 'ctxt.Arch.Family == sys.AMD64 &&'.
  574. if ctxt.Arch.Family == sys.AMD64 && autoffset < objabi.StackSmall && !p.From.Sym.NoSplit() {
  575. leaf := true
  576. LeafSearch:
  577. for q := p; q != nil; q = q.Link {
  578. switch q.As {
  579. case obj.ACALL:
  580. // Treat common runtime calls that take no arguments
  581. // the same as duffcopy and duffzero.
  582. if !isZeroArgRuntimeCall(q.To.Sym) {
  583. leaf = false
  584. break LeafSearch
  585. }
  586. fallthrough
  587. case obj.ADUFFCOPY, obj.ADUFFZERO:
  588. if autoffset >= objabi.StackSmall-8 {
  589. leaf = false
  590. break LeafSearch
  591. }
  592. }
  593. }
  594. if leaf {
  595. p.From.Sym.Set(obj.AttrNoSplit, true)
  596. }
  597. }
  598. if !p.From.Sym.NoSplit() || p.From.Sym.Wrapper() {
  599. p = obj.Appendp(p, newprog)
  600. p = load_g_cx(ctxt, p, newprog) // load g into CX
  601. }
  602. if !cursym.Func.Text.From.Sym.NoSplit() {
  603. p = stacksplit(ctxt, cursym, p, newprog, autoffset, int32(textarg)) // emit split check
  604. }
  605. // Delve debugger would like the next instruction to be noted as the end of the function prologue.
  606. // TODO: are there other cases (e.g., wrapper functions) that need marking?
  607. markedPrologue := false
  608. if autoffset != 0 {
  609. if autoffset%int32(ctxt.Arch.RegSize) != 0 {
  610. ctxt.Diag("unaligned stack size %d", autoffset)
  611. }
  612. p = obj.Appendp(p, newprog)
  613. p.As = AADJSP
  614. p.From.Type = obj.TYPE_CONST
  615. p.From.Offset = int64(autoffset)
  616. p.Spadj = autoffset
  617. p.Pos = p.Pos.WithXlogue(src.PosPrologueEnd)
  618. markedPrologue = true
  619. }
  620. if bpsize > 0 {
  621. // Save caller's BP
  622. p = obj.Appendp(p, newprog)
  623. p.As = AMOVQ
  624. p.From.Type = obj.TYPE_REG
  625. p.From.Reg = REG_BP
  626. p.To.Type = obj.TYPE_MEM
  627. p.To.Reg = REG_SP
  628. p.To.Scale = 1
  629. p.To.Offset = int64(autoffset) - int64(bpsize)
  630. if !markedPrologue {
  631. p.Pos = p.Pos.WithXlogue(src.PosPrologueEnd)
  632. }
  633. // Move current frame to BP
  634. p = obj.Appendp(p, newprog)
  635. p.As = ALEAQ
  636. p.From.Type = obj.TYPE_MEM
  637. p.From.Reg = REG_SP
  638. p.From.Scale = 1
  639. p.From.Offset = int64(autoffset) - int64(bpsize)
  640. p.To.Type = obj.TYPE_REG
  641. p.To.Reg = REG_BP
  642. }
  643. if cursym.Func.Text.From.Sym.Wrapper() {
  644. // if g._panic != nil && g._panic.argp == FP {
  645. // g._panic.argp = bottom-of-frame
  646. // }
  647. //
  648. // MOVQ g_panic(CX), BX
  649. // TESTQ BX, BX
  650. // JNE checkargp
  651. // end:
  652. // NOP
  653. // ... rest of function ...
  654. // checkargp:
  655. // LEAQ (autoffset+8)(SP), DI
  656. // CMPQ panic_argp(BX), DI
  657. // JNE end
  658. // MOVQ SP, panic_argp(BX)
  659. // JMP end
  660. //
  661. // The NOP is needed to give the jumps somewhere to land.
  662. // It is a liblink NOP, not an x86 NOP: it encodes to 0 instruction bytes.
  663. //
  664. // The layout is chosen to help static branch prediction:
  665. // Both conditional jumps are unlikely, so they are arranged to be forward jumps.
  666. // MOVQ g_panic(CX), BX
  667. p = obj.Appendp(p, newprog)
  668. p.As = AMOVQ
  669. p.From.Type = obj.TYPE_MEM
  670. p.From.Reg = REG_CX
  671. p.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // g_panic
  672. p.To.Type = obj.TYPE_REG
  673. p.To.Reg = REG_BX
  674. if ctxt.Arch.Family == sys.I386 {
  675. p.As = AMOVL
  676. }
  677. // TESTQ BX, BX
  678. p = obj.Appendp(p, newprog)
  679. p.As = ATESTQ
  680. p.From.Type = obj.TYPE_REG
  681. p.From.Reg = REG_BX
  682. p.To.Type = obj.TYPE_REG
  683. p.To.Reg = REG_BX
  684. if ctxt.Arch.Family == sys.I386 {
  685. p.As = ATESTL
  686. }
  687. // JNE checkargp (checkargp to be resolved later)
  688. jne := obj.Appendp(p, newprog)
  689. jne.As = AJNE
  690. jne.To.Type = obj.TYPE_BRANCH
  691. // end:
  692. // NOP
  693. end := obj.Appendp(jne, newprog)
  694. end.As = obj.ANOP
  695. // Fast forward to end of function.
  696. var last *obj.Prog
  697. for last = end; last.Link != nil; last = last.Link {
  698. }
  699. // LEAQ (autoffset+8)(SP), DI
  700. p = obj.Appendp(last, newprog)
  701. p.As = ALEAQ
  702. p.From.Type = obj.TYPE_MEM
  703. p.From.Reg = REG_SP
  704. p.From.Offset = int64(autoffset) + int64(ctxt.Arch.RegSize)
  705. p.To.Type = obj.TYPE_REG
  706. p.To.Reg = REG_DI
  707. if ctxt.Arch.Family == sys.I386 {
  708. p.As = ALEAL
  709. }
  710. // Set jne branch target.
  711. jne.To.SetTarget(p)
  712. // CMPQ panic_argp(BX), DI
  713. p = obj.Appendp(p, newprog)
  714. p.As = ACMPQ
  715. p.From.Type = obj.TYPE_MEM
  716. p.From.Reg = REG_BX
  717. p.From.Offset = 0 // Panic.argp
  718. p.To.Type = obj.TYPE_REG
  719. p.To.Reg = REG_DI
  720. if ctxt.Arch.Family == sys.I386 {
  721. p.As = ACMPL
  722. }
  723. // JNE end
  724. p = obj.Appendp(p, newprog)
  725. p.As = AJNE
  726. p.To.Type = obj.TYPE_BRANCH
  727. p.To.SetTarget(end)
  728. // MOVQ SP, panic_argp(BX)
  729. p = obj.Appendp(p, newprog)
  730. p.As = AMOVQ
  731. p.From.Type = obj.TYPE_REG
  732. p.From.Reg = REG_SP
  733. p.To.Type = obj.TYPE_MEM
  734. p.To.Reg = REG_BX
  735. p.To.Offset = 0 // Panic.argp
  736. if ctxt.Arch.Family == sys.I386 {
  737. p.As = AMOVL
  738. }
  739. // JMP end
  740. p = obj.Appendp(p, newprog)
  741. p.As = obj.AJMP
  742. p.To.Type = obj.TYPE_BRANCH
  743. p.To.SetTarget(end)
  744. // Reset p for following code.
  745. p = end
  746. }
  747. var deltasp int32
  748. for p = cursym.Func.Text; p != nil; p = p.Link {
  749. pcsize := ctxt.Arch.RegSize
  750. switch p.From.Name {
  751. case obj.NAME_AUTO:
  752. p.From.Offset += int64(deltasp) - int64(bpsize)
  753. case obj.NAME_PARAM:
  754. p.From.Offset += int64(deltasp) + int64(pcsize)
  755. }
  756. if p.GetFrom3() != nil {
  757. switch p.GetFrom3().Name {
  758. case obj.NAME_AUTO:
  759. p.GetFrom3().Offset += int64(deltasp) - int64(bpsize)
  760. case obj.NAME_PARAM:
  761. p.GetFrom3().Offset += int64(deltasp) + int64(pcsize)
  762. }
  763. }
  764. switch p.To.Name {
  765. case obj.NAME_AUTO:
  766. p.To.Offset += int64(deltasp) - int64(bpsize)
  767. case obj.NAME_PARAM:
  768. p.To.Offset += int64(deltasp) + int64(pcsize)
  769. }
  770. switch p.As {
  771. default:
  772. continue
  773. case APUSHL, APUSHFL:
  774. deltasp += 4
  775. p.Spadj = 4
  776. continue
  777. case APUSHQ, APUSHFQ:
  778. deltasp += 8
  779. p.Spadj = 8
  780. continue
  781. case APUSHW, APUSHFW:
  782. deltasp += 2
  783. p.Spadj = 2
  784. continue
  785. case APOPL, APOPFL:
  786. deltasp -= 4
  787. p.Spadj = -4
  788. continue
  789. case APOPQ, APOPFQ:
  790. deltasp -= 8
  791. p.Spadj = -8
  792. continue
  793. case APOPW, APOPFW:
  794. deltasp -= 2
  795. p.Spadj = -2
  796. continue
  797. case AADJSP:
  798. p.Spadj = int32(p.From.Offset)
  799. deltasp += int32(p.From.Offset)
  800. continue
  801. case obj.ARET:
  802. // do nothing
  803. }
  804. if autoffset != deltasp {
  805. ctxt.Diag("unbalanced PUSH/POP")
  806. }
  807. if autoffset != 0 {
  808. to := p.To // Keep To attached to RET for retjmp below
  809. p.To = obj.Addr{}
  810. if bpsize > 0 {
  811. // Restore caller's BP
  812. p.As = AMOVQ
  813. p.From.Type = obj.TYPE_MEM
  814. p.From.Reg = REG_SP
  815. p.From.Scale = 1
  816. p.From.Offset = int64(autoffset) - int64(bpsize)
  817. p.To.Type = obj.TYPE_REG
  818. p.To.Reg = REG_BP
  819. p = obj.Appendp(p, newprog)
  820. }
  821. p.As = AADJSP
  822. p.From.Type = obj.TYPE_CONST
  823. p.From.Offset = int64(-autoffset)
  824. p.Spadj = -autoffset
  825. p = obj.Appendp(p, newprog)
  826. p.As = obj.ARET
  827. p.To = to
  828. // If there are instructions following
  829. // this ARET, they come from a branch
  830. // with the same stackframe, so undo
  831. // the cleanup.
  832. p.Spadj = +autoffset
  833. }
  834. if p.To.Sym != nil { // retjmp
  835. p.As = obj.AJMP
  836. }
  837. }
  838. }
  839. func isZeroArgRuntimeCall(s *obj.LSym) bool {
  840. if s == nil {
  841. return false
  842. }
  843. switch s.Name {
  844. case "runtime.panicdivide", "runtime.panicwrap", "runtime.panicshift":
  845. return true
  846. }
  847. if strings.HasPrefix(s.Name, "runtime.panicIndex") || strings.HasPrefix(s.Name, "runtime.panicSlice") {
  848. // These functions do take arguments (in registers),
  849. // but use no stack before they do a stack check. We
  850. // should include them. See issue 31219.
  851. return true
  852. }
  853. return false
  854. }
  855. func indir_cx(ctxt *obj.Link, a *obj.Addr) {
  856. a.Type = obj.TYPE_MEM
  857. a.Reg = REG_CX
  858. }
  859. // Append code to p to load g into cx.
  860. // Overwrites p with the first instruction (no first appendp).
  861. // Overwriting p is unusual but it lets use this in both the
  862. // prologue (caller must call appendp first) and in the epilogue.
  863. // Returns last new instruction.
  864. func load_g_cx(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) *obj.Prog {
  865. p.As = AMOVQ
  866. if ctxt.Arch.PtrSize == 4 {
  867. p.As = AMOVL
  868. }
  869. p.From.Type = obj.TYPE_MEM
  870. p.From.Reg = REG_TLS
  871. p.From.Offset = 0
  872. p.To.Type = obj.TYPE_REG
  873. p.To.Reg = REG_CX
  874. next := p.Link
  875. progedit(ctxt, p, newprog)
  876. for p.Link != next {
  877. p = p.Link
  878. progedit(ctxt, p, newprog)
  879. }
  880. if p.From.Index == REG_TLS {
  881. p.From.Scale = 2
  882. }
  883. return p
  884. }
  885. // Append code to p to check for stack split.
  886. // Appends to (does not overwrite) p.
  887. // Assumes g is in CX.
  888. // Returns last new instruction.
  889. func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgAlloc, framesize int32, textarg int32) *obj.Prog {
  890. cmp := ACMPQ
  891. lea := ALEAQ
  892. mov := AMOVQ
  893. sub := ASUBQ
  894. if ctxt.Arch.Family == sys.I386 {
  895. cmp = ACMPL
  896. lea = ALEAL
  897. mov = AMOVL
  898. sub = ASUBL
  899. }
  900. var q1 *obj.Prog
  901. if framesize <= objabi.StackSmall {
  902. // small stack: SP <= stackguard
  903. // CMPQ SP, stackguard
  904. p = obj.Appendp(p, newprog)
  905. p.As = cmp
  906. p.From.Type = obj.TYPE_REG
  907. p.From.Reg = REG_SP
  908. indir_cx(ctxt, &p.To)
  909. p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
  910. if cursym.CFunc() {
  911. p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
  912. }
  913. // Mark the stack bound check and morestack call async nonpreemptible.
  914. // If we get preempted here, when resumed the preemption request is
  915. // cleared, but we'll still call morestack, which will double the stack
  916. // unnecessarily. See issue #35470.
  917. p = ctxt.StartUnsafePoint(p, newprog)
  918. } else if framesize <= objabi.StackBig {
  919. // large stack: SP-framesize <= stackguard-StackSmall
  920. // LEAQ -xxx(SP), AX
  921. // CMPQ AX, stackguard
  922. p = obj.Appendp(p, newprog)
  923. p.As = lea
  924. p.From.Type = obj.TYPE_MEM
  925. p.From.Reg = REG_SP
  926. p.From.Offset = -(int64(framesize) - objabi.StackSmall)
  927. p.To.Type = obj.TYPE_REG
  928. p.To.Reg = REG_AX
  929. p = obj.Appendp(p, newprog)
  930. p.As = cmp
  931. p.From.Type = obj.TYPE_REG
  932. p.From.Reg = REG_AX
  933. indir_cx(ctxt, &p.To)
  934. p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
  935. if cursym.CFunc() {
  936. p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
  937. }
  938. p = ctxt.StartUnsafePoint(p, newprog) // see the comment above
  939. } else {
  940. // Such a large stack we need to protect against wraparound.
  941. // If SP is close to zero:
  942. // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
  943. // The +StackGuard on both sides is required to keep the left side positive:
  944. // SP is allowed to be slightly below stackguard. See stack.h.
  945. //
  946. // Preemption sets stackguard to StackPreempt, a very large value.
  947. // That breaks the math above, so we have to check for that explicitly.
  948. // MOVQ stackguard, SI
  949. // CMPQ SI, $StackPreempt
  950. // JEQ label-of-call-to-morestack
  951. // LEAQ StackGuard(SP), AX
  952. // SUBQ SI, AX
  953. // CMPQ AX, $(framesize+(StackGuard-StackSmall))
  954. p = obj.Appendp(p, newprog)
  955. p.As = mov
  956. indir_cx(ctxt, &p.From)
  957. p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
  958. if cursym.CFunc() {
  959. p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
  960. }
  961. p.To.Type = obj.TYPE_REG
  962. p.To.Reg = REG_SI
  963. p = ctxt.StartUnsafePoint(p, newprog) // see the comment above
  964. p = obj.Appendp(p, newprog)
  965. p.As = cmp
  966. p.From.Type = obj.TYPE_REG
  967. p.From.Reg = REG_SI
  968. p.To.Type = obj.TYPE_CONST
  969. p.To.Offset = objabi.StackPreempt
  970. if ctxt.Arch.Family == sys.I386 {
  971. p.To.Offset = int64(uint32(objabi.StackPreempt & (1<<32 - 1)))
  972. }
  973. p = obj.Appendp(p, newprog)
  974. p.As = AJEQ
  975. p.To.Type = obj.TYPE_BRANCH
  976. q1 = p
  977. p = obj.Appendp(p, newprog)
  978. p.As = lea
  979. p.From.Type = obj.TYPE_MEM
  980. p.From.Reg = REG_SP
  981. p.From.Offset = int64(objabi.StackGuard)
  982. p.To.Type = obj.TYPE_REG
  983. p.To.Reg = REG_AX
  984. p = obj.Appendp(p, newprog)
  985. p.As = sub
  986. p.From.Type = obj.TYPE_REG
  987. p.From.Reg = REG_SI
  988. p.To.Type = obj.TYPE_REG
  989. p.To.Reg = REG_AX
  990. p = obj.Appendp(p, newprog)
  991. p.As = cmp
  992. p.From.Type = obj.TYPE_REG
  993. p.From.Reg = REG_AX
  994. p.To.Type = obj.TYPE_CONST
  995. p.To.Offset = int64(framesize) + (int64(objabi.StackGuard) - objabi.StackSmall)
  996. }
  997. // common
  998. jls := obj.Appendp(p, newprog)
  999. jls.As = AJLS
  1000. jls.To.Type = obj.TYPE_BRANCH
  1001. end := ctxt.EndUnsafePoint(jls, newprog, -1)
  1002. var last *obj.Prog
  1003. for last = cursym.Func.Text; last.Link != nil; last = last.Link {
  1004. }
  1005. // Now we are at the end of the function, but logically
  1006. // we are still in function prologue. We need to fix the
  1007. // SP data and PCDATA.
  1008. spfix := obj.Appendp(last, newprog)
  1009. spfix.As = obj.ANOP
  1010. spfix.Spadj = -framesize
  1011. pcdata := ctxt.EmitEntryStackMap(cursym, spfix, newprog)
  1012. pcdata = ctxt.StartUnsafePoint(pcdata, newprog)
  1013. call := obj.Appendp(pcdata, newprog)
  1014. call.Pos = cursym.Func.Text.Pos
  1015. call.As = obj.ACALL
  1016. call.To.Type = obj.TYPE_BRANCH
  1017. call.To.Name = obj.NAME_EXTERN
  1018. morestack := "runtime.morestack"
  1019. switch {
  1020. case cursym.CFunc():
  1021. morestack = "runtime.morestackc"
  1022. case !cursym.Func.Text.From.Sym.NeedCtxt():
  1023. morestack = "runtime.morestack_noctxt"
  1024. }
  1025. call.To.Sym = ctxt.Lookup(morestack)
  1026. // When compiling 386 code for dynamic linking, the call needs to be adjusted
  1027. // to follow PIC rules. This in turn can insert more instructions, so we need
  1028. // to keep track of the start of the call (where the jump will be to) and the
  1029. // end (which following instructions are appended to).
  1030. callend := call
  1031. progedit(ctxt, callend, newprog)
  1032. for ; callend.Link != nil; callend = callend.Link {
  1033. progedit(ctxt, callend.Link, newprog)
  1034. }
  1035. pcdata = ctxt.EndUnsafePoint(callend, newprog, -1)
  1036. jmp := obj.Appendp(pcdata, newprog)
  1037. jmp.As = obj.AJMP
  1038. jmp.To.Type = obj.TYPE_BRANCH
  1039. jmp.To.SetTarget(cursym.Func.Text.Link)
  1040. jmp.Spadj = +framesize
  1041. jls.To.SetTarget(call)
  1042. if q1 != nil {
  1043. q1.To.SetTarget(call)
  1044. }
  1045. return end
  1046. }
  1047. var unaryDst = map[obj.As]bool{
  1048. ABSWAPL: true,
  1049. ABSWAPQ: true,
  1050. ACLDEMOTE: true,
  1051. ACLFLUSH: true,
  1052. ACLFLUSHOPT: true,
  1053. ACLWB: true,
  1054. ACMPXCHG16B: true,
  1055. ACMPXCHG8B: true,
  1056. ADECB: true,
  1057. ADECL: true,
  1058. ADECQ: true,
  1059. ADECW: true,
  1060. AFBSTP: true,
  1061. AFFREE: true,
  1062. AFLDENV: true,
  1063. AFSAVE: true,
  1064. AFSTCW: true,
  1065. AFSTENV: true,
  1066. AFSTSW: true,
  1067. AFXSAVE64: true,
  1068. AFXSAVE: true,
  1069. AINCB: true,
  1070. AINCL: true,
  1071. AINCQ: true,
  1072. AINCW: true,
  1073. ANEGB: true,
  1074. ANEGL: true,
  1075. ANEGQ: true,
  1076. ANEGW: true,
  1077. ANOTB: true,
  1078. ANOTL: true,
  1079. ANOTQ: true,
  1080. ANOTW: true,
  1081. APOPL: true,
  1082. APOPQ: true,
  1083. APOPW: true,
  1084. ARDFSBASEL: true,
  1085. ARDFSBASEQ: true,
  1086. ARDGSBASEL: true,
  1087. ARDGSBASEQ: true,
  1088. ARDRANDL: true,
  1089. ARDRANDQ: true,
  1090. ARDRANDW: true,
  1091. ARDSEEDL: true,
  1092. ARDSEEDQ: true,
  1093. ARDSEEDW: true,
  1094. ASETCC: true,
  1095. ASETCS: true,
  1096. ASETEQ: true,
  1097. ASETGE: true,
  1098. ASETGT: true,
  1099. ASETHI: true,
  1100. ASETLE: true,
  1101. ASETLS: true,
  1102. ASETLT: true,
  1103. ASETMI: true,
  1104. ASETNE: true,
  1105. ASETOC: true,
  1106. ASETOS: true,
  1107. ASETPC: true,
  1108. ASETPL: true,
  1109. ASETPS: true,
  1110. ASGDT: true,
  1111. ASIDT: true,
  1112. ASLDTL: true,
  1113. ASLDTQ: true,
  1114. ASLDTW: true,
  1115. ASMSWL: true,
  1116. ASMSWQ: true,
  1117. ASMSWW: true,
  1118. ASTMXCSR: true,
  1119. ASTRL: true,
  1120. ASTRQ: true,
  1121. ASTRW: true,
  1122. AXSAVE64: true,
  1123. AXSAVE: true,
  1124. AXSAVEC64: true,
  1125. AXSAVEC: true,
  1126. AXSAVEOPT64: true,
  1127. AXSAVEOPT: true,
  1128. AXSAVES64: true,
  1129. AXSAVES: true,
  1130. }
  1131. var Linkamd64 = obj.LinkArch{
  1132. Arch: sys.ArchAMD64,
  1133. Init: instinit,
  1134. Preprocess: preprocess,
  1135. Assemble: span6,
  1136. Progedit: progedit,
  1137. UnaryDst: unaryDst,
  1138. DWARFRegisters: AMD64DWARFRegisters,
  1139. }
  1140. var Link386 = obj.LinkArch{
  1141. Arch: sys.Arch386,
  1142. Init: instinit,
  1143. Preprocess: preprocess,
  1144. Assemble: span6,
  1145. Progedit: progedit,
  1146. UnaryDst: unaryDst,
  1147. DWARFRegisters: X86DWARFRegisters,
  1148. }