func progedit(ctxt *liblink.Link, p *liblink.Prog) { var literal string var s *liblink.LSym var tlsfallback *liblink.LSym p.From.Class = 0 p.To.Class = 0 // Rewrite B/BL to symbol as D_BRANCH. switch p.As { case AB, ABL, ADUFFZERO, ADUFFCOPY: if p.To.Type_ == D_OREG && (p.To.Name == D_EXTERN || p.To.Name == D_STATIC) && p.To.Sym != nil { p.To.Type_ = D_BRANCH } break } // Replace TLS register fetches on older ARM procesors. switch p.As { // Treat MRC 15, 0, <reg>, C13, C0, 3 specially. case AMRC: if p.To.Offset&0xffff0fff == 0xee1d0f70 { // Because the instruction might be rewriten to a BL which returns in R0 // the register must be zero. if p.To.Offset&0xf000 != 0 { ctxt.Diag("%L: TLS MRC instruction must write to R0 as it might get translated into a BL instruction", p.Lineno) } if ctxt.Goarm < 7 { // Replace it with BL runtime.read_tls_fallback(SB) for ARM CPUs that lack the tls extension. if tlsfallback == nil { tlsfallback = liblink.Linklookup(ctxt, "runtime.read_tls_fallback", 0) } // MOVW LR, R11 p.As = AMOVW p.From.Type_ = D_REG p.From.Reg = REGLINK p.To.Type_ = D_REG p.To.Reg = REGTMP // BL runtime.read_tls_fallback(SB) p = liblink.Appendp(ctxt, p) p.As = ABL p.To.Type_ = D_BRANCH p.To.Sym = tlsfallback p.To.Offset = 0 // MOVW R11, LR p = liblink.Appendp(ctxt, p) p.As = AMOVW p.From.Type_ = D_REG p.From.Reg = REGTMP p.To.Type_ = D_REG p.To.Reg = REGLINK break } } // Otherwise, MRC/MCR instructions need no further treatment. p.As = AWORD break } // Rewrite float constants to values stored in memory. switch p.As { case AMOVF: if p.From.Type_ == D_FCONST && chipfloat5(ctxt, p.From.U.Dval) < 0 && (chipzero5(ctxt, p.From.U.Dval) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) { var i32 uint32 var f32 float32 f32 = float32(p.From.U.Dval) i32 = math.Float32bits(f32) literal = fmt.Sprintf("$f32.%08x", i32) s = liblink.Linklookup(ctxt, literal, 0) if s.Type_ == 0 { s.Type_ = liblink.SRODATA liblink.Adduint32(ctxt, s, i32) s.Reachable = 0 } p.From.Type_ = D_OREG p.From.Sym = s p.From.Name = D_EXTERN p.From.Offset = 0 } case AMOVD: if p.From.Type_ == D_FCONST && chipfloat5(ctxt, p.From.U.Dval) < 0 && (chipzero5(ctxt, p.From.U.Dval) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) { var i64 uint64 i64 = math.Float64bits(p.From.U.Dval) literal = fmt.Sprintf("$f64.%016x", i64) s = liblink.Linklookup(ctxt, literal, 0) if s.Type_ == 0 { s.Type_ = liblink.SRODATA liblink.Adduint64(ctxt, s, i64) s.Reachable = 0 } p.From.Type_ = D_OREG p.From.Sym = s p.From.Name = D_EXTERN p.From.Offset = 0 } break } if ctxt.Flag_shared != 0 { // Shared libraries use R_ARM_TLS_IE32 instead of // R_ARM_TLS_LE32, replacing the link time constant TLS offset in // runtime.tlsg with an address to a GOT entry containing the // offset. Rewrite $runtime.tlsg(SB) to runtime.tlsg(SB) to // compensate. if ctxt.Tlsg == nil { ctxt.Tlsg = liblink.Linklookup(ctxt, "runtime.tlsg", 0) } if p.From.Type_ == D_CONST && p.From.Name == D_EXTERN && p.From.Sym == ctxt.Tlsg { p.From.Type_ = D_OREG } if p.To.Type_ == D_CONST && p.To.Name == D_EXTERN && p.To.Sym == ctxt.Tlsg { p.To.Type_ = D_OREG } } }