plist.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. // Copyright 2013 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package obj
  5. import (
  6. "github.com/twitchyliquid64/golang-asm/objabi"
  7. "fmt"
  8. "strings"
  9. )
  10. type Plist struct {
  11. Firstpc *Prog
  12. Curfn interface{} // holds a *gc.Node, if non-nil
  13. }
  14. // ProgAlloc is a function that allocates Progs.
  15. // It is used to provide access to cached/bulk-allocated Progs to the assemblers.
  16. type ProgAlloc func() *Prog
  17. func Flushplist(ctxt *Link, plist *Plist, newprog ProgAlloc, myimportpath string) {
  18. // Build list of symbols, and assign instructions to lists.
  19. var curtext *LSym
  20. var etext *Prog
  21. var text []*LSym
  22. var plink *Prog
  23. for p := plist.Firstpc; p != nil; p = plink {
  24. if ctxt.Debugasm > 0 && ctxt.Debugvlog {
  25. fmt.Printf("obj: %v\n", p)
  26. }
  27. plink = p.Link
  28. p.Link = nil
  29. switch p.As {
  30. case AEND:
  31. continue
  32. case ATEXT:
  33. s := p.From.Sym
  34. if s == nil {
  35. // func _() { }
  36. curtext = nil
  37. continue
  38. }
  39. text = append(text, s)
  40. etext = p
  41. curtext = s
  42. continue
  43. case AFUNCDATA:
  44. // Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information.
  45. if curtext == nil { // func _() {}
  46. continue
  47. }
  48. if p.To.Sym.Name == "go_args_stackmap" {
  49. if p.From.Type != TYPE_CONST || p.From.Offset != objabi.FUNCDATA_ArgsPointerMaps {
  50. ctxt.Diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps")
  51. }
  52. p.To.Sym = ctxt.LookupDerived(curtext, curtext.Name+".args_stackmap")
  53. }
  54. }
  55. if curtext == nil {
  56. etext = nil
  57. continue
  58. }
  59. etext.Link = p
  60. etext = p
  61. }
  62. if newprog == nil {
  63. newprog = ctxt.NewProg
  64. }
  65. // Add reference to Go arguments for C or assembly functions without them.
  66. for _, s := range text {
  67. if !strings.HasPrefix(s.Name, "\"\".") {
  68. continue
  69. }
  70. found := false
  71. for p := s.Func.Text; p != nil; p = p.Link {
  72. if p.As == AFUNCDATA && p.From.Type == TYPE_CONST && p.From.Offset == objabi.FUNCDATA_ArgsPointerMaps {
  73. found = true
  74. break
  75. }
  76. }
  77. if !found {
  78. p := Appendp(s.Func.Text, newprog)
  79. p.As = AFUNCDATA
  80. p.From.Type = TYPE_CONST
  81. p.From.Offset = objabi.FUNCDATA_ArgsPointerMaps
  82. p.To.Type = TYPE_MEM
  83. p.To.Name = NAME_EXTERN
  84. p.To.Sym = ctxt.LookupDerived(s, s.Name+".args_stackmap")
  85. }
  86. }
  87. // Turn functions into machine code images.
  88. for _, s := range text {
  89. mkfwd(s)
  90. linkpatch(ctxt, s, newprog)
  91. ctxt.Arch.Preprocess(ctxt, s, newprog)
  92. ctxt.Arch.Assemble(ctxt, s, newprog)
  93. if ctxt.Errors > 0 {
  94. continue
  95. }
  96. linkpcln(ctxt, s)
  97. if myimportpath != "" {
  98. ctxt.populateDWARF(plist.Curfn, s, myimportpath)
  99. }
  100. }
  101. }
  102. func (ctxt *Link) InitTextSym(s *LSym, flag int) {
  103. if s == nil {
  104. // func _() { }
  105. return
  106. }
  107. if s.Func != nil {
  108. ctxt.Diag("InitTextSym double init for %s", s.Name)
  109. }
  110. s.Func = new(FuncInfo)
  111. if s.OnList() {
  112. ctxt.Diag("symbol %s listed multiple times", s.Name)
  113. }
  114. name := strings.Replace(s.Name, "\"\"", ctxt.Pkgpath, -1)
  115. s.Func.FuncID = objabi.GetFuncID(name, flag&WRAPPER != 0)
  116. s.Set(AttrOnList, true)
  117. s.Set(AttrDuplicateOK, flag&DUPOK != 0)
  118. s.Set(AttrNoSplit, flag&NOSPLIT != 0)
  119. s.Set(AttrReflectMethod, flag&REFLECTMETHOD != 0)
  120. s.Set(AttrWrapper, flag&WRAPPER != 0)
  121. s.Set(AttrNeedCtxt, flag&NEEDCTXT != 0)
  122. s.Set(AttrNoFrame, flag&NOFRAME != 0)
  123. s.Set(AttrTopFrame, flag&TOPFRAME != 0)
  124. s.Type = objabi.STEXT
  125. ctxt.Text = append(ctxt.Text, s)
  126. // Set up DWARF entries for s
  127. ctxt.dwarfSym(s)
  128. }
  129. func (ctxt *Link) Globl(s *LSym, size int64, flag int) {
  130. if s.OnList() {
  131. ctxt.Diag("symbol %s listed multiple times", s.Name)
  132. }
  133. s.Set(AttrOnList, true)
  134. ctxt.Data = append(ctxt.Data, s)
  135. s.Size = size
  136. if s.Type == 0 {
  137. s.Type = objabi.SBSS
  138. }
  139. if flag&DUPOK != 0 {
  140. s.Set(AttrDuplicateOK, true)
  141. }
  142. if flag&RODATA != 0 {
  143. s.Type = objabi.SRODATA
  144. } else if flag&NOPTR != 0 {
  145. if s.Type == objabi.SDATA {
  146. s.Type = objabi.SNOPTRDATA
  147. } else {
  148. s.Type = objabi.SNOPTRBSS
  149. }
  150. } else if flag&TLSBSS != 0 {
  151. s.Type = objabi.STLSBSS
  152. }
  153. if strings.HasPrefix(s.Name, "\"\"."+StaticNamePref) {
  154. s.Set(AttrStatic, true)
  155. }
  156. }
  157. // EmitEntryLiveness generates PCDATA Progs after p to switch to the
  158. // liveness map active at the entry of function s. It returns the last
  159. // Prog generated.
  160. func (ctxt *Link) EmitEntryLiveness(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
  161. pcdata := ctxt.EmitEntryStackMap(s, p, newprog)
  162. pcdata = ctxt.EmitEntryRegMap(s, pcdata, newprog)
  163. return pcdata
  164. }
  165. // Similar to EmitEntryLiveness, but just emit stack map.
  166. func (ctxt *Link) EmitEntryStackMap(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
  167. pcdata := Appendp(p, newprog)
  168. pcdata.Pos = s.Func.Text.Pos
  169. pcdata.As = APCDATA
  170. pcdata.From.Type = TYPE_CONST
  171. pcdata.From.Offset = objabi.PCDATA_StackMapIndex
  172. pcdata.To.Type = TYPE_CONST
  173. pcdata.To.Offset = -1 // pcdata starts at -1 at function entry
  174. return pcdata
  175. }
  176. // Similar to EmitEntryLiveness, but just emit register map.
  177. func (ctxt *Link) EmitEntryRegMap(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
  178. pcdata := Appendp(p, newprog)
  179. pcdata.Pos = s.Func.Text.Pos
  180. pcdata.As = APCDATA
  181. pcdata.From.Type = TYPE_CONST
  182. pcdata.From.Offset = objabi.PCDATA_RegMapIndex
  183. pcdata.To.Type = TYPE_CONST
  184. pcdata.To.Offset = -1
  185. return pcdata
  186. }
  187. // StartUnsafePoint generates PCDATA Progs after p to mark the
  188. // beginning of an unsafe point. The unsafe point starts immediately
  189. // after p.
  190. // It returns the last Prog generated.
  191. func (ctxt *Link) StartUnsafePoint(p *Prog, newprog ProgAlloc) *Prog {
  192. pcdata := Appendp(p, newprog)
  193. pcdata.As = APCDATA
  194. pcdata.From.Type = TYPE_CONST
  195. pcdata.From.Offset = objabi.PCDATA_RegMapIndex
  196. pcdata.To.Type = TYPE_CONST
  197. pcdata.To.Offset = objabi.PCDATA_RegMapUnsafe
  198. return pcdata
  199. }
  200. // EndUnsafePoint generates PCDATA Progs after p to mark the end of an
  201. // unsafe point, restoring the register map index to oldval.
  202. // The unsafe point ends right after p.
  203. // It returns the last Prog generated.
  204. func (ctxt *Link) EndUnsafePoint(p *Prog, newprog ProgAlloc, oldval int64) *Prog {
  205. pcdata := Appendp(p, newprog)
  206. pcdata.As = APCDATA
  207. pcdata.From.Type = TYPE_CONST
  208. pcdata.From.Offset = objabi.PCDATA_RegMapIndex
  209. pcdata.To.Type = TYPE_CONST
  210. pcdata.To.Offset = oldval
  211. return pcdata
  212. }
  213. // MarkUnsafePoints inserts PCDATAs to mark nonpreemptible and restartable
  214. // instruction sequences, based on isUnsafePoint and isRestartable predicate.
  215. // p0 is the start of the instruction stream.
  216. // isUnsafePoint(p) returns true if p is not safe for async preemption.
  217. // isRestartable(p) returns true if we can restart at the start of p (this Prog)
  218. // upon async preemption. (Currently multi-Prog restartable sequence is not
  219. // supported.)
  220. // isRestartable can be nil. In this case it is treated as always returning false.
  221. // If isUnsafePoint(p) and isRestartable(p) are both true, it is treated as
  222. // an unsafe point.
  223. func MarkUnsafePoints(ctxt *Link, p0 *Prog, newprog ProgAlloc, isUnsafePoint, isRestartable func(*Prog) bool) {
  224. if isRestartable == nil {
  225. // Default implementation: nothing is restartable.
  226. isRestartable = func(*Prog) bool { return false }
  227. }
  228. prev := p0
  229. prevPcdata := int64(-1) // entry PC data value
  230. prevRestart := int64(0)
  231. for p := prev.Link; p != nil; p, prev = p.Link, p {
  232. if p.As == APCDATA && p.From.Offset == objabi.PCDATA_RegMapIndex {
  233. prevPcdata = p.To.Offset
  234. continue
  235. }
  236. if prevPcdata == objabi.PCDATA_RegMapUnsafe {
  237. continue // already unsafe
  238. }
  239. if isUnsafePoint(p) {
  240. q := ctxt.StartUnsafePoint(prev, newprog)
  241. q.Pc = p.Pc
  242. q.Link = p
  243. // Advance to the end of unsafe point.
  244. for p.Link != nil && isUnsafePoint(p.Link) {
  245. p = p.Link
  246. }
  247. if p.Link == nil {
  248. break // Reached the end, don't bother marking the end
  249. }
  250. p = ctxt.EndUnsafePoint(p, newprog, prevPcdata)
  251. p.Pc = p.Link.Pc
  252. continue
  253. }
  254. if isRestartable(p) {
  255. val := int64(objabi.PCDATA_Restart1)
  256. if val == prevRestart {
  257. val = objabi.PCDATA_Restart2
  258. }
  259. prevRestart = val
  260. q := Appendp(prev, newprog)
  261. q.As = APCDATA
  262. q.From.Type = TYPE_CONST
  263. q.From.Offset = objabi.PCDATA_RegMapIndex
  264. q.To.Type = TYPE_CONST
  265. q.To.Offset = val
  266. q.Pc = p.Pc
  267. q.Link = p
  268. if p.Link == nil {
  269. break // Reached the end, don't bother marking the end
  270. }
  271. if isRestartable(p.Link) {
  272. // Next Prog is also restartable. No need to mark the end
  273. // of this sequence. We'll just go ahead mark the next one.
  274. continue
  275. }
  276. p = Appendp(p, newprog)
  277. p.As = APCDATA
  278. p.From.Type = TYPE_CONST
  279. p.From.Offset = objabi.PCDATA_RegMapIndex
  280. p.To.Type = TYPE_CONST
  281. p.To.Offset = prevPcdata
  282. p.Pc = p.Link.Pc
  283. }
  284. }
  285. }