func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int { if ld.Linkmode == ld.LinkExternal { // TODO(minux): translate R_ADDRPOWER and R_CALLPOWER into standard ELF relocations. // R_ADDRPOWER corresponds to R_PPC_ADDR16_HA and R_PPC_ADDR16_LO. // R_CALLPOWER corresponds to R_PPC_REL24. return -1 } switch r.Type { case obj.R_CONST: *val = r.Add return 0 case obj.R_GOTOFF: *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0)) return 0 case obj.R_ADDRPOWER, obj.R_ADDRPOWER_DS: return archrelocaddr(r, s, val) case obj.R_CALLPOWER: // Bits 6 through 29 = (S + A - P) >> 2 t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off)) if t&3 != 0 { ld.Ctxt.Diag("relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t) } if int64(int32(t<<6)>>6) != t { // TODO(austin) This can happen if text > 32M. // Add a call trampoline to .text in that case. ld.Ctxt.Diag("relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t) } *val |= int64(uint32(t) &^ 0xfc000003) return 0 case obj.R_POWER_TOC: // S + A - .TOC. *val = ld.Symaddr(r.Sym) + r.Add - symtoc(s) return 0 case obj.R_POWER_TLS_LE: // The thread pointer points 0x7000 bytes after the start of the the // thread local storage area as documented in section "3.7.2 TLS // Runtime Handling" of "Power Architecture 64-Bit ELF V2 ABI // Specification". v := r.Sym.Value - 0x7000 if int64(int16(v)) != v { ld.Diag("TLS offset out of range %d", v) } *val = (*val &^ 0xffff) | (v & 0xffff) return 0 } return -1 }
// Convert the direct jump relocation r to refer to a trampoline if the target is too far func trampoline(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol) { switch r.Type { case obj.R_CALLARM: // r.Add is the instruction // low 24-bit encodes the target address t := (ld.Symaddr(r.Sym) + int64(signext24(r.Add&0xffffff)*4) - (s.Value + int64(r.Off))) / 4 if t > 0x7fffff || t < -0x800000 || (*ld.FlagDebugTramp > 1 && s.File != r.Sym.File) { // direct call too far, need to insert trampoline. // look up existing trampolines first. if we found one within the range // of direct call, we can reuse it. otherwise create a new one. offset := (signext24(r.Add&0xffffff) + 2) * 4 var tramp *ld.Symbol for i := 0; ; i++ { name := r.Sym.Name + fmt.Sprintf("%+d-tramp%d", offset, i) tramp = ctxt.Syms.Lookup(name, int(r.Sym.Version)) if tramp.Type == obj.SDYNIMPORT { // don't reuse trampoline defined in other module continue } if tramp.Value == 0 { // either the trampoline does not exist -- we need to create one, // or found one the address which is not assigned -- this will be // laid down immediately after the current function. use this one. break } t = (ld.Symaddr(tramp) - 8 - (s.Value + int64(r.Off))) / 4 if t >= -0x800000 && t < 0x7fffff { // found an existing trampoline that is not too far // we can just use it break } } if tramp.Type == 0 { // trampoline does not exist, create one ctxt.AddTramp(tramp) if ctxt.DynlinkingGo() { if immrot(uint32(offset)) == 0 { ld.Errorf(s, "odd offset in dynlink direct call: %v+%d", r.Sym, offset) } gentrampdyn(tramp, r.Sym, int64(offset)) } else if ld.Buildmode == ld.BuildmodeCArchive || ld.Buildmode == ld.BuildmodeCShared || ld.Buildmode == ld.BuildmodePIE { gentramppic(tramp, r.Sym, int64(offset)) } else { gentramp(tramp, r.Sym, int64(offset)) } } // modify reloc to point to tramp, which will be resolved later r.Sym = tramp r.Add = r.Add&0xff000000 | 0xfffffe // clear the offset embedded in the instruction r.Done = 0 } default: ld.Errorf(s, "trampoline called with non-jump reloc: %v", r.Type) } }
// Convert the direct jump relocation r to refer to a trampoline if the target is too far func trampoline(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol) { switch r.Type { case obj.R_CALLARM: // r.Add is the instruction // low 24-bit encodes the target address t := (ld.Symaddr(r.Sym) + int64(signext24(r.Add&0xffffff)*4) - (s.Value + int64(r.Off))) / 4 if t > 0x7fffff || t < -0x800000 || (*ld.FlagDebugTramp > 1 && s.File != r.Sym.File) { // direct call too far, need to insert trampoline offset := (signext24(r.Add&0xffffff) + 2) * 4 var tramp *ld.Symbol for i := 0; ; i++ { name := r.Sym.Name + fmt.Sprintf("%+d-tramp%d", offset, i) tramp = ctxt.Syms.Lookup(name, int(r.Sym.Version)) if tramp.Value == 0 { // either the trampoline does not exist -- we need to create one, // or found one the address which is not assigned -- this will be // laid down immediately after the current function. use this one. break } t = (ld.Symaddr(tramp) - 8 - (s.Value + int64(r.Off))) / 4 if t >= -0x800000 && t < 0x7fffff { // found an existing trampoline that is not too far // we can just use it break } } if tramp.Type == 0 { // trampoline does not exist, create one ctxt.AddTramp(tramp) tramp.Size = 12 // 3 instructions tramp.P = make([]byte, tramp.Size) t = ld.Symaddr(r.Sym) + int64(offset) o1 := uint32(0xe5900000 | 11<<12 | 15<<16) // MOVW (R15), R11 // R15 is actual pc + 8 o2 := uint32(0xe12fff10 | 11) // JMP (R11) o3 := uint32(t) // WORD $target ld.SysArch.ByteOrder.PutUint32(tramp.P, o1) ld.SysArch.ByteOrder.PutUint32(tramp.P[4:], o2) ld.SysArch.ByteOrder.PutUint32(tramp.P[8:], o3) } // modify reloc to point to tramp, which will be resolved later r.Sym = tramp r.Add = r.Add&0xff000000 | 0xfffffe // clear the offset embedded in the instruction r.Done = 0 } default: ld.Errorf(s, "trampoline called with non-jump reloc: %v", r.Type) } }
func archrelocaddr(r *ld.Reloc, s *ld.Symbol, val *int64) int { var o1, o2 uint32 if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { o1 = uint32(*val >> 32) o2 = uint32(*val) } else { o1 = uint32(*val) o2 = uint32(*val >> 32) } // We are spreading a 31-bit address across two instructions, putting the // high (adjusted) part in the low 16 bits of the first instruction and the // low part in the low 16 bits of the second instruction, or, in the DS case, // bits 15-2 (inclusive) of the address into bits 15-2 of the second // instruction (it is an error in this case if the low 2 bits of the address // are non-zero). t := ld.Symaddr(r.Sym) + r.Add if t < 0 || t >= 1<<31 { ld.Ctxt.Diag("relocation for %s is too big (>=2G): %d", s.Name, ld.Symaddr(r.Sym)) } if t&0x8000 != 0 { t += 0x10000 } switch r.Type { case obj.R_ADDRPOWER: o1 |= (uint32(t) >> 16) & 0xffff o2 |= uint32(t) & 0xffff case obj.R_ADDRPOWER_DS: o1 |= (uint32(t) >> 16) & 0xffff if t&3 != 0 { ld.Ctxt.Diag("bad DS reloc for %s: %d", s.Name, ld.Symaddr(r.Sym)) } o2 |= uint32(t) & 0xfffc default: return -1 } if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { *val = int64(o1)<<32 | int64(o2) } else { *val = int64(o2)<<32 | int64(o1) } return 0 }
func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int { if ld.Linkmode == ld.LinkExternal { return -1 } switch r.Type { case obj.R_CONST: *val = r.Add return 0 case obj.R_GOTOFF: *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0)) return 0 } return -1 }
func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int { if ld.Linkmode == ld.LinkExternal { return -1 } switch r.Type { case obj.R_CONST: *val = r.Add return 0 case obj.R_GOTOFF: *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)) return 0 } return -1 }
func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int { if ld.Linkmode == ld.LinkExternal { return -1 } switch r.Type { case obj.R_CONST: *val = r.Add return 0 case obj.R_GOTOFF: *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0)) return 0 case obj.R_ADDRMIPS: t := ld.Symaddr(r.Sym) + r.Add if t >= 1<<32 || t < -1<<32 { ld.Diag("program too large, address relocation = %v", t) } // the first instruction is always at the lower address, this is endian neutral; // but note that o1 and o2 should still use the target endian. o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off:]) o2 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off+4:]) o1 = o1&0xffff0000 | uint32(t>>16)&0xffff o2 = o2&0xffff0000 | uint32(t)&0xffff // when laid out, the instruction order must always be o1, o2. if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { *val = int64(o1)<<32 | int64(o2) } else { *val = int64(o2)<<32 | int64(o1) } return 0 case obj.R_CALLMIPS, obj.R_JMPMIPS: // Low 26 bits = (S + A) >> 2 t := ld.Symaddr(r.Sym) + r.Add o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off:]) *val = int64(o1&0xfc000000 | uint32(t>>2)&^0xfc000000) return 0 } return -1 }
func archrelocaddr(r *ld.Reloc, s *ld.LSym, val *int64) int { var o1, o2 uint32 if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { o1 = uint32(*val >> 32) o2 = uint32(*val) } else { o1 = uint32(*val) o2 = uint32(*val >> 32) } // We are inserting an address into two instructions: adrp and // then either addi or a load. address := ld.Symaddr(r.Sym) + r.Add pgaddress := (address &^ 0xfff) - ((s.Value + int64(r.Off)) &^ 0xfff) if pgaddress < -1<<31 || pgaddress >= 1<<31 { ld.Ctxt.Diag("relocation for %s is too big (>=2G): %d", s.Name, pgaddress) } pgoff := uint32(address & 0xfff) o1 |= uint32((((pgaddress >> 12) & 3) << 29) | (((pgaddress >> 12 >> 2) & 0x7ffff) << 5)) switch r.Type { case obj.R_ADDRARM64, obj.R_ARM64_LOAD8: o2 |= pgoff << 10 case obj.R_ARM64_LOAD16: if pgoff&0x1 != 0 { ld.Diag("offset for 16-byte load/store has unaligned value %d", pgoff) } o2 |= pgoff << 9 case obj.R_ARM64_LOAD32: if pgoff&0x3 != 0 { ld.Diag("offset for 32-byte load/store has unaligned value %d", pgoff) } o2 |= pgoff << 8 case obj.R_ARM64_LOAD64: if pgoff&0x7 != 0 { ld.Diag("offset for 64-byte load/store has unaligned value %d", pgoff) } o2 |= pgoff << 7 default: return -1 } if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { *val = int64(o1)<<32 | int64(o2) } else { *val = int64(o2)<<32 | int64(o1) } return 0 }
func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int { if ld.Linkmode == ld.LinkExternal { return -1 } switch r.Type { case obj.R_CONST: *val = r.Add return 0 case obj.R_GOTOFF: *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)) return 0 case obj.R_ADDRMIPS, obj.R_ADDRMIPSU: t := ld.Symaddr(r.Sym) + r.Add o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:]) if r.Type == obj.R_ADDRMIPS { *val = int64(o1&0xffff0000 | uint32(t)&0xffff) } else { *val = int64(o1&0xffff0000 | uint32((t+1<<15)>>16)&0xffff) } return 0 case obj.R_CALLMIPS, obj.R_JMPMIPS: // Low 26 bits = (S + A) >> 2 t := ld.Symaddr(r.Sym) + r.Add o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:]) *val = int64(o1&0xfc000000 | uint32(t>>2)&^0xfc000000) return 0 } return -1 }
// generate a trampoline to target+offset func gentramp(tramp, target *ld.Symbol, offset int64) { tramp.Size = 12 // 3 instructions tramp.P = make([]byte, tramp.Size) t := ld.Symaddr(target) + int64(offset) o1 := uint32(0xe5900000 | 11<<12 | 15<<16) // MOVW (R15), R11 // R15 is actual pc + 8 o2 := uint32(0xe12fff10 | 11) // JMP (R11) o3 := uint32(t) // WORD $target ld.SysArch.ByteOrder.PutUint32(tramp.P, o1) ld.SysArch.ByteOrder.PutUint32(tramp.P[4:], o2) ld.SysArch.ByteOrder.PutUint32(tramp.P[8:], o3) if ld.Linkmode == ld.LinkExternal { r := ld.Addrel(tramp) r.Off = 8 r.Type = obj.R_ADDR r.Siz = 4 r.Sym = target r.Add = offset } }
func archreloc(r *ld.Reloc, s *ld.Symbol, val *int64) int { if ld.Linkmode == ld.LinkExternal { switch r.Type { default: return -1 case obj.R_POWER_TLS, obj.R_POWER_TLS_LE, obj.R_POWER_TLS_IE: r.Done = 0 // check Outer is nil, Type is TLSBSS? r.Xadd = r.Add r.Xsym = r.Sym return 0 case obj.R_ADDRPOWER, obj.R_ADDRPOWER_DS, obj.R_ADDRPOWER_TOCREL, obj.R_ADDRPOWER_TOCREL_DS, obj.R_ADDRPOWER_GOT, obj.R_ADDRPOWER_PCREL: r.Done = 0 // set up addend for eventual relocation via outer symbol. rs := r.Sym r.Xadd = r.Add for rs.Outer != nil { r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer) rs = rs.Outer } if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil { ld.Diag("missing section for %s", rs.Name) } r.Xsym = rs return 0 case obj.R_CALLPOWER: r.Done = 0 r.Xsym = r.Sym r.Xadd = r.Add return 0 } } switch r.Type { case obj.R_CONST: *val = r.Add return 0 case obj.R_GOTOFF: *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0)) return 0 case obj.R_ADDRPOWER, obj.R_ADDRPOWER_DS: return archrelocaddr(r, s, val) case obj.R_CALLPOWER: // Bits 6 through 29 = (S + A - P) >> 2 t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off)) if t&3 != 0 { ld.Ctxt.Diag("relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t) } if int64(int32(t<<6)>>6) != t { // TODO(austin) This can happen if text > 32M. // Add a call trampoline to .text in that case. ld.Ctxt.Diag("relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t) } *val |= int64(uint32(t) &^ 0xfc000003) return 0 case obj.R_POWER_TOC: // S + A - .TOC. *val = ld.Symaddr(r.Sym) + r.Add - symtoc(s) return 0 case obj.R_POWER_TLS_LE: // The thread pointer points 0x7000 bytes after the start of the the // thread local storage area as documented in section "3.7.2 TLS // Runtime Handling" of "Power Architecture 64-Bit ELF V2 ABI // Specification". v := r.Sym.Value - 0x7000 if int64(int16(v)) != v { ld.Diag("TLS offset out of range %d", v) } *val = (*val &^ 0xffff) | (v & 0xffff) return 0 } return -1 }
func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int { if ld.Linkmode == ld.LinkExternal { switch r.Type { default: return -1 case obj.R_ADDRMIPS, obj.R_ADDRMIPSU: r.Done = 0 // set up addend for eventual relocation via outer symbol. rs := r.Sym r.Xadd = r.Add for rs.Outer != nil { r.Xadd += ld.Symaddr(ctxt, rs) - ld.Symaddr(ctxt, rs.Outer) rs = rs.Outer } if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil { ctxt.Diag("missing section for %s", rs.Name) } r.Xsym = rs return 0 case obj.R_ADDRMIPSTLS, obj.R_CALLMIPS, obj.R_JMPMIPS: r.Done = 0 r.Xsym = r.Sym r.Xadd = r.Add return 0 } } switch r.Type { case obj.R_CONST: *val = r.Add return 0 case obj.R_GOTOFF: *val = ld.Symaddr(ctxt, r.Sym) + r.Add - ld.Symaddr(ctxt, ld.Linklookup(ctxt, ".got", 0)) return 0 case obj.R_ADDRMIPS, obj.R_ADDRMIPSU: t := ld.Symaddr(ctxt, r.Sym) + r.Add o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:]) if r.Type == obj.R_ADDRMIPS { *val = int64(o1&0xffff0000 | uint32(t)&0xffff) } else { *val = int64(o1&0xffff0000 | uint32((t+1<<15)>>16)&0xffff) } return 0 case obj.R_ADDRMIPSTLS: // thread pointer is at 0x7000 offset from the start of TLS data area t := ld.Symaddr(ctxt, r.Sym) + r.Add - 0x7000 if t < -32768 || t >= 32678 { ctxt.Diag("TLS offset out of range %d", t) } o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:]) *val = int64(o1&0xffff0000 | uint32(t)&0xffff) return 0 case obj.R_CALLMIPS, obj.R_JMPMIPS: // Low 26 bits = (S + A) >> 2 t := ld.Symaddr(ctxt, r.Sym) + r.Add o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:]) *val = int64(o1&0xfc000000 | uint32(t>>2)&^0xfc000000) return 0 } return -1 }
func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int { if ld.Linkmode == ld.LinkExternal { switch r.Type { case obj.R_CALLARM: r.Done = 0 // set up addend for eventual relocation via outer symbol. rs := r.Sym r.Xadd = r.Add if r.Xadd&0x800000 != 0 { r.Xadd |= ^0xffffff } r.Xadd *= 4 for rs.Outer != nil { r.Xadd += ld.Symaddr(ctxt, rs) - ld.Symaddr(ctxt, rs.Outer) rs = rs.Outer } if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil { ctxt.Diag("missing section for %s", rs.Name) } r.Xsym = rs // ld64 for arm seems to want the symbol table to contain offset // into the section rather than pseudo virtual address that contains // the section load address. // we need to compensate that by removing the instruction's address // from addend. if ld.HEADTYPE == obj.Hdarwin { r.Xadd -= ld.Symaddr(ctxt, s) + int64(r.Off) } *val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&uint32(r.Xadd/4)))) return 0 } return -1 } switch r.Type { case obj.R_CONST: *val = r.Add return 0 case obj.R_GOTOFF: *val = ld.Symaddr(ctxt, r.Sym) + r.Add - ld.Symaddr(ctxt, ld.Linklookup(ctxt, ".got", 0)) return 0 // The following three arch specific relocations are only for generation of // Linux/ARM ELF's PLT entry (3 assembler instruction) case obj.R_PLT0: // add ip, pc, #0xXX00000 if ld.Symaddr(ctxt, ld.Linklookup(ctxt, ".got.plt", 0)) < ld.Symaddr(ctxt, ld.Linklookup(ctxt, ".plt", 0)) { ctxt.Diag(".got.plt should be placed after .plt section.") } *val = 0xe28fc600 + (0xff & (int64(uint32(ld.Symaddr(ctxt, r.Sym)-(ld.Symaddr(ctxt, ld.Linklookup(ctxt, ".plt", 0))+int64(r.Off))+r.Add)) >> 20)) return 0 case obj.R_PLT1: // add ip, ip, #0xYY000 *val = 0xe28cca00 + (0xff & (int64(uint32(ld.Symaddr(ctxt, r.Sym)-(ld.Symaddr(ctxt, ld.Linklookup(ctxt, ".plt", 0))+int64(r.Off))+r.Add+4)) >> 12)) return 0 case obj.R_PLT2: // ldr pc, [ip, #0xZZZ]! *val = 0xe5bcf000 + (0xfff & int64(uint32(ld.Symaddr(ctxt, r.Sym)-(ld.Symaddr(ctxt, ld.Linklookup(ctxt, ".plt", 0))+int64(r.Off))+r.Add+8))) return 0 case obj.R_CALLARM: // bl XXXXXX or b YYYYYY *val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&uint32((ld.Symaddr(ctxt, r.Sym)+int64((uint32(r.Add))*4)-(s.Value+int64(r.Off)))/4)))) return 0 } return -1 }
func machoreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int { var v uint32 rs := r.Xsym if r.Type == obj.R_PCREL { if rs.Type == obj.SHOSTOBJ { ctxt.Diag("pc-relative relocation of external symbol is not supported") return -1 } if r.Siz != 4 { return -1 } // emit a pair of "scattered" relocations that // resolve to the difference of section addresses of // the symbol and the instruction // this value is added to the field being relocated o1 := uint32(sectoff) o1 |= 1 << 31 // scattered bit o1 |= ld.MACHO_ARM_RELOC_SECTDIFF << 24 o1 |= 2 << 28 // size = 4 o2 := uint32(0) o2 |= 1 << 31 // scattered bit o2 |= ld.MACHO_ARM_RELOC_PAIR << 24 o2 |= 2 << 28 // size = 4 ld.Thearch.Lput(o1) ld.Thearch.Lput(uint32(ld.Symaddr(ctxt, rs))) ld.Thearch.Lput(o2) ld.Thearch.Lput(uint32(ctxt.Cursym.Value + int64(r.Off))) return 0 } if rs.Type == obj.SHOSTOBJ || r.Type == obj.R_CALLARM { if rs.Dynid < 0 { ctxt.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type) return -1 } v = uint32(rs.Dynid) v |= 1 << 27 // external relocation } else { v = uint32(rs.Sect.Extnum) if v == 0 { ctxt.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type) return -1 } } switch r.Type { default: return -1 case obj.R_ADDR: v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28 case obj.R_CALLARM: v |= 1 << 24 // pc-relative bit v |= ld.MACHO_ARM_RELOC_BR24 << 28 } switch r.Siz { default: return -1 case 1: v |= 0 << 25 case 2: v |= 1 << 25 case 4: v |= 2 << 25 case 8: v |= 3 << 25 } ld.Thearch.Lput(uint32(sectoff)) ld.Thearch.Lput(v) return 0 }
func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int { if ld.Linkmode == ld.LinkExternal { switch r.Type { default: return -1 case obj.R_ARM64_GOTPCREL: var o1, o2 uint32 if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { o1 = uint32(*val >> 32) o2 = uint32(*val) } else { o1 = uint32(*val) o2 = uint32(*val >> 32) } // Any relocation against a function symbol is redirected to // be against a local symbol instead (see putelfsym in // symtab.go) but unfortunately the system linker was buggy // when confronted with a R_AARCH64_ADR_GOT_PAGE relocation // against a local symbol until May 2015 // (https://sourceware.org/bugzilla/show_bug.cgi?id=18270). So // we convert the adrp; ld64 + R_ARM64_GOTPCREL into adrp; // add + R_ADDRARM64. if !(r.Sym.Version != 0 || (r.Sym.Type&obj.SHIDDEN != 0) || r.Sym.Attr.Local()) && r.Sym.Type == obj.STEXT && ld.DynlinkingGo() { if o2&0xffc00000 != 0xf9400000 { ld.Ctxt.Diag("R_ARM64_GOTPCREL against unexpected instruction %x", o2) } o2 = 0x91000000 | (o2 & 0x000003ff) r.Type = obj.R_ADDRARM64 } if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { *val = int64(o1)<<32 | int64(o2) } else { *val = int64(o2)<<32 | int64(o1) } fallthrough case obj.R_ADDRARM64: r.Done = 0 // set up addend for eventual relocation via outer symbol. rs := r.Sym r.Xadd = r.Add for rs.Outer != nil { r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer) rs = rs.Outer } if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil { ld.Diag("missing section for %s", rs.Name) } r.Xsym = rs // Note: ld64 currently has a bug that any non-zero addend for BR26 relocation // will make the linking fail because it thinks the code is not PIC even though // the BR26 relocation should be fully resolved at link time. // That is the reason why the next if block is disabled. When the bug in ld64 // is fixed, we can enable this block and also enable duff's device in cmd/7g. if false && ld.HEADTYPE == obj.Hdarwin { var o0, o1 uint32 if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { o0 = uint32(*val >> 32) o1 = uint32(*val) } else { o0 = uint32(*val) o1 = uint32(*val >> 32) } // Mach-O wants the addend to be encoded in the instruction // Note that although Mach-O supports ARM64_RELOC_ADDEND, it // can only encode 24-bit of signed addend, but the instructions // supports 33-bit of signed addend, so we always encode the // addend in place. o0 |= (uint32((r.Xadd>>12)&3) << 29) | (uint32((r.Xadd>>12>>2)&0x7ffff) << 5) o1 |= uint32(r.Xadd&0xfff) << 10 r.Xadd = 0 // when laid out, the instruction order must always be o1, o2. if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { *val = int64(o0)<<32 | int64(o1) } else { *val = int64(o1)<<32 | int64(o0) } } return 0 case obj.R_CALLARM64, obj.R_ARM64_TLS_LE, obj.R_ARM64_TLS_IE: r.Done = 0 r.Xsym = r.Sym r.Xadd = r.Add return 0 } } switch r.Type { case obj.R_CONST: *val = r.Add return 0 case obj.R_GOTOFF: *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0)) return 0 case obj.R_ADDRARM64: t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff) if t >= 1<<32 || t < -1<<32 { ld.Diag("program too large, address relocation distance = %d", t) } var o0, o1 uint32 if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { o0 = uint32(*val >> 32) o1 = uint32(*val) } else { o0 = uint32(*val) o1 = uint32(*val >> 32) } o0 |= (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5) o1 |= uint32(t&0xfff) << 10 // when laid out, the instruction order must always be o1, o2. if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { *val = int64(o0)<<32 | int64(o1) } else { *val = int64(o1)<<32 | int64(o0) } return 0 case obj.R_ARM64_TLS_LE: r.Done = 0 if ld.HEADTYPE != obj.Hlinux { ld.Diag("TLS reloc on unsupported OS %s", ld.Headstr(int(ld.HEADTYPE))) } // The TCB is two pointers. This is not documented anywhere, but is // de facto part of the ABI. v := r.Sym.Value + int64(2*ld.Thearch.Ptrsize) if v < 0 || v >= 32678 { ld.Diag("TLS offset out of range %d", v) } *val |= v << 5 return 0 case obj.R_CALLARM64: t := (ld.Symaddr(r.Sym) + r.Add) - (s.Value + int64(r.Off)) if t >= 1<<27 || t < -1<<27 { ld.Diag("program too large, call relocation distance = %d", t) } *val |= (t >> 2) & 0x03ffffff return 0 } return -1 }
func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int { if ld.Linkmode == ld.LinkExternal { switch r.Type { default: return -1 case obj.R_ADDRARM64: r.Done = 0 // set up addend for eventual relocation via outer symbol. rs := r.Sym r.Xadd = r.Add for rs.Outer != nil { r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer) rs = rs.Outer } if rs.Type != obj.SHOSTOBJ && rs.Sect == nil { ld.Diag("missing section for %s", rs.Name) } r.Xsym = rs // Note: ld64 currently has a bug that any non-zero addend for BR26 relocation // will make the linking fail because it thinks the code is not PIC even though // the BR26 relocation should be fully resolved at link time. // That is the reason why the next if block is disabled. When the bug in ld64 // is fixed, we can enable this block and also enable duff's device in cmd/7g. if false && ld.HEADTYPE == obj.Hdarwin { var o0, o1 uint32 if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { o0 = uint32(*val >> 32) o1 = uint32(*val) } else { o0 = uint32(*val) o1 = uint32(*val >> 32) } // Mach-O wants the addend to be encoded in the instruction // Note that although Mach-O supports ARM64_RELOC_ADDEND, it // can only encode 24-bit of signed addend, but the instructions // supports 33-bit of signed addend, so we always encode the // addend in place. o0 |= (uint32((r.Xadd>>12)&3) << 29) | (uint32((r.Xadd>>12>>2)&0x7ffff) << 5) o1 |= uint32(r.Xadd&0xfff) << 10 r.Xadd = 0 // when laid out, the instruction order must always be o1, o2. if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { *val = int64(o0)<<32 | int64(o1) } else { *val = int64(o1)<<32 | int64(o0) } } return 0 case obj.R_CALLARM64, obj.R_ARM64_TLS_LE, obj.R_ARM64_TLS_IE: r.Done = 0 r.Xsym = r.Sym r.Xadd = r.Add return 0 } } switch r.Type { case obj.R_CONST: *val = r.Add return 0 case obj.R_GOTOFF: *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0)) return 0 case obj.R_ADDRARM64: t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff) if t >= 1<<32 || t < -1<<32 { ld.Diag("program too large, address relocation distance = %d", t) } var o0, o1 uint32 if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { o0 = uint32(*val >> 32) o1 = uint32(*val) } else { o0 = uint32(*val) o1 = uint32(*val >> 32) } o0 |= (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5) o1 |= uint32(t&0xfff) << 10 // when laid out, the instruction order must always be o1, o2. if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { *val = int64(o0)<<32 | int64(o1) } else { *val = int64(o1)<<32 | int64(o0) } return 0 case obj.R_ARM64_TLS_LE: r.Done = 0 if ld.HEADTYPE != obj.Hlinux { ld.Diag("TLS reloc on unsupported OS %s", ld.Headstr(int(ld.HEADTYPE))) } // The TCB is two pointers. This is not documented anywhere, but is // de facto part of the ABI. v := r.Sym.Value + int64(2*ld.Thearch.Ptrsize) if v < 0 || v >= 32678 { ld.Diag("TLS offset out of range %d", v) } *val |= v << 5 return 0 case obj.R_CALLARM64: t := (ld.Symaddr(r.Sym) + r.Add) - (s.Value + int64(r.Off)) if t >= 1<<27 || t < -1<<27 { ld.Diag("program too large, call relocation distance = %d", t) } *val |= (t >> 2) & 0x03ffffff return 0 } return -1 }
func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int { if ld.Linkmode == ld.LinkExternal { switch r.Type { default: return -1 case obj.R_ADDRARM64: r.Done = 0 // set up addend for eventual relocation via outer symbol. rs := r.Sym r.Xadd = r.Add for rs.Outer != nil { r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer) rs = rs.Outer } if rs.Type != obj.SHOSTOBJ && rs.Sect == nil { ld.Diag("missing section for %s", rs.Name) } r.Xsym = rs // the first instruction is always at the lower address, this is endian neutral; // but note that o0 and o1 should still use the target endian. o0 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off : r.Off+4]) o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off+4 : r.Off+8]) // Note: ld64 currently has a bug that any non-zero addend for BR26 relocation // will make the linking fail because it thinks the code is not PIC even though // the BR26 relocation should be fully resolved at link time. // That is the reason why the next if block is disabled. When the bug in ld64 // is fixed, we can enable this block and also enable duff's device in cmd/7g. if false && ld.HEADTYPE == obj.Hdarwin { // Mach-O wants the addend to be encoded in the instruction // Note that although Mach-O supports ARM64_RELOC_ADDEND, it // can only encode 24-bit of signed addend, but the instructions // supports 33-bit of signed addend, so we always encode the // addend in place. o0 |= (uint32((r.Xadd>>12)&3) << 29) | (uint32((r.Xadd>>12>>2)&0x7ffff) << 5) o1 |= uint32(r.Xadd&0xfff) << 10 r.Xadd = 0 } // when laid out, the instruction order must always be o1, o2. if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { *val = int64(o0)<<32 | int64(o1) } else { *val = int64(o1)<<32 | int64(o0) } return 0 case obj.R_CALLARM64: r.Done = 0 r.Xsym = r.Sym *val = int64(0xfc000000 & uint32(r.Add)) r.Xadd = int64((uint32(r.Add) &^ 0xfc000000) * 4) r.Add = 0 return 0 } } switch r.Type { case obj.R_CONST: *val = r.Add return 0 case obj.R_GOTOFF: *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0)) return 0 case obj.R_ADDRARM64: t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff) if t >= 1<<32 || t < -1<<32 { ld.Diag("program too large, address relocation distance = %d", t) } // the first instruction is always at the lower address, this is endian neutral; // but note that o0 and o1 should still use the target endian. o0 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off : r.Off+4]) o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off+4 : r.Off+8]) o0 |= (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5) o1 |= uint32(t&0xfff) << 10 // when laid out, the instruction order must always be o1, o2. if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { *val = int64(o0)<<32 | int64(o1) } else { *val = int64(o1)<<32 | int64(o0) } return 0 case obj.R_CALLARM64: *val = int64((0xfc000000 & uint32(r.Add)) | uint32((ld.Symaddr(r.Sym)+r.Add*4-(s.Value+int64(r.Off)))/4)) return 0 } return -1 }
func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int { if ld.Linkmode == ld.LinkExternal { // TODO(minux): translate R_ADDRPOWER and R_CALLPOWER into standard ELF relocations. // R_ADDRPOWER corresponds to R_PPC_ADDR16_HA and R_PPC_ADDR16_LO. // R_CALLPOWER corresponds to R_PPC_REL24. return -1 } switch r.Type { case obj.R_CONST: *val = r.Add return 0 case obj.R_GOTOFF: *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0)) return 0 case obj.R_ADDRPOWER: // We are spreading a 31-bit address across two instructions, // putting the high (adjusted) part in the low 16 bits of the // first instruction and the low part in the low 16 bits of the // second instruction. t := ld.Symaddr(r.Sym) + r.Add if t < 0 || t >= 1<<31 { ld.Ctxt.Diag("relocation for %s is too big (>=2G): %d", s.Name, ld.Symaddr(r.Sym)) } var o1, o2 uint32 if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { o1 = uint32(*val >> 32) o2 = uint32(*val) } else { o1 = uint32(*val) o2 = uint32(*val >> 32) } if t&0x8000 != 0 { t += 0x10000 } // There is an almost-bug here. When R_ADDRPOWER is relocating a // load, the two instructions are addi and then a load. addi and // almost all loads are "D-form" instructions, which have a // 16-bit immediate in the lower 16-bits of the instruction // word. But the load doubleword instruction is a "DS-form" // instruction: the immediate only occupies bits 16-29 of the // instruction and is implicity padded with zeros on the // right. The reason the belows isn't a bug is because we only // ever use immediates that have zeros on in their lower bits // with ld, and we combine the immediate with | so bits 30 and // 31 are preserved. o1 |= (uint32(t) >> 16) & 0xffff o2 |= uint32(t) & 0xffff if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { *val = int64(o1)<<32 | int64(o2) } else { *val = int64(o2)<<32 | int64(o1) } return 0 case obj.R_CALLPOWER: // Bits 6 through 29 = (S + A - P) >> 2 t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off)) if t&3 != 0 { ld.Ctxt.Diag("relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t) } if int64(int32(t<<6)>>6) != t { // TODO(austin) This can happen if text > 32M. // Add a call trampoline to .text in that case. ld.Ctxt.Diag("relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t) } *val |= int64(uint32(t) &^ 0xfc000003) return 0 case obj.R_POWER_TOC: // S + A - .TOC. *val = ld.Symaddr(r.Sym) + r.Add - symtoc(s) return 0 case obj.R_POWER_TLS_LE: // The thread pointer points 0x7000 bytes after the start of the the // thread local storage area as documented in section "3.7.2 TLS // Runtime Handling" of "Power Architecture 64-Bit ELF V2 ABI // Specification". v := r.Sym.Value - 0x7000 if int64(int16(v)) != v { ld.Diag("TLS offset out of range %d", v) } *val = (*val &^ 0xffff) | (v & 0xffff) return 0 } return -1 }
func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int { if ld.Linkmode == ld.LinkExternal { // TODO(minux): translate R_ADDRPOWER and R_CALLPOWER into standard ELF relocations. // R_ADDRPOWER corresponds to R_PPC_ADDR16_HA and R_PPC_ADDR16_LO. // R_CALLPOWER corresponds to R_PPC_REL24. return -1 } switch r.Type { case obj.R_CONST: *val = r.Add return 0 case obj.R_GOTOFF: *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0)) return 0 case obj.R_ADDRPOWER: // r->add is two ppc64 instructions holding an immediate 32-bit constant. // We want to add r->sym's address to that constant. // The encoding of the immediate x<<16 + y, // where x is the low 16 bits of the first instruction and y is the low 16 // bits of the second. Both x and y are signed (int16, not uint16). o1 := uint32(r.Add >> 32) o2 := uint32(r.Add) t := ld.Symaddr(r.Sym) if t < 0 { ld.Ctxt.Diag("relocation for %s is too big (>=2G): %d", s.Name, ld.Symaddr(r.Sym)) } t += int64((o1&0xffff)<<16 + uint32(int32(o2)<<16>>16)) if t&0x8000 != 0 { t += 0x10000 } o1 = o1&0xffff0000 | (uint32(t)>>16)&0xffff o2 = o2&0xffff0000 | uint32(t)&0xffff // when laid out, the instruction order must always be o1, o2. if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { *val = int64(o1)<<32 | int64(o2) } else { *val = int64(o2)<<32 | int64(o1) } return 0 case obj.R_CALLPOWER: // Bits 6 through 29 = (S + A - P) >> 2 var o1 uint32 if ld.Ctxt.Arch.ByteOrder == binary.BigEndian { o1 = ld.Be32(s.P[r.Off:]) } else { o1 = ld.Le32(s.P[r.Off:]) } t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off)) if t&3 != 0 { ld.Ctxt.Diag("relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t) } if int64(int32(t<<6)>>6) != t { // TODO(austin) This can happen if text > 32M. // Add a call trampoline to .text in that case. ld.Ctxt.Diag("relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t) } *val = int64(o1&0xfc000003 | uint32(t)&^0xfc000003) return 0 case obj.R_POWER_TOC: // S + A - .TOC. *val = ld.Symaddr(r.Sym) + r.Add - symtoc(s) return 0 } return -1 }
// resolve direct jump relocation r in s, and add trampoline if necessary func trampoline(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol) { t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off)) switch r.Type { case obj.R_CALLPOWER: // If branch offset is too far then create a trampoline. if int64(int32(t<<6)>>6) != t || (*ld.FlagDebugTramp > 1 && s.File != r.Sym.File) { var tramp *ld.Symbol for i := 0; ; i++ { // Using r.Add as part of the name is significant in functions like duffzero where the call // target is at some offset within the function. Calls to duff+8 and duff+256 must appear as // distinct trampolines. name := r.Sym.Name if r.Add == 0 { name = name + fmt.Sprintf("-tramp%d", i) } else { name = name + fmt.Sprintf("%+x-tramp%d", r.Add, i) } // Look up the trampoline in case it already exists tramp = ctxt.Syms.Lookup(name, int(r.Sym.Version)) if tramp.Value == 0 { break } t = ld.Symaddr(tramp) + r.Add - (s.Value + int64(r.Off)) // If the offset of the trampoline that has been found is within range, use it. if int64(int32(t<<6)>>6) == t { break } } if tramp.Type == 0 { ctxt.AddTramp(tramp) tramp.Size = 16 // 4 instructions tramp.P = make([]byte, tramp.Size) t = ld.Symaddr(r.Sym) + r.Add f := t & 0xffff0000 o1 := uint32(0x3fe00000 | (f >> 16)) // lis r31,trampaddr hi (r31 is temp reg) f = t & 0xffff o2 := uint32(0x63ff0000 | f) // ori r31,trampaddr lo o3 := uint32(0x7fe903a6) // mtctr o4 := uint32(0x4e800420) // bctr ld.SysArch.ByteOrder.PutUint32(tramp.P, o1) ld.SysArch.ByteOrder.PutUint32(tramp.P[4:], o2) ld.SysArch.ByteOrder.PutUint32(tramp.P[8:], o3) ld.SysArch.ByteOrder.PutUint32(tramp.P[12:], o4) } r.Sym = tramp r.Add = 0 // This was folded into the trampoline target address r.Done = 0 } default: ld.Errorf(s, "trampoline called with non-jump reloc: %v", r.Type) } }