|  | // Copyright 2017 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package sym | 
|  |  | 
|  | import ( | 
|  | "cmd/internal/objabi" | 
|  | "cmd/internal/sys" | 
|  | "debug/elf" | 
|  | ) | 
|  |  | 
|  | // Reloc is a relocation. | 
|  | // | 
|  | // The typical Reloc rewrites part of a symbol at offset Off to address Sym. | 
|  | // A Reloc is stored in a slice on the Symbol it rewrites. | 
|  | // | 
|  | // Relocations are generated by the compiler as the type | 
|  | // cmd/internal/obj.Reloc, which is encoded into the object file wire | 
|  | // format and decoded by the linker into this type. A separate type is | 
|  | // used to hold linker-specific state about the relocation. | 
|  | // | 
|  | // Some relocations are created by cmd/link. | 
|  | type Reloc struct { | 
|  | Off       int32            // offset to rewrite | 
|  | Siz       uint8            // number of bytes to rewrite, 1, 2, or 4 | 
|  | Done      bool             // set to true when relocation is complete | 
|  | Type      objabi.RelocType // the relocation type | 
|  | Add       int64            // addend | 
|  | Sym       *Symbol          // symbol the relocation addresses | 
|  | *relocExt                  // extra fields (see below), may be nil, call InitExt before use | 
|  | } | 
|  |  | 
|  | // relocExt contains extra fields in Reloc that are used only in | 
|  | // certain cases. | 
|  | type relocExt struct { | 
|  | Xadd    int64        // addend passed to external linker | 
|  | Xsym    *Symbol      // symbol passed to external linker | 
|  | Variant RelocVariant // variation on Type, currently used only on PPC64 and S390X | 
|  | } | 
|  |  | 
|  | func (r *Reloc) InitExt() { | 
|  | if r.relocExt == nil { | 
|  | r.relocExt = new(relocExt) | 
|  | } | 
|  | } | 
|  |  | 
|  | // RelocVariant is a linker-internal variation on a relocation. | 
|  | type RelocVariant uint8 | 
|  |  | 
|  | const ( | 
|  | RV_NONE RelocVariant = iota | 
|  | RV_POWER_LO | 
|  | RV_POWER_HI | 
|  | RV_POWER_HA | 
|  | RV_POWER_DS | 
|  |  | 
|  | // RV_390_DBL is a s390x-specific relocation variant that indicates that | 
|  | // the value to be placed into the relocatable field should first be | 
|  | // divided by 2. | 
|  | RV_390_DBL | 
|  |  | 
|  | RV_CHECK_OVERFLOW RelocVariant = 1 << 7 | 
|  | RV_TYPE_MASK      RelocVariant = RV_CHECK_OVERFLOW - 1 | 
|  | ) | 
|  |  | 
|  | func RelocName(arch *sys.Arch, r objabi.RelocType) string { | 
|  | // We didn't have some relocation types at Go1.4. | 
|  | // Uncomment code when we include those in bootstrap code. | 
|  |  | 
|  | switch { | 
|  | case r >= objabi.MachoRelocOffset: // Mach-O | 
|  | // nr := (r - objabi.MachoRelocOffset)>>1 | 
|  | // switch ctxt.Arch.Family { | 
|  | // case sys.AMD64: | 
|  | // 	return macho.RelocTypeX86_64(nr).String() | 
|  | // case sys.ARM: | 
|  | // 	return macho.RelocTypeARM(nr).String() | 
|  | // case sys.ARM64: | 
|  | // 	return macho.RelocTypeARM64(nr).String() | 
|  | // case sys.I386: | 
|  | // 	return macho.RelocTypeGeneric(nr).String() | 
|  | // default: | 
|  | // 	panic("unreachable") | 
|  | // } | 
|  | case r >= objabi.ElfRelocOffset: // ELF | 
|  | nr := r - objabi.ElfRelocOffset | 
|  | switch arch.Family { | 
|  | case sys.AMD64: | 
|  | return elf.R_X86_64(nr).String() | 
|  | case sys.ARM: | 
|  | return elf.R_ARM(nr).String() | 
|  | case sys.ARM64: | 
|  | return elf.R_AARCH64(nr).String() | 
|  | case sys.I386: | 
|  | return elf.R_386(nr).String() | 
|  | case sys.MIPS, sys.MIPS64: | 
|  | return elf.R_MIPS(nr).String() | 
|  | case sys.PPC64: | 
|  | return elf.R_PPC64(nr).String() | 
|  | case sys.S390X: | 
|  | return elf.R_390(nr).String() | 
|  | default: | 
|  | panic("unreachable") | 
|  | } | 
|  | } | 
|  |  | 
|  | return r.String() | 
|  | } | 
|  |  | 
|  | // RelocByOff implements sort.Interface for sorting relocations by offset. | 
|  | type RelocByOff []Reloc | 
|  |  | 
|  | func (x RelocByOff) Len() int { return len(x) } | 
|  |  | 
|  | func (x RelocByOff) Swap(i, j int) { x[i], x[j] = x[j], x[i] } | 
|  |  | 
|  | func (x RelocByOff) Less(i, j int) bool { | 
|  | a := &x[i] | 
|  | b := &x[j] | 
|  | if a.Off < b.Off { | 
|  | return true | 
|  | } | 
|  | if a.Off > b.Off { | 
|  | return false | 
|  | } | 
|  | return false | 
|  | } |