+++ /dev/null
-// Copyright 2020 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 amd64
-
-import (
- "cmd/internal/objabi"
- "cmd/link/internal/ld"
- "cmd/link/internal/loader"
- "cmd/link/internal/sym"
- "debug/elf"
-)
-
-// Temporary dumping around for sym.Symbol version of helper
-// functions in asm.go, still being used for some oses.
-// FIXME: get rid of this file when dodata() is completely
-// converted.
-
-func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
- targ := r.Sym
-
- switch r.Type {
- default:
- if r.Type >= objabi.ElfRelocOffset {
- ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type))
- return false
- }
-
- // Handle relocations found in ELF object files.
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC32):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ.Name)
- }
- // TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
- // sense and should be removed when someone has thought about it properly.
- if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
- ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
- }
- r.Type = objabi.R_PCREL
- r.Add += 4
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC64):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_X86_64_PC64 relocation for dynamic symbol %s", targ.Name)
- }
- if targ.Type == 0 || targ.Type == sym.SXREF {
- ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
- }
- r.Type = objabi.R_PCREL
- r.Add += 8
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PLT32):
- r.Type = objabi.R_PCREL
- r.Add += 4
- if targ.Type == sym.SDYNIMPORT {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add += int64(targ.Plt())
- }
-
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_GOTPCREL),
- objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_GOTPCRELX),
- objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_REX_GOTPCRELX):
- if targ.Type != sym.SDYNIMPORT {
- // have symbol
- if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
- makeWritable(s)
- // turn MOVQ of GOT entry into LEAQ of symbol itself
- s.P[r.Off-2] = 0x8d
-
- r.Type = objabi.R_PCREL
- r.Add += 4
- return true
- }
- }
-
- // fall back to using GOT and hope for the best (CMOV*)
- // TODO: just needs relocation, no need to put in .dynsym
- addgotsym(target, syms, targ)
-
- r.Type = objabi.R_PCREL
- r.Sym = syms.GOT
- r.Add += 4
- r.Add += int64(targ.Got())
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_64):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_X86_64_64 relocation for dynamic symbol %s", targ.Name)
- }
- r.Type = objabi.R_ADDR
- if target.IsPIE() && target.IsInternal() {
- // For internal linking PIE, this R_ADDR relocation cannot
- // be resolved statically. We need to generate a dynamic
- // relocation. Let the code below handle it.
- break
- }
- return true
-
- // Handle relocations found in Mach-O object files.
- case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 0,
- objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED*2 + 0,
- objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 0:
- // TODO: What is the difference between all these?
- r.Type = objabi.R_ADDR
-
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected reloc for dynamic symbol %s", targ.Name)
- }
- return true
-
- case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1:
- if targ.Type == sym.SDYNIMPORT {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add = int64(targ.Plt())
- r.Type = objabi.R_PCREL
- return true
- }
- fallthrough
-
- case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 1,
- objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED*2 + 1,
- objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_1*2 + 1,
- objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_2*2 + 1,
- objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
- r.Type = objabi.R_PCREL
-
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected pc-relative reloc for dynamic symbol %s", targ.Name)
- }
- return true
-
- case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
- if targ.Type != sym.SDYNIMPORT {
- // have symbol
- // turn MOVQ of GOT entry into LEAQ of symbol itself
- if r.Off < 2 || s.P[r.Off-2] != 0x8b {
- ld.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ.Name)
- return false
- }
-
- makeWritable(s)
- s.P[r.Off-2] = 0x8d
- r.Type = objabi.R_PCREL
- return true
- }
- fallthrough
-
- case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT*2 + 1:
- if targ.Type != sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
- }
- addgotsym(target, syms, targ)
- r.Type = objabi.R_PCREL
- r.Sym = syms.GOT
- r.Add += int64(targ.Got())
- return true
- }
-
- switch r.Type {
- case objabi.R_CALL,
- objabi.R_PCREL:
- if targ.Type != sym.SDYNIMPORT {
- // nothing to do, the relocation will be laid out in reloc
- return true
- }
- if target.IsExternal() {
- // External linker will do this relocation.
- return true
- }
- // Internal linking, for both ELF and Mach-O.
- // Build a PLT entry and change the relocation target to that entry.
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add = int64(targ.Plt())
- return true
-
- case objabi.R_ADDR:
- if s.Type == sym.STEXT && target.IsElf() {
- if target.IsSolaris() {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add += int64(targ.Plt())
- return true
- }
- // The code is asking for the address of an external
- // function. We provide it with the address of the
- // correspondent GOT symbol.
- addgotsym(target, syms, targ)
-
- r.Sym = syms.GOT
- r.Add += int64(targ.Got())
- return true
- }
-
- // Process dynamic relocations for the data sections.
- if target.IsPIE() && target.IsInternal() {
- // When internally linking, generate dynamic relocations
- // for all typical R_ADDR relocations. The exception
- // are those R_ADDR that are created as part of generating
- // the dynamic relocations and must be resolved statically.
- //
- // There are three phases relevant to understanding this:
- //
- // dodata() // we are here
- // address() // symbol address assignment
- // reloc() // resolution of static R_ADDR relocs
- //
- // At this point symbol addresses have not been
- // assigned yet (as the final size of the .rela section
- // will affect the addresses), and so we cannot write
- // the Elf64_Rela.r_offset now. Instead we delay it
- // until after the 'address' phase of the linker is
- // complete. We do this via Addaddrplus, which creates
- // a new R_ADDR relocation which will be resolved in
- // the 'reloc' phase.
- //
- // These synthetic static R_ADDR relocs must be skipped
- // now, or else we will be caught in an infinite loop
- // of generating synthetic relocs for our synthetic
- // relocs.
- //
- // Furthermore, the rela sections contain dynamic
- // relocations with R_ADDR relocations on
- // Elf64_Rela.r_offset. This field should contain the
- // symbol offset as determined by reloc(), not the
- // final dynamically linked address as a dynamic
- // relocation would provide.
- switch s.Name {
- case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic":
- return false
- }
- } else {
- // Either internally linking a static executable,
- // in which case we can resolve these relocations
- // statically in the 'reloc' phase, or externally
- // linking, in which case the relocation will be
- // prepared in the 'reloc' phase and passed to the
- // external linker in the 'asmb' phase.
- if s.Type != sym.SDATA && s.Type != sym.SRODATA {
- break
- }
- }
-
- if target.IsElf() {
- // Generate R_X86_64_RELATIVE relocations for best
- // efficiency in the dynamic linker.
- //
- // As noted above, symbol addresses have not been
- // assigned yet, so we can't generate the final reloc
- // entry yet. We ultimately want:
- //
- // r_offset = s + r.Off
- // r_info = R_X86_64_RELATIVE
- // r_addend = targ + r.Add
- //
- // The dynamic linker will set *offset = base address +
- // addend.
- //
- // AddAddrPlus is used for r_offset and r_addend to
- // generate new R_ADDR relocations that will update
- // these fields in the 'reloc' phase.
- rela := syms.Rela
- rela.AddAddrPlus(target.Arch, s, int64(r.Off))
- if r.Siz == 8 {
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(0, uint32(elf.R_X86_64_RELATIVE)))
- } else {
- ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
- }
- rela.AddAddrPlus(target.Arch, targ, int64(r.Add))
- // Not mark r done here. So we still apply it statically,
- // so in the file content we'll also have the right offset
- // to the relocation target. So it can be examined statically
- // (e.g. go version).
- return true
- }
-
- if target.IsDarwin() && s.Size == int64(target.Arch.PtrSize) && r.Off == 0 {
- // Mach-O relocations are a royal pain to lay out.
- // They use a compact stateful bytecode representation
- // that is too much bother to deal with.
- // Instead, interpret the C declaration
- // void *_Cvar_stderr = &stderr;
- // as making _Cvar_stderr the name of a GOT entry
- // for stderr. This is separate from the usual GOT entry,
- // just in case the C code assigns to the variable,
- // and of course it only works for single pointers,
- // but we only need to support cgo and that's all it needs.
- ld.Adddynsym(target, syms, targ)
-
- got := syms.GOT
- s.Type = got.Type
- s.Attr |= sym.AttrSubSymbol
- s.Outer = got
- s.Sub = got.Sub
- got.Sub = s
- s.Value = got.Size
- got.AddUint64(target.Arch, 0)
- syms.LinkEditGOT.AddUint32(target.Arch, uint32(targ.Dynid))
- r.Type = objabi.ElfRelocOffset // ignore during relocsym
- return true
- }
- }
-
- return false
-}
-
-func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Plt() >= 0 {
- return
- }
-
- ld.Adddynsym(target, syms, s)
-
- if target.IsElf() {
- plt := syms.PLT
- got := syms.GOTPLT
- rela := syms.RelaPLT
- if plt.Size == 0 {
- panic("plt is not set up")
- }
-
- // jmpq *got+size(IP)
- plt.AddUint8(0xff)
-
- plt.AddUint8(0x25)
- plt.AddPCRelPlus(target.Arch, got, got.Size)
-
- // add to got: pointer to current pos in plt
- got.AddAddrPlus(target.Arch, plt, plt.Size)
-
- // pushq $x
- plt.AddUint8(0x68)
-
- plt.AddUint32(target.Arch, uint32((got.Size-24-8)/8))
-
- // jmpq .plt
- plt.AddUint8(0xe9)
-
- plt.AddUint32(target.Arch, uint32(-(plt.Size + 4)))
-
- // rela
- rela.AddAddrPlus(target.Arch, got, got.Size-8)
-
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_JMP_SLOT)))
- rela.AddUint64(target.Arch, 0)
-
- s.SetPlt(int32(plt.Size - 16))
- } else if target.IsDarwin() {
- // To do lazy symbol lookup right, we're supposed
- // to tell the dynamic loader which library each
- // symbol comes from and format the link info
- // section just so. I'm too lazy (ha!) to do that
- // so for now we'll just use non-lazy pointers,
- // which don't need to be told which library to use.
- //
- // https://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
- // has details about what we're avoiding.
-
- addgotsym(target, syms, s)
- plt := syms.PLT
-
- syms.LinkEditPLT.AddUint32(target.Arch, uint32(s.Dynid))
-
- // jmpq *got+size(IP)
- s.SetPlt(int32(plt.Size))
-
- plt.AddUint8(0xff)
- plt.AddUint8(0x25)
- plt.AddPCRelPlus(target.Arch, syms.GOT, int64(s.Got()))
- } else {
- ld.Errorf(s, "addpltsym: unsupported binary format")
- }
-}
-
-func addgotsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Got() >= 0 {
- return
- }
-
- ld.Adddynsym(target, syms, s)
- got := syms.GOT
- s.SetGot(int32(got.Size))
- got.AddUint64(target.Arch, 0)
-
- if target.IsElf() {
- rela := syms.Rela
- rela.AddAddrPlus(target.Arch, got, int64(s.Got()))
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_GLOB_DAT)))
- rela.AddUint64(target.Arch, 0)
- } else if target.IsDarwin() {
- syms.LinkEditGOT.AddUint32(target.Arch, uint32(s.Dynid))
- } else {
- ld.Errorf(s, "addgotsym: unsupported binary format")
- }
-}
Dwarfregsp: dwarfRegSP,
Dwarfreglr: dwarfRegLR,
- Adddynrel: adddynrel,
Adddynrel2: adddynrel2,
Archinit: archinit,
Archreloc: archreloc,
+++ /dev/null
-// Copyright 2020 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 arm
-
-import (
- "cmd/internal/objabi"
- "cmd/link/internal/ld"
- "cmd/link/internal/loader"
- "cmd/link/internal/sym"
- "debug/elf"
-)
-
-// Temporary dumping ground for sym.Symbol version of helper
-// functions in asm.go, still being used for some oses.
-// FIXME: get rid of this file when dodata() is completely
-// converted.
-
-func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
- targ := r.Sym
-
- switch r.Type {
- default:
- if r.Type >= objabi.ElfRelocOffset {
- ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type))
- return false
- }
-
- // Handle relocations found in ELF object files.
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_PLT32):
- r.Type = objabi.R_CALLARM
-
- if targ.Type == sym.SDYNIMPORT {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4))
- }
-
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_THM_PC22): // R_ARM_THM_CALL
- ld.Exitf("R_ARM_THM_CALL, are you using -marm?")
- return false
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOT32): // R_ARM_GOT_BREL
- if targ.Type != sym.SDYNIMPORT {
- addgotsyminternal(target, syms, targ)
- } else {
- addgotsym(target, syms, targ)
- }
-
- r.Type = objabi.R_CONST // write r->add during relocsym
- r.Sym = nil
- r.Add += int64(targ.Got())
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOT_PREL): // GOT(nil) + A - nil
- if targ.Type != sym.SDYNIMPORT {
- addgotsyminternal(target, syms, targ)
- } else {
- addgotsym(target, syms, targ)
- }
-
- r.Type = objabi.R_PCREL
- r.Sym = syms.GOT
- r.Add += int64(targ.Got()) + 4
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOTOFF): // R_ARM_GOTOFF32
- r.Type = objabi.R_GOTOFF
-
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_GOTPC): // R_ARM_BASE_PREL
- r.Type = objabi.R_PCREL
-
- r.Sym = syms.GOT
- r.Add += 4
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_CALL):
- r.Type = objabi.R_CALLARM
- if targ.Type == sym.SDYNIMPORT {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4))
- }
-
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_REL32): // R_ARM_REL32
- r.Type = objabi.R_PCREL
-
- r.Add += 4
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_ABS32):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ.Name)
- }
- r.Type = objabi.R_ADDR
- return true
-
- // we can just ignore this, because we are targeting ARM V5+ anyway
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_V4BX):
- if r.Sym != nil {
- // R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it
- r.Sym.Type = 0
- }
-
- r.Sym = nil
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_PC24),
- objabi.ElfRelocOffset + objabi.RelocType(elf.R_ARM_JUMP24):
- r.Type = objabi.R_CALLARM
- if targ.Type == sym.SDYNIMPORT {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4))
- }
-
- return true
- }
-
- // Handle references to ELF symbols from our own object files.
- if targ.Type != sym.SDYNIMPORT {
- return true
- }
-
- switch r.Type {
- case objabi.R_CALLARM:
- if target.IsExternal() {
- // External linker will do this relocation.
- return true
- }
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add = int64(targ.Plt())
- return true
-
- case objabi.R_ADDR:
- if s.Type != sym.SDATA {
- break
- }
- if target.IsElf() {
- ld.Adddynsym(target, syms, targ)
- rel := syms.Rel
- rel.AddAddrPlus(target.Arch, s, int64(r.Off))
- rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(targ.Dynid), uint32(elf.R_ARM_GLOB_DAT))) // we need a nil + A dynamic reloc
- r.Type = objabi.R_CONST // write r->add during relocsym
- r.Sym = nil
- return true
- }
- }
-
- return false
-}
-
-func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Plt() >= 0 {
- return
- }
-
- ld.Adddynsym(target, syms, s)
-
- if target.IsElf() {
- plt := syms.PLT
- got := syms.GOTPLT
- rel := syms.RelPLT
- if plt.Size == 0 {
- panic("plt is not set up")
- }
-
- // .got entry
- s.SetGot(int32(got.Size))
-
- // In theory, all GOT should point to the first PLT entry,
- // Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's
- // dynamic linker won't, so we'd better do it ourselves.
- got.AddAddrPlus(target.Arch, plt, 0)
-
- // .plt entry, this depends on the .got entry
- s.SetPlt(int32(plt.Size))
-
- addpltreloc(plt, got, s, objabi.R_PLT0) // add lr, pc, #0xXX00000
- addpltreloc(plt, got, s, objabi.R_PLT1) // add lr, lr, #0xYY000
- addpltreloc(plt, got, s, objabi.R_PLT2) // ldr pc, [lr, #0xZZZ]!
-
- // rel
- rel.AddAddrPlus(target.Arch, got, int64(s.Got()))
-
- rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_ARM_JUMP_SLOT)))
- } else {
- ld.Errorf(s, "addpltsym: unsupported binary format")
- }
-}
-
-func addpltreloc(plt *sym.Symbol, got *sym.Symbol, s *sym.Symbol, typ objabi.RelocType) {
- r := plt.AddRel()
- r.Sym = got
- r.Off = int32(plt.Size)
- r.Siz = 4
- r.Type = typ
- r.Add = int64(s.Got()) - 8
-
- plt.Attr |= sym.AttrReachable
- plt.Size += 4
- plt.Grow(plt.Size)
-}
-
-func addgotsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Got() >= 0 {
- return
- }
-
- ld.Adddynsym(target, syms, s)
- got := syms.GOT
- s.SetGot(int32(got.Size))
- got.AddUint32(target.Arch, 0)
-
- if target.IsElf() {
- rel := syms.Rel
- rel.AddAddrPlus(target.Arch, got, int64(s.Got()))
- rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_ARM_GLOB_DAT)))
- } else {
- ld.Errorf(s, "addgotsym: unsupported binary format")
- }
-}
-
-func addgotsyminternal(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Got() >= 0 {
- return
- }
-
- got := syms.GOT
- s.SetGot(int32(got.Size))
-
- got.AddAddrPlus(target.Arch, s, 0)
-
- if target.IsElf() {
- } else {
- ld.Errorf(s, "addgotsyminternal: unsupported binary format")
- }
-}
Dwarfregsp: dwarfRegSP,
Dwarfreglr: dwarfRegLR,
- Adddynrel: adddynrel,
Adddynrel2: adddynrel2,
Archinit: archinit,
Archreloc: archreloc,
+++ /dev/null
-// Copyright 2020 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 arm64
-
-import (
- "cmd/internal/objabi"
- "cmd/link/internal/ld"
- "cmd/link/internal/loader"
- "cmd/link/internal/sym"
- "debug/elf"
-)
-
-// Temporary dumping ground for sym.Symbol version of helper
-// functions in asm.go, still being used for some oses.
-// FIXME: get rid of this file when dodata() is completely
-// converted.
-
-func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
- targ := r.Sym
-
- switch r.Type {
- default:
- if r.Type >= objabi.ElfRelocOffset {
- ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type))
- return false
- }
-
- // Handle relocations found in ELF object files.
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_PREL32):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_AARCH64_PREL32 relocation for dynamic symbol %s", targ.Name)
- }
- // TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
- // sense and should be removed when someone has thought about it properly.
- if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
- ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
- }
- r.Type = objabi.R_PCREL
- r.Add += 4
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_PREL64):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_AARCH64_PREL64 relocation for dynamic symbol %s", targ.Name)
- }
- if targ.Type == 0 || targ.Type == sym.SXREF {
- ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
- }
- r.Type = objabi.R_PCREL
- r.Add += 8
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_CALL26),
- objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_JUMP26):
- if targ.Type == sym.SDYNIMPORT {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add += int64(targ.Plt())
- }
- if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
- ld.Errorf(s, "unknown symbol %s in callarm64", targ.Name)
- }
- r.Type = objabi.R_CALLARM64
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADR_GOT_PAGE),
- objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LD64_GOT_LO12_NC):
- if targ.Type != sym.SDYNIMPORT {
- // have symbol
- // TODO: turn LDR of GOT entry into ADR of symbol itself
- }
-
- // fall back to using GOT
- // TODO: just needs relocation, no need to put in .dynsym
- addgotsym(target, syms, targ)
-
- r.Type = objabi.R_ARM64_GOT
- r.Sym = syms.GOT
- r.Add += int64(targ.Got())
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADR_PREL_PG_HI21),
- objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ADD_ABS_LO12_NC):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
- }
- if targ.Type == 0 || targ.Type == sym.SXREF {
- ld.Errorf(s, "unknown symbol %s", targ.Name)
- }
- r.Type = objabi.R_ARM64_PCREL
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_ABS64):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_AARCH64_ABS64 relocation for dynamic symbol %s", targ.Name)
- }
- r.Type = objabi.R_ADDR
- if target.IsPIE() && target.IsInternal() {
- // For internal linking PIE, this R_ADDR relocation cannot
- // be resolved statically. We need to generate a dynamic
- // relocation. Let the code below handle it.
- break
- }
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST8_ABS_LO12_NC):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
- }
- r.Type = objabi.R_ARM64_LDST8
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST32_ABS_LO12_NC):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
- }
- r.Type = objabi.R_ARM64_LDST32
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST64_ABS_LO12_NC):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
- }
- r.Type = objabi.R_ARM64_LDST64
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST128_ABS_LO12_NC):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
- }
- r.Type = objabi.R_ARM64_LDST128
- return true
- }
-
- switch r.Type {
- case objabi.R_CALL,
- objabi.R_PCREL,
- objabi.R_CALLARM64:
- if targ.Type != sym.SDYNIMPORT {
- // nothing to do, the relocation will be laid out in reloc
- return true
- }
- if target.IsExternal() {
- // External linker will do this relocation.
- return true
- }
-
- case objabi.R_ADDR:
- if s.Type == sym.STEXT && target.IsElf() {
- // The code is asking for the address of an external
- // function. We provide it with the address of the
- // correspondent GOT symbol.
- addgotsym(target, syms, targ)
-
- r.Sym = syms.GOT
- r.Add += int64(targ.Got())
- return true
- }
-
- // Process dynamic relocations for the data sections.
- if target.IsPIE() && target.IsInternal() {
- // When internally linking, generate dynamic relocations
- // for all typical R_ADDR relocations. The exception
- // are those R_ADDR that are created as part of generating
- // the dynamic relocations and must be resolved statically.
- //
- // There are three phases relevant to understanding this:
- //
- // dodata() // we are here
- // address() // symbol address assignment
- // reloc() // resolution of static R_ADDR relocs
- //
- // At this point symbol addresses have not been
- // assigned yet (as the final size of the .rela section
- // will affect the addresses), and so we cannot write
- // the Elf64_Rela.r_offset now. Instead we delay it
- // until after the 'address' phase of the linker is
- // complete. We do this via Addaddrplus, which creates
- // a new R_ADDR relocation which will be resolved in
- // the 'reloc' phase.
- //
- // These synthetic static R_ADDR relocs must be skipped
- // now, or else we will be caught in an infinite loop
- // of generating synthetic relocs for our synthetic
- // relocs.
- //
- // Furthermore, the rela sections contain dynamic
- // relocations with R_ADDR relocations on
- // Elf64_Rela.r_offset. This field should contain the
- // symbol offset as determined by reloc(), not the
- // final dynamically linked address as a dynamic
- // relocation would provide.
- switch s.Name {
- case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic":
- return false
- }
- } else {
- // Either internally linking a static executable,
- // in which case we can resolve these relocations
- // statically in the 'reloc' phase, or externally
- // linking, in which case the relocation will be
- // prepared in the 'reloc' phase and passed to the
- // external linker in the 'asmb' phase.
- if s.Type != sym.SDATA && s.Type != sym.SRODATA {
- break
- }
- }
-
- if target.IsElf() {
- // Generate R_AARCH64_RELATIVE relocations for best
- // efficiency in the dynamic linker.
- //
- // As noted above, symbol addresses have not been
- // assigned yet, so we can't generate the final reloc
- // entry yet. We ultimately want:
- //
- // r_offset = s + r.Off
- // r_info = R_AARCH64_RELATIVE
- // r_addend = targ + r.Add
- //
- // The dynamic linker will set *offset = base address +
- // addend.
- //
- // AddAddrPlus is used for r_offset and r_addend to
- // generate new R_ADDR relocations that will update
- // these fields in the 'reloc' phase.
- rela := syms.Rela
- rela.AddAddrPlus(target.Arch, s, int64(r.Off))
- if r.Siz == 8 {
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(0, uint32(elf.R_AARCH64_RELATIVE)))
- } else {
- ld.Errorf(s, "unexpected relocation for dynamic symbol %s", targ.Name)
- }
- rela.AddAddrPlus(target.Arch, targ, int64(r.Add))
- // Not mark r done here. So we still apply it statically,
- // so in the file content we'll also have the right offset
- // to the relocation target. So it can be examined statically
- // (e.g. go version).
- return true
- }
- }
- return false
-}
-func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Plt() >= 0 {
- return
- }
-
- ld.Adddynsym(target, syms, s)
-
- if target.IsElf() {
- plt := syms.PLT
- gotplt := syms.GOTPLT
- rela := syms.RelaPLT
- if plt.Size == 0 {
- panic("plt is not set up")
- }
-
- // adrp x16, &got.plt[0]
- plt.AddAddrPlus4(gotplt, gotplt.Size)
- plt.SetUint32(target.Arch, plt.Size-4, 0x90000010)
- plt.R[len(plt.R)-1].Type = objabi.R_ARM64_GOT
-
- // <offset> is the offset value of &got.plt[n] to &got.plt[0]
- // ldr x17, [x16, <offset>]
- plt.AddAddrPlus4(gotplt, gotplt.Size)
- plt.SetUint32(target.Arch, plt.Size-4, 0xf9400211)
- plt.R[len(plt.R)-1].Type = objabi.R_ARM64_GOT
-
- // add x16, x16, <offset>
- plt.AddAddrPlus4(gotplt, gotplt.Size)
- plt.SetUint32(target.Arch, plt.Size-4, 0x91000210)
- plt.R[len(plt.R)-1].Type = objabi.R_ARM64_PCREL
-
- // br x17
- plt.AddUint32(target.Arch, 0xd61f0220)
-
- // add to got.plt: pointer to plt[0]
- gotplt.AddAddrPlus(target.Arch, plt, 0)
-
- // rela
- rela.AddAddrPlus(target.Arch, gotplt, gotplt.Size-8)
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_AARCH64_JUMP_SLOT)))
- rela.AddUint64(target.Arch, 0)
-
- s.SetPlt(int32(plt.Size - 16))
- } else {
- ld.Errorf(s, "addpltsym: unsupported binary format")
- }
-}
-
-func addgotsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Got() >= 0 {
- return
- }
-
- ld.Adddynsym(target, syms, s)
- got := syms.GOT
- s.SetGot(int32(got.Size))
- got.AddUint64(target.Arch, 0)
-
- if target.IsElf() {
- rela := syms.Rela
- rela.AddAddrPlus(target.Arch, got, int64(s.Got()))
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_AARCH64_GLOB_DAT)))
- rela.AddUint64(target.Arch, 0)
- } else {
- ld.Errorf(s, "addgotsym: unsupported binary format")
- }
-}
Dwarfregsp: dwarfRegSP,
Dwarfreglr: dwarfRegLR,
- Adddynrel: adddynrel,
Adddynrel2: adddynrel2,
Archinit: archinit,
Archreloc: archreloc,
package ld
import (
- "cmd/internal/gcprog"
- "cmd/internal/objabi"
- "cmd/link/internal/loader"
"cmd/link/internal/sym"
- "fmt"
- "log"
- "os"
- "sort"
"strings"
- "sync"
)
// Temporary dumping around for sym.Symbol version of helper
// FIXME: get rid of this file when dodata() is completely
// converted.
-func (ctxt *Link) dodata() {
- // Give zeros sized symbols space if necessary.
- fixZeroSizedSymbols(ctxt)
-
- // Collect data symbols by type into data.
- state := dodataState{ctxt: ctxt}
- for _, s := range ctxt.loader.Syms {
- if s == nil {
- continue
- }
- if !s.Attr.Reachable() || s.Attr.Special() || s.Attr.SubSymbol() {
- continue
- }
- if s.Type <= sym.STEXT || s.Type >= sym.SXREF {
- continue
- }
- state.data[s.Type] = append(state.data[s.Type], s)
- }
-
- // Now that we have the data symbols, but before we start
- // to assign addresses, record all the necessary
- // dynamic relocations. These will grow the relocation
- // symbol, which is itself data.
- //
- // On darwin, we need the symbol table numbers for dynreloc.
- if ctxt.HeadType == objabi.Hdarwin {
- panic("not supported")
- //machosymorder(ctxt)
- }
- state.dynreloc(ctxt)
-
- // Move any RO data with relocations to a separate section.
- state.makeRelroForSharedLib(ctxt)
-
- // Temporary for debugging.
- symToIdx := make(map[*sym.Symbol]loader.Sym)
- for s := loader.Sym(1); s < loader.Sym(ctxt.loader.NSym()); s++ {
- sp := ctxt.loader.Syms[s]
- if sp != nil {
- symToIdx[sp] = s
- }
- }
-
- // Sort symbols.
- var wg sync.WaitGroup
- for symn := range state.data {
- symn := sym.SymKind(symn)
- wg.Add(1)
- go func() {
- state.data[symn], state.dataMaxAlign[symn] = dodataSect(ctxt, symn, state.data[symn], symToIdx)
- wg.Done()
- }()
- }
- wg.Wait()
-
- if ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal {
- // These symbols must have the same alignment as their section.
- // Otherwize, ld might change the layout of Go sections.
- ctxt.Syms.ROLookup("runtime.data", 0).Align = state.dataMaxAlign[sym.SDATA]
- ctxt.Syms.ROLookup("runtime.bss", 0).Align = state.dataMaxAlign[sym.SBSS]
- }
-
- // Create *sym.Section objects and assign symbols to sections for
- // data/rodata (and related) symbols.
- state.allocateDataSections(ctxt)
-
- // Create *sym.Section objects and assign symbols to sections for
- // DWARF symbols.
- state.allocateDwarfSections(ctxt)
-
- /* number the sections */
- n := int16(1)
-
- for _, sect := range Segtext.Sections {
- sect.Extnum = n
- n++
- }
- for _, sect := range Segrodata.Sections {
- sect.Extnum = n
- n++
- }
- for _, sect := range Segrelrodata.Sections {
- sect.Extnum = n
- n++
- }
- for _, sect := range Segdata.Sections {
- sect.Extnum = n
- n++
- }
- for _, sect := range Segdwarf.Sections {
- sect.Extnum = n
- n++
- }
-}
-
-// makeRelroForSharedLib creates a section of readonly data if necessary.
-func (state *dodataState) makeRelroForSharedLib(target *Link) {
- if !target.UseRelro() {
- return
- }
-
- // "read only" data with relocations needs to go in its own section
- // when building a shared library. We do this by boosting objects of
- // type SXXX with relocations to type SXXXRELRO.
- for _, symnro := range sym.ReadOnly {
- symnrelro := sym.RelROMap[symnro]
-
- ro := []*sym.Symbol{}
- relro := state.data[symnrelro]
-
- for _, s := range state.data[symnro] {
- isRelro := len(s.R) > 0
- switch s.Type {
- case sym.STYPE, sym.STYPERELRO, sym.SGOFUNCRELRO:
- // Symbols are not sorted yet, so it is possible
- // that an Outer symbol has been changed to a
- // relro Type before it reaches here.
- isRelro = true
- case sym.SFUNCTAB:
- if target.IsAIX() && s.Name == "runtime.etypes" {
- // runtime.etypes must be at the end of
- // the relro datas.
- isRelro = true
- }
- }
- if isRelro {
- s.Type = symnrelro
- if s.Outer != nil {
- s.Outer.Type = s.Type
- }
- relro = append(relro, s)
- } else {
- ro = append(ro, s)
- }
- }
-
- // Check that we haven't made two symbols with the same .Outer into
- // different types (because references two symbols with non-nil Outer
- // become references to the outer symbol + offset it's vital that the
- // symbol and the outer end up in the same section).
- for _, s := range relro {
- if s.Outer != nil && s.Outer.Type != s.Type {
- Errorf(s, "inconsistent types for symbol and its Outer %s (%v != %v)",
- s.Outer.Name, s.Type, s.Outer.Type)
- }
- }
-
- state.data[symnro] = ro
- state.data[symnrelro] = relro
- }
-}
-
-func dynrelocsym(ctxt *Link, s *sym.Symbol) {
- target := &ctxt.Target
- ldr := ctxt.loader
- syms := &ctxt.ArchSyms
- for ri := range s.R {
- r := &s.R[ri]
- if ctxt.BuildMode == BuildModePIE && ctxt.LinkMode == LinkInternal {
- // It's expected that some relocations will be done
- // later by relocsym (R_TLS_LE, R_ADDROFF), so
- // don't worry if Adddynrel returns false.
- thearch.Adddynrel(target, ldr, syms, s, r)
- continue
- }
-
- if r.Sym != nil && r.Sym.Type == sym.SDYNIMPORT || r.Type >= objabi.ElfRelocOffset {
- if r.Sym != nil && !r.Sym.Attr.Reachable() {
- Errorf(s, "dynamic relocation to unreachable symbol %s", r.Sym.Name)
- }
- if !thearch.Adddynrel(target, ldr, syms, s, r) {
- Errorf(s, "unsupported dynamic relocation for symbol %s (type=%d (%s) stype=%d (%s))", r.Sym.Name, r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Sym.Type, r.Sym.Type)
- }
- }
- }
-}
-
-func (state *dodataState) dynreloc(ctxt *Link) {
- if ctxt.HeadType == objabi.Hwindows {
- return
- }
- // -d suppresses dynamic loader format, so we may as well not
- // compute these sections or mark their symbols as reachable.
- if *FlagD {
- return
- }
-
- for _, s := range ctxt.Textp {
- dynrelocsym(ctxt, s)
- }
- for _, syms := range state.data {
- for _, s := range syms {
- dynrelocsym(ctxt, s)
- }
- }
- if ctxt.IsELF {
- elfdynhash(ctxt)
- }
-}
-
func Addstring(s *sym.Symbol, str string) int64 {
if s.Type == 0 {
s.Type = sym.SNOPTRDATA
s.Align = align
return align
}
-
-func aligndatsize(datsize int64, s *sym.Symbol) int64 {
- return Rnd(datsize, int64(symalign(s)))
-}
-
-type GCProg struct {
- ctxt *Link
- sym *sym.Symbol
- w gcprog.Writer
-}
-
-func (p *GCProg) Init(ctxt *Link, name string) {
- p.ctxt = ctxt
- p.sym = ctxt.Syms.Lookup(name, 0)
- p.w.Init(p.writeByte(ctxt))
- if debugGCProg {
- fmt.Fprintf(os.Stderr, "ld: start GCProg %s\n", name)
- p.w.Debug(os.Stderr)
- }
-}
-
-func (p *GCProg) writeByte(ctxt *Link) func(x byte) {
- return func(x byte) {
- p.sym.AddUint8(x)
- }
-}
-
-func (p *GCProg) End(size int64) {
- p.w.ZeroUntil(size / int64(p.ctxt.Arch.PtrSize))
- p.w.End()
- if debugGCProg {
- fmt.Fprintf(os.Stderr, "ld: end GCProg\n")
- }
-}
-
-func (p *GCProg) AddSym(s *sym.Symbol) {
- typ := s.Gotype
- // Things without pointers should be in sym.SNOPTRDATA or sym.SNOPTRBSS;
- // everything we see should have pointers and should therefore have a type.
- if typ == nil {
- switch s.Name {
- case "runtime.data", "runtime.edata", "runtime.bss", "runtime.ebss":
- // Ignore special symbols that are sometimes laid out
- // as real symbols. See comment about dyld on darwin in
- // the address function.
- return
- }
- Errorf(s, "missing Go type information for global symbol: size %d", s.Size)
- return
- }
-
- ptrsize := int64(p.ctxt.Arch.PtrSize)
- nptr := decodetypePtrdata(p.ctxt.Arch, typ.P) / ptrsize
-
- if debugGCProg {
- fmt.Fprintf(os.Stderr, "gcprog sym: %s at %d (ptr=%d+%d)\n", s.Name, s.Value, s.Value/ptrsize, nptr)
- }
-
- if decodetypeUsegcprog(p.ctxt.Arch, typ.P) == 0 {
- // Copy pointers from mask into program.
- mask := decodetypeGcmask(p.ctxt, typ)
- for i := int64(0); i < nptr; i++ {
- if (mask[i/8]>>uint(i%8))&1 != 0 {
- p.w.Ptr(s.Value/ptrsize + i)
- }
- }
- return
- }
-
- // Copy program.
- prog := decodetypeGcprog(p.ctxt, typ)
- p.w.ZeroUntil(s.Value / ptrsize)
- p.w.Append(prog[4:], nptr)
-}
-
-// dataSortKey is used to sort a slice of data symbol *sym.Symbol pointers.
-// The sort keys are kept inline to improve cache behavior while sorting.
-type dataSortKey struct {
- size int64
- name string
- sym *sym.Symbol
- symIdx loader.Sym
-}
-
-type bySizeAndName []dataSortKey
-
-func (d bySizeAndName) Len() int { return len(d) }
-func (d bySizeAndName) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
-func (d bySizeAndName) Less(i, j int) bool {
- s1, s2 := d[i], d[j]
- if s1.size != s2.size {
- return s1.size < s2.size
- }
- if s1.name != s2.name {
- return s1.name < s2.name
- }
- return s1.symIdx < s2.symIdx
-}
-
-// fixZeroSizedSymbols gives a few special symbols with zero size some space.
-func fixZeroSizedSymbols(ctxt *Link) {
- // The values in moduledata are filled out by relocations
- // pointing to the addresses of these special symbols.
- // Typically these symbols have no size and are not laid
- // out with their matching section.
- //
- // However on darwin, dyld will find the special symbol
- // in the first loaded module, even though it is local.
- //
- // (An hypothesis, formed without looking in the dyld sources:
- // these special symbols have no size, so their address
- // matches a real symbol. The dynamic linker assumes we
- // want the normal symbol with the same address and finds
- // it in the other module.)
- //
- // To work around this we lay out the symbls whose
- // addresses are vital for multi-module programs to work
- // as normal symbols, and give them a little size.
- //
- // On AIX, as all DATA sections are merged together, ld might not put
- // these symbols at the beginning of their respective section if there
- // aren't real symbols, their alignment might not match the
- // first symbol alignment. Therefore, there are explicitly put at the
- // beginning of their section with the same alignment.
- if !(ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) && !(ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
- return
- }
-
- bss := ctxt.Syms.Lookup("runtime.bss", 0)
- bss.Size = 8
- bss.Attr.Set(sym.AttrSpecial, false)
-
- ctxt.Syms.Lookup("runtime.ebss", 0).Attr.Set(sym.AttrSpecial, false)
-
- data := ctxt.Syms.Lookup("runtime.data", 0)
- data.Size = 8
- data.Attr.Set(sym.AttrSpecial, false)
-
- edata := ctxt.Syms.Lookup("runtime.edata", 0)
- edata.Attr.Set(sym.AttrSpecial, false)
- if ctxt.HeadType == objabi.Haix {
- // XCOFFTOC symbols are part of .data section.
- edata.Type = sym.SXCOFFTOC
- }
-
- types := ctxt.Syms.Lookup("runtime.types", 0)
- types.Type = sym.STYPE
- types.Size = 8
- types.Attr.Set(sym.AttrSpecial, false)
-
- etypes := ctxt.Syms.Lookup("runtime.etypes", 0)
- etypes.Type = sym.SFUNCTAB
- etypes.Attr.Set(sym.AttrSpecial, false)
-
- if ctxt.HeadType == objabi.Haix {
- rodata := ctxt.Syms.Lookup("runtime.rodata", 0)
- rodata.Type = sym.SSTRING
- rodata.Size = 8
- rodata.Attr.Set(sym.AttrSpecial, false)
-
- ctxt.Syms.Lookup("runtime.erodata", 0).Attr.Set(sym.AttrSpecial, false)
- }
-}
-
-// allocateDataSectionForSym creates a new sym.Section into which a a
-// single symbol will be placed. Here "seg" is the segment into which
-// the section will go, "s" is the symbol to be placed into the new
-// section, and "rwx" contains permissions for the section.
-func (state *dodataState) allocateDataSectionForSym(seg *sym.Segment, s *sym.Symbol, rwx int) *sym.Section {
- sect := addsection(state.ctxt.loader, state.ctxt.Arch, seg, s.Name, rwx)
- sect.Align = symalign(s)
- state.datsize = Rnd(state.datsize, int64(sect.Align))
- sect.Vaddr = uint64(state.datsize)
- return sect
-}
-
-// assignDsymsToSection assigns a collection of data symbols to a
-// newly created section. "sect" is the section into which to place
-// the symbols, "syms" holds the list of symbols to assign,
-// "forceType" (if non-zero) contains a new sym type to apply to each
-// sym during the assignment, and "aligner" is a hook to call to
-// handle alignment during the assignment process.
-func (state *dodataState) assignDsymsToSection(sect *sym.Section, syms []*sym.Symbol, forceType sym.SymKind, aligner func(datsize int64, s *sym.Symbol) int64) {
- for _, s := range syms {
- state.datsize = aligner(state.datsize, s)
- s.Sect = sect
- if forceType != sym.Sxxx {
- s.Type = forceType
- }
- s.Value = int64(uint64(state.datsize) - sect.Vaddr)
- state.datsize += s.Size
- }
- sect.Length = uint64(state.datsize) - sect.Vaddr
-}
-
-func (state *dodataState) assignToSection(sect *sym.Section, symn sym.SymKind, forceType sym.SymKind) {
- state.assignDsymsToSection(sect, state.data[symn], forceType, aligndatsize)
- state.checkdatsize(symn)
-}
-
-// allocateSingleSymSections walks through the bucketed data symbols
-// with type 'symn', creates a new section for each sym, and assigns
-// the sym to a newly created section. Section name is set from the
-// symbol name. "Seg" is the segment into which to place the new
-// section, "forceType" is the new sym.SymKind to assign to the symbol
-// within the section, and "rwx" holds section permissions.
-func (state *dodataState) allocateSingleSymSections(seg *sym.Segment, symn sym.SymKind, forceType sym.SymKind, rwx int) {
- for _, s := range state.data[symn] {
- sect := state.allocateDataSectionForSym(seg, s, rwx)
- s.Sect = sect
- s.Type = forceType
- s.Value = int64(uint64(state.datsize) - sect.Vaddr)
- state.datsize += s.Size
- sect.Length = uint64(state.datsize) - sect.Vaddr
- }
- state.checkdatsize(symn)
-}
-
-// allocateNamedSectionAndAssignSyms creates a new section with the
-// specified name, then walks through the bucketed data symbols with
-// type 'symn' and assigns each of them to this new section. "Seg" is
-// the segment into which to place the new section, "secName" is the
-// name to give to the new section, "forceType" (if non-zero) contains
-// a new sym type to apply to each sym during the assignment, and
-// "rwx" holds section permissions.
-func (state *dodataState) allocateNamedSectionAndAssignSyms(seg *sym.Segment, secName string, symn sym.SymKind, forceType sym.SymKind, rwx int) *sym.Section {
-
- sect := state.allocateNamedDataSection(seg, secName, []sym.SymKind{symn}, rwx)
- state.assignDsymsToSection(sect, state.data[symn], forceType, aligndatsize)
- return sect
-}
-
-// allocateDataSections allocates sym.Section objects for data/rodata
-// (and related) symbols, and then assigns symbols to those sections.
-func (state *dodataState) allocateDataSections(ctxt *Link) {
- // Allocate sections.
- // Data is processed before segtext, because we need
- // to see all symbols in the .data and .bss sections in order
- // to generate garbage collection information.
-
- // Writable data sections that do not need any specialized handling.
- writable := []sym.SymKind{
- sym.SBUILDINFO,
- sym.SELFSECT,
- sym.SMACHO,
- sym.SMACHOGOT,
- sym.SWINDOWS,
- }
- for _, symn := range writable {
- state.allocateSingleSymSections(&Segdata, symn, sym.SDATA, 06)
- }
-
- // .got (and .toc on ppc64)
- if len(state.data[sym.SELFGOT]) > 0 {
- sect := state.allocateNamedSectionAndAssignSyms(&Segdata, ".got", sym.SELFGOT, sym.SDATA, 06)
- if ctxt.IsPPC64() {
- for _, s := range state.data[sym.SELFGOT] {
- // Resolve .TOC. symbol for this object file (ppc64)
- toc := ctxt.Syms.ROLookup(".TOC.", int(s.Version))
- if toc != nil {
- toc.Sect = sect
- toc.Outer = s
- toc.Sub = s.Sub
- s.Sub = toc
-
- toc.Value = 0x8000
- }
- }
- }
- }
-
- /* pointer-free data */
- sect := state.allocateNamedSectionAndAssignSyms(&Segdata, ".noptrdata", sym.SNOPTRDATA, sym.SDATA, 06)
- ctxt.Syms.Lookup("runtime.noptrdata", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.enoptrdata", 0).Sect = sect
-
- hasinitarr := ctxt.linkShared
-
- /* shared library initializer */
- switch ctxt.BuildMode {
- case BuildModeCArchive, BuildModeCShared, BuildModeShared, BuildModePlugin:
- hasinitarr = true
- }
-
- if ctxt.HeadType == objabi.Haix {
- if len(state.data[sym.SINITARR]) > 0 {
- Errorf(nil, "XCOFF format doesn't allow .init_array section")
- }
- }
-
- if hasinitarr && len(state.data[sym.SINITARR]) > 0 {
- state.allocateNamedSectionAndAssignSyms(&Segdata, ".init_array", sym.SINITARR, sym.Sxxx, 06)
- }
-
- /* data */
- sect = state.allocateNamedSectionAndAssignSyms(&Segdata, ".data", sym.SDATA, sym.SDATA, 06)
- ctxt.Syms.Lookup("runtime.data", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.edata", 0).Sect = sect
- dataGcEnd := state.datsize - int64(sect.Vaddr)
-
- // On AIX, TOC entries must be the last of .data
- // These aren't part of gc as they won't change during the runtime.
- state.assignToSection(sect, sym.SXCOFFTOC, sym.SDATA)
- state.checkdatsize(sym.SDATA)
- sect.Length = uint64(state.datsize) - sect.Vaddr
-
- /* bss */
- sect = state.allocateNamedSectionAndAssignSyms(&Segdata, ".bss", sym.SBSS, sym.Sxxx, 06)
- ctxt.Syms.Lookup("runtime.bss", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.ebss", 0).Sect = sect
- bssGcEnd := state.datsize - int64(sect.Vaddr)
-
- // Emit gcdata for bcc symbols now that symbol values have been assigned.
- gcsToEmit := []struct {
- symName string
- symKind sym.SymKind
- gcEnd int64
- }{
- {"runtime.gcdata", sym.SDATA, dataGcEnd},
- {"runtime.gcbss", sym.SBSS, bssGcEnd},
- }
- for _, g := range gcsToEmit {
- var gc GCProg
- gc.Init(ctxt, g.symName)
- for _, s := range state.data[g.symKind] {
- gc.AddSym(s)
- }
- gc.End(g.gcEnd)
- }
-
- /* pointer-free bss */
- sect = state.allocateNamedSectionAndAssignSyms(&Segdata, ".noptrbss", sym.SNOPTRBSS, sym.Sxxx, 06)
- ctxt.Syms.Lookup("runtime.noptrbss", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.enoptrbss", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.end", 0).Sect = sect
-
- // Coverage instrumentation counters for libfuzzer.
- if len(state.data[sym.SLIBFUZZER_EXTRA_COUNTER]) > 0 {
- state.allocateNamedSectionAndAssignSyms(&Segdata, "__libfuzzer_extra_counters", sym.SLIBFUZZER_EXTRA_COUNTER, sym.Sxxx, 06)
- }
-
- if len(state.data[sym.STLSBSS]) > 0 {
- var sect *sym.Section
- // FIXME: not clear why it is sometimes necessary to suppress .tbss section creation.
- if (ctxt.IsELF || ctxt.HeadType == objabi.Haix) && (ctxt.LinkMode == LinkExternal || !*FlagD) {
- sect = addsection(ctxt.loader, ctxt.Arch, &Segdata, ".tbss", 06)
- sect.Align = int32(ctxt.Arch.PtrSize)
- // FIXME: why does this need to be set to zero?
- sect.Vaddr = 0
- }
- state.datsize = 0
-
- for _, s := range state.data[sym.STLSBSS] {
- state.datsize = aligndatsize(state.datsize, s)
- s.Sect = sect
- s.Value = state.datsize
- state.datsize += s.Size
- }
- state.checkdatsize(sym.STLSBSS)
-
- if sect != nil {
- sect.Length = uint64(state.datsize)
- }
- }
-
- /*
- * We finished data, begin read-only data.
- * Not all systems support a separate read-only non-executable data section.
- * ELF and Windows PE systems do.
- * OS X and Plan 9 do not.
- * And if we're using external linking mode, the point is moot,
- * since it's not our decision; that code expects the sections in
- * segtext.
- */
- var segro *sym.Segment
- if ctxt.IsELF && ctxt.LinkMode == LinkInternal {
- segro = &Segrodata
- } else if ctxt.HeadType == objabi.Hwindows {
- segro = &Segrodata
- } else {
- segro = &Segtext
- }
-
- state.datsize = 0
-
- /* read-only executable ELF, Mach-O sections */
- if len(state.data[sym.STEXT]) != 0 {
- Errorf(nil, "dodata found an sym.STEXT symbol: %s", state.data[sym.STEXT][0].Name)
- }
- state.allocateSingleSymSections(&Segtext, sym.SELFRXSECT, sym.SRODATA, 04)
-
- /* read-only data */
- sect = state.allocateNamedDataSection(segro, ".rodata", sym.ReadOnly, 04)
- ctxt.Syms.Lookup("runtime.rodata", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.erodata", 0).Sect = sect
- if !ctxt.UseRelro() {
- ctxt.Syms.Lookup("runtime.types", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.etypes", 0).Sect = sect
- }
- for _, symn := range sym.ReadOnly {
- symnStartValue := state.datsize
- state.assignToSection(sect, symn, sym.SRODATA)
- if ctxt.HeadType == objabi.Haix {
- // Read-only symbols might be wrapped inside their outer
- // symbol.
- // XCOFF symbol table needs to know the size of
- // these outer symbols.
- xcoffUpdateOuterSize(ctxt, state.datsize-symnStartValue, symn)
- }
- }
-
- /* read-only ELF, Mach-O sections */
- state.allocateSingleSymSections(segro, sym.SELFROSECT, sym.SRODATA, 04)
- state.allocateSingleSymSections(segro, sym.SMACHOPLT, sym.SRODATA, 04)
-
- // There is some data that are conceptually read-only but are written to by
- // relocations. On GNU systems, we can arrange for the dynamic linker to
- // mprotect sections after relocations are applied by giving them write
- // permissions in the object file and calling them ".data.rel.ro.FOO". We
- // divide the .rodata section between actual .rodata and .data.rel.ro.rodata,
- // but for the other sections that this applies to, we just write a read-only
- // .FOO section or a read-write .data.rel.ro.FOO section depending on the
- // situation.
- // TODO(mwhudson): It would make sense to do this more widely, but it makes
- // the system linker segfault on darwin.
- const relroPerm = 06
- const fallbackPerm = 04
- relroSecPerm := fallbackPerm
- genrelrosecname := func(suffix string) string {
- return suffix
- }
- seg := segro
-
- if ctxt.UseRelro() {
- segrelro := &Segrelrodata
- if ctxt.LinkMode == LinkExternal && ctxt.HeadType != objabi.Haix {
- // Using a separate segment with an external
- // linker results in some programs moving
- // their data sections unexpectedly, which
- // corrupts the moduledata. So we use the
- // rodata segment and let the external linker
- // sort out a rel.ro segment.
- segrelro = segro
- } else {
- // Reset datsize for new segment.
- state.datsize = 0
- }
-
- genrelrosecname = func(suffix string) string {
- return ".data.rel.ro" + suffix
- }
- relroReadOnly := []sym.SymKind{}
- for _, symnro := range sym.ReadOnly {
- symn := sym.RelROMap[symnro]
- relroReadOnly = append(relroReadOnly, symn)
- }
- seg = segrelro
- relroSecPerm = relroPerm
-
- /* data only written by relocations */
- sect = state.allocateNamedDataSection(segrelro, genrelrosecname(""), relroReadOnly, relroSecPerm)
-
- ctxt.Syms.Lookup("runtime.types", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.etypes", 0).Sect = sect
-
- for i, symnro := range sym.ReadOnly {
- if i == 0 && symnro == sym.STYPE && ctxt.HeadType != objabi.Haix {
- // Skip forward so that no type
- // reference uses a zero offset.
- // This is unlikely but possible in small
- // programs with no other read-only data.
- state.datsize++
- }
-
- symn := sym.RelROMap[symnro]
- symnStartValue := state.datsize
-
- for _, s := range state.data[symn] {
- if s.Outer != nil && s.Outer.Sect != nil && s.Outer.Sect != sect {
- Errorf(s, "s.Outer (%s) in different section from s, %s != %s", s.Outer.Name, s.Outer.Sect.Name, sect.Name)
- }
- }
- state.assignToSection(sect, symn, sym.SRODATA)
- if ctxt.HeadType == objabi.Haix {
- // Read-only symbols might be wrapped inside their outer
- // symbol.
- // XCOFF symbol table needs to know the size of
- // these outer symbols.
- xcoffUpdateOuterSize(ctxt, state.datsize-symnStartValue, symn)
- }
- }
-
- sect.Length = uint64(state.datsize) - sect.Vaddr
- }
-
- /* typelink */
- sect = state.allocateNamedDataSection(seg, genrelrosecname(".typelink"), []sym.SymKind{sym.STYPELINK}, relroSecPerm)
- typelink := ctxt.Syms.Lookup("runtime.typelink", 0)
- typelink.Sect = sect
- typelink.Type = sym.SRODATA
- state.datsize += typelink.Size
- state.checkdatsize(sym.STYPELINK)
- sect.Length = uint64(state.datsize) - sect.Vaddr
-
- /* itablink */
- sect = state.allocateNamedSectionAndAssignSyms(seg, genrelrosecname(".itablink"), sym.SITABLINK, sym.Sxxx, relroSecPerm)
- ctxt.Syms.Lookup("runtime.itablink", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.eitablink", 0).Sect = sect
- if ctxt.HeadType == objabi.Haix {
- // Store .itablink size because its symbols are wrapped
- // under an outer symbol: runtime.itablink.
- xcoffUpdateOuterSize(ctxt, int64(sect.Length), sym.SITABLINK)
- }
-
- /* gosymtab */
- sect = state.allocateNamedSectionAndAssignSyms(seg, genrelrosecname(".gosymtab"), sym.SSYMTAB, sym.SRODATA, relroSecPerm)
- ctxt.Syms.Lookup("runtime.symtab", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.esymtab", 0).Sect = sect
-
- /* gopclntab */
- sect = state.allocateNamedSectionAndAssignSyms(seg, genrelrosecname(".gopclntab"), sym.SPCLNTAB, sym.SRODATA, relroSecPerm)
- ctxt.Syms.Lookup("runtime.pclntab", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.epclntab", 0).Sect = sect
-
- // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
- if state.datsize != int64(uint32(state.datsize)) {
- Errorf(nil, "read-only data segment too large: %d", state.datsize)
- }
-
- for symn := sym.SELFRXSECT; symn < sym.SXREF; symn++ {
- ctxt.datap = append(ctxt.datap, state.data[symn]...)
- }
-}
-
-// allocateDwarfSections allocates sym.Section objects for DWARF
-// symbols, and assigns symbols to sections.
-func (state *dodataState) allocateDwarfSections(ctxt *Link) {
-
- alignOne := func(datsize int64, s *sym.Symbol) int64 { return datsize }
-
- for i := 0; i < len(dwarfp); i++ {
- // First the section symbol.
- s := dwarfp[i].secSym()
- sect := state.allocateNamedDataSection(&Segdwarf, s.Name, []sym.SymKind{}, 04)
- sect.Sym = s
- s.Sect = sect
- curType := s.Type
- s.Type = sym.SRODATA
- s.Value = int64(uint64(state.datsize) - sect.Vaddr)
- state.datsize += s.Size
-
- // Then any sub-symbols for the section symbol.
- subSyms := dwarfp[i].subSyms()
- state.assignDsymsToSection(sect, subSyms, sym.SRODATA, alignOne)
-
- for j := 0; j < len(subSyms); j++ {
- s := subSyms[j]
- if ctxt.HeadType == objabi.Haix && curType == sym.SDWARFLOC {
- // Update the size of .debug_loc for this symbol's
- // package.
- addDwsectCUSize(".debug_loc", s.File, uint64(s.Size))
- }
- }
- sect.Length = uint64(state.datsize) - sect.Vaddr
- state.checkdatsize(curType)
- }
-}
-
-func dodataSect(ctxt *Link, symn sym.SymKind, syms []*sym.Symbol, symToIdx map[*sym.Symbol]loader.Sym) (result []*sym.Symbol, maxAlign int32) {
- if ctxt.HeadType == objabi.Hdarwin {
- // Some symbols may no longer belong in syms
- // due to movement in machosymorder.
- newSyms := make([]*sym.Symbol, 0, len(syms))
- for _, s := range syms {
- if s.Type == symn {
- newSyms = append(newSyms, s)
- }
- }
- syms = newSyms
- }
-
- var head, tail *sym.Symbol
- symsSort := make([]dataSortKey, 0, len(syms))
- for _, s := range syms {
- if s.Attr.OnList() {
- log.Fatalf("symbol %s listed multiple times", s.Name)
- }
- s.Attr |= sym.AttrOnList
- switch {
- case s.Size < int64(len(s.P)):
- Errorf(s, "initialize bounds (%d < %d)", s.Size, len(s.P))
- case s.Size < 0:
- Errorf(s, "negative size (%d bytes)", s.Size)
- case s.Size > cutoff:
- Errorf(s, "symbol too large (%d bytes)", s.Size)
- }
-
- // If the usually-special section-marker symbols are being laid
- // out as regular symbols, put them either at the beginning or
- // end of their section.
- if (ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) || (ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
- switch s.Name {
- case "runtime.text", "runtime.bss", "runtime.data", "runtime.types", "runtime.rodata":
- head = s
- continue
- case "runtime.etext", "runtime.ebss", "runtime.edata", "runtime.etypes", "runtime.erodata":
- tail = s
- continue
- }
- }
-
- key := dataSortKey{
- size: s.Size,
- name: s.Name,
- sym: s,
- symIdx: symToIdx[s],
- }
-
- switch s.Type {
- case sym.SELFGOT:
- // For ppc64, we want to interleave the .got and .toc sections
- // from input files. Both are type sym.SELFGOT, so in that case
- // we skip size comparison and fall through to the name
- // comparison (conveniently, .got sorts before .toc).
- key.size = 0
- }
-
- symsSort = append(symsSort, key)
- }
-
- sort.Sort(bySizeAndName(symsSort))
-
- off := 0
- if head != nil {
- syms[0] = head
- off++
- }
- for i, symSort := range symsSort {
- syms[i+off] = symSort.sym
- align := symalign(symSort.sym)
- if maxAlign < align {
- maxAlign = align
- }
- }
- if tail != nil {
- syms[len(syms)-1] = tail
- }
-
- if ctxt.IsELF && symn == sym.SELFROSECT {
- // Make .rela and .rela.plt contiguous, the ELF ABI requires this
- // and Solaris actually cares.
- reli, plti := -1, -1
- for i, s := range syms {
- switch s.Name {
- case ".rel.plt", ".rela.plt":
- plti = i
- case ".rel", ".rela":
- reli = i
- }
- }
- if reli >= 0 && plti >= 0 && plti != reli+1 {
- var first, second int
- if plti > reli {
- first, second = reli, plti
- } else {
- first, second = plti, reli
- }
- rel, plt := syms[reli], syms[plti]
- copy(syms[first+2:], syms[first+1:second])
- syms[first+0] = rel
- syms[first+1] = plt
-
- // Make sure alignment doesn't introduce a gap.
- // Setting the alignment explicitly prevents
- // symalign from basing it on the size and
- // getting it wrong.
- rel.Align = int32(ctxt.Arch.RegSize)
- plt.Align = int32(ctxt.Arch.RegSize)
- }
- }
-
- return syms, maxAlign
-}
package ld
import (
- "bytes"
"cmd/internal/objabi"
"cmd/internal/sys"
- "cmd/link/internal/sym"
"debug/elf"
- "fmt"
)
// Decoding the type.* symbols. This has to be in sync with
tflagExtraStar = 1 << 1
)
-func decodeReloc(s *sym.Symbol, off int32) *sym.Reloc {
- for i := range s.R {
- if s.R[i].Off == off {
- return &s.R[i]
- }
- }
- return nil
-}
-
-func decodeRelocSym(s *sym.Symbol, off int32) *sym.Symbol {
- r := decodeReloc(s, off)
- if r == nil {
- return nil
- }
- return r.Sym
-}
-
func decodeInuxi(arch *sys.Arch, p []byte, sz int) uint64 {
switch sz {
case 2:
return nil
}
-// Type.commonType.gc
-func decodetypeGcprog(ctxt *Link, s *sym.Symbol) []byte {
- if s.Type == sym.SDYNIMPORT {
- addr := decodetypeGcprogShlib(ctxt, s.P)
- sect := findShlibSection(ctxt, s.File, addr)
- if sect != nil {
- // A gcprog is a 4-byte uint32 indicating length, followed by
- // the actual program.
- progsize := make([]byte, 4)
- sect.ReadAt(progsize, int64(addr-sect.Addr))
- progbytes := make([]byte, ctxt.Arch.ByteOrder.Uint32(progsize))
- sect.ReadAt(progbytes, int64(addr-sect.Addr+4))
- return append(progsize, progbytes...)
- }
- Exitf("cannot find gcprog for %s", s.Name)
- return nil
- }
- return decodeRelocSym(s, 2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize)).P
-}
-
func decodetypeGcprogShlib(ctxt *Link, data []byte) uint64 {
if ctxt.Arch.Family == sys.ARM64 {
return 0
return decodeInuxi(ctxt.Arch, data[2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize):], ctxt.Arch.PtrSize)
}
-func decodetypeGcmask(ctxt *Link, s *sym.Symbol) []byte {
- if s.Type == sym.SDYNIMPORT {
- addr := decodetypeGcprogShlib(ctxt, s.P)
- ptrdata := decodetypePtrdata(ctxt.Arch, s.P)
- sect := findShlibSection(ctxt, s.File, addr)
- if sect != nil {
- r := make([]byte, ptrdata/int64(ctxt.Arch.PtrSize))
- sect.ReadAt(r, int64(addr-sect.Addr))
- return r
- }
- Exitf("cannot find gcmask for %s", s.Name)
- return nil
- }
- mask := decodeRelocSym(s, 2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize))
- return mask.P
-}
-
-// Type.ArrayType.elem and Type.SliceType.Elem
-func decodetypeArrayElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
- return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30
-}
-
-func decodetypeArrayLen(arch *sys.Arch, s *sym.Symbol) int64 {
- return int64(decodeInuxi(arch, s.P[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
-}
-
-// Type.PtrType.elem
-func decodetypePtrElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
- return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30
-}
-
-// Type.MapType.key, elem
-func decodetypeMapKey(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
- return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30
-}
-
-func decodetypeMapValue(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
- return decodeRelocSym(s, int32(commonsize(arch))+int32(arch.PtrSize)) // 0x20 / 0x38
-}
-
-// Type.ChanType.elem
-func decodetypeChanElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
- return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30
-}
-
// Type.FuncType.dotdotdot
func decodetypeFuncDotdotdot(arch *sys.Arch, p []byte) bool {
return uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2))&(1<<15) != 0
return int(uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2)) & (1<<15 - 1))
}
-func decodetypeFuncInType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
- uadd := commonsize(arch) + 4
- if arch.PtrSize == 8 {
- uadd += 4
- }
- if decodetypeHasUncommon(arch, s.P) {
- uadd += uncommonSize()
- }
- return decodeRelocSym(s, int32(uadd+i*arch.PtrSize))
-}
-
-func decodetypeFuncOutType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
- return decodetypeFuncInType(arch, s, i+decodetypeFuncInCount(arch, s.P))
-}
-
-// Type.StructType.fields.Slice::length
-func decodetypeStructFieldCount(arch *sys.Arch, s *sym.Symbol) int {
- return int(decodeInuxi(arch, s.P[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
-}
-
-func decodetypeStructFieldArrayOff(arch *sys.Arch, s *sym.Symbol, i int) int {
- off := commonsize(arch) + 4*arch.PtrSize
- if decodetypeHasUncommon(arch, s.P) {
- off += uncommonSize()
- }
- off += i * structfieldSize(arch)
- return off
-}
-
-// decodetypeStr returns the contents of an rtype's str field (a nameOff).
-func decodetypeStr(arch *sys.Arch, s *sym.Symbol) string {
- str := decodetypeName(s, 4*arch.PtrSize+8)
- if s.P[2*arch.PtrSize+4]&tflagExtraStar != 0 {
- return str[1:]
- }
- return str
-}
-
-// decodetypeName decodes the name from a reflect.name.
-func decodetypeName(s *sym.Symbol, off int) string {
- r := decodeReloc(s, int32(off))
- if r == nil {
- return ""
- }
-
- data := r.Sym.P
- namelen := int(uint16(data[1])<<8 | uint16(data[2]))
- return string(data[3 : 3+namelen])
-}
-
-func decodetypeStructFieldName(arch *sys.Arch, s *sym.Symbol, i int) string {
- off := decodetypeStructFieldArrayOff(arch, s, i)
- return decodetypeName(s, off)
-}
-
-func decodetypeStructFieldType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
- off := decodetypeStructFieldArrayOff(arch, s, i)
- return decodeRelocSym(s, int32(off+arch.PtrSize))
-}
-
-func decodetypeStructFieldOffs(arch *sys.Arch, s *sym.Symbol, i int) int64 {
- return decodetypeStructFieldOffsAnon(arch, s, i) >> 1
-}
-
-func decodetypeStructFieldOffsAnon(arch *sys.Arch, s *sym.Symbol, i int) int64 {
- off := decodetypeStructFieldArrayOff(arch, s, i)
- return int64(decodeInuxi(arch, s.P[off+2*arch.PtrSize:], arch.PtrSize))
-}
-
// InterfaceType.methods.length
func decodetypeIfaceMethodCount(arch *sys.Arch, p []byte) int64 {
return int64(decodeInuxi(arch, p[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
kindStruct = 25
kindMask = (1 << 5) - 1
)
-
-// decodeMethodSig decodes an array of method signature information.
-// Each element of the array is size bytes. The first 4 bytes is a
-// nameOff for the method name, and the next 4 bytes is a typeOff for
-// the function type.
-//
-// Conveniently this is the layout of both runtime.method and runtime.imethod.
-func decodeMethodSig(arch *sys.Arch, s *sym.Symbol, off, size, count int) []methodsig {
- var buf bytes.Buffer
- var methods []methodsig
- for i := 0; i < count; i++ {
- buf.WriteString(decodetypeName(s, off))
- mtypSym := decodeRelocSym(s, int32(off+4))
-
- buf.WriteRune('(')
- inCount := decodetypeFuncInCount(arch, mtypSym.P)
- for i := 0; i < inCount; i++ {
- if i > 0 {
- buf.WriteString(", ")
- }
- buf.WriteString(decodetypeFuncInType(arch, mtypSym, i).Name)
- }
- buf.WriteString(") (")
- outCount := decodetypeFuncOutCount(arch, mtypSym.P)
- for i := 0; i < outCount; i++ {
- if i > 0 {
- buf.WriteString(", ")
- }
- buf.WriteString(decodetypeFuncOutType(arch, mtypSym, i).Name)
- }
- buf.WriteRune(')')
-
- off += size
- methods = append(methods, methodsig(buf.String()))
- buf.Reset()
- }
- return methods
-}
-
-func decodeIfaceMethods(arch *sys.Arch, s *sym.Symbol) []methodsig {
- if decodetypeKind(arch, s.P)&kindMask != kindInterface {
- panic(fmt.Sprintf("symbol %q is not an interface", s.Name))
- }
- r := decodeReloc(s, int32(commonsize(arch)+arch.PtrSize))
- if r == nil {
- return nil
- }
- if r.Sym != s {
- panic(fmt.Sprintf("imethod slice pointer in %q leads to a different symbol", s.Name))
- }
- off := int(r.Add) // array of reflect.imethod values
- numMethods := int(decodetypeIfaceMethodCount(arch, s.P))
- sizeofIMethod := 4 + 4
- return decodeMethodSig(arch, s, off, sizeofIMethod, numMethods)
-}
-
-func decodetypeMethods(arch *sys.Arch, s *sym.Symbol) []methodsig {
- if !decodetypeHasUncommon(arch, s.P) {
- panic(fmt.Sprintf("no methods on %q", s.Name))
- }
- off := commonsize(arch) // reflect.rtype
- switch decodetypeKind(arch, s.P) & kindMask {
- case kindStruct: // reflect.structType
- off += 4 * arch.PtrSize
- case kindPtr: // reflect.ptrType
- off += arch.PtrSize
- case kindFunc: // reflect.funcType
- off += arch.PtrSize // 4 bytes, pointer aligned
- case kindSlice: // reflect.sliceType
- off += arch.PtrSize
- case kindArray: // reflect.arrayType
- off += 3 * arch.PtrSize
- case kindChan: // reflect.chanType
- off += 2 * arch.PtrSize
- case kindMap: // reflect.mapType
- off += 4*arch.PtrSize + 8
- case kindInterface: // reflect.interfaceType
- off += 3 * arch.PtrSize
- default:
- // just Sizeof(rtype)
- }
-
- mcount := int(decodeInuxi(arch, s.P[off+4:], 2))
- moff := int(decodeInuxi(arch, s.P[off+4+2+2:], 4))
- off += moff // offset to array of reflect.method values
- const sizeofMethod = 4 * 4 // sizeof reflect.method in program
- return decodeMethodSig(arch, s, off, sizeofMethod, mcount)
-}
}
}
-func elfadddynsym(target *Target, syms *ArchSyms, s *sym.Symbol) {
- if elf64 {
- s.Dynid = int32(Nelfsym)
- Nelfsym++
-
- d := syms.DynSym
-
- name := s.Extname()
- d.AddUint32(target.Arch, uint32(Addstring(syms.DynStr, name)))
-
- /* type */
- t := STB_GLOBAL << 4
-
- if s.Attr.CgoExport() && s.Type == sym.STEXT {
- t |= STT_FUNC
- } else {
- t |= STT_OBJECT
- }
- d.AddUint8(uint8(t))
-
- /* reserved */
- d.AddUint8(0)
-
- /* section where symbol is defined */
- if s.Type == sym.SDYNIMPORT {
- d.AddUint16(target.Arch, SHN_UNDEF)
- } else {
- d.AddUint16(target.Arch, 1)
- }
-
- /* value */
- if s.Type == sym.SDYNIMPORT {
- d.AddUint64(target.Arch, 0)
- } else {
- d.AddAddr(target.Arch, s)
- }
-
- /* size of object */
- d.AddUint64(target.Arch, uint64(s.Size))
-
- if target.Arch.Family == sys.AMD64 && !s.Attr.CgoExportDynamic() && s.Dynimplib() != "" && !seenlib[s.Dynimplib()] {
- elfWriteDynEnt(target.Arch, syms.Dynamic, DT_NEEDED, uint64(Addstring(syms.DynStr, s.Dynimplib())))
- }
- } else {
- s.Dynid = int32(Nelfsym)
- Nelfsym++
-
- d := syms.DynSym
-
- /* name */
- name := s.Extname()
-
- d.AddUint32(target.Arch, uint32(Addstring(syms.DynStr, name)))
-
- /* value */
- if s.Type == sym.SDYNIMPORT {
- d.AddUint32(target.Arch, 0)
- } else {
- d.AddAddr(target.Arch, s)
- }
-
- /* size of object */
- d.AddUint32(target.Arch, uint32(s.Size))
-
- /* type */
- t := STB_GLOBAL << 4
-
- // TODO(mwhudson): presumably the behavior should actually be the same on both arm and 386.
- if target.Arch.Family == sys.I386 && s.Attr.CgoExport() && s.Type == sym.STEXT {
- t |= STT_FUNC
- } else if target.Arch.Family == sys.ARM && s.Attr.CgoExportDynamic() && s.Type == sym.STEXT {
- t |= STT_FUNC
- } else {
- t |= STT_OBJECT
- }
- d.AddUint8(uint8(t))
- d.AddUint8(0)
-
- /* shndx */
- if s.Type == sym.SDYNIMPORT {
- d.AddUint16(target.Arch, SHN_UNDEF)
- } else {
- d.AddUint16(target.Arch, 1)
- }
- }
-}
-
func elfadddynsym2(ldr *loader.Loader, target *Target, syms *ArchSyms, s loader.Sym) {
ldr.SetSymDynid(s, int32(Nelfsym))
Nelfsym++
package ld
import (
- "cmd/internal/sys"
"cmd/link/internal/sym"
)
elfstr[nelfstr].off = off
nelfstr++
}
-
-func elfWriteDynEntSym(arch *sys.Arch, s *sym.Symbol, tag int, t *sym.Symbol) {
- Elfwritedynentsymplus(arch, s, tag, t, 0)
-}
-
-func elfdynhash(ctxt *Link) {
- if !ctxt.IsELF {
- return
- }
-
- nsym := Nelfsym
- s := ctxt.Syms.Lookup(".hash", 0)
- s.Type = sym.SELFROSECT
- s.Attr |= sym.AttrReachable
-
- i := nsym
- nbucket := 1
- for i > 0 {
- nbucket++
- i >>= 1
- }
-
- var needlib *Elflib
- need := make([]*Elfaux, nsym)
- chain := make([]uint32, nsym)
- buckets := make([]uint32, nbucket)
-
- for _, sy := range ctxt.loader.Syms {
- if sy == nil {
- continue
- }
- if sy.Dynid <= 0 {
- continue
- }
-
- if sy.Dynimpvers() != "" {
- need[sy.Dynid] = addelflib(&needlib, sy.Dynimplib(), sy.Dynimpvers())
- }
-
- name := sy.Extname()
- hc := elfhash(name)
-
- b := hc % uint32(nbucket)
- chain[sy.Dynid] = buckets[b]
- buckets[b] = uint32(sy.Dynid)
- }
-
- // s390x (ELF64) hash table entries are 8 bytes
- if ctxt.Arch.Family == sys.S390X {
- s.AddUint64(ctxt.Arch, uint64(nbucket))
- s.AddUint64(ctxt.Arch, uint64(nsym))
- for i := 0; i < nbucket; i++ {
- s.AddUint64(ctxt.Arch, uint64(buckets[i]))
- }
- for i := 0; i < nsym; i++ {
- s.AddUint64(ctxt.Arch, uint64(chain[i]))
- }
- } else {
- s.AddUint32(ctxt.Arch, uint32(nbucket))
- s.AddUint32(ctxt.Arch, uint32(nsym))
- for i := 0; i < nbucket; i++ {
- s.AddUint32(ctxt.Arch, buckets[i])
- }
- for i := 0; i < nsym; i++ {
- s.AddUint32(ctxt.Arch, chain[i])
- }
- }
-
- // version symbols
- dynstr := ctxt.Syms.Lookup(".dynstr", 0)
-
- s = ctxt.Syms.Lookup(".gnu.version_r", 0)
- i = 2
- nfile := 0
- for l := needlib; l != nil; l = l.next {
- nfile++
-
- // header
- s.AddUint16(ctxt.Arch, 1) // table version
- j := 0
- for x := l.aux; x != nil; x = x.next {
- j++
- }
- s.AddUint16(ctxt.Arch, uint16(j)) // aux count
- s.AddUint32(ctxt.Arch, uint32(Addstring(dynstr, l.file))) // file string offset
- s.AddUint32(ctxt.Arch, 16) // offset from header to first aux
- if l.next != nil {
- s.AddUint32(ctxt.Arch, 16+uint32(j)*16) // offset from this header to next
- } else {
- s.AddUint32(ctxt.Arch, 0)
- }
-
- for x := l.aux; x != nil; x = x.next {
- x.num = i
- i++
-
- // aux struct
- s.AddUint32(ctxt.Arch, elfhash(x.vers)) // hash
- s.AddUint16(ctxt.Arch, 0) // flags
- s.AddUint16(ctxt.Arch, uint16(x.num)) // other - index we refer to this by
- s.AddUint32(ctxt.Arch, uint32(Addstring(dynstr, x.vers))) // version string offset
- if x.next != nil {
- s.AddUint32(ctxt.Arch, 16) // offset from this aux to next
- } else {
- s.AddUint32(ctxt.Arch, 0)
- }
- }
- }
-
- // version references
- s = ctxt.Syms.Lookup(".gnu.version", 0)
-
- for i := 0; i < nsym; i++ {
- if i == 0 {
- s.AddUint16(ctxt.Arch, 0) // first entry - no symbol
- } else if need[i] == nil {
- s.AddUint16(ctxt.Arch, 1) // global
- } else {
- s.AddUint16(ctxt.Arch, uint16(need[i].num))
- }
- }
-
- s = ctxt.Syms.Lookup(".dynamic", 0)
- elfverneed = nfile
- if elfverneed != 0 {
- elfWriteDynEntSym(ctxt.Arch, s, DT_VERNEED, ctxt.Syms.Lookup(".gnu.version_r", 0))
- elfWriteDynEnt(ctxt.Arch, s, DT_VERNEEDNUM, uint64(nfile))
- elfWriteDynEntSym(ctxt.Arch, s, DT_VERSYM, ctxt.Syms.Lookup(".gnu.version", 0))
- }
-
- sy := ctxt.Syms.Lookup(elfRelType+".plt", 0)
- if sy.Size > 0 {
- if elfRelType == ".rela" {
- elfWriteDynEnt(ctxt.Arch, s, DT_PLTREL, DT_RELA)
- } else {
- elfWriteDynEnt(ctxt.Arch, s, DT_PLTREL, DT_REL)
- }
- elfWriteDynEntSymSize(ctxt.Arch, s, DT_PLTRELSZ, sy)
- elfWriteDynEntSym(ctxt.Arch, s, DT_JMPREL, sy)
- }
-
- elfWriteDynEnt(ctxt.Arch, s, DT_NULL, 0)
-}
}
}
-func Adddynsym(target *Target, syms *ArchSyms, s *sym.Symbol) {
- if s.Dynid >= 0 || target.LinkMode == LinkExternal {
- return
- }
-
- if target.IsELF {
- elfadddynsym(target, syms, s)
- } else if target.HeadType == objabi.Hdarwin {
- Errorf(s, "adddynsym: missed symbol (Extname=%s)", s.Extname())
- } else if target.HeadType == objabi.Hwindows {
- // already taken care of
- } else {
- Errorf(s, "adddynsym: unsupported binary format")
- }
-}
-
func fieldtrack(arch *sys.Arch, l *loader.Loader) {
var buf bytes.Buffer
for i := loader.Sym(1); i < loader.Sym(l.NSym()); i++ {
cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
memprofile = flag.String("memprofile", "", "write memory profile to `file`")
memprofilerate = flag.Int64("memprofilerate", 0, "set runtime.MemProfileRate to `rate`")
- flagnewDoData = flag.Bool("newdodata", true, "New style dodata")
benchmarkFlag = flag.String("benchmark", "", "set to 'mem' or 'cpu' to enable phase benchmarking")
benchmarkFileFlag = flag.String("benchmarkprofile", "", "emit phase profiles to `base`_phase.{cpu,mem}prof")
dwarfGenerateDebugSyms(ctxt)
bench.Start("symtab")
symGroupType := ctxt.symtab()
- if *flagnewDoData {
- bench.Start("dodata")
- ctxt.dodata2(symGroupType)
- }
+ bench.Start("dodata")
+ ctxt.dodata2(symGroupType)
bench.Start("loadlibfull")
ctxt.loadlibfull(symGroupType) // XXX do it here for now
- if !*flagnewDoData {
- bench.Start("dodata")
- ctxt.dodata()
- }
bench.Start("address")
order := ctxt.address()
bench.Start("dwarfcompress")
+++ /dev/null
-// Copyright 2020 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 ppc64
-
-import (
- "cmd/internal/objabi"
- "cmd/link/internal/ld"
- "cmd/link/internal/loader"
- "cmd/link/internal/sym"
- "debug/elf"
-)
-
-// Temporary dumping ground for sym.Symbol version of helper
-// functions in asm.go, still being used for some oses.
-// FIXME: get rid of this file when dodata() is completely
-// converted.
-
-func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
- if target.IsElf() {
- return addelfdynrel(target, syms, s, r)
- } else if target.IsAIX() {
- return ld.Xcoffadddynrel(target, ldr, s, r)
- }
- return false
-}
-
-func addelfdynrel(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
- targ := r.Sym
- r.InitExt()
-
- switch r.Type {
- default:
- if r.Type >= objabi.ElfRelocOffset {
- ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type))
- return false
- }
-
- // Handle relocations found in ELF object files.
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL24):
- r.Type = objabi.R_CALLPOWER
-
- // This is a local call, so the caller isn't setting
- // up r12 and r2 is the same for the caller and
- // callee. Hence, we need to go to the local entry
- // point. (If we don't do this, the callee will try
- // to use r12 to compute r2.)
- r.Add += int64(r.Sym.Localentry()) * 4
-
- if targ.Type == sym.SDYNIMPORT {
- // Should have been handled in elfsetupplt
- ld.Errorf(s, "unexpected R_PPC64_REL24 for dyn import")
- }
-
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC_REL32):
- r.Type = objabi.R_PCREL
- r.Add += 4
-
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_PPC_REL32 for dyn import")
- }
-
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_ADDR64):
- r.Type = objabi.R_ADDR
- if targ.Type == sym.SDYNIMPORT {
- // These happen in .toc sections
- ld.Adddynsym(target, syms, targ)
-
- rela := syms.Rela
- rela.AddAddrPlus(target.Arch, s, int64(r.Off))
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(targ.Dynid), uint32(elf.R_PPC64_ADDR64)))
- rela.AddUint64(target.Arch, uint64(r.Add))
- r.Type = objabi.ElfRelocOffset // ignore during relocsym
- }
-
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16):
- r.Type = objabi.R_POWER_TOC
- r.Variant = sym.RV_POWER_LO | sym.RV_CHECK_OVERFLOW
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_LO):
- r.Type = objabi.R_POWER_TOC
- r.Variant = sym.RV_POWER_LO
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_HA):
- r.Type = objabi.R_POWER_TOC
- r.Variant = sym.RV_POWER_HA | sym.RV_CHECK_OVERFLOW
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_HI):
- r.Type = objabi.R_POWER_TOC
- r.Variant = sym.RV_POWER_HI | sym.RV_CHECK_OVERFLOW
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_DS):
- r.Type = objabi.R_POWER_TOC
- r.Variant = sym.RV_POWER_DS | sym.RV_CHECK_OVERFLOW
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_TOC16_LO_DS):
- r.Type = objabi.R_POWER_TOC
- r.Variant = sym.RV_POWER_DS
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL16_LO):
- r.Type = objabi.R_PCREL
- r.Variant = sym.RV_POWER_LO
- r.Add += 2 // Compensate for relocation size of 2
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL16_HI):
- r.Type = objabi.R_PCREL
- r.Variant = sym.RV_POWER_HI | sym.RV_CHECK_OVERFLOW
- r.Add += 2
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_PPC64_REL16_HA):
- r.Type = objabi.R_PCREL
- r.Variant = sym.RV_POWER_HA | sym.RV_CHECK_OVERFLOW
- r.Add += 2
- return true
- }
-
- // Handle references to ELF symbols from our own object files.
- if targ.Type != sym.SDYNIMPORT {
- return true
- }
-
- // TODO(austin): Translate our relocations to ELF
-
- return false
-}
Dwarfregsp: dwarfRegSP,
Dwarfreglr: dwarfRegLR,
- Adddynrel: adddynrel,
Adddynrel2: adddynrel2,
Archinit: archinit,
Archreloc: archreloc,
+++ /dev/null
-// Copyright 2020 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 s390x
-
-import (
- "cmd/internal/objabi"
- "cmd/link/internal/ld"
- "cmd/link/internal/loader"
- "cmd/link/internal/sym"
- "debug/elf"
-)
-
-func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
- targ := r.Sym
- r.InitExt()
-
- switch r.Type {
- default:
- if r.Type >= objabi.ElfRelocOffset {
- ld.Errorf(s, "unexpected relocation type %d", r.Type)
- return false
- }
-
- // Handle relocations found in ELF object files.
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_12),
- objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT12):
- ld.Errorf(s, "s390x 12-bit relocations have not been implemented (relocation type %d)", r.Type-objabi.ElfRelocOffset)
- return false
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_8),
- objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_16),
- objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_32),
- objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_64):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_390_nn relocation for dynamic symbol %s", targ.Name)
- }
- r.Type = objabi.R_ADDR
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC16),
- objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC32),
- objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC64):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_390_PCnn relocation for dynamic symbol %s", targ.Name)
- }
- // TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
- // sense and should be removed when someone has thought about it properly.
- if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
- ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
- }
- r.Type = objabi.R_PCREL
- r.Add += int64(r.Siz)
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT16),
- objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT32),
- objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOT64):
- ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-objabi.ElfRelocOffset)
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT16DBL),
- objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT32DBL):
- r.Type = objabi.R_PCREL
- r.Variant = sym.RV_390_DBL
- r.Add += int64(r.Siz)
- if targ.Type == sym.SDYNIMPORT {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add += int64(targ.Plt())
- }
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT32),
- objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PLT64):
- r.Type = objabi.R_PCREL
- r.Add += int64(r.Siz)
- if targ.Type == sym.SDYNIMPORT {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add += int64(targ.Plt())
- }
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_COPY):
- ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-objabi.ElfRelocOffset)
- return false
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GLOB_DAT):
- ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-objabi.ElfRelocOffset)
- return false
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_JMP_SLOT):
- ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-objabi.ElfRelocOffset)
- return false
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_RELATIVE):
- ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-objabi.ElfRelocOffset)
- return false
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTOFF):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_390_GOTOFF relocation for dynamic symbol %s", targ.Name)
- }
- r.Type = objabi.R_GOTOFF
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTPC):
- r.Type = objabi.R_PCREL
- r.Sym = syms.GOT
- r.Add += int64(r.Siz)
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC16DBL),
- objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_PC32DBL):
- r.Type = objabi.R_PCREL
- r.Variant = sym.RV_390_DBL
- r.Add += int64(r.Siz)
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_390_PCnnDBL relocation for dynamic symbol %s", targ.Name)
- }
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTPCDBL):
- r.Type = objabi.R_PCREL
- r.Variant = sym.RV_390_DBL
- r.Sym = syms.GOT
- r.Add += int64(r.Siz)
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_390_GOTENT):
- addgotsym(target, syms, targ)
-
- r.Type = objabi.R_PCREL
- r.Variant = sym.RV_390_DBL
- r.Sym = syms.GOT
- r.Add += int64(targ.Got())
- r.Add += int64(r.Siz)
- return true
- }
- // Handle references to ELF symbols from our own object files.
- if targ.Type != sym.SDYNIMPORT {
- return true
- }
-
- return false
-}
-
-func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Plt() >= 0 {
- return
- }
-
- ld.Adddynsym(target, syms, s)
-
- if target.IsElf() {
- plt := syms.PLT
- got := syms.GOT
- rela := syms.RelaPLT
- if plt.Size == 0 {
- panic("plt is not set up")
- }
- // larl %r1,_GLOBAL_OFFSET_TABLE_+index
-
- plt.AddUint8(0xc0)
- plt.AddUint8(0x10)
- plt.AddPCRelPlus(target.Arch, got, got.Size+6) // need variant?
-
- // add to got: pointer to current pos in plt
- got.AddAddrPlus(target.Arch, plt, plt.Size+8) // weird but correct
- // lg %r1,0(%r1)
- plt.AddUint8(0xe3)
- plt.AddUint8(0x10)
- plt.AddUint8(0x10)
- plt.AddUint8(0x00)
- plt.AddUint8(0x00)
- plt.AddUint8(0x04)
- // br %r1
- plt.AddUint8(0x07)
- plt.AddUint8(0xf1)
- // basr %r1,%r0
- plt.AddUint8(0x0d)
- plt.AddUint8(0x10)
- // lgf %r1,12(%r1)
- plt.AddUint8(0xe3)
- plt.AddUint8(0x10)
- plt.AddUint8(0x10)
- plt.AddUint8(0x0c)
- plt.AddUint8(0x00)
- plt.AddUint8(0x14)
- // jg .plt
- plt.AddUint8(0xc0)
- plt.AddUint8(0xf4)
-
- plt.AddUint32(target.Arch, uint32(-((plt.Size - 2) >> 1))) // roll-your-own relocation
- //.plt index
- plt.AddUint32(target.Arch, uint32(rela.Size)) // rela size before current entry
-
- // rela
- rela.AddAddrPlus(target.Arch, got, got.Size-8)
-
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_390_JMP_SLOT)))
- rela.AddUint64(target.Arch, 0)
-
- s.SetPlt(int32(plt.Size - 32))
-
- } else {
- ld.Errorf(s, "addpltsym: unsupported binary format")
- }
-}
-
-func addgotsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Got() >= 0 {
- return
- }
-
- ld.Adddynsym(target, syms, s)
- got := syms.GOT
- s.SetGot(int32(got.Size))
- got.AddUint64(target.Arch, 0)
-
- if target.IsElf() {
- rela := syms.Rela
- rela.AddAddrPlus(target.Arch, got, int64(s.Got()))
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_390_GLOB_DAT)))
- rela.AddUint64(target.Arch, 0)
- } else {
- ld.Errorf(s, "addgotsym: unsupported binary format")
- }
-}
Dwarfregsp: dwarfRegSP,
Dwarfreglr: dwarfRegLR,
- Adddynrel: adddynrel,
Adddynrel2: adddynrel2,
Archinit: archinit,
Archreloc: archreloc,
+++ /dev/null
-// Copyright 2020 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 x86
-
-import (
- "cmd/internal/objabi"
- "cmd/link/internal/ld"
- "cmd/link/internal/loader"
- "cmd/link/internal/sym"
- "debug/elf"
-)
-
-// Temporary dumping around for sym.Symbol version of helper
-// functions in asm.go, still being used for some oses.
-// FIXME: get rid of this file when dodata() is completely
-// converted.
-
-func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
- targ := r.Sym
-
- switch r.Type {
- default:
- if r.Type >= objabi.ElfRelocOffset {
- ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(target.Arch, r.Type))
- return false
- }
-
- // Handle relocations found in ELF object files.
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_PC32):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_386_PC32 relocation for dynamic symbol %s", targ.Name)
- }
- // TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
- // sense and should be removed when someone has thought about it properly.
- if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
- ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
- }
- r.Type = objabi.R_PCREL
- r.Add += 4
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_PLT32):
- r.Type = objabi.R_PCREL
- r.Add += 4
- if targ.Type == sym.SDYNIMPORT {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add += int64(targ.Plt())
- }
-
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32),
- objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32X):
- if targ.Type != sym.SDYNIMPORT {
- // have symbol
- if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
- // turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
- s.P[r.Off-2] = 0x8d
-
- r.Type = objabi.R_GOTOFF
- return true
- }
-
- if r.Off >= 2 && s.P[r.Off-2] == 0xff && s.P[r.Off-1] == 0xb3 {
- // turn PUSHL of GOT entry into PUSHL of symbol itself.
- // use unnecessary SS prefix to keep instruction same length.
- s.P[r.Off-2] = 0x36
-
- s.P[r.Off-1] = 0x68
- r.Type = objabi.R_ADDR
- return true
- }
-
- ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
- return false
- }
-
- addgotsym(target, syms, targ)
- r.Type = objabi.R_CONST // write r->add during relocsym
- r.Sym = nil
- r.Add += int64(targ.Got())
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTOFF):
- r.Type = objabi.R_GOTOFF
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTPC):
- r.Type = objabi.R_PCREL
- r.Sym = syms.GOT
- r.Add += 4
- return true
-
- case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_32):
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected R_386_32 relocation for dynamic symbol %s", targ.Name)
- }
- r.Type = objabi.R_ADDR
- return true
-
- case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0:
- r.Type = objabi.R_ADDR
- if targ.Type == sym.SDYNIMPORT {
- ld.Errorf(s, "unexpected reloc for dynamic symbol %s", targ.Name)
- }
- return true
-
- case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1:
- if targ.Type == sym.SDYNIMPORT {
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add = int64(targ.Plt())
- r.Type = objabi.R_PCREL
- return true
- }
-
- r.Type = objabi.R_PCREL
- return true
-
- case objabi.MachoRelocOffset + ld.MACHO_FAKE_GOTPCREL:
- if targ.Type != sym.SDYNIMPORT {
- // have symbol
- // turn MOVL of GOT entry into LEAL of symbol itself
- if r.Off < 2 || s.P[r.Off-2] != 0x8b {
- ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
- return false
- }
-
- s.P[r.Off-2] = 0x8d
- r.Type = objabi.R_PCREL
- return true
- }
-
- addgotsym(target, syms, targ)
- r.Sym = syms.GOT
- r.Add += int64(targ.Got())
- r.Type = objabi.R_PCREL
- return true
- }
-
- // Handle references to ELF symbols from our own object files.
- if targ.Type != sym.SDYNIMPORT {
- return true
- }
- switch r.Type {
- case objabi.R_CALL,
- objabi.R_PCREL:
- if target.IsExternal() {
- // External linker will do this relocation.
- return true
- }
- addpltsym(target, syms, targ)
- r.Sym = syms.PLT
- r.Add = int64(targ.Plt())
- return true
-
- case objabi.R_ADDR:
- if s.Type != sym.SDATA {
- break
- }
- if target.IsElf() {
- ld.Adddynsym(target, syms, targ)
- rel := syms.Rel
- rel.AddAddrPlus(target.Arch, s, int64(r.Off))
- rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(targ.Dynid), uint32(elf.R_386_32)))
- r.Type = objabi.R_CONST // write r->add during relocsym
- r.Sym = nil
- return true
- }
-
- if target.IsDarwin() && s.Size == int64(target.Arch.PtrSize) && r.Off == 0 {
- // Mach-O relocations are a royal pain to lay out.
- // They use a compact stateful bytecode representation
- // that is too much bother to deal with.
- // Instead, interpret the C declaration
- // void *_Cvar_stderr = &stderr;
- // as making _Cvar_stderr the name of a GOT entry
- // for stderr. This is separate from the usual GOT entry,
- // just in case the C code assigns to the variable,
- // and of course it only works for single pointers,
- // but we only need to support cgo and that's all it needs.
- ld.Adddynsym(target, syms, targ)
-
- got := syms.GOT
- s.Type = got.Type
- s.Attr |= sym.AttrSubSymbol
- s.Outer = got
- s.Sub = got.Sub
- got.Sub = s
- s.Value = got.Size
- got.AddUint32(target.Arch, 0)
- syms.LinkEditGOT.AddUint32(target.Arch, uint32(targ.Dynid))
- r.Type = objabi.ElfRelocOffset // ignore during relocsym
- return true
- }
- }
-
- return false
-}
-
-func addpltsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Plt() >= 0 {
- return
- }
-
- ld.Adddynsym(target, syms, s)
-
- if target.IsElf() {
- plt := syms.PLT
- got := syms.GOTPLT
- rel := syms.RelPLT
- if plt.Size == 0 {
- panic("plt is not set up")
- }
-
- // jmpq *got+size
- plt.AddUint8(0xff)
-
- plt.AddUint8(0x25)
- plt.AddAddrPlus(target.Arch, got, got.Size)
-
- // add to got: pointer to current pos in plt
- got.AddAddrPlus(target.Arch, plt, plt.Size)
-
- // pushl $x
- plt.AddUint8(0x68)
-
- plt.AddUint32(target.Arch, uint32(rel.Size))
-
- // jmp .plt
- plt.AddUint8(0xe9)
-
- plt.AddUint32(target.Arch, uint32(-(plt.Size + 4)))
-
- // rel
- rel.AddAddrPlus(target.Arch, got, got.Size-4)
-
- rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_386_JMP_SLOT)))
-
- s.SetPlt(int32(plt.Size - 16))
- } else if target.IsDarwin() {
- // Same laziness as in 6l.
-
- plt := syms.PLT
-
- addgotsym(target, syms, s)
-
- syms.LinkEditPLT.AddUint32(target.Arch, uint32(s.Dynid))
-
- // jmpq *got+size(IP)
- s.SetPlt(int32(plt.Size))
-
- plt.AddUint8(0xff)
- plt.AddUint8(0x25)
- plt.AddAddrPlus(target.Arch, syms.GOT, int64(s.Got()))
- } else {
- ld.Errorf(s, "addpltsym: unsupported binary format")
- }
-}
-
-func addgotsym(target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol) {
- if s.Got() >= 0 {
- return
- }
-
- ld.Adddynsym(target, syms, s)
- got := syms.GOT
- s.SetGot(int32(got.Size))
- got.AddUint32(target.Arch, 0)
-
- if target.IsElf() {
- rel := syms.Rel
- rel.AddAddrPlus(target.Arch, got, int64(s.Got()))
- rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_386_GLOB_DAT)))
- } else if target.IsDarwin() {
- syms.LinkEditGOT.AddUint32(target.Arch, uint32(s.Dynid))
- } else {
- ld.Errorf(s, "addgotsym: unsupported binary format")
- }
-}
Dwarfregsp: dwarfRegSP,
Dwarfreglr: dwarfRegLR,
- Adddynrel: adddynrel,
Adddynrel2: adddynrel2,
Archinit: archinit,
Archreloc: archreloc,