func archreloc(r *ld.Reloc, s *ld.LSym, 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(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 // 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(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(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.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(ld.Linklookup(ld.Ctxt, ".got.plt", 0)) < ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0)) { ld.Diag(".got.plt should be placed after .plt section.") } *val = 0xe28fc600 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.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(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.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(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.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(r.Sym)+int64((uint32(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 { 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.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_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 }