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 { switch r.Type { case ld.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 != ld.SHOSTOBJ && 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 == ld.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 ld.R_CONST: *val = r.Add return 0 case ld.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 ld.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 ld.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 ld.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 ld.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 ld.R_ADDRARM64: r.Done = 0 // 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]) // 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) } // 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 != ld.SHOSTOBJ && rs.Sect == nil { ld.Diag("missing section for %s", rs.Name) } r.Xsym = rs return 0 case ld.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 ld.R_CONST: *val = r.Add return 0 case ld.R_GOTOFF: *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0)) return 0 case ld.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 ld.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 }