// Inferno utils/8l/span.c // http://code.google.com/p/inferno-os/source/browse/utils/8l/span.c // // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) // Portions Copyright © 1997-1999 Vita Nuova Limited // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) // Portions Copyright © 2004,2006 Bruce Ellis // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others // Portions Copyright © 2009 The Go Authors. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. package i386 import ( "cmd/internal/obj" "fmt" "log" "strings" ) // Instruction layout. const ( MaxAlign = 32 FuncAlign = 16 ) type Optab struct { as int16 ytab []byte prefix uint8 op [13]uint8 } var opindex [ALAST + 1]*Optab const ( Yxxx = 0 + iota Ynone Yi0 Yi1 Yi8 Yi32 Yiauto Yal Ycl Yax Ycx Yrb Yrl Yrf Yf0 Yrx Ymb Yml Ym Ybr Ycol Ytextsize Ytls Ycs Yss Yds Yes Yfs Ygs Ygdtr Yidtr Yldtr Ymsw Ytask Ycr0 Ycr1 Ycr2 Ycr3 Ycr4 Ycr5 Ycr6 Ycr7 Ydr0 Ydr1 Ydr2 Ydr3 Ydr4 Ydr5 Ydr6 Ydr7 Ytr0 Ytr1 Ytr2 Ytr3 Ytr4 Ytr5 Ytr6 Ytr7 Ymr Ymm Yxr Yxm Ymax Zxxx = 0 + iota - 63 Zlit Zlitm_r Z_rp Zbr Zcall Zcallcon Zcallind Zcallindreg Zib_ Zib_rp Zibo_m Zil_ Zil_rp Zilo_m Zjmp Zjmpcon Zloop Zm_o Zm_r Zm2_r Zm_r_xm Zm_r_i_xm Zaut_r Zo_m Zpseudo Zr_m Zr_m_xm Zr_m_i_xm Zrp_ Z_ib Z_il Zm_ibo Zm_ilo Zib_rr Zil_rr Zclr Zibm_r Zbyte Zmov Zmax Px = 0 Pe = 0x66 Pm = 0x0f Pq = 0xff Pb = 0xfe Pf2 = 0xf2 Pf3 = 0xf3 ) var ycover [Ymax * Ymax]uint8 var reg [MAXREG]int var ynone = []uint8{ Ynone, Ynone, Zlit, 1, 0, } var ytext = []uint8{ Ymb, Ytextsize, Zpseudo, 1, 0, } var ynop = []uint8{ Ynone, Ynone, Zpseudo, 0, Ynone, Yiauto, Zpseudo, 0, Ynone, Yml, Zpseudo, 0, Ynone, Yrf, Zpseudo, 0, Yiauto, Ynone, Zpseudo, 0, Ynone, Yxr, Zpseudo, 0, Yml, Ynone, Zpseudo, 0, Yrf, Ynone, Zpseudo, 0, Yxr, Ynone, Zpseudo, 1, 0, } var yfuncdata = []uint8{ Yi32, Ym, Zpseudo, 0, 0, } var ypcdata = []uint8{ Yi32, Yi32, Zpseudo, 0, 0, } var yxorb = []uint8{ Yi32, Yal, Zib_, 1, Yi32, Ymb, Zibo_m, 2, Yrb, Ymb, Zr_m, 1, Ymb, Yrb, Zm_r, 1, 0, } var yxorl = []uint8{ Yi8, Yml, Zibo_m, 2, Yi32, Yax, Zil_, 1, Yi32, Yml, Zilo_m, 2, Yrl, Yml, Zr_m, 1, Yml, Yrl, Zm_r, 1, 0, } var yaddl = []uint8{ Yi8, Yml, Zibo_m, 2, Yi32, Yax, Zil_, 1, Yi32, Yml, Zilo_m, 2, Yrl, Yml, Zr_m, 1, Yml, Yrl, Zm_r, 1, 0, } var yincb = []uint8{ Ynone, Ymb, Zo_m, 2, 0, } var yincl = []uint8{ Ynone, Yrl, Z_rp, 1, Ynone, Yml, Zo_m, 2, 0, } var ycmpb = []uint8{ Yal, Yi32, Z_ib, 1, Ymb, Yi32, Zm_ibo, 2, Ymb, Yrb, Zm_r, 1, Yrb, Ymb, Zr_m, 1, 0, } var ycmpl = []uint8{ Yml, Yi8, Zm_ibo, 2, Yax, Yi32, Z_il, 1, Yml, Yi32, Zm_ilo, 2, Yml, Yrl, Zm_r, 1, Yrl, Yml, Zr_m, 1, 0, } var yshb = []uint8{ Yi1, Ymb, Zo_m, 2, Yi32, Ymb, Zibo_m, 2, Ycx, Ymb, Zo_m, 2, 0, } var yshl = []uint8{ Yi1, Yml, Zo_m, 2, Yi32, Yml, Zibo_m, 2, Ycl, Yml, Zo_m, 2, Ycx, Yml, Zo_m, 2, 0, } var ytestb = []uint8{ Yi32, Yal, Zib_, 1, Yi32, Ymb, Zibo_m, 2, Yrb, Ymb, Zr_m, 1, Ymb, Yrb, Zm_r, 1, 0, } var ytestl = []uint8{ Yi32, Yax, Zil_, 1, Yi32, Yml, Zilo_m, 2, Yrl, Yml, Zr_m, 1, Yml, Yrl, Zm_r, 1, 0, } var ymovb = []uint8{ Yrb, Ymb, Zr_m, 1, Ymb, Yrb, Zm_r, 1, Yi32, Yrb, Zib_rp, 1, Yi32, Ymb, Zibo_m, 2, 0, } var ymovw = []uint8{ Yrl, Yml, Zr_m, 1, Yml, Yrl, Zm_r, 1, Yi0, Yrl, Zclr, 1 + 2, // Yi0, Yml, Zibo_m, 2, // shorter but slower AND $0,dst Yi32, Yrl, Zil_rp, 1, Yi32, Yml, Zilo_m, 2, Yiauto, Yrl, Zaut_r, 1, 0, } var ymovl = []uint8{ Yrl, Yml, Zr_m, 1, Yml, Yrl, Zm_r, 1, Yi0, Yrl, Zclr, 1 + 2, // Yi0, Yml, Zibo_m, 2, // shorter but slower AND $0,dst Yi32, Yrl, Zil_rp, 1, Yi32, Yml, Zilo_m, 2, Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit) Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit) Yiauto, Yrl, Zaut_r, 1, 0, } var ymovq = []uint8{ Yml, Yxr, Zm_r_xm, 2, 0, } var ym_rl = []uint8{ Ym, Yrl, Zm_r, 1, 0, } var yrl_m = []uint8{ Yrl, Ym, Zr_m, 1, 0, } var ymb_rl = []uint8{ Ymb, Yrl, Zm_r, 1, 0, } var yml_rl = []uint8{ Yml, Yrl, Zm_r, 1, 0, } var yrb_mb = []uint8{ Yrb, Ymb, Zr_m, 1, 0, } var yrl_ml = []uint8{ Yrl, Yml, Zr_m, 1, 0, } var yml_mb = []uint8{ Yrb, Ymb, Zr_m, 1, Ymb, Yrb, Zm_r, 1, 0, } var yxchg = []uint8{ Yax, Yrl, Z_rp, 1, Yrl, Yax, Zrp_, 1, Yrl, Yml, Zr_m, 1, Yml, Yrl, Zm_r, 1, 0, } var ydivl = []uint8{ Yml, Ynone, Zm_o, 2, 0, } var ydivb = []uint8{ Ymb, Ynone, Zm_o, 2, 0, } var yimul = []uint8{ Yml, Ynone, Zm_o, 2, Yi8, Yrl, Zib_rr, 1, Yi32, Yrl, Zil_rr, 1, 0, } var ybyte = []uint8{ Yi32, Ynone, Zbyte, 1, 0, } var yin = []uint8{ Yi32, Ynone, Zib_, 1, Ynone, Ynone, Zlit, 1, 0, } var yint = []uint8{ Yi32, Ynone, Zib_, 1, 0, } var ypushl = []uint8{ Yrl, Ynone, Zrp_, 1, Ym, Ynone, Zm_o, 2, Yi8, Ynone, Zib_, 1, Yi32, Ynone, Zil_, 1, 0, } var ypopl = []uint8{ Ynone, Yrl, Z_rp, 1, Ynone, Ym, Zo_m, 2, 0, } var ybswap = []uint8{ Ynone, Yrl, Z_rp, 1, 0, } var yscond = []uint8{ Ynone, Ymb, Zo_m, 2, 0, } var yjcond = []uint8{ Ynone, Ybr, Zbr, 0, Yi0, Ybr, Zbr, 0, Yi1, Ybr, Zbr, 1, 0, } var yloop = []uint8{ Ynone, Ybr, Zloop, 1, 0, } var ycall = []uint8{ Ynone, Yml, Zcallindreg, 0, Yrx, Yrx, Zcallindreg, 2, Ynone, Ycol, Zcallind, 2, Ynone, Ybr, Zcall, 0, Ynone, Yi32, Zcallcon, 1, 0, } var yduff = []uint8{ Ynone, Yi32, Zcall, 1, 0, } var yjmp = []uint8{ Ynone, Yml, Zo_m, 2, Ynone, Ybr, Zjmp, 0, Ynone, Yi32, Zjmpcon, 1, 0, } var yfmvd = []uint8{ Ym, Yf0, Zm_o, 2, Yf0, Ym, Zo_m, 2, Yrf, Yf0, Zm_o, 2, Yf0, Yrf, Zo_m, 2, 0, } var yfmvdp = []uint8{ Yf0, Ym, Zo_m, 2, Yf0, Yrf, Zo_m, 2, 0, } var yfmvf = []uint8{ Ym, Yf0, Zm_o, 2, Yf0, Ym, Zo_m, 2, 0, } var yfmvx = []uint8{ Ym, Yf0, Zm_o, 2, 0, } var yfmvp = []uint8{ Yf0, Ym, Zo_m, 2, 0, } var yfcmv = []uint8{ Yrf, Yf0, Zm_o, 2, 0, } var yfadd = []uint8{ Ym, Yf0, Zm_o, 2, Yrf, Yf0, Zm_o, 2, Yf0, Yrf, Zo_m, 2, 0, } var yfaddp = []uint8{ Yf0, Yrf, Zo_m, 2, 0, } var yfxch = []uint8{ Yf0, Yrf, Zo_m, 2, Yrf, Yf0, Zm_o, 2, 0, } var ycompp = []uint8{ Yf0, Yrf, Zo_m, 2, /* botch is really f0,f1 */ 0, } var ystsw = []uint8{ Ynone, Ym, Zo_m, 2, Ynone, Yax, Zlit, 1, 0, } var ystcw = []uint8{ Ynone, Ym, Zo_m, 2, Ym, Ynone, Zm_o, 2, 0, } var ysvrs = []uint8{ Ynone, Ym, Zo_m, 2, Ym, Ynone, Zm_o, 2, 0, } var ymskb = []uint8{ Yxr, Yrl, Zm_r_xm, 2, Ymr, Yrl, Zm_r_xm, 1, 0, } var yxm = []uint8{ Yxm, Yxr, Zm_r_xm, 1, 0, } var yxcvm1 = []uint8{ Yxm, Yxr, Zm_r_xm, 2, Yxm, Ymr, Zm_r_xm, 2, 0, } var yxcvm2 = []uint8{ Yxm, Yxr, Zm_r_xm, 2, Ymm, Yxr, Zm_r_xm, 2, 0, } var yxmq = []uint8{ Yxm, Yxr, Zm_r_xm, 2, 0, } var yxr = []uint8{ Yxr, Yxr, Zm_r_xm, 1, 0, } var yxr_ml = []uint8{ Yxr, Yml, Zr_m_xm, 1, 0, } var yxcmp = []uint8{ Yxm, Yxr, Zm_r_xm, 1, 0, } var yxcmpi = []uint8{ Yxm, Yxr, Zm_r_i_xm, 2, 0, } var yxmov = []uint8{ Yxm, Yxr, Zm_r_xm, 1, Yxr, Yxm, Zr_m_xm, 1, 0, } var yxcvfl = []uint8{ Yxm, Yrl, Zm_r_xm, 1, 0, } var yxcvlf = []uint8{ Yml, Yxr, Zm_r_xm, 1, 0, } /* static uchar yxcvfq[] = { Yxm, Yrl, Zm_r_xm, 2, 0 }; static uchar yxcvqf[] = { Yml, Yxr, Zm_r_xm, 2, 0 }; */ var yxrrl = []uint8{ Yxr, Yrl, Zm_r, 1, 0, } var yprefetch = []uint8{ Ym, Ynone, Zm_o, 2, 0, } var yaes = []uint8{ Yxm, Yxr, Zlitm_r, 2, 0, } var yinsrd = []uint8{ Yml, Yxr, Zibm_r, 2, 0, } var ymshufb = []uint8{ Yxm, Yxr, Zm2_r, 2, 0, } var yxshuf = []uint8{ Yxm, Yxr, Zibm_r, 2, 0, } var optab = /* as, ytab, andproto, opcode */ []Optab{ Optab{obj.AXXX, nil, 0, [13]uint8{}}, Optab{AAAA, ynone, Px, [13]uint8{0x37}}, Optab{AAAD, ynone, Px, [13]uint8{0xd5, 0x0a}}, Optab{AAAM, ynone, Px, [13]uint8{0xd4, 0x0a}}, Optab{AAAS, ynone, Px, [13]uint8{0x3f}}, Optab{AADCB, yxorb, Pb, [13]uint8{0x14, 0x80, 02, 0x10, 0x10}}, Optab{AADCL, yxorl, Px, [13]uint8{0x83, 02, 0x15, 0x81, 02, 0x11, 0x13}}, Optab{AADCW, yxorl, Pe, [13]uint8{0x83, 02, 0x15, 0x81, 02, 0x11, 0x13}}, Optab{AADDB, yxorb, Px, [13]uint8{0x04, 0x80, 00, 0x00, 0x02}}, Optab{AADDL, yaddl, Px, [13]uint8{0x83, 00, 0x05, 0x81, 00, 0x01, 0x03}}, Optab{AADDW, yaddl, Pe, [13]uint8{0x83, 00, 0x05, 0x81, 00, 0x01, 0x03}}, Optab{AADJSP, nil, 0, [13]uint8{}}, Optab{AANDB, yxorb, Pb, [13]uint8{0x24, 0x80, 04, 0x20, 0x22}}, Optab{AANDL, yxorl, Px, [13]uint8{0x83, 04, 0x25, 0x81, 04, 0x21, 0x23}}, Optab{AANDW, yxorl, Pe, [13]uint8{0x83, 04, 0x25, 0x81, 04, 0x21, 0x23}}, Optab{AARPL, yrl_ml, Px, [13]uint8{0x63}}, Optab{ABOUNDL, yrl_m, Px, [13]uint8{0x62}}, Optab{ABOUNDW, yrl_m, Pe, [13]uint8{0x62}}, Optab{ABSFL, yml_rl, Pm, [13]uint8{0xbc}}, Optab{ABSFW, yml_rl, Pq, [13]uint8{0xbc}}, Optab{ABSRL, yml_rl, Pm, [13]uint8{0xbd}}, Optab{ABSRW, yml_rl, Pq, [13]uint8{0xbd}}, Optab{ABTL, yml_rl, Pm, [13]uint8{0xa3}}, Optab{ABTW, yml_rl, Pq, [13]uint8{0xa3}}, Optab{ABTCL, yml_rl, Pm, [13]uint8{0xbb}}, Optab{ABTCW, yml_rl, Pq, [13]uint8{0xbb}}, Optab{ABTRL, yml_rl, Pm, [13]uint8{0xb3}}, Optab{ABTRW, yml_rl, Pq, [13]uint8{0xb3}}, Optab{ABTSL, yml_rl, Pm, [13]uint8{0xab}}, Optab{ABTSW, yml_rl, Pq, [13]uint8{0xab}}, Optab{ABYTE, ybyte, Px, [13]uint8{1}}, Optab{obj.ACALL, ycall, Px, [13]uint8{0xff, 02, 0xff, 0x15, 0xe8}}, Optab{ACLC, ynone, Px, [13]uint8{0xf8}}, Optab{ACLD, ynone, Px, [13]uint8{0xfc}}, Optab{ACLI, ynone, Px, [13]uint8{0xfa}}, Optab{ACLTS, ynone, Pm, [13]uint8{0x06}}, Optab{ACMC, ynone, Px, [13]uint8{0xf5}}, Optab{ACMPB, ycmpb, Pb, [13]uint8{0x3c, 0x80, 07, 0x38, 0x3a}}, Optab{ACMPL, ycmpl, Px, [13]uint8{0x83, 07, 0x3d, 0x81, 07, 0x39, 0x3b}}, Optab{ACMPW, ycmpl, Pe, [13]uint8{0x83, 07, 0x3d, 0x81, 07, 0x39, 0x3b}}, Optab{ACMPSB, ynone, Pb, [13]uint8{0xa6}}, Optab{ACMPSL, ynone, Px, [13]uint8{0xa7}}, Optab{ACMPSW, ynone, Pe, [13]uint8{0xa7}}, Optab{ADAA, ynone, Px, [13]uint8{0x27}}, Optab{ADAS, ynone, Px, [13]uint8{0x2f}}, Optab{obj.ADATA, nil, 0, [13]uint8{}}, Optab{ADECB, yincb, Pb, [13]uint8{0xfe, 01}}, Optab{ADECL, yincl, Px, [13]uint8{0x48, 0xff, 01}}, Optab{ADECW, yincl, Pe, [13]uint8{0x48, 0xff, 01}}, Optab{ADIVB, ydivb, Pb, [13]uint8{0xf6, 06}}, Optab{ADIVL, ydivl, Px, [13]uint8{0xf7, 06}}, Optab{ADIVW, ydivl, Pe, [13]uint8{0xf7, 06}}, Optab{AENTER, nil, 0, [13]uint8{}}, /* botch */ Optab{obj.AGLOBL, nil, 0, [13]uint8{}}, Optab{AHLT, ynone, Px, [13]uint8{0xf4}}, Optab{AIDIVB, ydivb, Pb, [13]uint8{0xf6, 07}}, Optab{AIDIVL, ydivl, Px, [13]uint8{0xf7, 07}}, Optab{AIDIVW, ydivl, Pe, [13]uint8{0xf7, 07}}, Optab{AIMULB, ydivb, Pb, [13]uint8{0xf6, 05}}, Optab{AIMULL, yimul, Px, [13]uint8{0xf7, 05, 0x6b, 0x69}}, Optab{AIMULW, yimul, Pe, [13]uint8{0xf7, 05, 0x6b, 0x69}}, Optab{AINB, yin, Pb, [13]uint8{0xe4, 0xec}}, Optab{AINL, yin, Px, [13]uint8{0xe5, 0xed}}, Optab{AINW, yin, Pe, [13]uint8{0xe5, 0xed}}, Optab{AINCB, yincb, Pb, [13]uint8{0xfe, 00}}, Optab{AINCL, yincl, Px, [13]uint8{0x40, 0xff, 00}}, Optab{AINCW, yincl, Pe, [13]uint8{0x40, 0xff, 00}}, Optab{AINSB, ynone, Pb, [13]uint8{0x6c}}, Optab{AINSL, ynone, Px, [13]uint8{0x6d}}, Optab{AINSW, ynone, Pe, [13]uint8{0x6d}}, Optab{AINT, yint, Px, [13]uint8{0xcd}}, Optab{AINTO, ynone, Px, [13]uint8{0xce}}, Optab{AIRETL, ynone, Px, [13]uint8{0xcf}}, Optab{AIRETW, ynone, Pe, [13]uint8{0xcf}}, Optab{AJCC, yjcond, Px, [13]uint8{0x73, 0x83, 00}}, Optab{AJCS, yjcond, Px, [13]uint8{0x72, 0x82}}, Optab{AJCXZL, yloop, Px, [13]uint8{0xe3}}, Optab{AJCXZW, yloop, Px, [13]uint8{0xe3}}, Optab{AJEQ, yjcond, Px, [13]uint8{0x74, 0x84}}, Optab{AJGE, yjcond, Px, [13]uint8{0x7d, 0x8d}}, Optab{AJGT, yjcond, Px, [13]uint8{0x7f, 0x8f}}, Optab{AJHI, yjcond, Px, [13]uint8{0x77, 0x87}}, Optab{AJLE, yjcond, Px, [13]uint8{0x7e, 0x8e}}, Optab{AJLS, yjcond, Px, [13]uint8{0x76, 0x86}}, Optab{AJLT, yjcond, Px, [13]uint8{0x7c, 0x8c}}, Optab{AJMI, yjcond, Px, [13]uint8{0x78, 0x88}}, Optab{obj.AJMP, yjmp, Px, [13]uint8{0xff, 04, 0xeb, 0xe9}}, Optab{AJNE, yjcond, Px, [13]uint8{0x75, 0x85}}, Optab{AJOC, yjcond, Px, [13]uint8{0x71, 0x81, 00}}, Optab{AJOS, yjcond, Px, [13]uint8{0x70, 0x80, 00}}, Optab{AJPC, yjcond, Px, [13]uint8{0x7b, 0x8b}}, Optab{AJPL, yjcond, Px, [13]uint8{0x79, 0x89}}, Optab{AJPS, yjcond, Px, [13]uint8{0x7a, 0x8a}}, Optab{ALAHF, ynone, Px, [13]uint8{0x9f}}, Optab{ALARL, yml_rl, Pm, [13]uint8{0x02}}, Optab{ALARW, yml_rl, Pq, [13]uint8{0x02}}, Optab{ALEAL, ym_rl, Px, [13]uint8{0x8d}}, Optab{ALEAW, ym_rl, Pe, [13]uint8{0x8d}}, Optab{ALEAVEL, ynone, Px, [13]uint8{0xc9}}, Optab{ALEAVEW, ynone, Pe, [13]uint8{0xc9}}, Optab{ALOCK, ynone, Px, [13]uint8{0xf0}}, Optab{ALODSB, ynone, Pb, [13]uint8{0xac}}, Optab{ALODSL, ynone, Px, [13]uint8{0xad}}, Optab{ALODSW, ynone, Pe, [13]uint8{0xad}}, Optab{ALONG, ybyte, Px, [13]uint8{4}}, Optab{ALOOP, yloop, Px, [13]uint8{0xe2}}, Optab{ALOOPEQ, yloop, Px, [13]uint8{0xe1}}, Optab{ALOOPNE, yloop, Px, [13]uint8{0xe0}}, Optab{ALSLL, yml_rl, Pm, [13]uint8{0x03}}, Optab{ALSLW, yml_rl, Pq, [13]uint8{0x03}}, Optab{AMOVB, ymovb, Pb, [13]uint8{0x88, 0x8a, 0xb0, 0xc6, 00}}, Optab{AMOVL, ymovl, Px, [13]uint8{0x89, 0x8b, 0x31, 0x83, 04, 0xb8, 0xc7, 00, Pe, 0x6e, Pe, 0x7e, 0}}, Optab{AMOVW, ymovw, Pe, [13]uint8{0x89, 0x8b, 0x31, 0x83, 04, 0xb8, 0xc7, 00, 0}}, Optab{AMOVQ, ymovq, Pf3, [13]uint8{0x7e}}, Optab{AMOVBLSX, ymb_rl, Pm, [13]uint8{0xbe}}, Optab{AMOVBLZX, ymb_rl, Pm, [13]uint8{0xb6}}, Optab{AMOVBWSX, ymb_rl, Pq, [13]uint8{0xbe}}, Optab{AMOVBWZX, ymb_rl, Pq, [13]uint8{0xb6}}, Optab{AMOVWLSX, yml_rl, Pm, [13]uint8{0xbf}}, Optab{AMOVWLZX, yml_rl, Pm, [13]uint8{0xb7}}, Optab{AMOVSB, ynone, Pb, [13]uint8{0xa4}}, Optab{AMOVSL, ynone, Px, [13]uint8{0xa5}}, Optab{AMOVSW, ynone, Pe, [13]uint8{0xa5}}, Optab{AMULB, ydivb, Pb, [13]uint8{0xf6, 04}}, Optab{AMULL, ydivl, Px, [13]uint8{0xf7, 04}}, Optab{AMULW, ydivl, Pe, [13]uint8{0xf7, 04}}, Optab{ANEGB, yscond, Px, [13]uint8{0xf6, 03}}, Optab{ANEGL, yscond, Px, [13]uint8{0xf7, 03}}, // TODO(rsc): yscond is wrong here. Optab{ANEGW, yscond, Pe, [13]uint8{0xf7, 03}}, // TODO(rsc): yscond is wrong here. Optab{obj.ANOP, ynop, Px, [13]uint8{0, 0}}, Optab{ANOTB, yscond, Px, [13]uint8{0xf6, 02}}, Optab{ANOTL, yscond, Px, [13]uint8{0xf7, 02}}, // TODO(rsc): yscond is wrong here. Optab{ANOTW, yscond, Pe, [13]uint8{0xf7, 02}}, // TODO(rsc): yscond is wrong here. Optab{AORB, yxorb, Pb, [13]uint8{0x0c, 0x80, 01, 0x08, 0x0a}}, Optab{AORL, yxorl, Px, [13]uint8{0x83, 01, 0x0d, 0x81, 01, 0x09, 0x0b}}, Optab{AORW, yxorl, Pe, [13]uint8{0x83, 01, 0x0d, 0x81, 01, 0x09, 0x0b}}, Optab{AOUTB, yin, Pb, [13]uint8{0xe6, 0xee}}, Optab{AOUTL, yin, Px, [13]uint8{0xe7, 0xef}}, Optab{AOUTW, yin, Pe, [13]uint8{0xe7, 0xef}}, Optab{AOUTSB, ynone, Pb, [13]uint8{0x6e}}, Optab{AOUTSL, ynone, Px, [13]uint8{0x6f}}, Optab{AOUTSW, ynone, Pe, [13]uint8{0x6f}}, Optab{APAUSE, ynone, Px, [13]uint8{0xf3, 0x90}}, Optab{APOPAL, ynone, Px, [13]uint8{0x61}}, Optab{APOPAW, ynone, Pe, [13]uint8{0x61}}, Optab{APOPFL, ynone, Px, [13]uint8{0x9d}}, Optab{APOPFW, ynone, Pe, [13]uint8{0x9d}}, Optab{APOPL, ypopl, Px, [13]uint8{0x58, 0x8f, 00}}, Optab{APOPW, ypopl, Pe, [13]uint8{0x58, 0x8f, 00}}, Optab{APUSHAL, ynone, Px, [13]uint8{0x60}}, Optab{APUSHAW, ynone, Pe, [13]uint8{0x60}}, Optab{APUSHFL, ynone, Px, [13]uint8{0x9c}}, Optab{APUSHFW, ynone, Pe, [13]uint8{0x9c}}, Optab{APUSHL, ypushl, Px, [13]uint8{0x50, 0xff, 06, 0x6a, 0x68}}, Optab{APUSHW, ypushl, Pe, [13]uint8{0x50, 0xff, 06, 0x6a, 0x68}}, Optab{ARCLB, yshb, Pb, [13]uint8{0xd0, 02, 0xc0, 02, 0xd2, 02}}, Optab{ARCLL, yshl, Px, [13]uint8{0xd1, 02, 0xc1, 02, 0xd3, 02, 0xd3, 02}}, Optab{ARCLW, yshl, Pe, [13]uint8{0xd1, 02, 0xc1, 02, 0xd3, 02, 0xd3, 02}}, Optab{ARCRB, yshb, Pb, [13]uint8{0xd0, 03, 0xc0, 03, 0xd2, 03}}, Optab{ARCRL, yshl, Px, [13]uint8{0xd1, 03, 0xc1, 03, 0xd3, 03, 0xd3, 03}}, Optab{ARCRW, yshl, Pe, [13]uint8{0xd1, 03, 0xc1, 03, 0xd3, 03, 0xd3, 03}}, Optab{AREP, ynone, Px, [13]uint8{0xf3}}, Optab{AREPN, ynone, Px, [13]uint8{0xf2}}, Optab{obj.ARET, ynone, Px, [13]uint8{0xc3}}, Optab{AROLB, yshb, Pb, [13]uint8{0xd0, 00, 0xc0, 00, 0xd2, 00}}, Optab{AROLL, yshl, Px, [13]uint8{0xd1, 00, 0xc1, 00, 0xd3, 00, 0xd3, 00}}, Optab{AROLW, yshl, Pe, [13]uint8{0xd1, 00, 0xc1, 00, 0xd3, 00, 0xd3, 00}}, Optab{ARORB, yshb, Pb, [13]uint8{0xd0, 01, 0xc0, 01, 0xd2, 01}}, Optab{ARORL, yshl, Px, [13]uint8{0xd1, 01, 0xc1, 01, 0xd3, 01, 0xd3, 01}}, Optab{ARORW, yshl, Pe, [13]uint8{0xd1, 01, 0xc1, 01, 0xd3, 01, 0xd3, 01}}, Optab{ASAHF, ynone, Px, [13]uint8{0x9e}}, Optab{ASALB, yshb, Pb, [13]uint8{0xd0, 04, 0xc0, 04, 0xd2, 04}}, Optab{ASALL, yshl, Px, [13]uint8{0xd1, 04, 0xc1, 04, 0xd3, 04, 0xd3, 04}}, Optab{ASALW, yshl, Pe, [13]uint8{0xd1, 04, 0xc1, 04, 0xd3, 04, 0xd3, 04}}, Optab{ASARB, yshb, Pb, [13]uint8{0xd0, 07, 0xc0, 07, 0xd2, 07}}, Optab{ASARL, yshl, Px, [13]uint8{0xd1, 07, 0xc1, 07, 0xd3, 07, 0xd3, 07}}, Optab{ASARW, yshl, Pe, [13]uint8{0xd1, 07, 0xc1, 07, 0xd3, 07, 0xd3, 07}}, Optab{ASBBB, yxorb, Pb, [13]uint8{0x1c, 0x80, 03, 0x18, 0x1a}}, Optab{ASBBL, yxorl, Px, [13]uint8{0x83, 03, 0x1d, 0x81, 03, 0x19, 0x1b}}, Optab{ASBBW, yxorl, Pe, [13]uint8{0x83, 03, 0x1d, 0x81, 03, 0x19, 0x1b}}, Optab{ASCASB, ynone, Pb, [13]uint8{0xae}}, Optab{ASCASL, ynone, Px, [13]uint8{0xaf}}, Optab{ASCASW, ynone, Pe, [13]uint8{0xaf}}, Optab{ASETCC, yscond, Pm, [13]uint8{0x93, 00}}, Optab{ASETCS, yscond, Pm, [13]uint8{0x92, 00}}, Optab{ASETEQ, yscond, Pm, [13]uint8{0x94, 00}}, Optab{ASETGE, yscond, Pm, [13]uint8{0x9d, 00}}, Optab{ASETGT, yscond, Pm, [13]uint8{0x9f, 00}}, Optab{ASETHI, yscond, Pm, [13]uint8{0x97, 00}}, Optab{ASETLE, yscond, Pm, [13]uint8{0x9e, 00}}, Optab{ASETLS, yscond, Pm, [13]uint8{0x96, 00}}, Optab{ASETLT, yscond, Pm, [13]uint8{0x9c, 00}}, Optab{ASETMI, yscond, Pm, [13]uint8{0x98, 00}}, Optab{ASETNE, yscond, Pm, [13]uint8{0x95, 00}}, Optab{ASETOC, yscond, Pm, [13]uint8{0x91, 00}}, Optab{ASETOS, yscond, Pm, [13]uint8{0x90, 00}}, Optab{ASETPC, yscond, Pm, [13]uint8{0x9b, 00}}, Optab{ASETPL, yscond, Pm, [13]uint8{0x99, 00}}, Optab{ASETPS, yscond, Pm, [13]uint8{0x9a, 00}}, Optab{ACDQ, ynone, Px, [13]uint8{0x99}}, Optab{ACWD, ynone, Pe, [13]uint8{0x99}}, Optab{ASHLB, yshb, Pb, [13]uint8{0xd0, 04, 0xc0, 04, 0xd2, 04}}, Optab{ASHLL, yshl, Px, [13]uint8{0xd1, 04, 0xc1, 04, 0xd3, 04, 0xd3, 04}}, Optab{ASHLW, yshl, Pe, [13]uint8{0xd1, 04, 0xc1, 04, 0xd3, 04, 0xd3, 04}}, Optab{ASHRB, yshb, Pb, [13]uint8{0xd0, 05, 0xc0, 05, 0xd2, 05}}, Optab{ASHRL, yshl, Px, [13]uint8{0xd1, 05, 0xc1, 05, 0xd3, 05, 0xd3, 05}}, Optab{ASHRW, yshl, Pe, [13]uint8{0xd1, 05, 0xc1, 05, 0xd3, 05, 0xd3, 05}}, Optab{ASTC, ynone, Px, [13]uint8{0xf9}}, Optab{ASTD, ynone, Px, [13]uint8{0xfd}}, Optab{ASTI, ynone, Px, [13]uint8{0xfb}}, Optab{ASTOSB, ynone, Pb, [13]uint8{0xaa}}, Optab{ASTOSL, ynone, Px, [13]uint8{0xab}}, Optab{ASTOSW, ynone, Pe, [13]uint8{0xab}}, Optab{ASUBB, yxorb, Pb, [13]uint8{0x2c, 0x80, 05, 0x28, 0x2a}}, Optab{ASUBL, yaddl, Px, [13]uint8{0x83, 05, 0x2d, 0x81, 05, 0x29, 0x2b}}, Optab{ASUBW, yaddl, Pe, [13]uint8{0x83, 05, 0x2d, 0x81, 05, 0x29, 0x2b}}, Optab{ASYSCALL, ynone, Px, [13]uint8{0xcd, 100}}, Optab{ATESTB, ytestb, Pb, [13]uint8{0xa8, 0xf6, 00, 0x84, 0x84}}, Optab{ATESTL, ytestl, Px, [13]uint8{0xa9, 0xf7, 00, 0x85, 0x85}}, Optab{ATESTW, ytestl, Pe, [13]uint8{0xa9, 0xf7, 00, 0x85, 0x85}}, Optab{obj.ATEXT, ytext, Px, [13]uint8{}}, Optab{AVERR, ydivl, Pm, [13]uint8{0x00, 04}}, Optab{AVERW, ydivl, Pm, [13]uint8{0x00, 05}}, Optab{AWAIT, ynone, Px, [13]uint8{0x9b}}, Optab{AWORD, ybyte, Px, [13]uint8{2}}, Optab{AXCHGB, yml_mb, Pb, [13]uint8{0x86, 0x86}}, Optab{AXCHGL, yxchg, Px, [13]uint8{0x90, 0x90, 0x87, 0x87}}, Optab{AXCHGW, yxchg, Pe, [13]uint8{0x90, 0x90, 0x87, 0x87}}, Optab{AXLAT, ynone, Px, [13]uint8{0xd7}}, Optab{AXORB, yxorb, Pb, [13]uint8{0x34, 0x80, 06, 0x30, 0x32}}, Optab{AXORL, yxorl, Px, [13]uint8{0x83, 06, 0x35, 0x81, 06, 0x31, 0x33}}, Optab{AXORW, yxorl, Pe, [13]uint8{0x83, 06, 0x35, 0x81, 06, 0x31, 0x33}}, Optab{AFMOVB, yfmvx, Px, [13]uint8{0xdf, 04}}, Optab{AFMOVBP, yfmvp, Px, [13]uint8{0xdf, 06}}, Optab{AFMOVD, yfmvd, Px, [13]uint8{0xdd, 00, 0xdd, 02, 0xd9, 00, 0xdd, 02}}, Optab{AFMOVDP, yfmvdp, Px, [13]uint8{0xdd, 03, 0xdd, 03}}, Optab{AFMOVF, yfmvf, Px, [13]uint8{0xd9, 00, 0xd9, 02}}, Optab{AFMOVFP, yfmvp, Px, [13]uint8{0xd9, 03}}, Optab{AFMOVL, yfmvf, Px, [13]uint8{0xdb, 00, 0xdb, 02}}, Optab{AFMOVLP, yfmvp, Px, [13]uint8{0xdb, 03}}, Optab{AFMOVV, yfmvx, Px, [13]uint8{0xdf, 05}}, Optab{AFMOVVP, yfmvp, Px, [13]uint8{0xdf, 07}}, Optab{AFMOVW, yfmvf, Px, [13]uint8{0xdf, 00, 0xdf, 02}}, Optab{AFMOVWP, yfmvp, Px, [13]uint8{0xdf, 03}}, Optab{AFMOVX, yfmvx, Px, [13]uint8{0xdb, 05}}, Optab{AFMOVXP, yfmvp, Px, [13]uint8{0xdb, 07}}, Optab{AFCOMB, nil, 0, [13]uint8{}}, Optab{AFCOMBP, nil, 0, [13]uint8{}}, Optab{AFCOMD, yfadd, Px, [13]uint8{0xdc, 02, 0xd8, 02, 0xdc, 02}}, /* botch */ Optab{AFCOMDP, yfadd, Px, [13]uint8{0xdc, 03, 0xd8, 03, 0xdc, 03}}, /* botch */ Optab{AFCOMDPP, ycompp, Px, [13]uint8{0xde, 03}}, Optab{AFCOMF, yfmvx, Px, [13]uint8{0xd8, 02}}, Optab{AFCOMFP, yfmvx, Px, [13]uint8{0xd8, 03}}, Optab{AFCOMI, yfmvx, Px, [13]uint8{0xdb, 06}}, Optab{AFCOMIP, yfmvx, Px, [13]uint8{0xdf, 06}}, Optab{AFCOML, yfmvx, Px, [13]uint8{0xda, 02}}, Optab{AFCOMLP, yfmvx, Px, [13]uint8{0xda, 03}}, Optab{AFCOMW, yfmvx, Px, [13]uint8{0xde, 02}}, Optab{AFCOMWP, yfmvx, Px, [13]uint8{0xde, 03}}, Optab{AFUCOM, ycompp, Px, [13]uint8{0xdd, 04}}, Optab{AFUCOMI, ycompp, Px, [13]uint8{0xdb, 05}}, Optab{AFUCOMIP, ycompp, Px, [13]uint8{0xdf, 05}}, Optab{AFUCOMP, ycompp, Px, [13]uint8{0xdd, 05}}, Optab{AFUCOMPP, ycompp, Px, [13]uint8{0xda, 13}}, Optab{AFADDDP, yfaddp, Px, [13]uint8{0xde, 00}}, Optab{AFADDW, yfmvx, Px, [13]uint8{0xde, 00}}, Optab{AFADDL, yfmvx, Px, [13]uint8{0xda, 00}}, Optab{AFADDF, yfmvx, Px, [13]uint8{0xd8, 00}}, Optab{AFADDD, yfadd, Px, [13]uint8{0xdc, 00, 0xd8, 00, 0xdc, 00}}, Optab{AFMULDP, yfaddp, Px, [13]uint8{0xde, 01}}, Optab{AFMULW, yfmvx, Px, [13]uint8{0xde, 01}}, Optab{AFMULL, yfmvx, Px, [13]uint8{0xda, 01}}, Optab{AFMULF, yfmvx, Px, [13]uint8{0xd8, 01}}, Optab{AFMULD, yfadd, Px, [13]uint8{0xdc, 01, 0xd8, 01, 0xdc, 01}}, Optab{AFSUBDP, yfaddp, Px, [13]uint8{0xde, 05}}, Optab{AFSUBW, yfmvx, Px, [13]uint8{0xde, 04}}, Optab{AFSUBL, yfmvx, Px, [13]uint8{0xda, 04}}, Optab{AFSUBF, yfmvx, Px, [13]uint8{0xd8, 04}}, Optab{AFSUBD, yfadd, Px, [13]uint8{0xdc, 04, 0xd8, 04, 0xdc, 05}}, Optab{AFSUBRDP, yfaddp, Px, [13]uint8{0xde, 04}}, Optab{AFSUBRW, yfmvx, Px, [13]uint8{0xde, 05}}, Optab{AFSUBRL, yfmvx, Px, [13]uint8{0xda, 05}}, Optab{AFSUBRF, yfmvx, Px, [13]uint8{0xd8, 05}}, Optab{AFSUBRD, yfadd, Px, [13]uint8{0xdc, 05, 0xd8, 05, 0xdc, 04}}, Optab{AFDIVDP, yfaddp, Px, [13]uint8{0xde, 07}}, Optab{AFDIVW, yfmvx, Px, [13]uint8{0xde, 06}}, Optab{AFDIVL, yfmvx, Px, [13]uint8{0xda, 06}}, Optab{AFDIVF, yfmvx, Px, [13]uint8{0xd8, 06}}, Optab{AFDIVD, yfadd, Px, [13]uint8{0xdc, 06, 0xd8, 06, 0xdc, 07}}, Optab{AFDIVRDP, yfaddp, Px, [13]uint8{0xde, 06}}, Optab{AFDIVRW, yfmvx, Px, [13]uint8{0xde, 07}}, Optab{AFDIVRL, yfmvx, Px, [13]uint8{0xda, 07}}, Optab{AFDIVRF, yfmvx, Px, [13]uint8{0xd8, 07}}, Optab{AFDIVRD, yfadd, Px, [13]uint8{0xdc, 07, 0xd8, 07, 0xdc, 06}}, Optab{AFXCHD, yfxch, Px, [13]uint8{0xd9, 01, 0xd9, 01}}, Optab{AFFREE, nil, 0, [13]uint8{}}, Optab{AFLDCW, ystcw, Px, [13]uint8{0xd9, 05, 0xd9, 05}}, Optab{AFLDENV, ystcw, Px, [13]uint8{0xd9, 04, 0xd9, 04}}, Optab{AFRSTOR, ysvrs, Px, [13]uint8{0xdd, 04, 0xdd, 04}}, Optab{AFSAVE, ysvrs, Px, [13]uint8{0xdd, 06, 0xdd, 06}}, Optab{AFSTCW, ystcw, Px, [13]uint8{0xd9, 07, 0xd9, 07}}, Optab{AFSTENV, ystcw, Px, [13]uint8{0xd9, 06, 0xd9, 06}}, Optab{AFSTSW, ystsw, Px, [13]uint8{0xdd, 07, 0xdf, 0xe0}}, Optab{AF2XM1, ynone, Px, [13]uint8{0xd9, 0xf0}}, Optab{AFABS, ynone, Px, [13]uint8{0xd9, 0xe1}}, Optab{AFCHS, ynone, Px, [13]uint8{0xd9, 0xe0}}, Optab{AFCLEX, ynone, Px, [13]uint8{0xdb, 0xe2}}, Optab{AFCOS, ynone, Px, [13]uint8{0xd9, 0xff}}, Optab{AFDECSTP, ynone, Px, [13]uint8{0xd9, 0xf6}}, Optab{AFINCSTP, ynone, Px, [13]uint8{0xd9, 0xf7}}, Optab{AFINIT, ynone, Px, [13]uint8{0xdb, 0xe3}}, Optab{AFLD1, ynone, Px, [13]uint8{0xd9, 0xe8}}, Optab{AFLDL2E, ynone, Px, [13]uint8{0xd9, 0xea}}, Optab{AFLDL2T, ynone, Px, [13]uint8{0xd9, 0xe9}}, Optab{AFLDLG2, ynone, Px, [13]uint8{0xd9, 0xec}}, Optab{AFLDLN2, ynone, Px, [13]uint8{0xd9, 0xed}}, Optab{AFLDPI, ynone, Px, [13]uint8{0xd9, 0xeb}}, Optab{AFLDZ, ynone, Px, [13]uint8{0xd9, 0xee}}, Optab{AFNOP, ynone, Px, [13]uint8{0xd9, 0xd0}}, Optab{AFPATAN, ynone, Px, [13]uint8{0xd9, 0xf3}}, Optab{AFPREM, ynone, Px, [13]uint8{0xd9, 0xf8}}, Optab{AFPREM1, ynone, Px, [13]uint8{0xd9, 0xf5}}, Optab{AFPTAN, ynone, Px, [13]uint8{0xd9, 0xf2}}, Optab{AFRNDINT, ynone, Px, [13]uint8{0xd9, 0xfc}}, Optab{AFSCALE, ynone, Px, [13]uint8{0xd9, 0xfd}}, Optab{AFSIN, ynone, Px, [13]uint8{0xd9, 0xfe}}, Optab{AFSINCOS, ynone, Px, [13]uint8{0xd9, 0xfb}}, Optab{AFSQRT, ynone, Px, [13]uint8{0xd9, 0xfa}}, Optab{AFTST, ynone, Px, [13]uint8{0xd9, 0xe4}}, Optab{AFXAM, ynone, Px, [13]uint8{0xd9, 0xe5}}, Optab{AFXTRACT, ynone, Px, [13]uint8{0xd9, 0xf4}}, Optab{AFYL2X, ynone, Px, [13]uint8{0xd9, 0xf1}}, Optab{AFYL2XP1, ynone, Px, [13]uint8{0xd9, 0xf9}}, Optab{obj.AEND, nil, 0, [13]uint8{}}, Optab{ACMPXCHGB, yrb_mb, Pm, [13]uint8{0xb0}}, Optab{ACMPXCHGL, yrl_ml, Pm, [13]uint8{0xb1}}, Optab{ACMPXCHGW, yrl_ml, Pm, [13]uint8{0xb1}}, Optab{ACMPXCHG8B, yscond, Pm, [13]uint8{0xc7, 01}}, // TODO(rsc): yscond is wrong here. Optab{ACPUID, ynone, Pm, [13]uint8{0xa2}}, Optab{ARDTSC, ynone, Pm, [13]uint8{0x31}}, Optab{AXADDB, yrb_mb, Pb, [13]uint8{0x0f, 0xc0}}, Optab{AXADDL, yrl_ml, Pm, [13]uint8{0xc1}}, Optab{AXADDW, yrl_ml, Pe, [13]uint8{0x0f, 0xc1}}, Optab{ACMOVLCC, yml_rl, Pm, [13]uint8{0x43}}, Optab{ACMOVLCS, yml_rl, Pm, [13]uint8{0x42}}, Optab{ACMOVLEQ, yml_rl, Pm, [13]uint8{0x44}}, Optab{ACMOVLGE, yml_rl, Pm, [13]uint8{0x4d}}, Optab{ACMOVLGT, yml_rl, Pm, [13]uint8{0x4f}}, Optab{ACMOVLHI, yml_rl, Pm, [13]uint8{0x47}}, Optab{ACMOVLLE, yml_rl, Pm, [13]uint8{0x4e}}, Optab{ACMOVLLS, yml_rl, Pm, [13]uint8{0x46}}, Optab{ACMOVLLT, yml_rl, Pm, [13]uint8{0x4c}}, Optab{ACMOVLMI, yml_rl, Pm, [13]uint8{0x48}}, Optab{ACMOVLNE, yml_rl, Pm, [13]uint8{0x45}}, Optab{ACMOVLOC, yml_rl, Pm, [13]uint8{0x41}}, Optab{ACMOVLOS, yml_rl, Pm, [13]uint8{0x40}}, Optab{ACMOVLPC, yml_rl, Pm, [13]uint8{0x4b}}, Optab{ACMOVLPL, yml_rl, Pm, [13]uint8{0x49}}, Optab{ACMOVLPS, yml_rl, Pm, [13]uint8{0x4a}}, Optab{ACMOVWCC, yml_rl, Pq, [13]uint8{0x43}}, Optab{ACMOVWCS, yml_rl, Pq, [13]uint8{0x42}}, Optab{ACMOVWEQ, yml_rl, Pq, [13]uint8{0x44}}, Optab{ACMOVWGE, yml_rl, Pq, [13]uint8{0x4d}}, Optab{ACMOVWGT, yml_rl, Pq, [13]uint8{0x4f}}, Optab{ACMOVWHI, yml_rl, Pq, [13]uint8{0x47}}, Optab{ACMOVWLE, yml_rl, Pq, [13]uint8{0x4e}}, Optab{ACMOVWLS, yml_rl, Pq, [13]uint8{0x46}}, Optab{ACMOVWLT, yml_rl, Pq, [13]uint8{0x4c}}, Optab{ACMOVWMI, yml_rl, Pq, [13]uint8{0x48}}, Optab{ACMOVWNE, yml_rl, Pq, [13]uint8{0x45}}, Optab{ACMOVWOC, yml_rl, Pq, [13]uint8{0x41}}, Optab{ACMOVWOS, yml_rl, Pq, [13]uint8{0x40}}, Optab{ACMOVWPC, yml_rl, Pq, [13]uint8{0x4b}}, Optab{ACMOVWPL, yml_rl, Pq, [13]uint8{0x49}}, Optab{ACMOVWPS, yml_rl, Pq, [13]uint8{0x4a}}, Optab{AFCMOVCC, yfcmv, Px, [13]uint8{0xdb, 00}}, Optab{AFCMOVCS, yfcmv, Px, [13]uint8{0xda, 00}}, Optab{AFCMOVEQ, yfcmv, Px, [13]uint8{0xda, 01}}, Optab{AFCMOVHI, yfcmv, Px, [13]uint8{0xdb, 02}}, Optab{AFCMOVLS, yfcmv, Px, [13]uint8{0xda, 02}}, Optab{AFCMOVNE, yfcmv, Px, [13]uint8{0xdb, 01}}, Optab{AFCMOVNU, yfcmv, Px, [13]uint8{0xdb, 03}}, Optab{AFCMOVUN, yfcmv, Px, [13]uint8{0xda, 03}}, Optab{ALFENCE, ynone, Pm, [13]uint8{0xae, 0xe8}}, Optab{AMFENCE, ynone, Pm, [13]uint8{0xae, 0xf0}}, Optab{ASFENCE, ynone, Pm, [13]uint8{0xae, 0xf8}}, Optab{AEMMS, ynone, Pm, [13]uint8{0x77}}, Optab{APREFETCHT0, yprefetch, Pm, [13]uint8{0x18, 01}}, Optab{APREFETCHT1, yprefetch, Pm, [13]uint8{0x18, 02}}, Optab{APREFETCHT2, yprefetch, Pm, [13]uint8{0x18, 03}}, Optab{APREFETCHNTA, yprefetch, Pm, [13]uint8{0x18, 00}}, Optab{ABSWAPL, ybswap, Pm, [13]uint8{0xc8}}, Optab{obj.AUNDEF, ynone, Px, [13]uint8{0x0f, 0x0b}}, Optab{AADDPD, yxm, Pq, [13]uint8{0x58}}, Optab{AADDPS, yxm, Pm, [13]uint8{0x58}}, Optab{AADDSD, yxm, Pf2, [13]uint8{0x58}}, Optab{AADDSS, yxm, Pf3, [13]uint8{0x58}}, Optab{AANDNPD, yxm, Pq, [13]uint8{0x55}}, Optab{AANDNPS, yxm, Pm, [13]uint8{0x55}}, Optab{AANDPD, yxm, Pq, [13]uint8{0x54}}, Optab{AANDPS, yxm, Pq, [13]uint8{0x54}}, Optab{ACMPPD, yxcmpi, Px, [13]uint8{Pe, 0xc2}}, Optab{ACMPPS, yxcmpi, Pm, [13]uint8{0xc2, 0}}, Optab{ACMPSD, yxcmpi, Px, [13]uint8{Pf2, 0xc2}}, Optab{ACMPSS, yxcmpi, Px, [13]uint8{Pf3, 0xc2}}, Optab{ACOMISD, yxcmp, Pe, [13]uint8{0x2f}}, Optab{ACOMISS, yxcmp, Pm, [13]uint8{0x2f}}, Optab{ACVTPL2PD, yxcvm2, Px, [13]uint8{Pf3, 0xe6, Pe, 0x2a}}, Optab{ACVTPL2PS, yxcvm2, Pm, [13]uint8{0x5b, 0, 0x2a, 0}}, Optab{ACVTPD2PL, yxcvm1, Px, [13]uint8{Pf2, 0xe6, Pe, 0x2d}}, Optab{ACVTPD2PS, yxm, Pe, [13]uint8{0x5a}}, Optab{ACVTPS2PL, yxcvm1, Px, [13]uint8{Pe, 0x5b, Pm, 0x2d}}, Optab{ACVTPS2PD, yxm, Pm, [13]uint8{0x5a}}, Optab{ACVTSD2SL, yxcvfl, Pf2, [13]uint8{0x2d}}, Optab{ACVTSD2SS, yxm, Pf2, [13]uint8{0x5a}}, Optab{ACVTSL2SD, yxcvlf, Pf2, [13]uint8{0x2a}}, Optab{ACVTSL2SS, yxcvlf, Pf3, [13]uint8{0x2a}}, Optab{ACVTSS2SD, yxm, Pf3, [13]uint8{0x5a}}, Optab{ACVTSS2SL, yxcvfl, Pf3, [13]uint8{0x2d}}, Optab{ACVTTPD2PL, yxcvm1, Px, [13]uint8{Pe, 0xe6, Pe, 0x2c}}, Optab{ACVTTPS2PL, yxcvm1, Px, [13]uint8{Pf3, 0x5b, Pm, 0x2c}}, Optab{ACVTTSD2SL, yxcvfl, Pf2, [13]uint8{0x2c}}, Optab{ACVTTSS2SL, yxcvfl, Pf3, [13]uint8{0x2c}}, Optab{ADIVPD, yxm, Pe, [13]uint8{0x5e}}, Optab{ADIVPS, yxm, Pm, [13]uint8{0x5e}}, Optab{ADIVSD, yxm, Pf2, [13]uint8{0x5e}}, Optab{ADIVSS, yxm, Pf3, [13]uint8{0x5e}}, Optab{AMASKMOVOU, yxr, Pe, [13]uint8{0xf7}}, Optab{AMAXPD, yxm, Pe, [13]uint8{0x5f}}, Optab{AMAXPS, yxm, Pm, [13]uint8{0x5f}}, Optab{AMAXSD, yxm, Pf2, [13]uint8{0x5f}}, Optab{AMAXSS, yxm, Pf3, [13]uint8{0x5f}}, Optab{AMINPD, yxm, Pe, [13]uint8{0x5d}}, Optab{AMINPS, yxm, Pm, [13]uint8{0x5d}}, Optab{AMINSD, yxm, Pf2, [13]uint8{0x5d}}, Optab{AMINSS, yxm, Pf3, [13]uint8{0x5d}}, Optab{AMOVAPD, yxmov, Pe, [13]uint8{0x28, 0x29}}, Optab{AMOVAPS, yxmov, Pm, [13]uint8{0x28, 0x29}}, Optab{AMOVO, yxmov, Pe, [13]uint8{0x6f, 0x7f}}, Optab{AMOVOU, yxmov, Pf3, [13]uint8{0x6f, 0x7f}}, Optab{AMOVHLPS, yxr, Pm, [13]uint8{0x12}}, Optab{AMOVHPD, yxmov, Pe, [13]uint8{0x16, 0x17}}, Optab{AMOVHPS, yxmov, Pm, [13]uint8{0x16, 0x17}}, Optab{AMOVLHPS, yxr, Pm, [13]uint8{0x16}}, Optab{AMOVLPD, yxmov, Pe, [13]uint8{0x12, 0x13}}, Optab{AMOVLPS, yxmov, Pm, [13]uint8{0x12, 0x13}}, Optab{AMOVMSKPD, yxrrl, Pq, [13]uint8{0x50}}, Optab{AMOVMSKPS, yxrrl, Pm, [13]uint8{0x50}}, Optab{AMOVNTO, yxr_ml, Pe, [13]uint8{0xe7}}, Optab{AMOVNTPD, yxr_ml, Pe, [13]uint8{0x2b}}, Optab{AMOVNTPS, yxr_ml, Pm, [13]uint8{0x2b}}, Optab{AMOVSD, yxmov, Pf2, [13]uint8{0x10, 0x11}}, Optab{AMOVSS, yxmov, Pf3, [13]uint8{0x10, 0x11}}, Optab{AMOVUPD, yxmov, Pe, [13]uint8{0x10, 0x11}}, Optab{AMOVUPS, yxmov, Pm, [13]uint8{0x10, 0x11}}, Optab{AMULPD, yxm, Pe, [13]uint8{0x59}}, Optab{AMULPS, yxm, Ym, [13]uint8{0x59}}, Optab{AMULSD, yxm, Pf2, [13]uint8{0x59}}, Optab{AMULSS, yxm, Pf3, [13]uint8{0x59}}, Optab{AORPD, yxm, Pq, [13]uint8{0x56}}, Optab{AORPS, yxm, Pm, [13]uint8{0x56}}, Optab{APADDQ, yxm, Pe, [13]uint8{0xd4}}, Optab{APAND, yxm, Pe, [13]uint8{0xdb}}, Optab{APCMPEQB, yxmq, Pe, [13]uint8{0x74}}, Optab{APMAXSW, yxm, Pe, [13]uint8{0xee}}, Optab{APMAXUB, yxm, Pe, [13]uint8{0xde}}, Optab{APMINSW, yxm, Pe, [13]uint8{0xea}}, Optab{APMINUB, yxm, Pe, [13]uint8{0xda}}, Optab{APMOVMSKB, ymskb, Px, [13]uint8{Pe, 0xd7, 0xd7}}, Optab{APSADBW, yxm, Pq, [13]uint8{0xf6}}, Optab{APSUBB, yxm, Pe, [13]uint8{0xf8}}, Optab{APSUBL, yxm, Pe, [13]uint8{0xfa}}, Optab{APSUBQ, yxm, Pe, [13]uint8{0xfb}}, Optab{APSUBSB, yxm, Pe, [13]uint8{0xe8}}, Optab{APSUBSW, yxm, Pe, [13]uint8{0xe9}}, Optab{APSUBUSB, yxm, Pe, [13]uint8{0xd8}}, Optab{APSUBUSW, yxm, Pe, [13]uint8{0xd9}}, Optab{APSUBW, yxm, Pe, [13]uint8{0xf9}}, Optab{APUNPCKHQDQ, yxm, Pe, [13]uint8{0x6d}}, Optab{APUNPCKLQDQ, yxm, Pe, [13]uint8{0x6c}}, Optab{APXOR, yxm, Pe, [13]uint8{0xef}}, Optab{ARCPPS, yxm, Pm, [13]uint8{0x53}}, Optab{ARCPSS, yxm, Pf3, [13]uint8{0x53}}, Optab{ARSQRTPS, yxm, Pm, [13]uint8{0x52}}, Optab{ARSQRTSS, yxm, Pf3, [13]uint8{0x52}}, Optab{ASQRTPD, yxm, Pe, [13]uint8{0x51}}, Optab{ASQRTPS, yxm, Pm, [13]uint8{0x51}}, Optab{ASQRTSD, yxm, Pf2, [13]uint8{0x51}}, Optab{ASQRTSS, yxm, Pf3, [13]uint8{0x51}}, Optab{ASUBPD, yxm, Pe, [13]uint8{0x5c}}, Optab{ASUBPS, yxm, Pm, [13]uint8{0x5c}}, Optab{ASUBSD, yxm, Pf2, [13]uint8{0x5c}}, Optab{ASUBSS, yxm, Pf3, [13]uint8{0x5c}}, Optab{AUCOMISD, yxcmp, Pe, [13]uint8{0x2e}}, Optab{AUCOMISS, yxcmp, Pm, [13]uint8{0x2e}}, Optab{AUNPCKHPD, yxm, Pe, [13]uint8{0x15}}, Optab{AUNPCKHPS, yxm, Pm, [13]uint8{0x15}}, Optab{AUNPCKLPD, yxm, Pe, [13]uint8{0x14}}, Optab{AUNPCKLPS, yxm, Pm, [13]uint8{0x14}}, Optab{AXORPD, yxm, Pe, [13]uint8{0x57}}, Optab{AXORPS, yxm, Pm, [13]uint8{0x57}}, Optab{APSHUFHW, yxshuf, Pf3, [13]uint8{0x70, 00}}, Optab{APSHUFL, yxshuf, Pq, [13]uint8{0x70, 00}}, Optab{APSHUFLW, yxshuf, Pf2, [13]uint8{0x70, 00}}, Optab{AAESENC, yaes, Pq, [13]uint8{0x38, 0xdc, 0}}, Optab{APINSRD, yinsrd, Pq, [13]uint8{0x3a, 0x22, 00}}, Optab{APSHUFB, ymshufb, Pq, [13]uint8{0x38, 0x00}}, Optab{obj.AUSEFIELD, ynop, Px, [13]uint8{0, 0}}, Optab{obj.ATYPE, nil, 0, [13]uint8{}}, Optab{obj.AFUNCDATA, yfuncdata, Px, [13]uint8{0, 0}}, Optab{obj.APCDATA, ypcdata, Px, [13]uint8{0, 0}}, Optab{obj.ACHECKNIL, nil, 0, [13]uint8{}}, Optab{obj.AVARDEF, nil, 0, [13]uint8{}}, Optab{obj.AVARKILL, nil, 0, [13]uint8{}}, Optab{obj.ADUFFCOPY, yduff, Px, [13]uint8{0xe8}}, Optab{obj.ADUFFZERO, yduff, Px, [13]uint8{0xe8}}, Optab{0, nil, 0, [13]uint8{}}, } // single-instruction no-ops of various lengths. // constructed by hand and disassembled with gdb to verify. // see http://www.agner.org/optimize/optimizing_assembly.pdf for discussion. var nop = [][16]uint8{ [16]uint8{0x90}, [16]uint8{0x66, 0x90}, [16]uint8{0x0F, 0x1F, 0x00}, [16]uint8{0x0F, 0x1F, 0x40, 0x00}, [16]uint8{0x0F, 0x1F, 0x44, 0x00, 0x00}, [16]uint8{0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00}, [16]uint8{0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00}, [16]uint8{0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, [16]uint8{0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, } // Native Client rejects the repeated 0x66 prefix. // {0x66, 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, func fillnop(p []byte, n int) { var m int for n > 0 { m = n if m > len(nop) { m = len(nop) } copy(p[:m], nop[m-1][:m]) p = p[m:] n -= m } } func naclpad(ctxt *obj.Link, s *obj.LSym, c int32, pad int32) int32 { obj.Symgrow(ctxt, s, int64(c)+int64(pad)) fillnop(s.P[c:], int(pad)) return c + pad } func span8(ctxt *obj.Link, s *obj.LSym) { var p *obj.Prog var q *obj.Prog var c int32 var v int32 var loop int32 var bp []byte var n int var m int var i int ctxt.Cursym = s if s.Text == nil || s.Text.Link == nil { return } if ycover[0] == 0 { instinit() } for p = s.Text; p != nil; p = p.Link { if p.To.Type == obj.TYPE_BRANCH { if p.Pcond == nil { p.Pcond = p } } if p.As == AADJSP { p.To.Type = obj.TYPE_REG p.To.Reg = REG_SP v = int32(-p.From.Offset) p.From.Offset = int64(v) p.As = AADDL if v < 0 { p.As = ASUBL v = -v p.From.Offset = int64(v) } if v == 0 { p.As = obj.ANOP } } } for p = s.Text; p != nil; p = p.Link { p.Back = 2 // use short branches first time through q = p.Pcond if q != nil && (q.Back&2 != 0) { p.Back |= 1 // backward jump } if p.As == AADJSP { p.To.Type = obj.TYPE_REG p.To.Reg = REG_SP v = int32(-p.From.Offset) p.From.Offset = int64(v) p.As = AADDL if v < 0 { p.As = ASUBL v = -v p.From.Offset = int64(v) } if v == 0 { p.As = obj.ANOP } } } n = 0 for { loop = 0 for i = 0; i < len(s.R); i++ { s.R[i] = obj.Reloc{} } s.R = s.R[:0] s.P = s.P[:0] c = 0 for p = s.Text; p != nil; p = p.Link { if ctxt.Headtype == obj.Hnacl && p.Isize > 0 { var deferreturn *obj.LSym if deferreturn == nil { deferreturn = obj.Linklookup(ctxt, "runtime.deferreturn", 0) } // pad everything to avoid crossing 32-byte boundary if c>>5 != (c+int32(p.Isize)-1)>>5 { c = naclpad(ctxt, s, c, -c&31) } // pad call deferreturn to start at 32-byte boundary // so that subtracting 5 in jmpdefer will jump back // to that boundary and rerun the call. if p.As == obj.ACALL && p.To.Sym == deferreturn { c = naclpad(ctxt, s, c, -c&31) } // pad call to end at 32-byte boundary if p.As == obj.ACALL { c = naclpad(ctxt, s, c, -(c+int32(p.Isize))&31) } // the linker treats REP and STOSQ as different instructions // but in fact the REP is a prefix on the STOSQ. // make sure REP has room for 2 more bytes, so that // padding will not be inserted before the next instruction. if p.As == AREP && c>>5 != (c+3-1)>>5 { c = naclpad(ctxt, s, c, -c&31) } // same for LOCK. // various instructions follow; the longest is 4 bytes. // give ourselves 8 bytes so as to avoid surprises. if p.As == ALOCK && c>>5 != (c+8-1)>>5 { c = naclpad(ctxt, s, c, -c&31) } } p.Pc = int64(c) // process forward jumps to p for q = p.Comefrom; q != nil; q = q.Forwd { v = int32(p.Pc - (q.Pc + int64(q.Mark))) if q.Back&2 != 0 { // short if v > 127 { loop++ q.Back ^= 2 } if q.As == AJCXZW { s.P[q.Pc+2] = byte(v) } else { s.P[q.Pc+1] = byte(v) } } else { bp = s.P[q.Pc+int64(q.Mark)-4:] bp[0] = byte(v) bp = bp[1:] bp[0] = byte(v >> 8) bp = bp[1:] bp[0] = byte(v >> 16) bp = bp[1:] bp[0] = byte(v >> 24) } } p.Comefrom = nil p.Pc = int64(c) asmins(ctxt, p) m = -cap(ctxt.Andptr) + cap(ctxt.And[:]) if int(p.Isize) != m { p.Isize = uint8(m) loop++ } obj.Symgrow(ctxt, s, p.Pc+int64(m)) copy(s.P[p.Pc:][:m], ctxt.And[:m]) p.Mark = uint16(m) c += int32(m) } n++ if n > 20 { ctxt.Diag("span must be looping") log.Fatalf("bad code") } if !(loop != 0) { break } } if ctxt.Headtype == obj.Hnacl { c = naclpad(ctxt, s, c, -c&31) } c += -c & (FuncAlign - 1) s.Size = int64(c) if false { /* debug['a'] > 1 */ fmt.Printf("span1 %s %d (%d tries)\n %.6x", s.Name, s.Size, n, 0) for i = 0; i < len(s.P); i++ { fmt.Printf(" %.2x", s.P[i]) if i%16 == 15 { fmt.Printf("\n %.6x", uint(i+1)) } } if i%16 != 0 { fmt.Printf("\n") } for i = 0; i < len(s.R); i++ { var r *obj.Reloc r = &s.R[i] fmt.Printf(" rel %#.4x/%d %s%+d\n", uint32(r.Off), r.Siz, r.Sym.Name, r.Add) } } } func instinit() { var i int var c int for i = 1; optab[i].as != 0; i++ { c = int(optab[i].as) if opindex[c] != nil { log.Fatalf("phase error in optab: %d (%v)", i, Aconv(c)) } opindex[c] = &optab[i] } for i = 0; i < Ymax; i++ { ycover[i*Ymax+i] = 1 } ycover[Yi0*Ymax+Yi8] = 1 ycover[Yi1*Ymax+Yi8] = 1 ycover[Yi0*Ymax+Yi32] = 1 ycover[Yi1*Ymax+Yi32] = 1 ycover[Yi8*Ymax+Yi32] = 1 ycover[Yal*Ymax+Yrb] = 1 ycover[Ycl*Ymax+Yrb] = 1 ycover[Yax*Ymax+Yrb] = 1 ycover[Ycx*Ymax+Yrb] = 1 ycover[Yrx*Ymax+Yrb] = 1 ycover[Yax*Ymax+Yrx] = 1 ycover[Ycx*Ymax+Yrx] = 1 ycover[Yax*Ymax+Yrl] = 1 ycover[Ycx*Ymax+Yrl] = 1 ycover[Yrx*Ymax+Yrl] = 1 ycover[Yf0*Ymax+Yrf] = 1 ycover[Yal*Ymax+Ymb] = 1 ycover[Ycl*Ymax+Ymb] = 1 ycover[Yax*Ymax+Ymb] = 1 ycover[Ycx*Ymax+Ymb] = 1 ycover[Yrx*Ymax+Ymb] = 1 ycover[Yrb*Ymax+Ymb] = 1 ycover[Ym*Ymax+Ymb] = 1 ycover[Yax*Ymax+Yml] = 1 ycover[Ycx*Ymax+Yml] = 1 ycover[Yrx*Ymax+Yml] = 1 ycover[Yrl*Ymax+Yml] = 1 ycover[Ym*Ymax+Yml] = 1 ycover[Yax*Ymax+Ymm] = 1 ycover[Ycx*Ymax+Ymm] = 1 ycover[Yrx*Ymax+Ymm] = 1 ycover[Yrl*Ymax+Ymm] = 1 ycover[Ym*Ymax+Ymm] = 1 ycover[Ymr*Ymax+Ymm] = 1 ycover[Ym*Ymax+Yxm] = 1 ycover[Yxr*Ymax+Yxm] = 1 for i = 0; i < MAXREG; i++ { reg[i] = -1 if i >= REG_AL && i <= REG_BH { reg[i] = (i - REG_AL) & 7 } if i >= REG_AX && i <= REG_DI { reg[i] = (i - REG_AX) & 7 } if i >= REG_F0 && i <= REG_F0+7 { reg[i] = (i - REG_F0) & 7 } if i >= REG_X0 && i <= REG_X0+7 { reg[i] = (i - REG_X0) & 7 } } } func prefixof(ctxt *obj.Link, a *obj.Addr) int { if a.Type == obj.TYPE_MEM && a.Name == obj.NAME_NONE { switch a.Reg { case REG_CS: return 0x2e case REG_DS: return 0x3e case REG_ES: return 0x26 case REG_FS: return 0x64 case REG_GS: return 0x65 // NOTE: Systems listed here should be only systems that // support direct TLS references like 8(TLS) implemented as // direct references from FS or GS. Systems that require // the initial-exec model, where you load the TLS base into // a register and then index from that register, do not reach // this code and should not be listed. case REG_TLS: switch ctxt.Headtype { default: log.Fatalf("unknown TLS base register for %s", obj.Headstr(ctxt.Headtype)) case obj.Hdarwin, obj.Hdragonfly, obj.Hfreebsd, obj.Hnetbsd, obj.Hopenbsd: return 0x65 // GS } } } return 0 } func oclass(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int { var v int32 // TODO(rsc): This special case is for SHRQ $3, AX:DX, // which encodes as SHRQ $32(DX*0), AX. // Similarly SHRQ CX, AX:DX is really SHRQ CX(DX*0), AX. // Change encoding and remove. if (a.Type == obj.TYPE_CONST || a.Type == obj.TYPE_REG) && a.Index != REG_NONE && a.Scale == 0 { return Ycol } switch a.Type { case obj.TYPE_NONE: return Ynone case obj.TYPE_BRANCH: return Ybr // TODO(rsc): Why this is also Ycol is a mystery. Should split the two meanings. case obj.TYPE_INDIR: if a.Name != obj.NAME_NONE && a.Reg == REG_NONE && a.Index == REG_NONE && a.Scale == 0 { return Ycol } return Yxxx case obj.TYPE_MEM: return Ym case obj.TYPE_ADDR: switch a.Name { case obj.NAME_EXTERN, obj.NAME_STATIC: return Yi32 case obj.NAME_AUTO, obj.NAME_PARAM: return Yiauto } // DUFFZERO/DUFFCOPY encoding forgot to set a->index // and got Yi32 in an earlier version of this code. // Keep doing that until we fix yduff etc. if a.Sym != nil && strings.HasPrefix(a.Sym.Name, "runtime.duff") { return Yi32 } if a.Sym != nil || a.Name != obj.NAME_NONE { ctxt.Diag("unexpected addr: %v", Dconv(p, 0, a)) } fallthrough // fall through case obj.TYPE_CONST: if a.Sym != nil { ctxt.Diag("TYPE_CONST with symbol: %v", Dconv(p, 0, a)) } v = int32(a.Offset) if v == 0 { return Yi0 } if v == 1 { return Yi1 } if v >= -128 && v <= 127 { return Yi8 } return Yi32 case obj.TYPE_TEXTSIZE: return Ytextsize } if a.Type != obj.TYPE_REG { ctxt.Diag("unexpected addr1: type=%d %v", a.Type, Dconv(p, 0, a)) return Yxxx } switch a.Reg { case REG_AL: return Yal case REG_AX: return Yax case REG_CL, REG_DL, REG_BL, REG_AH, REG_CH, REG_DH, REG_BH: return Yrb case REG_CX: return Ycx case REG_DX, REG_BX: return Yrx case REG_SP, REG_BP, REG_SI, REG_DI: return Yrl case REG_F0 + 0: return Yf0 case REG_F0 + 1, REG_F0 + 2, REG_F0 + 3, REG_F0 + 4, REG_F0 + 5, REG_F0 + 6, REG_F0 + 7: return Yrf case REG_X0 + 0, REG_X0 + 1, REG_X0 + 2, REG_X0 + 3, REG_X0 + 4, REG_X0 + 5, REG_X0 + 6, REG_X0 + 7: return Yxr case REG_CS: return Ycs case REG_SS: return Yss case REG_DS: return Yds case REG_ES: return Yes case REG_FS: return Yfs case REG_GS: return Ygs case REG_TLS: return Ytls case REG_GDTR: return Ygdtr case REG_IDTR: return Yidtr case REG_LDTR: return Yldtr case REG_MSW: return Ymsw case REG_TASK: return Ytask case REG_CR + 0: return Ycr0 case REG_CR + 1: return Ycr1 case REG_CR + 2: return Ycr2 case REG_CR + 3: return Ycr3 case REG_CR + 4: return Ycr4 case REG_CR + 5: return Ycr5 case REG_CR + 6: return Ycr6 case REG_CR + 7: return Ycr7 case REG_DR + 0: return Ydr0 case REG_DR + 1: return Ydr1 case REG_DR + 2: return Ydr2 case REG_DR + 3: return Ydr3 case REG_DR + 4: return Ydr4 case REG_DR + 5: return Ydr5 case REG_DR + 6: return Ydr6 case REG_DR + 7: return Ydr7 case REG_TR + 0: return Ytr0 case REG_TR + 1: return Ytr1 case REG_TR + 2: return Ytr2 case REG_TR + 3: return Ytr3 case REG_TR + 4: return Ytr4 case REG_TR + 5: return Ytr5 case REG_TR + 6: return Ytr6 case REG_TR + 7: return Ytr7 } return Yxxx } func asmidx(ctxt *obj.Link, scale int, index int, base int) { var i int switch index { default: goto bad case obj.TYPE_NONE: i = 4 << 3 goto bas case REG_AX, REG_CX, REG_DX, REG_BX, REG_BP, REG_SI, REG_DI: i = reg[index] << 3 break } switch scale { default: goto bad case 1: break case 2: i |= 1 << 6 case 4: i |= 2 << 6 case 8: i |= 3 << 6 break } bas: switch base { default: goto bad case REG_NONE: /* must be mod=00 */ i |= 5 case REG_AX, REG_CX, REG_DX, REG_BX, REG_SP, REG_BP, REG_SI, REG_DI: i |= reg[base] break } ctxt.Andptr[0] = byte(i) ctxt.Andptr = ctxt.Andptr[1:] return bad: ctxt.Diag("asmidx: bad address %d,%d,%d", scale, index, base) ctxt.Andptr[0] = 0 ctxt.Andptr = ctxt.Andptr[1:] return } func put4(ctxt *obj.Link, v int32) { ctxt.Andptr[0] = byte(v) ctxt.Andptr[1] = byte(v >> 8) ctxt.Andptr[2] = byte(v >> 16) ctxt.Andptr[3] = byte(v >> 24) ctxt.Andptr = ctxt.Andptr[4:] } func relput4(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) { var v int64 var rel obj.Reloc var r *obj.Reloc v = int64(vaddr(ctxt, p, a, &rel)) if rel.Siz != 0 { if rel.Siz != 4 { ctxt.Diag("bad reloc") } r = obj.Addrel(ctxt.Cursym) *r = rel r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:]))) } put4(ctxt, int32(v)) } func vaddr(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r *obj.Reloc) int32 { var s *obj.LSym if r != nil { *r = obj.Reloc{} } switch a.Name { case obj.NAME_STATIC, obj.NAME_EXTERN: s = a.Sym if s != nil { if r == nil { ctxt.Diag("need reloc for %v", Dconv(p, 0, a)) log.Fatalf("bad code") } r.Type = obj.R_ADDR r.Siz = 4 r.Off = -1 r.Sym = s r.Add = a.Offset return 0 } return int32(a.Offset) } if (a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR) && a.Reg == REG_TLS { if r == nil { ctxt.Diag("need reloc for %v", Dconv(p, 0, a)) log.Fatalf("bad code") } r.Type = obj.R_TLS_LE r.Siz = 4 r.Off = -1 // caller must fill in r.Add = a.Offset return 0 } return int32(a.Offset) } func asmand(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int) { var v int32 var base int var rel obj.Reloc v = int32(a.Offset) rel.Siz = 0 switch a.Type { case obj.TYPE_ADDR: if a.Name == obj.NAME_NONE { ctxt.Diag("unexpected TYPE_ADDR with NAME_NONE") } if a.Index == REG_TLS { ctxt.Diag("unexpected TYPE_ADDR with index==REG_TLS") } goto bad case obj.TYPE_REG: if (a.Reg < REG_AL || REG_F7 < a.Reg) && (a.Reg < REG_X0 || REG_X0+7 < a.Reg) { goto bad } if v != 0 { goto bad } ctxt.Andptr[0] = byte(3<<6 | reg[a.Reg]<<0 | r<<3) ctxt.Andptr = ctxt.Andptr[1:] return } if a.Type != obj.TYPE_MEM { goto bad } if a.Index != REG_NONE && a.Index != REG_TLS { base = int(a.Reg) switch a.Name { case obj.NAME_EXTERN, obj.NAME_STATIC: base = REG_NONE v = vaddr(ctxt, p, a, &rel) case obj.NAME_AUTO, obj.NAME_PARAM: base = REG_SP break } if base == REG_NONE { ctxt.Andptr[0] = byte(0<<6 | 4<<0 | r<<3) ctxt.Andptr = ctxt.Andptr[1:] asmidx(ctxt, int(a.Scale), int(a.Index), base) goto putrelv } if v == 0 && rel.Siz == 0 && base != REG_BP { ctxt.Andptr[0] = byte(0<<6 | 4<<0 | r<<3) ctxt.Andptr = ctxt.Andptr[1:] asmidx(ctxt, int(a.Scale), int(a.Index), base) return } if v >= -128 && v < 128 && rel.Siz == 0 { ctxt.Andptr[0] = byte(1<<6 | 4<<0 | r<<3) ctxt.Andptr = ctxt.Andptr[1:] asmidx(ctxt, int(a.Scale), int(a.Index), base) ctxt.Andptr[0] = byte(v) ctxt.Andptr = ctxt.Andptr[1:] return } ctxt.Andptr[0] = byte(2<<6 | 4<<0 | r<<3) ctxt.Andptr = ctxt.Andptr[1:] asmidx(ctxt, int(a.Scale), int(a.Index), base) goto putrelv } base = int(a.Reg) switch a.Name { case obj.NAME_STATIC, obj.NAME_EXTERN: base = REG_NONE v = vaddr(ctxt, p, a, &rel) case obj.NAME_AUTO, obj.NAME_PARAM: base = REG_SP break } if base == REG_TLS { v = vaddr(ctxt, p, a, &rel) } if base == REG_NONE || (REG_CS <= base && base <= REG_GS) || base == REG_TLS { ctxt.Andptr[0] = byte(0<<6 | 5<<0 | r<<3) ctxt.Andptr = ctxt.Andptr[1:] goto putrelv } if base == REG_SP { if v == 0 && rel.Siz == 0 { ctxt.Andptr[0] = byte(0<<6 | 4<<0 | r<<3) ctxt.Andptr = ctxt.Andptr[1:] asmidx(ctxt, int(a.Scale), REG_NONE, base) return } if v >= -128 && v < 128 && rel.Siz == 0 { ctxt.Andptr[0] = byte(1<<6 | 4<<0 | r<<3) ctxt.Andptr = ctxt.Andptr[1:] asmidx(ctxt, int(a.Scale), REG_NONE, base) ctxt.Andptr[0] = byte(v) ctxt.Andptr = ctxt.Andptr[1:] return } ctxt.Andptr[0] = byte(2<<6 | 4<<0 | r<<3) ctxt.Andptr = ctxt.Andptr[1:] asmidx(ctxt, int(a.Scale), REG_NONE, base) goto putrelv } if REG_AX <= base && base <= REG_DI { if a.Index == REG_TLS { rel = obj.Reloc{} rel.Type = obj.R_TLS_IE rel.Siz = 4 rel.Sym = nil rel.Add = int64(v) v = 0 } if v == 0 && rel.Siz == 0 && base != REG_BP { ctxt.Andptr[0] = byte(0<<6 | reg[base]<<0 | r<<3) ctxt.Andptr = ctxt.Andptr[1:] return } if v >= -128 && v < 128 && rel.Siz == 0 { ctxt.Andptr[0] = byte(1<<6 | reg[base]<<0 | r<<3) ctxt.Andptr[1] = byte(v) ctxt.Andptr = ctxt.Andptr[2:] return } ctxt.Andptr[0] = byte(2<<6 | reg[base]<<0 | r<<3) ctxt.Andptr = ctxt.Andptr[1:] goto putrelv } goto bad putrelv: if rel.Siz != 0 { var r *obj.Reloc if rel.Siz != 4 { ctxt.Diag("bad rel") goto bad } r = obj.Addrel(ctxt.Cursym) *r = rel r.Off = int32(ctxt.Curp.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:]))) } put4(ctxt, v) return bad: ctxt.Diag("asmand: bad address %v", Dconv(p, 0, a)) return } const ( E = 0xff ) var ymovtab = []uint8{ /* push */ APUSHL, Ycs, Ynone, 0, 0x0e, E, 0, 0, APUSHL, Yss, Ynone, 0, 0x16, E, 0, 0, APUSHL, Yds, Ynone, 0, 0x1e, E, 0, 0, APUSHL, Yes, Ynone, 0, 0x06, E, 0, 0, APUSHL, Yfs, Ynone, 0, 0x0f, 0xa0, E, 0, APUSHL, Ygs, Ynone, 0, 0x0f, 0xa8, E, 0, APUSHW, Ycs, Ynone, 0, Pe, 0x0e, E, 0, APUSHW, Yss, Ynone, 0, Pe, 0x16, E, 0, APUSHW, Yds, Ynone, 0, Pe, 0x1e, E, 0, APUSHW, Yes, Ynone, 0, Pe, 0x06, E, 0, APUSHW, Yfs, Ynone, 0, Pe, 0x0f, 0xa0, E, APUSHW, Ygs, Ynone, 0, Pe, 0x0f, 0xa8, E, /* pop */ APOPL, Ynone, Yds, 0, 0x1f, E, 0, 0, APOPL, Ynone, Yes, 0, 0x07, E, 0, 0, APOPL, Ynone, Yss, 0, 0x17, E, 0, 0, APOPL, Ynone, Yfs, 0, 0x0f, 0xa1, E, 0, APOPL, Ynone, Ygs, 0, 0x0f, 0xa9, E, 0, APOPW, Ynone, Yds, 0, Pe, 0x1f, E, 0, APOPW, Ynone, Yes, 0, Pe, 0x07, E, 0, APOPW, Ynone, Yss, 0, Pe, 0x17, E, 0, APOPW, Ynone, Yfs, 0, Pe, 0x0f, 0xa1, E, APOPW, Ynone, Ygs, 0, Pe, 0x0f, 0xa9, E, /* mov seg */ AMOVW, Yes, Yml, 1, 0x8c, 0, 0, 0, AMOVW, Ycs, Yml, 1, 0x8c, 1, 0, 0, AMOVW, Yss, Yml, 1, 0x8c, 2, 0, 0, AMOVW, Yds, Yml, 1, 0x8c, 3, 0, 0, AMOVW, Yfs, Yml, 1, 0x8c, 4, 0, 0, AMOVW, Ygs, Yml, 1, 0x8c, 5, 0, 0, AMOVW, Yml, Yes, 2, 0x8e, 0, 0, 0, AMOVW, Yml, Ycs, 2, 0x8e, 1, 0, 0, AMOVW, Yml, Yss, 2, 0x8e, 2, 0, 0, AMOVW, Yml, Yds, 2, 0x8e, 3, 0, 0, AMOVW, Yml, Yfs, 2, 0x8e, 4, 0, 0, AMOVW, Yml, Ygs, 2, 0x8e, 5, 0, 0, /* mov cr */ AMOVL, Ycr0, Yml, 3, 0x0f, 0x20, 0, 0, AMOVL, Ycr2, Yml, 3, 0x0f, 0x20, 2, 0, AMOVL, Ycr3, Yml, 3, 0x0f, 0x20, 3, 0, AMOVL, Ycr4, Yml, 3, 0x0f, 0x20, 4, 0, AMOVL, Yml, Ycr0, 4, 0x0f, 0x22, 0, 0, AMOVL, Yml, Ycr2, 4, 0x0f, 0x22, 2, 0, AMOVL, Yml, Ycr3, 4, 0x0f, 0x22, 3, 0, AMOVL, Yml, Ycr4, 4, 0x0f, 0x22, 4, 0, /* mov dr */ AMOVL, Ydr0, Yml, 3, 0x0f, 0x21, 0, 0, AMOVL, Ydr6, Yml, 3, 0x0f, 0x21, 6, 0, AMOVL, Ydr7, Yml, 3, 0x0f, 0x21, 7, 0, AMOVL, Yml, Ydr0, 4, 0x0f, 0x23, 0, 0, AMOVL, Yml, Ydr6, 4, 0x0f, 0x23, 6, 0, AMOVL, Yml, Ydr7, 4, 0x0f, 0x23, 7, 0, /* mov tr */ AMOVL, Ytr6, Yml, 3, 0x0f, 0x24, 6, 0, AMOVL, Ytr7, Yml, 3, 0x0f, 0x24, 7, 0, AMOVL, Yml, Ytr6, 4, 0x0f, 0x26, 6, E, AMOVL, Yml, Ytr7, 4, 0x0f, 0x26, 7, E, /* lgdt, sgdt, lidt, sidt */ AMOVL, Ym, Ygdtr, 4, 0x0f, 0x01, 2, 0, AMOVL, Ygdtr, Ym, 3, 0x0f, 0x01, 0, 0, AMOVL, Ym, Yidtr, 4, 0x0f, 0x01, 3, 0, AMOVL, Yidtr, Ym, 3, 0x0f, 0x01, 1, 0, /* lldt, sldt */ AMOVW, Yml, Yldtr, 4, 0x0f, 0x00, 2, 0, AMOVW, Yldtr, Yml, 3, 0x0f, 0x00, 0, 0, /* lmsw, smsw */ AMOVW, Yml, Ymsw, 4, 0x0f, 0x01, 6, 0, AMOVW, Ymsw, Yml, 3, 0x0f, 0x01, 4, 0, /* ltr, str */ AMOVW, Yml, Ytask, 4, 0x0f, 0x00, 3, 0, AMOVW, Ytask, Yml, 3, 0x0f, 0x00, 1, 0, /* load full pointer */ AMOVL, Yml, Ycol, 5, 0, 0, 0, 0, AMOVW, Yml, Ycol, 5, Pe, 0, 0, 0, /* double shift */ ASHLL, Ycol, Yml, 6, 0xa4, 0xa5, 0, 0, ASHRL, Ycol, Yml, 6, 0xac, 0xad, 0, 0, /* extra imul */ AIMULW, Yml, Yrl, 7, Pq, 0xaf, 0, 0, AIMULL, Yml, Yrl, 7, Pm, 0xaf, 0, 0, /* load TLS base pointer */ AMOVL, Ytls, Yrl, 8, 0, 0, 0, 0, 0, } // byteswapreg returns a byte-addressable register (AX, BX, CX, DX) // which is not referenced in a. // If a is empty, it returns BX to account for MULB-like instructions // that might use DX and AX. func byteswapreg(ctxt *obj.Link, a *obj.Addr) int { var cana int var canb int var canc int var cand int cand = 1 canc = cand canb = canc cana = canb if a.Type == obj.TYPE_NONE { cand = 0 cana = cand } if a.Type == obj.TYPE_REG || ((a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR) && a.Name == obj.NAME_NONE) { switch a.Reg { case REG_NONE: cand = 0 cana = cand case REG_AX, REG_AL, REG_AH: cana = 0 case REG_BX, REG_BL, REG_BH: canb = 0 case REG_CX, REG_CL, REG_CH: canc = 0 case REG_DX, REG_DL, REG_DH: cand = 0 break } } if a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR { switch a.Index { case REG_AX: cana = 0 case REG_BX: canb = 0 case REG_CX: canc = 0 case REG_DX: cand = 0 break } } if cana != 0 { return REG_AX } if canb != 0 { return REG_BX } if canc != 0 { return REG_CX } if cand != 0 { return REG_DX } ctxt.Diag("impossible byte register") log.Fatalf("bad code") return 0 } func subreg(p *obj.Prog, from int, to int) { if false { /* debug['Q'] */ fmt.Printf("\n%v\ts/%v/%v/\n", p, Rconv(from), Rconv(to)) } if int(p.From.Reg) == from { p.From.Reg = int16(to) p.Ft = 0 } if int(p.To.Reg) == from { p.To.Reg = int16(to) p.Tt = 0 } if int(p.From.Index) == from { p.From.Index = int16(to) p.Ft = 0 } if int(p.To.Index) == from { p.To.Index = int16(to) p.Tt = 0 } if false { /* debug['Q'] */ fmt.Printf("%v\n", p) } } func mediaop(ctxt *obj.Link, o *Optab, op int, osize int, z int) int { switch op { case Pm, Pe, Pf2, Pf3: if osize != 1 { if op != Pm { ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] } ctxt.Andptr[0] = Pm ctxt.Andptr = ctxt.Andptr[1:] z++ op = int(o.op[z]) break } fallthrough default: if -cap(ctxt.Andptr) == -cap(ctxt.And) || ctxt.And[-cap(ctxt.Andptr)+cap(ctxt.And[:])-1] != Pm { ctxt.Andptr[0] = Pm ctxt.Andptr = ctxt.Andptr[1:] } break } ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] return z } func doasm(ctxt *obj.Link, p *obj.Prog) { var o *Optab var q *obj.Prog var pp obj.Prog var t []byte var z int var op int var ft int var tt int var breg int var v int32 var pre int32 var rel obj.Reloc var r *obj.Reloc var a *obj.Addr ctxt.Curp = p // TODO pre = int32(prefixof(ctxt, &p.From)) if pre != 0 { ctxt.Andptr[0] = byte(pre) ctxt.Andptr = ctxt.Andptr[1:] } pre = int32(prefixof(ctxt, &p.To)) if pre != 0 { ctxt.Andptr[0] = byte(pre) ctxt.Andptr = ctxt.Andptr[1:] } if p.Ft == 0 { p.Ft = uint8(oclass(ctxt, p, &p.From)) } if p.Tt == 0 { p.Tt = uint8(oclass(ctxt, p, &p.To)) } ft = int(p.Ft) * Ymax tt = int(p.Tt) * Ymax o = opindex[p.As] t = o.ytab if t == nil { ctxt.Diag("asmins: noproto %v", p) return } for z = 0; t[0] != 0; (func() { z += int(t[3]); t = t[4:] })() { if ycover[ft+int(t[0])] != 0 { if ycover[tt+int(t[1])] != 0 { goto found } } } goto domov found: switch o.prefix { case Pq: /* 16 bit escape and opcode escape */ ctxt.Andptr[0] = Pe ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = Pm ctxt.Andptr = ctxt.Andptr[1:] case Pf2, /* xmm opcode escape */ Pf3: ctxt.Andptr[0] = byte(o.prefix) ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = Pm ctxt.Andptr = ctxt.Andptr[1:] case Pm: /* opcode escape */ ctxt.Andptr[0] = Pm ctxt.Andptr = ctxt.Andptr[1:] case Pe: /* 16 bit escape */ ctxt.Andptr[0] = Pe ctxt.Andptr = ctxt.Andptr[1:] case Pb: /* botch */ break } op = int(o.op[z]) switch t[2] { default: ctxt.Diag("asmins: unknown z %d %v", t[2], p) return case Zpseudo: break case Zlit: for ; ; z++ { op = int(o.op[z]) if !(op != 0) { break } ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] } case Zlitm_r: for ; ; z++ { op = int(o.op[z]) if !(op != 0) { break } ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] } asmand(ctxt, p, &p.From, reg[p.To.Reg]) case Zm_r: ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] asmand(ctxt, p, &p.From, reg[p.To.Reg]) case Zm2_r: ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = byte(o.op[z+1]) ctxt.Andptr = ctxt.Andptr[1:] asmand(ctxt, p, &p.From, reg[p.To.Reg]) case Zm_r_xm: mediaop(ctxt, o, op, int(t[3]), z) asmand(ctxt, p, &p.From, reg[p.To.Reg]) case Zm_r_i_xm: mediaop(ctxt, o, op, int(t[3]), z) asmand(ctxt, p, &p.From, reg[p.To.Reg]) ctxt.Andptr[0] = byte(p.To.Offset) ctxt.Andptr = ctxt.Andptr[1:] case Zibm_r: for { tmp2 := z z++ op = int(o.op[tmp2]) if !(op != 0) { break } ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] } asmand(ctxt, p, &p.From, reg[p.To.Reg]) ctxt.Andptr[0] = byte(p.To.Offset) ctxt.Andptr = ctxt.Andptr[1:] case Zaut_r: ctxt.Andptr[0] = 0x8d ctxt.Andptr = ctxt.Andptr[1:] /* leal */ if p.From.Type != obj.TYPE_ADDR { ctxt.Diag("asmins: Zaut sb type ADDR") } p.From.Type = obj.TYPE_MEM p.Ft = 0 asmand(ctxt, p, &p.From, reg[p.To.Reg]) p.From.Type = obj.TYPE_ADDR p.Ft = 0 case Zm_o: ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] asmand(ctxt, p, &p.From, int(o.op[z+1])) case Zr_m: ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] asmand(ctxt, p, &p.To, reg[p.From.Reg]) case Zr_m_xm: mediaop(ctxt, o, op, int(t[3]), z) asmand(ctxt, p, &p.To, reg[p.From.Reg]) case Zr_m_i_xm: mediaop(ctxt, o, op, int(t[3]), z) asmand(ctxt, p, &p.To, reg[p.From.Reg]) ctxt.Andptr[0] = byte(p.From.Offset) ctxt.Andptr = ctxt.Andptr[1:] case Zcallindreg: r = obj.Addrel(ctxt.Cursym) r.Off = int32(p.Pc) r.Type = obj.R_CALLIND r.Siz = 0 fallthrough // fallthrough case Zo_m: ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] asmand(ctxt, p, &p.To, int(o.op[z+1])) case Zm_ibo: ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] asmand(ctxt, p, &p.From, int(o.op[z+1])) ctxt.Andptr[0] = byte(vaddr(ctxt, p, &p.To, nil)) ctxt.Andptr = ctxt.Andptr[1:] case Zibo_m: ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] asmand(ctxt, p, &p.To, int(o.op[z+1])) ctxt.Andptr[0] = byte(vaddr(ctxt, p, &p.From, nil)) ctxt.Andptr = ctxt.Andptr[1:] case Z_ib, Zib_: if t[2] == Zib_ { a = &p.From } else { a = &p.To } v = vaddr(ctxt, p, a, nil) ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = byte(v) ctxt.Andptr = ctxt.Andptr[1:] case Zib_rp: ctxt.Andptr[0] = byte(op + reg[p.To.Reg]) ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = byte(vaddr(ctxt, p, &p.From, nil)) ctxt.Andptr = ctxt.Andptr[1:] case Zil_rp: ctxt.Andptr[0] = byte(op + reg[p.To.Reg]) ctxt.Andptr = ctxt.Andptr[1:] if o.prefix == Pe { v = vaddr(ctxt, p, &p.From, nil) ctxt.Andptr[0] = byte(v) ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = byte(v >> 8) ctxt.Andptr = ctxt.Andptr[1:] } else { relput4(ctxt, p, &p.From) } case Zib_rr: ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] asmand(ctxt, p, &p.To, reg[p.To.Reg]) ctxt.Andptr[0] = byte(vaddr(ctxt, p, &p.From, nil)) ctxt.Andptr = ctxt.Andptr[1:] case Z_il, Zil_: if t[2] == Zil_ { a = &p.From } else { a = &p.To } ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] if o.prefix == Pe { v = vaddr(ctxt, p, a, nil) ctxt.Andptr[0] = byte(v) ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = byte(v >> 8) ctxt.Andptr = ctxt.Andptr[1:] } else { relput4(ctxt, p, a) } case Zm_ilo, Zilo_m: ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] if t[2] == Zilo_m { a = &p.From asmand(ctxt, p, &p.To, int(o.op[z+1])) } else { a = &p.To asmand(ctxt, p, &p.From, int(o.op[z+1])) } if o.prefix == Pe { v = vaddr(ctxt, p, a, nil) ctxt.Andptr[0] = byte(v) ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = byte(v >> 8) ctxt.Andptr = ctxt.Andptr[1:] } else { relput4(ctxt, p, a) } case Zil_rr: ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] asmand(ctxt, p, &p.To, reg[p.To.Reg]) if o.prefix == Pe { v = vaddr(ctxt, p, &p.From, nil) ctxt.Andptr[0] = byte(v) ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = byte(v >> 8) ctxt.Andptr = ctxt.Andptr[1:] } else { relput4(ctxt, p, &p.From) } case Z_rp: ctxt.Andptr[0] = byte(op + reg[p.To.Reg]) ctxt.Andptr = ctxt.Andptr[1:] case Zrp_: ctxt.Andptr[0] = byte(op + reg[p.From.Reg]) ctxt.Andptr = ctxt.Andptr[1:] case Zclr: ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] asmand(ctxt, p, &p.To, reg[p.To.Reg]) case Zcall: if p.To.Sym == nil { ctxt.Diag("call without target") log.Fatalf("bad code") } ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] r = obj.Addrel(ctxt.Cursym) r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:]))) r.Type = obj.R_CALL r.Siz = 4 r.Sym = p.To.Sym r.Add = p.To.Offset put4(ctxt, 0) case Zbr, Zjmp, Zloop: if p.To.Sym != nil { if t[2] != Zjmp { ctxt.Diag("branch to ATEXT") log.Fatalf("bad code") } ctxt.Andptr[0] = byte(o.op[z+1]) ctxt.Andptr = ctxt.Andptr[1:] r = obj.Addrel(ctxt.Cursym) r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:]))) r.Sym = p.To.Sym r.Type = obj.R_PCREL r.Siz = 4 put4(ctxt, 0) break } // Assumes q is in this function. // Fill in backward jump now. q = p.Pcond if q == nil { ctxt.Diag("jmp/branch/loop without target") log.Fatalf("bad code") } if p.Back&1 != 0 { v = int32(q.Pc - (p.Pc + 2)) if v >= -128 { if p.As == AJCXZW { ctxt.Andptr[0] = 0x67 ctxt.Andptr = ctxt.Andptr[1:] } ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = byte(v) ctxt.Andptr = ctxt.Andptr[1:] } else if t[2] == Zloop { ctxt.Diag("loop too far: %v", p) } else { v -= 5 - 2 if t[2] == Zbr { ctxt.Andptr[0] = 0x0f ctxt.Andptr = ctxt.Andptr[1:] v-- } ctxt.Andptr[0] = byte(o.op[z+1]) ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = byte(v) ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = byte(v >> 8) ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = byte(v >> 16) ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = byte(v >> 24) ctxt.Andptr = ctxt.Andptr[1:] } break } // Annotate target; will fill in later. p.Forwd = q.Comefrom q.Comefrom = p if p.Back&2 != 0 { // short if p.As == AJCXZW { ctxt.Andptr[0] = 0x67 ctxt.Andptr = ctxt.Andptr[1:] } ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = 0 ctxt.Andptr = ctxt.Andptr[1:] } else if t[2] == Zloop { ctxt.Diag("loop too far: %v", p) } else { if t[2] == Zbr { ctxt.Andptr[0] = 0x0f ctxt.Andptr = ctxt.Andptr[1:] } ctxt.Andptr[0] = byte(o.op[z+1]) ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = 0 ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = 0 ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = 0 ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = 0 ctxt.Andptr = ctxt.Andptr[1:] } case Zcallcon, Zjmpcon: if t[2] == Zcallcon { ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] } else { ctxt.Andptr[0] = byte(o.op[z+1]) ctxt.Andptr = ctxt.Andptr[1:] } r = obj.Addrel(ctxt.Cursym) r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:]))) r.Type = obj.R_PCREL r.Siz = 4 r.Add = p.To.Offset put4(ctxt, 0) case Zcallind: ctxt.Andptr[0] = byte(op) ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = byte(o.op[z+1]) ctxt.Andptr = ctxt.Andptr[1:] r = obj.Addrel(ctxt.Cursym) r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:]))) r.Type = obj.R_ADDR r.Siz = 4 r.Add = p.To.Offset r.Sym = p.To.Sym put4(ctxt, 0) case Zbyte: v = vaddr(ctxt, p, &p.From, &rel) if rel.Siz != 0 { rel.Siz = uint8(op) r = obj.Addrel(ctxt.Cursym) *r = rel r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:]))) } ctxt.Andptr[0] = byte(v) ctxt.Andptr = ctxt.Andptr[1:] if op > 1 { ctxt.Andptr[0] = byte(v >> 8) ctxt.Andptr = ctxt.Andptr[1:] if op > 2 { ctxt.Andptr[0] = byte(v >> 16) ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = byte(v >> 24) ctxt.Andptr = ctxt.Andptr[1:] } } case Zmov: goto domov } return domov: for t = []byte(ymovtab); t[0] != 0; t = t[8:] { if p.As == int16(t[0]) { if ycover[ft+int(t[1])] != 0 { if ycover[tt+int(t[2])] != 0 { goto mfound } } } } /* * here, the assembly has failed. * if its a byte instruction that has * unaddressable registers, try to * exchange registers and reissue the * instruction with the operands renamed. */ bad: pp = *p z = int(p.From.Reg) if p.From.Type == obj.TYPE_REG && z >= REG_BP && z <= REG_DI { breg = byteswapreg(ctxt, &p.To) if breg != REG_AX { ctxt.Andptr[0] = 0x87 ctxt.Andptr = ctxt.Andptr[1:] /* xchg lhs,bx */ asmand(ctxt, p, &p.From, reg[breg]) subreg(&pp, z, breg) doasm(ctxt, &pp) ctxt.Andptr[0] = 0x87 ctxt.Andptr = ctxt.Andptr[1:] /* xchg lhs,bx */ asmand(ctxt, p, &p.From, reg[breg]) } else { ctxt.Andptr[0] = byte(0x90 + reg[z]) ctxt.Andptr = ctxt.Andptr[1:] /* xchg lsh,ax */ subreg(&pp, z, REG_AX) doasm(ctxt, &pp) ctxt.Andptr[0] = byte(0x90 + reg[z]) ctxt.Andptr = ctxt.Andptr[1:] /* xchg lsh,ax */ } return } z = int(p.To.Reg) if p.To.Type == obj.TYPE_REG && z >= REG_BP && z <= REG_DI { breg = byteswapreg(ctxt, &p.From) if breg != REG_AX { ctxt.Andptr[0] = 0x87 ctxt.Andptr = ctxt.Andptr[1:] /* xchg rhs,bx */ asmand(ctxt, p, &p.To, reg[breg]) subreg(&pp, z, breg) doasm(ctxt, &pp) ctxt.Andptr[0] = 0x87 ctxt.Andptr = ctxt.Andptr[1:] /* xchg rhs,bx */ asmand(ctxt, p, &p.To, reg[breg]) } else { ctxt.Andptr[0] = byte(0x90 + reg[z]) ctxt.Andptr = ctxt.Andptr[1:] /* xchg rsh,ax */ subreg(&pp, z, REG_AX) doasm(ctxt, &pp) ctxt.Andptr[0] = byte(0x90 + reg[z]) ctxt.Andptr = ctxt.Andptr[1:] /* xchg rsh,ax */ } return } ctxt.Diag("doasm: notfound t2=%d from=%d to=%d %v", t[2], p.Ft, p.Tt, p) return mfound: switch t[3] { default: ctxt.Diag("asmins: unknown mov %d %v", t[3], p) case 0: /* lit */ for z = 4; t[z] != E; z++ { ctxt.Andptr[0] = t[z] ctxt.Andptr = ctxt.Andptr[1:] } case 1: /* r,m */ ctxt.Andptr[0] = t[4] ctxt.Andptr = ctxt.Andptr[1:] asmand(ctxt, p, &p.To, int(t[5])) case 2: /* m,r */ ctxt.Andptr[0] = t[4] ctxt.Andptr = ctxt.Andptr[1:] asmand(ctxt, p, &p.From, int(t[5])) case 3: /* r,m - 2op */ ctxt.Andptr[0] = t[4] ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = t[5] ctxt.Andptr = ctxt.Andptr[1:] asmand(ctxt, p, &p.To, int(t[6])) case 4: /* m,r - 2op */ ctxt.Andptr[0] = t[4] ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = t[5] ctxt.Andptr = ctxt.Andptr[1:] asmand(ctxt, p, &p.From, int(t[6])) case 5: /* load full pointer, trash heap */ if t[4] != 0 { ctxt.Andptr[0] = t[4] ctxt.Andptr = ctxt.Andptr[1:] } switch p.To.Index { default: goto bad case REG_DS: ctxt.Andptr[0] = 0xc5 ctxt.Andptr = ctxt.Andptr[1:] case REG_SS: ctxt.Andptr[0] = 0x0f ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = 0xb2 ctxt.Andptr = ctxt.Andptr[1:] case REG_ES: ctxt.Andptr[0] = 0xc4 ctxt.Andptr = ctxt.Andptr[1:] case REG_FS: ctxt.Andptr[0] = 0x0f ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = 0xb4 ctxt.Andptr = ctxt.Andptr[1:] case REG_GS: ctxt.Andptr[0] = 0x0f ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = 0xb5 ctxt.Andptr = ctxt.Andptr[1:] break } asmand(ctxt, p, &p.From, reg[p.To.Reg]) case 6: /* double shift */ switch p.From.Type { default: goto bad case obj.TYPE_CONST: ctxt.Andptr[0] = 0x0f ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = t[4] ctxt.Andptr = ctxt.Andptr[1:] asmand(ctxt, p, &p.To, reg[p.From.Index]) ctxt.Andptr[0] = byte(p.From.Offset) ctxt.Andptr = ctxt.Andptr[1:] case obj.TYPE_REG: switch p.From.Reg { default: goto bad case REG_CL, REG_CX: ctxt.Andptr[0] = 0x0f ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = t[5] ctxt.Andptr = ctxt.Andptr[1:] asmand(ctxt, p, &p.To, reg[p.From.Index]) break } break } case 7: /* imul rm,r */ if t[4] == Pq { ctxt.Andptr[0] = Pe ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = Pm ctxt.Andptr = ctxt.Andptr[1:] } else { ctxt.Andptr[0] = t[4] ctxt.Andptr = ctxt.Andptr[1:] } ctxt.Andptr[0] = t[5] ctxt.Andptr = ctxt.Andptr[1:] asmand(ctxt, p, &p.From, reg[p.To.Reg]) // NOTE: The systems listed here are the ones that use the "TLS initial exec" model, // where you load the TLS base register into a register and then index off that // register to access the actual TLS variables. Systems that allow direct TLS access // are handled in prefixof above and should not be listed here. case 8: /* mov tls, r */ switch ctxt.Headtype { default: log.Fatalf("unknown TLS base location for %s", obj.Headstr(ctxt.Headtype)) // ELF TLS base is 0(GS). case obj.Hlinux, obj.Hnacl: pp.From = p.From pp.From.Type = obj.TYPE_MEM pp.From.Reg = REG_GS pp.From.Offset = 0 pp.From.Index = REG_NONE pp.From.Scale = 0 ctxt.Andptr[0] = 0x65 ctxt.Andptr = ctxt.Andptr[1:] // GS ctxt.Andptr[0] = 0x8B ctxt.Andptr = ctxt.Andptr[1:] asmand(ctxt, p, &pp.From, reg[p.To.Reg]) case obj.Hplan9: if ctxt.Plan9privates == nil { ctxt.Plan9privates = obj.Linklookup(ctxt, "_privates", 0) } pp.From = obj.Addr{} pp.From.Type = obj.TYPE_MEM pp.From.Name = obj.NAME_EXTERN pp.From.Sym = ctxt.Plan9privates pp.From.Offset = 0 pp.From.Index = REG_NONE ctxt.Andptr[0] = 0x8B ctxt.Andptr = ctxt.Andptr[1:] asmand(ctxt, p, &pp.From, reg[p.To.Reg]) // Windows TLS base is always 0x14(FS). case obj.Hwindows: pp.From = p.From pp.From.Type = obj.TYPE_MEM pp.From.Reg = REG_FS pp.From.Offset = 0x14 pp.From.Index = REG_NONE pp.From.Scale = 0 ctxt.Andptr[0] = 0x64 ctxt.Andptr = ctxt.Andptr[1:] // FS ctxt.Andptr[0] = 0x8B ctxt.Andptr = ctxt.Andptr[1:] asmand(ctxt, p, &pp.From, reg[p.To.Reg]) break } break } } var naclret = []uint8{ 0x5d, // POPL BP // 0x8b, 0x7d, 0x00, // MOVL (BP), DI - catch return to invalid address, for debugging 0x83, 0xe5, 0xe0, // ANDL $~31, BP 0xff, 0xe5, // JMP BP } func asmins(ctxt *obj.Link, p *obj.Prog) { var r *obj.Reloc ctxt.Andptr = ctxt.And[:] if p.As == obj.AUSEFIELD { r = obj.Addrel(ctxt.Cursym) r.Off = 0 r.Sym = p.From.Sym r.Type = obj.R_USEFIELD r.Siz = 0 return } if ctxt.Headtype == obj.Hnacl { switch p.As { case obj.ARET: copy(ctxt.Andptr, naclret) ctxt.Andptr = ctxt.Andptr[len(naclret):] return case obj.ACALL, obj.AJMP: if p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_DI { ctxt.Andptr[0] = 0x83 ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = byte(0xe0 | (p.To.Reg - REG_AX)) ctxt.Andptr = ctxt.Andptr[1:] ctxt.Andptr[0] = 0xe0 ctxt.Andptr = ctxt.Andptr[1:] } case AINT: ctxt.Andptr[0] = 0xf4 ctxt.Andptr = ctxt.Andptr[1:] return } } doasm(ctxt, p) if -cap(ctxt.Andptr) > -cap(ctxt.And[len(ctxt.And):]) { fmt.Printf("and[] is too short - %d byte instruction\n", -cap(ctxt.Andptr)+cap(ctxt.And[:])) log.Fatalf("bad code") } }