| // 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 |
| } |