util.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. // Copyright 2015 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. "bytes"
  7. "github.com/twitchyliquid64/golang-asm/objabi"
  8. "fmt"
  9. "io"
  10. "strings"
  11. )
  12. const REG_NONE = 0
  13. // Line returns a string containing the filename and line number for p
  14. func (p *Prog) Line() string {
  15. return p.Ctxt.OutermostPos(p.Pos).Format(false, true)
  16. }
  17. func (p *Prog) InnermostLine(w io.Writer) {
  18. p.Ctxt.InnermostPos(p.Pos).WriteTo(w, false, true)
  19. }
  20. // InnermostLineNumber returns a string containing the line number for the
  21. // innermost inlined function (if any inlining) at p's position
  22. func (p *Prog) InnermostLineNumber() string {
  23. return p.Ctxt.InnermostPos(p.Pos).LineNumber()
  24. }
  25. // InnermostLineNumberHTML returns a string containing the line number for the
  26. // innermost inlined function (if any inlining) at p's position
  27. func (p *Prog) InnermostLineNumberHTML() string {
  28. return p.Ctxt.InnermostPos(p.Pos).LineNumberHTML()
  29. }
  30. // InnermostFilename returns a string containing the innermost
  31. // (in inlining) filename at p's position
  32. func (p *Prog) InnermostFilename() string {
  33. // TODO For now, this is only used for debugging output, and if we need more/better information, it might change.
  34. // An example of what we might want to see is the full stack of positions for inlined code, so we get some visibility into what is recorded there.
  35. pos := p.Ctxt.InnermostPos(p.Pos)
  36. if !pos.IsKnown() {
  37. return "<unknown file name>"
  38. }
  39. return pos.Filename()
  40. }
  41. var armCondCode = []string{
  42. ".EQ",
  43. ".NE",
  44. ".CS",
  45. ".CC",
  46. ".MI",
  47. ".PL",
  48. ".VS",
  49. ".VC",
  50. ".HI",
  51. ".LS",
  52. ".GE",
  53. ".LT",
  54. ".GT",
  55. ".LE",
  56. "",
  57. ".NV",
  58. }
  59. /* ARM scond byte */
  60. const (
  61. C_SCOND = (1 << 4) - 1
  62. C_SBIT = 1 << 4
  63. C_PBIT = 1 << 5
  64. C_WBIT = 1 << 6
  65. C_FBIT = 1 << 7
  66. C_UBIT = 1 << 7
  67. C_SCOND_XOR = 14
  68. )
  69. // CConv formats opcode suffix bits (Prog.Scond).
  70. func CConv(s uint8) string {
  71. if s == 0 {
  72. return ""
  73. }
  74. for i := range opSuffixSpace {
  75. sset := &opSuffixSpace[i]
  76. if sset.arch == objabi.GOARCH {
  77. return sset.cconv(s)
  78. }
  79. }
  80. return fmt.Sprintf("SC???%d", s)
  81. }
  82. // CConvARM formats ARM opcode suffix bits (mostly condition codes).
  83. func CConvARM(s uint8) string {
  84. // TODO: could be great to move suffix-related things into
  85. // ARM asm backends some day.
  86. // obj/x86 can be used as an example.
  87. sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR]
  88. if s&C_SBIT != 0 {
  89. sc += ".S"
  90. }
  91. if s&C_PBIT != 0 {
  92. sc += ".P"
  93. }
  94. if s&C_WBIT != 0 {
  95. sc += ".W"
  96. }
  97. if s&C_UBIT != 0 { /* ambiguous with FBIT */
  98. sc += ".U"
  99. }
  100. return sc
  101. }
  102. func (p *Prog) String() string {
  103. if p == nil {
  104. return "<nil Prog>"
  105. }
  106. if p.Ctxt == nil {
  107. return "<Prog without ctxt>"
  108. }
  109. return fmt.Sprintf("%.5d (%v)\t%s", p.Pc, p.Line(), p.InstructionString())
  110. }
  111. func (p *Prog) InnermostString(w io.Writer) {
  112. if p == nil {
  113. io.WriteString(w, "<nil Prog>")
  114. return
  115. }
  116. if p.Ctxt == nil {
  117. io.WriteString(w, "<Prog without ctxt>")
  118. return
  119. }
  120. fmt.Fprintf(w, "%.5d (", p.Pc)
  121. p.InnermostLine(w)
  122. io.WriteString(w, ")\t")
  123. p.WriteInstructionString(w)
  124. }
  125. // InstructionString returns a string representation of the instruction without preceding
  126. // program counter or file and line number.
  127. func (p *Prog) InstructionString() string {
  128. buf := new(bytes.Buffer)
  129. p.WriteInstructionString(buf)
  130. return buf.String()
  131. }
  132. // WriteInstructionString writes a string representation of the instruction without preceding
  133. // program counter or file and line number.
  134. func (p *Prog) WriteInstructionString(w io.Writer) {
  135. if p == nil {
  136. io.WriteString(w, "<nil Prog>")
  137. return
  138. }
  139. if p.Ctxt == nil {
  140. io.WriteString(w, "<Prog without ctxt>")
  141. return
  142. }
  143. sc := CConv(p.Scond)
  144. io.WriteString(w, p.As.String())
  145. io.WriteString(w, sc)
  146. sep := "\t"
  147. if p.From.Type != TYPE_NONE {
  148. io.WriteString(w, sep)
  149. WriteDconv(w, p, &p.From)
  150. sep = ", "
  151. }
  152. if p.Reg != REG_NONE {
  153. // Should not happen but might as well show it if it does.
  154. fmt.Fprintf(w, "%s%v", sep, Rconv(int(p.Reg)))
  155. sep = ", "
  156. }
  157. for i := range p.RestArgs {
  158. io.WriteString(w, sep)
  159. WriteDconv(w, p, &p.RestArgs[i])
  160. sep = ", "
  161. }
  162. if p.As == ATEXT {
  163. // If there are attributes, print them. Otherwise, skip the comma.
  164. // In short, print one of these two:
  165. // TEXT foo(SB), DUPOK|NOSPLIT, $0
  166. // TEXT foo(SB), $0
  167. s := p.From.Sym.Attribute.TextAttrString()
  168. if s != "" {
  169. fmt.Fprintf(w, "%s%s", sep, s)
  170. sep = ", "
  171. }
  172. }
  173. if p.To.Type != TYPE_NONE {
  174. io.WriteString(w, sep)
  175. WriteDconv(w, p, &p.To)
  176. }
  177. if p.RegTo2 != REG_NONE {
  178. fmt.Fprintf(w, "%s%v", sep, Rconv(int(p.RegTo2)))
  179. }
  180. }
  181. func (ctxt *Link) NewProg() *Prog {
  182. p := new(Prog)
  183. p.Ctxt = ctxt
  184. return p
  185. }
  186. func (ctxt *Link) CanReuseProgs() bool {
  187. return ctxt.Debugasm == 0
  188. }
  189. func Dconv(p *Prog, a *Addr) string {
  190. buf := new(bytes.Buffer)
  191. WriteDconv(buf, p, a)
  192. return buf.String()
  193. }
  194. func WriteDconv(w io.Writer, p *Prog, a *Addr) {
  195. switch a.Type {
  196. default:
  197. fmt.Fprintf(w, "type=%d", a.Type)
  198. case TYPE_NONE:
  199. if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil {
  200. a.WriteNameTo(w)
  201. fmt.Fprintf(w, "(%v)(NONE)", Rconv(int(a.Reg)))
  202. }
  203. case TYPE_REG:
  204. // TODO(rsc): This special case is for x86 instructions like
  205. // PINSRQ CX,$1,X6
  206. // where the $1 is included in the p->to Addr.
  207. // Move into a new field.
  208. if a.Offset != 0 && (a.Reg < RBaseARM64 || a.Reg >= RBaseMIPS) {
  209. fmt.Fprintf(w, "$%d,%v", a.Offset, Rconv(int(a.Reg)))
  210. return
  211. }
  212. if a.Name != NAME_NONE || a.Sym != nil {
  213. a.WriteNameTo(w)
  214. fmt.Fprintf(w, "(%v)(REG)", Rconv(int(a.Reg)))
  215. } else {
  216. io.WriteString(w, Rconv(int(a.Reg)))
  217. }
  218. if (RBaseARM64+1<<10+1<<9) /* arm64.REG_ELEM */ <= a.Reg &&
  219. a.Reg < (RBaseARM64+1<<11) /* arm64.REG_ELEM_END */ {
  220. fmt.Fprintf(w, "[%d]", a.Index)
  221. }
  222. case TYPE_BRANCH:
  223. if a.Sym != nil {
  224. fmt.Fprintf(w, "%s(SB)", a.Sym.Name)
  225. } else if a.Target() != nil {
  226. fmt.Fprint(w, a.Target().Pc)
  227. } else {
  228. fmt.Fprintf(w, "%d(PC)", a.Offset)
  229. }
  230. case TYPE_INDIR:
  231. io.WriteString(w, "*")
  232. a.WriteNameTo(w)
  233. case TYPE_MEM:
  234. a.WriteNameTo(w)
  235. if a.Index != REG_NONE {
  236. if a.Scale == 0 {
  237. // arm64 shifted or extended register offset, scale = 0.
  238. fmt.Fprintf(w, "(%v)", Rconv(int(a.Index)))
  239. } else {
  240. fmt.Fprintf(w, "(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
  241. }
  242. }
  243. case TYPE_CONST:
  244. io.WriteString(w, "$")
  245. a.WriteNameTo(w)
  246. if a.Reg != 0 {
  247. fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
  248. }
  249. case TYPE_TEXTSIZE:
  250. if a.Val.(int32) == objabi.ArgsSizeUnknown {
  251. fmt.Fprintf(w, "$%d", a.Offset)
  252. } else {
  253. fmt.Fprintf(w, "$%d-%d", a.Offset, a.Val.(int32))
  254. }
  255. case TYPE_FCONST:
  256. str := fmt.Sprintf("%.17g", a.Val.(float64))
  257. // Make sure 1 prints as 1.0
  258. if !strings.ContainsAny(str, ".e") {
  259. str += ".0"
  260. }
  261. fmt.Fprintf(w, "$(%s)", str)
  262. case TYPE_SCONST:
  263. fmt.Fprintf(w, "$%q", a.Val.(string))
  264. case TYPE_ADDR:
  265. io.WriteString(w, "$")
  266. a.WriteNameTo(w)
  267. case TYPE_SHIFT:
  268. v := int(a.Offset)
  269. ops := "<<>>->@>"
  270. switch objabi.GOARCH {
  271. case "arm":
  272. op := ops[((v>>5)&3)<<1:]
  273. if v&(1<<4) != 0 {
  274. fmt.Fprintf(w, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
  275. } else {
  276. fmt.Fprintf(w, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
  277. }
  278. if a.Reg != 0 {
  279. fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
  280. }
  281. case "arm64":
  282. op := ops[((v>>22)&3)<<1:]
  283. r := (v >> 16) & 31
  284. fmt.Fprintf(w, "%s%c%c%d", Rconv(r+RBaseARM64), op[0], op[1], (v>>10)&63)
  285. default:
  286. panic("TYPE_SHIFT is not supported on " + objabi.GOARCH)
  287. }
  288. case TYPE_REGREG:
  289. fmt.Fprintf(w, "(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
  290. case TYPE_REGREG2:
  291. fmt.Fprintf(w, "%v, %v", Rconv(int(a.Offset)), Rconv(int(a.Reg)))
  292. case TYPE_REGLIST:
  293. io.WriteString(w, RLconv(a.Offset))
  294. }
  295. }
  296. func (a *Addr) WriteNameTo(w io.Writer) {
  297. switch a.Name {
  298. default:
  299. fmt.Fprintf(w, "name=%d", a.Name)
  300. case NAME_NONE:
  301. switch {
  302. case a.Reg == REG_NONE:
  303. fmt.Fprint(w, a.Offset)
  304. case a.Offset == 0:
  305. fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
  306. case a.Offset != 0:
  307. fmt.Fprintf(w, "%d(%v)", a.Offset, Rconv(int(a.Reg)))
  308. }
  309. // Note: a.Reg == REG_NONE encodes the default base register for the NAME_ type.
  310. case NAME_EXTERN:
  311. reg := "SB"
  312. if a.Reg != REG_NONE {
  313. reg = Rconv(int(a.Reg))
  314. }
  315. if a.Sym != nil {
  316. fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
  317. } else {
  318. fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
  319. }
  320. case NAME_GOTREF:
  321. reg := "SB"
  322. if a.Reg != REG_NONE {
  323. reg = Rconv(int(a.Reg))
  324. }
  325. if a.Sym != nil {
  326. fmt.Fprintf(w, "%s%s@GOT(%s)", a.Sym.Name, offConv(a.Offset), reg)
  327. } else {
  328. fmt.Fprintf(w, "%s@GOT(%s)", offConv(a.Offset), reg)
  329. }
  330. case NAME_STATIC:
  331. reg := "SB"
  332. if a.Reg != REG_NONE {
  333. reg = Rconv(int(a.Reg))
  334. }
  335. if a.Sym != nil {
  336. fmt.Fprintf(w, "%s<>%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
  337. } else {
  338. fmt.Fprintf(w, "<>%s(%s)", offConv(a.Offset), reg)
  339. }
  340. case NAME_AUTO:
  341. reg := "SP"
  342. if a.Reg != REG_NONE {
  343. reg = Rconv(int(a.Reg))
  344. }
  345. if a.Sym != nil {
  346. fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
  347. } else {
  348. fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
  349. }
  350. case NAME_PARAM:
  351. reg := "FP"
  352. if a.Reg != REG_NONE {
  353. reg = Rconv(int(a.Reg))
  354. }
  355. if a.Sym != nil {
  356. fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
  357. } else {
  358. fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
  359. }
  360. case NAME_TOCREF:
  361. reg := "SB"
  362. if a.Reg != REG_NONE {
  363. reg = Rconv(int(a.Reg))
  364. }
  365. if a.Sym != nil {
  366. fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
  367. } else {
  368. fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
  369. }
  370. }
  371. }
  372. func offConv(off int64) string {
  373. if off == 0 {
  374. return ""
  375. }
  376. return fmt.Sprintf("%+d", off)
  377. }
  378. // opSuffixSet is like regListSet, but for opcode suffixes.
  379. //
  380. // Unlike some other similar structures, uint8 space is not
  381. // divided by its own values set (because there are only 256 of them).
  382. // Instead, every arch may interpret/format all 8 bits as they like,
  383. // as long as they register proper cconv function for it.
  384. type opSuffixSet struct {
  385. arch string
  386. cconv func(suffix uint8) string
  387. }
  388. var opSuffixSpace []opSuffixSet
  389. // RegisterOpSuffix assigns cconv function for formatting opcode suffixes
  390. // when compiling for GOARCH=arch.
  391. //
  392. // cconv is never called with 0 argument.
  393. func RegisterOpSuffix(arch string, cconv func(uint8) string) {
  394. opSuffixSpace = append(opSuffixSpace, opSuffixSet{
  395. arch: arch,
  396. cconv: cconv,
  397. })
  398. }
  399. type regSet struct {
  400. lo int
  401. hi int
  402. Rconv func(int) string
  403. }
  404. // Few enough architectures that a linear scan is fastest.
  405. // Not even worth sorting.
  406. var regSpace []regSet
  407. /*
  408. Each architecture defines a register space as a unique
  409. integer range.
  410. Here is the list of architectures and the base of their register spaces.
  411. */
  412. const (
  413. // Because of masking operations in the encodings, each register
  414. // space should start at 0 modulo some power of 2.
  415. RBase386 = 1 * 1024
  416. RBaseAMD64 = 2 * 1024
  417. RBaseARM = 3 * 1024
  418. RBasePPC64 = 4 * 1024 // range [4k, 8k)
  419. RBaseARM64 = 8 * 1024 // range [8k, 13k)
  420. RBaseMIPS = 13 * 1024 // range [13k, 14k)
  421. RBaseS390X = 14 * 1024 // range [14k, 15k)
  422. RBaseRISCV = 15 * 1024 // range [15k, 16k)
  423. RBaseWasm = 16 * 1024
  424. )
  425. // RegisterRegister binds a pretty-printer (Rconv) for register
  426. // numbers to a given register number range. Lo is inclusive,
  427. // hi exclusive (valid registers are lo through hi-1).
  428. func RegisterRegister(lo, hi int, Rconv func(int) string) {
  429. regSpace = append(regSpace, regSet{lo, hi, Rconv})
  430. }
  431. func Rconv(reg int) string {
  432. if reg == REG_NONE {
  433. return "NONE"
  434. }
  435. for i := range regSpace {
  436. rs := &regSpace[i]
  437. if rs.lo <= reg && reg < rs.hi {
  438. return rs.Rconv(reg)
  439. }
  440. }
  441. return fmt.Sprintf("R???%d", reg)
  442. }
  443. type regListSet struct {
  444. lo int64
  445. hi int64
  446. RLconv func(int64) string
  447. }
  448. var regListSpace []regListSet
  449. // Each architecture is allotted a distinct subspace: [Lo, Hi) for declaring its
  450. // arch-specific register list numbers.
  451. const (
  452. RegListARMLo = 0
  453. RegListARMHi = 1 << 16
  454. // arm64 uses the 60th bit to differentiate from other archs
  455. RegListARM64Lo = 1 << 60
  456. RegListARM64Hi = 1<<61 - 1
  457. // x86 uses the 61th bit to differentiate from other archs
  458. RegListX86Lo = 1 << 61
  459. RegListX86Hi = 1<<62 - 1
  460. )
  461. // RegisterRegisterList binds a pretty-printer (RLconv) for register list
  462. // numbers to a given register list number range. Lo is inclusive,
  463. // hi exclusive (valid register list are lo through hi-1).
  464. func RegisterRegisterList(lo, hi int64, rlconv func(int64) string) {
  465. regListSpace = append(regListSpace, regListSet{lo, hi, rlconv})
  466. }
  467. func RLconv(list int64) string {
  468. for i := range regListSpace {
  469. rls := &regListSpace[i]
  470. if rls.lo <= list && list < rls.hi {
  471. return rls.RLconv(list)
  472. }
  473. }
  474. return fmt.Sprintf("RL???%d", list)
  475. }
  476. type opSet struct {
  477. lo As
  478. names []string
  479. }
  480. // Not even worth sorting
  481. var aSpace []opSet
  482. // RegisterOpcode binds a list of instruction names
  483. // to a given instruction number range.
  484. func RegisterOpcode(lo As, Anames []string) {
  485. if len(Anames) > AllowedOpCodes {
  486. panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes))
  487. }
  488. aSpace = append(aSpace, opSet{lo, Anames})
  489. }
  490. func (a As) String() string {
  491. if 0 <= a && int(a) < len(Anames) {
  492. return Anames[a]
  493. }
  494. for i := range aSpace {
  495. as := &aSpace[i]
  496. if as.lo <= a && int(a-as.lo) < len(as.names) {
  497. return as.names[a-as.lo]
  498. }
  499. }
  500. return fmt.Sprintf("A???%d", a)
  501. }
  502. var Anames = []string{
  503. "XXX",
  504. "CALL",
  505. "DUFFCOPY",
  506. "DUFFZERO",
  507. "END",
  508. "FUNCDATA",
  509. "JMP",
  510. "NOP",
  511. "PCALIGN",
  512. "PCDATA",
  513. "RET",
  514. "GETCALLERPC",
  515. "TEXT",
  516. "UNDEF",
  517. }
  518. func Bool2int(b bool) int {
  519. // The compiler currently only optimizes this form.
  520. // See issue 6011.
  521. var i int
  522. if b {
  523. i = 1
  524. } else {
  525. i = 0
  526. }
  527. return i
  528. }