summaryrefslogtreecommitdiff
path: root/src/cmd/link
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/link')
-rw-r--r--src/cmd/link/dwarf_test.go10
-rw-r--r--src/cmd/link/internal/amd64/asm.go69
-rw-r--r--src/cmd/link/internal/arm/asm.go4
-rw-r--r--src/cmd/link/internal/arm64/asm.go165
-rw-r--r--src/cmd/link/internal/arm64/obj.go2
-rw-r--r--src/cmd/link/internal/ld/config.go25
-rw-r--r--src/cmd/link/internal/ld/data.go7
-rw-r--r--src/cmd/link/internal/ld/deadcode.go6
-rw-r--r--src/cmd/link/internal/ld/dwarf_test.go17
-rw-r--r--src/cmd/link/internal/ld/elf.go1143
-rw-r--r--src/cmd/link/internal/ld/go.go3
-rw-r--r--src/cmd/link/internal/ld/ld_test.go77
-rw-r--r--src/cmd/link/internal/ld/lib.go55
-rw-r--r--src/cmd/link/internal/ld/macho.go340
-rw-r--r--src/cmd/link/internal/ld/main.go26
-rw-r--r--src/cmd/link/internal/ld/pcln.go17
-rw-r--r--src/cmd/link/internal/ld/symtab.go75
-rw-r--r--src/cmd/link/internal/loader/loader.go13
-rw-r--r--src/cmd/link/internal/loader/symbolbuilder.go18
-rw-r--r--src/cmd/link/internal/loadmacho/ldmacho.go57
-rw-r--r--src/cmd/link/internal/mips64/obj.go5
-rw-r--r--src/cmd/link/internal/ppc64/asm.go7
-rw-r--r--src/cmd/link/internal/riscv64/asm.go163
-rw-r--r--src/cmd/link/internal/riscv64/obj.go3
-rw-r--r--src/cmd/link/internal/s390x/asm.go2
-rw-r--r--src/cmd/link/internal/x86/asm.go4
-rw-r--r--src/cmd/link/link_test.go56
27 files changed, 1380 insertions, 989 deletions
diff --git a/src/cmd/link/dwarf_test.go b/src/cmd/link/dwarf_test.go
index 88480064dd..db710bed6a 100644
--- a/src/cmd/link/dwarf_test.go
+++ b/src/cmd/link/dwarf_test.go
@@ -195,14 +195,18 @@ func TestDWARFiOS(t *testing.T) {
}
// Check to see if the ios tools are installed. It's possible to have the command line tools
// installed without the iOS sdk.
- if output, err := exec.Command("xcodebuild -showsdks").CombinedOutput(); err != nil {
+ if output, err := exec.Command("xcodebuild", "-showsdks").CombinedOutput(); err != nil {
t.Skipf("error running xcodebuild, required for iOS cross build: %v", err)
} else if !strings.Contains(string(output), "iOS SDK") {
t.Skipf("iOS SDK not detected.")
}
cc := "CC=" + runtime.GOROOT() + "/misc/ios/clangwrap.sh"
// iOS doesn't allow unmapped segments, so iOS executables don't have DWARF.
- testDWARF(t, "", false, cc, "CGO_ENABLED=1", "GOOS=darwin", "GOARCH=arm64")
+ t.Run("exe", func(t *testing.T) {
+ testDWARF(t, "", false, cc, "CGO_ENABLED=1", "GOOS=ios", "GOARCH=arm64")
+ })
// However, c-archive iOS objects have embedded DWARF.
- testDWARF(t, "c-archive", true, cc, "CGO_ENABLED=1", "GOOS=darwin", "GOARCH=arm64")
+ t.Run("c-archive", func(t *testing.T) {
+ testDWARF(t, "c-archive", true, cc, "CGO_ENABLED=1", "GOOS=ios", "GOARCH=arm64")
+ })
}
diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go
index e5a6ef51b0..360c5338ba 100644
--- a/src/cmd/link/internal/amd64/asm.go
+++ b/src/cmd/link/internal/amd64/asm.go
@@ -76,9 +76,9 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
targType = ldr.SymType(targ)
}
- switch r.Type() {
+ switch rt := r.Type(); rt {
default:
- if r.Type() >= objabi.ElfRelocOffset {
+ if rt >= objabi.ElfRelocOffset {
ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
return false
}
@@ -167,13 +167,24 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
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?
su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_ADDR)
if targType == sym.SDYNIMPORT {
ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ))
}
+ 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.
+ if rt == objabi.MachoRelocOffset+ld.MACHO_X86_64_RELOC_UNSIGNED*2 {
+ break
+ } else {
+ // MACHO_X86_64_RELOC_SIGNED or MACHO_X86_64_RELOC_BRANCH
+ // Can this happen? The object is expected to be PIC.
+ ldr.Errorf(s, "unsupported relocation for PIE: %v", rt)
+ }
+ }
return true
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1:
@@ -223,7 +234,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
if targType != sym.SDYNIMPORT {
ldr.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", ldr.SymName(targ))
}
- ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_X86_64_GLOB_DAT))
+ ld.AddGotSym(target, ldr, syms, targ, 0)
su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_PCREL)
su.SetRelocSym(rIdx, syms.GOT)
@@ -343,7 +354,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
rela := ldr.MakeSymbolUpdater(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)))
+ rela.AddUint64(target.Arch, elf.R_INFO(0, uint32(elf.R_X86_64_RELATIVE)))
} else {
ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
}
@@ -355,28 +366,15 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
return true
}
- if target.IsDarwin() && ldr.SymSize(s) == int64(target.Arch.PtrSize) && r.Off() == 0 {
+ if target.IsDarwin() {
// 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(ldr, target, syms, targ)
-
- got := ldr.MakeSymbolUpdater(syms.GOT)
- su := ldr.MakeSymbolUpdater(s)
- su.SetType(got.Type())
- got.AddInteriorSym(s)
- su.SetValue(got.Size())
- got.AddUint64(target.Arch, 0)
- leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT)
- leg.AddUint32(target.Arch, uint32(ldr.SymDynid(targ)))
- su.SetRelocType(rIdx, objabi.ElfRelocOffset) // ignore during relocsym
+ // They use a compact stateful bytecode representation.
+ // Here we record what are needed and encode them later.
+ ld.MachoAddRebase(s, int64(r.Off()))
+ // 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
}
}
@@ -622,31 +620,21 @@ func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
rela.AddAddrPlus(target.Arch, got.Sym(), got.Size()-8)
sDynid := ldr.SymDynid(s)
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(sDynid), uint32(elf.R_X86_64_JMP_SLOT)))
+ rela.AddUint64(target.Arch, elf.R_INFO(uint32(sDynid), uint32(elf.R_X86_64_JMP_SLOT)))
rela.AddUint64(target.Arch, 0)
ldr.SetPlt(s, 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.
-
- ld.AddGotSym(target, ldr, syms, s, uint32(elf.R_X86_64_GLOB_DAT))
- plt := ldr.MakeSymbolUpdater(syms.PLT)
+ ld.AddGotSym(target, ldr, syms, s, 0)
sDynid := ldr.SymDynid(s)
lep := ldr.MakeSymbolUpdater(syms.LinkEditPLT)
lep.AddUint32(target.Arch, uint32(sDynid))
- // jmpq *got+size(IP)
+ plt := ldr.MakeSymbolUpdater(syms.PLT)
ldr.SetPlt(s, int32(plt.Size()))
+ // jmpq *got+size(IP)
plt.AddUint8(0xff)
plt.AddUint8(0x25)
plt.AddPCRelPlus(target.Arch, syms.GOT, int64(ldr.SymGot(s)))
@@ -654,6 +642,7 @@ func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
ldr.Errorf(s, "addpltsym: unsupported binary format")
}
}
+
func tlsIEtoLE(P []byte, off, size int) {
// Transform the PC-relative instruction into a constant load.
// That is,
diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go
index 611c96ce35..755b472694 100644
--- a/src/cmd/link/internal/arm/asm.go
+++ b/src/cmd/link/internal/arm/asm.go
@@ -231,7 +231,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
ld.Adddynsym(ldr, target, syms, targ)
rel := ldr.MakeSymbolUpdater(syms.Rel)
rel.AddAddrPlus(target.Arch, s, int64(r.Off()))
- rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(targ)), uint32(elf.R_ARM_GLOB_DAT))) // we need a nil + A dynamic reloc
+ rel.AddUint32(target.Arch, elf.R_INFO32(uint32(ldr.SymDynid(targ)), uint32(elf.R_ARM_GLOB_DAT))) // we need a nil + A dynamic reloc
su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_CONST) // write r->add during relocsym
su.SetRelocSym(rIdx, 0)
@@ -629,7 +629,7 @@ func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
// rel
rel.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
- rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_ARM_JUMP_SLOT)))
+ rel.AddUint32(target.Arch, elf.R_INFO32(uint32(ldr.SymDynid(s)), uint32(elf.R_ARM_JUMP_SLOT)))
} else {
ldr.Errorf(s, "addpltsym: unsupported binary format")
}
diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go
index 945b83822c..cb16180657 100644
--- a/src/cmd/link/internal/arm64/asm.go
+++ b/src/cmd/link/internal/arm64/asm.go
@@ -71,13 +71,13 @@ func gentext(ctxt *ld.Link, ldr *loader.Loader) {
}
func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool {
-
targ := r.Sym()
var targType sym.SymKind
if targ != 0 {
targType = ldr.SymType(targ)
}
+ const pcrel = 1
switch r.Type() {
default:
if r.Type() >= objabi.ElfRelocOffset {
@@ -201,6 +201,75 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_ARM64_LDST128)
return true
+
+ // Handle relocations found in Mach-O object files.
+ case objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_UNSIGNED*2:
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ))
+ }
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, 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.MachoRelocOffset + ld.MACHO_ARM64_RELOC_BRANCH26*2 + pcrel:
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_CALLARM64)
+ if targType == sym.SDYNIMPORT {
+ addpltsym(target, ldr, syms, targ)
+ su.SetRelocSym(rIdx, syms.PLT)
+ su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
+ }
+ return true
+
+ case objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_PAGE21*2 + pcrel,
+ objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_PAGEOFF12*2:
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
+ }
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_ARM64_PCREL)
+ return true
+
+ case objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGE21*2 + pcrel,
+ objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12*2:
+ if targType != sym.SDYNIMPORT {
+ // have symbol
+ // turn MOVD sym@GOT (adrp+ldr) into MOVD $sym (adrp+add)
+ data := ldr.Data(s)
+ off := r.Off()
+ if int(off+3) >= len(data) {
+ ldr.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", ldr.SymName(targ))
+ return false
+ }
+ o := target.Arch.ByteOrder.Uint32(data[off:])
+ su := ldr.MakeSymbolUpdater(s)
+ switch {
+ case (o>>24)&0x9f == 0x90: // adrp
+ // keep instruction unchanged, change relocation type below
+ case o>>24 == 0xf9: // ldr
+ // rewrite to add
+ o = (0x91 << 24) | (o & (1<<22 - 1))
+ su.MakeWritable()
+ su.SetUint32(target.Arch, int64(off), o)
+ default:
+ ldr.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", ldr.SymName(targ))
+ return false
+ }
+ su.SetRelocType(rIdx, objabi.R_ARM64_PCREL)
+ return true
+ }
+ ld.AddGotSym(target, ldr, syms, targ, 0)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_ARM64_GOT)
+ su.SetRelocSym(rIdx, syms.GOT)
+ su.SetRelocAdd(rIdx, int64(ldr.SymGot(targ)))
+ return true
}
// Reread the reloc to incorporate any changes in type above.
@@ -219,6 +288,16 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
// External linker will do this relocation.
return true
}
+ // Internal linking.
+ if r.Add() != 0 {
+ ldr.Errorf(s, "PLT call with non-zero addend (%v)", r.Add())
+ }
+ // Build a PLT entry and change the relocation target to that entry.
+ addpltsym(target, ldr, syms, targ)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocSym(rIdx, syms.PLT)
+ su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
+ return true
case objabi.R_ADDR:
if ldr.SymType(s) == sym.STEXT && target.IsElf() {
@@ -302,7 +381,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
rela := ldr.MakeSymbolUpdater(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)))
+ rela.AddUint64(target.Arch, elf.R_INFO(0, uint32(elf.R_AARCH64_RELATIVE)))
} else {
ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
}
@@ -313,6 +392,18 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
// (e.g. go version).
return true
}
+
+ if target.IsDarwin() {
+ // Mach-O relocations are a royal pain to lay out.
+ // They use a compact stateful bytecode representation.
+ // Here we record what are needed and encode them later.
+ ld.MachoAddRebase(s, int64(r.Off()))
+ // 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
}
@@ -371,7 +462,7 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sy
rt := r.Type
siz := r.Size
- if ldr.SymType(rs) == sym.SHOSTOBJ || rt == objabi.R_CALLARM64 || rt == objabi.R_ADDRARM64 {
+ if ldr.SymType(rs) == sym.SHOSTOBJ || rt == objabi.R_CALLARM64 || rt == objabi.R_ADDRARM64 || rt == objabi.R_ARM64_GOTPCREL {
if ldr.SymDynid(rs) < 0 {
ldr.Errorf(s, "reloc %d (%s) to non-macho symbol %s type=%d (%s)", rt, sym.RelocName(arch, rt), ldr.SymName(rs), ldr.SymType(rs), ldr.SymType(rs))
return false
@@ -415,6 +506,22 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sy
}
v |= 1 << 24 // pc-relative bit
v |= ld.MACHO_ARM64_RELOC_PAGE21 << 28
+ case objabi.R_ARM64_GOTPCREL:
+ siz = 4
+ // Two relocation entries: MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12 MACHO_ARM64_RELOC_GOT_LOAD_PAGE21
+ // if r.Xadd is non-zero, add two MACHO_ARM64_RELOC_ADDEND.
+ if r.Xadd != 0 {
+ out.Write32(uint32(sectoff + 4))
+ out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(r.Xadd&0xffffff))
+ }
+ out.Write32(uint32(sectoff + 4))
+ out.Write32(v | (ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12 << 28) | (2 << 25))
+ if r.Xadd != 0 {
+ out.Write32(uint32(sectoff))
+ out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(r.Xadd&0xffffff))
+ }
+ v |= 1 << 24 // pc-relative bit
+ v |= ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGE21 << 28
}
switch siz {
@@ -457,7 +564,7 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
}
nExtReloc = 2 // need two ELF/Mach-O relocations. see elfreloc1/machoreloc1
- if target.IsDarwin() && rt == objabi.R_ADDRARM64 && xadd != 0 {
+ if target.IsDarwin() && xadd != 0 {
nExtReloc = 4 // need another two relocations for non-zero addend
}
@@ -633,14 +740,28 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
}
o0 := (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
return val | int64(o0), noExtReloc, isOk
- } else if (val>>24)&0x91 == 0x91 {
- // R_AARCH64_ADD_ABS_LO12_NC
+ } else if (val>>24)&0x9f == 0x91 {
+ // ELF R_AARCH64_ADD_ABS_LO12_NC or Mach-O ARM64_RELOC_PAGEOFF12
// patch instruction: add
t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
o1 := uint32(t&0xfff) << 10
return val | int64(o1), noExtReloc, isOk
+ } else if (val>>24)&0x3b == 0x39 {
+ // Mach-O ARM64_RELOC_PAGEOFF12
+ // patch ldr/str(b/h/w/d/q) (integer or vector) instructions, which have different scaling factors.
+ // Mach-O uses same relocation type for them.
+ shift := uint32(val) >> 30
+ if shift == 0 && (val>>20)&0x048 == 0x048 { // 128-bit vector load
+ shift = 4
+ }
+ t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
+ if t&(1<<shift-1) != 0 {
+ ldr.Errorf(s, "invalid address: %x for relocation type: ARM64_RELOC_PAGEOFF12", t)
+ }
+ o1 := (uint32(t&0xfff) >> shift) << 10
+ return val | int64(o1), noExtReloc, isOk
} else {
- ldr.Errorf(s, "unsupported instruction for %x R_PCRELARM64", val)
+ ldr.Errorf(s, "unsupported instruction for %x R_ARM64_PCREL", val)
}
case objabi.R_ARM64_LDST8:
@@ -792,10 +913,38 @@ func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
rela.AddAddrPlus(target.Arch, gotplt.Sym(), gotplt.Size()-8)
sDynid := ldr.SymDynid(s)
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(sDynid), uint32(elf.R_AARCH64_JUMP_SLOT)))
+ rela.AddUint64(target.Arch, elf.R_INFO(uint32(sDynid), uint32(elf.R_AARCH64_JUMP_SLOT)))
rela.AddUint64(target.Arch, 0)
ldr.SetPlt(s, int32(plt.Size()-16))
+ } else if target.IsDarwin() {
+ ld.AddGotSym(target, ldr, syms, s, 0)
+
+ sDynid := ldr.SymDynid(s)
+ lep := ldr.MakeSymbolUpdater(syms.LinkEditPLT)
+ lep.AddUint32(target.Arch, uint32(sDynid))
+
+ plt := ldr.MakeSymbolUpdater(syms.PLT)
+ ldr.SetPlt(s, int32(plt.Size()))
+
+ // adrp x16, GOT
+ plt.AddUint32(target.Arch, 0x90000010)
+ r, _ := plt.AddRel(objabi.R_ARM64_GOT)
+ r.SetOff(int32(plt.Size() - 4))
+ r.SetSiz(4)
+ r.SetSym(syms.GOT)
+ r.SetAdd(int64(ldr.SymGot(s)))
+
+ // ldr x17, [x16, <offset>]
+ plt.AddUint32(target.Arch, 0xf9400211)
+ r, _ = plt.AddRel(objabi.R_ARM64_GOT)
+ r.SetOff(int32(plt.Size() - 4))
+ r.SetSiz(4)
+ r.SetSym(syms.GOT)
+ r.SetAdd(int64(ldr.SymGot(s)))
+
+ // br x17
+ plt.AddUint32(target.Arch, 0xd61f0220)
} else {
ldr.Errorf(s, "addpltsym: unsupported binary format")
}
diff --git a/src/cmd/link/internal/arm64/obj.go b/src/cmd/link/internal/arm64/obj.go
index a980cfee52..ab3dfd99f7 100644
--- a/src/cmd/link/internal/arm64/obj.go
+++ b/src/cmd/link/internal/arm64/obj.go
@@ -102,7 +102,7 @@ func archinit(ctxt *ld.Link) {
case objabi.Hdarwin: /* apple MACH */
ld.HEADR = ld.INITIAL_MACHO_HEADR
if *ld.FlagTextAddr == -1 {
- *ld.FlagTextAddr = 4096 + int64(ld.HEADR)
+ *ld.FlagTextAddr = 1<<32 + int64(ld.HEADR)
}
if *ld.FlagRound == -1 {
*ld.FlagRound = 16384 // 16K page alignment
diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go
index 9aa59fa3e3..54a94cebba 100644
--- a/src/cmd/link/internal/ld/config.go
+++ b/src/cmd/link/internal/ld/config.go
@@ -35,11 +35,15 @@ func (mode *BuildMode) Set(s string) error {
default:
return fmt.Errorf("invalid buildmode: %q", s)
case "exe":
+ if objabi.GOOS == "darwin" && objabi.GOARCH == "arm64" {
+ *mode = BuildModePIE // On darwin/arm64 everything is PIE.
+ break
+ }
*mode = BuildModeExe
case "pie":
switch objabi.GOOS {
- case "aix", "android", "linux", "windows":
- case "darwin", "freebsd":
+ case "aix", "android", "linux", "windows", "darwin", "ios":
+ case "freebsd":
switch objabi.GOARCH {
case "amd64":
default:
@@ -95,7 +99,13 @@ func (mode *BuildMode) Set(s string) error {
default:
return badmode()
}
- case "darwin", "freebsd":
+ case "darwin":
+ switch objabi.GOARCH {
+ case "amd64", "arm64":
+ default:
+ return badmode()
+ }
+ case "freebsd":
switch objabi.GOARCH {
case "amd64":
default:
@@ -175,7 +185,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
}()
}
- if sys.MustLinkExternal(objabi.GOOS, objabi.GOARCH) {
+ if sys.MustLinkExternal(objabi.GOOS, objabi.GOARCH) && !(objabi.GOOS == "darwin" && objabi.GOARCH == "arm64") { // XXX allow internal linking for darwin/arm64 but not change the default
return true, fmt.Sprintf("%s/%s requires external linking", objabi.GOOS, objabi.GOARCH)
}
@@ -186,7 +196,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
// Internally linking cgo is incomplete on some architectures.
// https://golang.org/issue/14449
// https://golang.org/issue/21961
- if iscgo && ctxt.Arch.InFamily(sys.MIPS64, sys.MIPS, sys.PPC64) {
+ if iscgo && ctxt.Arch.InFamily(sys.MIPS64, sys.MIPS, sys.PPC64, sys.RISCV64) {
return true, objabi.GOARCH + " does not support internal cgo"
}
if iscgo && objabi.GOOS == "android" {
@@ -210,6 +220,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
switch objabi.GOOS + "/" + objabi.GOARCH {
case "linux/amd64", "linux/arm64", "android/arm64":
case "windows/386", "windows/amd64", "windows/arm":
+ case "darwin/amd64", "darwin/arm64":
default:
// Internal linking does not support TLS_IE.
return true, "buildmode=pie"
@@ -250,6 +261,8 @@ func determineLinkMode(ctxt *Link) {
default:
if extNeeded || (iscgo && externalobj) {
ctxt.LinkMode = LinkExternal
+ } else if ctxt.IsDarwin() && ctxt.IsARM64() {
+ ctxt.LinkMode = LinkExternal // default to external linking for now
} else {
ctxt.LinkMode = LinkInternal
}
@@ -263,8 +276,6 @@ func determineLinkMode(ctxt *Link) {
}
case LinkExternal:
switch {
- case objabi.GOARCH == "riscv64":
- Exitf("external linking not supported for %s/riscv64", objabi.GOOS)
case objabi.GOARCH == "ppc64" && objabi.GOOS != "aix":
Exitf("external linking not supported for %s/ppc64", objabi.GOOS)
}
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index 3cd7b4ad0b..00130044ab 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -951,6 +951,9 @@ func writeBlock(ctxt *Link, out *OutBuf, ldr *loader.Loader, syms []loader.Sym,
}
P := out.WriteSym(ldr, s)
st.relocsym(s, P)
+ if f, ok := ctxt.generatorSyms[s]; ok {
+ f(ctxt, s)
+ }
addr += int64(len(P))
siz := ldr.SymSize(s)
if addr < val+siz {
@@ -2188,7 +2191,7 @@ func (ctxt *Link) textaddress() {
ctxt.Textp[0] = text
}
- va := uint64(*FlagTextAddr)
+ va := uint64(Rnd(*FlagTextAddr, int64(Funcalign)))
n := 1
sect.Vaddr = va
ntramps := 0
@@ -2214,7 +2217,7 @@ func (ctxt *Link) textaddress() {
// Set the address of the start/end symbols, if not already
// (i.e. not darwin+dynlink or AIX+external, see above).
ldr.SetSymValue(etext, int64(va))
- ldr.SetSymValue(text, *FlagTextAddr)
+ ldr.SetSymValue(text, int64(Segtext.Sections[0].Vaddr))
}
// merge tramps into Textp, keeping Textp in address order
diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go
index 74d61fa495..d8813fa936 100644
--- a/src/cmd/link/internal/ld/deadcode.go
+++ b/src/cmd/link/internal/ld/deadcode.go
@@ -62,6 +62,12 @@ func (d *deadcodePass) init() {
}
}
names = append(names, *flagEntrySymbol)
+ if !d.ctxt.linkShared && d.ctxt.BuildMode != BuildModePlugin {
+ // runtime.buildVersion and runtime.modinfo are referenced in .go.buildinfo section
+ // (see function buildinfo in data.go). They should normally be reachable from the
+ // runtime. Just make it explicit, in case.
+ names = append(names, "runtime.buildVersion", "runtime.modinfo")
+ }
if d.ctxt.BuildMode == BuildModePlugin {
names = append(names, objabi.PathToPrefix(*flagPluginPath)+"..inittask", objabi.PathToPrefix(*flagPluginPath)+".main", "go.plugin.tabs")
diff --git a/src/cmd/link/internal/ld/dwarf_test.go b/src/cmd/link/internal/ld/dwarf_test.go
index 22948521f5..a66506d392 100644
--- a/src/cmd/link/internal/ld/dwarf_test.go
+++ b/src/cmd/link/internal/ld/dwarf_test.go
@@ -238,6 +238,10 @@ func TestSizes(t *testing.T) {
if runtime.GOOS == "plan9" {
t.Skip("skipping on plan9; no DWARF symbol table in executables")
}
+
+ // External linking may bring in C symbols with unknown size. Skip.
+ testenv.MustInternalLink(t)
+
t.Parallel()
// DWARF sizes should never be -1.
@@ -919,6 +923,7 @@ func TestAbstractOriginSanityIssue26237(t *testing.T) {
func TestRuntimeTypeAttrInternal(t *testing.T) {
testenv.MustHaveGoBuild(t)
+ testenv.MustInternalLink(t)
if runtime.GOOS == "plan9" {
t.Skip("skipping on plan9; no DWARF symbol table in executables")
@@ -1018,6 +1023,9 @@ func main() {
t.Fatalf("*main.X DIE had no runtime type attr. DIE: %v", dies[0])
}
+ if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" {
+ return // everything is PIE on ARM64, addresses are relocated
+ }
if rtAttr.(uint64)+types.Addr != addr {
t.Errorf("DWARF type offset was %#x+%#x, but test program said %#x", rtAttr.(uint64), types.Addr, addr)
}
@@ -1203,6 +1211,15 @@ func main() {
}
}
+ // When external linking, we put all symbols in the symbol table (so the
+ // external linker can find them). Skip the symbol table check.
+ // TODO: maybe there is some way to tell the external linker not to put
+ // those symbols in the executable's symbol table? Prefix the symbol name
+ // with "." or "L" to pretend it is a label?
+ if !testenv.CanInternalLink() {
+ return
+ }
+
syms, err := f.Symbols()
if err != nil {
t.Fatalf("error reading symbols: %v", err)
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
index f5a2f899fc..37b2dc640d 100644
--- a/src/cmd/link/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -10,6 +10,7 @@ import (
"cmd/link/internal/loader"
"cmd/link/internal/sym"
"crypto/sha1"
+ "debug/elf"
"encoding/binary"
"encoding/hex"
"fmt"
@@ -75,255 +76,6 @@ type elfNote struct {
nType uint32
}
-const (
- EI_MAG0 = 0
- EI_MAG1 = 1
- EI_MAG2 = 2
- EI_MAG3 = 3
- EI_CLASS = 4
- EI_DATA = 5
- EI_VERSION = 6
- EI_OSABI = 7
- EI_ABIVERSION = 8
- OLD_EI_BRAND = 8
- EI_PAD = 9
- EI_NIDENT = 16
- ELFMAG0 = 0x7f
- ELFMAG1 = 'E'
- ELFMAG2 = 'L'
- ELFMAG3 = 'F'
- SELFMAG = 4
- EV_NONE = 0
- EV_CURRENT = 1
- ELFCLASSNONE = 0
- ELFCLASS32 = 1
- ELFCLASS64 = 2
- ELFDATANONE = 0
- ELFDATA2LSB = 1
- ELFDATA2MSB = 2
- ELFOSABI_NONE = 0
- ELFOSABI_HPUX = 1
- ELFOSABI_NETBSD = 2
- ELFOSABI_LINUX = 3
- ELFOSABI_HURD = 4
- ELFOSABI_86OPEN = 5
- ELFOSABI_SOLARIS = 6
- ELFOSABI_AIX = 7
- ELFOSABI_IRIX = 8
- ELFOSABI_FREEBSD = 9
- ELFOSABI_TRU64 = 10
- ELFOSABI_MODESTO = 11
- ELFOSABI_OPENBSD = 12
- ELFOSABI_OPENVMS = 13
- ELFOSABI_NSK = 14
- ELFOSABI_ARM = 97
- ELFOSABI_STANDALONE = 255
- ELFOSABI_SYSV = ELFOSABI_NONE
- ELFOSABI_MONTEREY = ELFOSABI_AIX
- ET_NONE = 0
- ET_REL = 1
- ET_EXEC = 2
- ET_DYN = 3
- ET_CORE = 4
- ET_LOOS = 0xfe00
- ET_HIOS = 0xfeff
- ET_LOPROC = 0xff00
- ET_HIPROC = 0xffff
- EM_NONE = 0
- EM_M32 = 1
- EM_SPARC = 2
- EM_386 = 3
- EM_68K = 4
- EM_88K = 5
- EM_860 = 7
- EM_MIPS = 8
- EM_S370 = 9
- EM_MIPS_RS3_LE = 10
- EM_PARISC = 15
- EM_VPP500 = 17
- EM_SPARC32PLUS = 18
- EM_960 = 19
- EM_PPC = 20
- EM_PPC64 = 21
- EM_S390 = 22
- EM_V800 = 36
- EM_FR20 = 37
- EM_RH32 = 38
- EM_RCE = 39
- EM_ARM = 40
- EM_SH = 42
- EM_SPARCV9 = 43
- EM_TRICORE = 44
- EM_ARC = 45
- EM_H8_300 = 46
- EM_H8_300H = 47
- EM_H8S = 48
- EM_H8_500 = 49
- EM_IA_64 = 50
- EM_MIPS_X = 51
- EM_COLDFIRE = 52
- EM_68HC12 = 53
- EM_MMA = 54
- EM_PCP = 55
- EM_NCPU = 56
- EM_NDR1 = 57
- EM_STARCORE = 58
- EM_ME16 = 59
- EM_ST100 = 60
- EM_TINYJ = 61
- EM_X86_64 = 62
- EM_AARCH64 = 183
- EM_486 = 6
- EM_MIPS_RS4_BE = 10
- EM_ALPHA_STD = 41
- EM_ALPHA = 0x9026
- EM_RISCV = 243
- SHN_UNDEF = 0
- SHN_LORESERVE = 0xff00
- SHN_LOPROC = 0xff00
- SHN_HIPROC = 0xff1f
- SHN_LOOS = 0xff20
- SHN_HIOS = 0xff3f
- SHN_ABS = 0xfff1
- SHN_COMMON = 0xfff2
- SHN_XINDEX = 0xffff
- SHN_HIRESERVE = 0xffff
- SHT_NULL = 0
- SHT_PROGBITS = 1
- SHT_SYMTAB = 2
- SHT_STRTAB = 3
- SHT_RELA = 4
- SHT_HASH = 5
- SHT_DYNAMIC = 6
- SHT_NOTE = 7
- SHT_NOBITS = 8
- SHT_REL = 9
- SHT_SHLIB = 10
- SHT_DYNSYM = 11
- SHT_INIT_ARRAY = 14
- SHT_FINI_ARRAY = 15
- SHT_PREINIT_ARRAY = 16
- SHT_GROUP = 17
- SHT_SYMTAB_SHNDX = 18
- SHT_LOOS = 0x60000000
- SHT_HIOS = 0x6fffffff
- SHT_GNU_VERDEF = 0x6ffffffd
- SHT_GNU_VERNEED = 0x6ffffffe
- SHT_GNU_VERSYM = 0x6fffffff
- SHT_LOPROC = 0x70000000
- SHT_ARM_ATTRIBUTES = 0x70000003
- SHT_HIPROC = 0x7fffffff
- SHT_LOUSER = 0x80000000
- SHT_HIUSER = 0xffffffff
- SHF_WRITE = 0x1
- SHF_ALLOC = 0x2
- SHF_EXECINSTR = 0x4
- SHF_MERGE = 0x10
- SHF_STRINGS = 0x20
- SHF_INFO_LINK = 0x40
- SHF_LINK_ORDER = 0x80
- SHF_OS_NONCONFORMING = 0x100
- SHF_GROUP = 0x200
- SHF_TLS = 0x400
- SHF_MASKOS = 0x0ff00000
- SHF_MASKPROC = 0xf0000000
- PT_NULL = 0
- PT_LOAD = 1
- PT_DYNAMIC = 2
- PT_INTERP = 3
- PT_NOTE = 4
- PT_SHLIB = 5
- PT_PHDR = 6
- PT_TLS = 7
- PT_LOOS = 0x60000000
- PT_HIOS = 0x6fffffff
- PT_LOPROC = 0x70000000
- PT_HIPROC = 0x7fffffff
- PT_GNU_STACK = 0x6474e551
- PT_GNU_RELRO = 0x6474e552
- PT_PAX_FLAGS = 0x65041580
- PT_SUNWSTACK = 0x6ffffffb
- PF_X = 0x1
- PF_W = 0x2
- PF_R = 0x4
- PF_MASKOS = 0x0ff00000
- PF_MASKPROC = 0xf0000000
- DT_NULL = 0
- DT_NEEDED = 1
- DT_PLTRELSZ = 2
- DT_PLTGOT = 3
- DT_HASH = 4
- DT_STRTAB = 5
- DT_SYMTAB = 6
- DT_RELA = 7
- DT_RELASZ = 8
- DT_RELAENT = 9
- DT_STRSZ = 10
- DT_SYMENT = 11
- DT_INIT = 12
- DT_FINI = 13
- DT_SONAME = 14
- DT_RPATH = 15
- DT_SYMBOLIC = 16
- DT_REL = 17
- DT_RELSZ = 18
- DT_RELENT = 19
- DT_PLTREL = 20
- DT_DEBUG = 21
- DT_TEXTREL = 22
- DT_JMPREL = 23
- DT_BIND_NOW = 24
- DT_INIT_ARRAY = 25
- DT_FINI_ARRAY = 26
- DT_INIT_ARRAYSZ = 27
- DT_FINI_ARRAYSZ = 28
- DT_RUNPATH = 29
- DT_FLAGS = 30
- DT_ENCODING = 32
- DT_PREINIT_ARRAY = 32
- DT_PREINIT_ARRAYSZ = 33
- DT_LOOS = 0x6000000d
- DT_HIOS = 0x6ffff000
- DT_LOPROC = 0x70000000
- DT_HIPROC = 0x7fffffff
- DT_VERNEED = 0x6ffffffe
- DT_VERNEEDNUM = 0x6fffffff
- DT_VERSYM = 0x6ffffff0
- DT_PPC64_GLINK = DT_LOPROC + 0
- DT_PPC64_OPT = DT_LOPROC + 3
- DF_ORIGIN = 0x0001
- DF_SYMBOLIC = 0x0002
- DF_TEXTREL = 0x0004
- DF_BIND_NOW = 0x0008
- DF_STATIC_TLS = 0x0010
- NT_PRSTATUS = 1
- NT_FPREGSET = 2
- NT_PRPSINFO = 3
- STB_LOCAL = 0
- STB_GLOBAL = 1
- STB_WEAK = 2
- STB_LOOS = 10
- STB_HIOS = 12
- STB_LOPROC = 13
- STB_HIPROC = 15
- STT_NOTYPE = 0
- STT_OBJECT = 1
- STT_FUNC = 2
- STT_SECTION = 3
- STT_FILE = 4
- STT_COMMON = 5
- STT_TLS = 6
- STT_LOOS = 10
- STT_HIOS = 12
- STT_LOPROC = 13
- STT_HIPROC = 15
- STV_DEFAULT = 0x0
- STV_INTERNAL = 0x1
- STV_HIDDEN = 0x2
- STV_PROTECTED = 0x3
- STN_UNDEF = 0
-)
-
/* For accessing the fields of r_info. */
/* For constructing r_info from field values. */
@@ -348,53 +100,20 @@ const (
/*
* ELF header.
*/
-type ElfEhdr struct {
- ident [EI_NIDENT]uint8
- type_ uint16
- machine uint16
- version uint32
- entry uint64
- phoff uint64
- shoff uint64
- flags uint32
- ehsize uint16
- phentsize uint16
- phnum uint16
- shentsize uint16
- shnum uint16
- shstrndx uint16
-}
+type ElfEhdr elf.Header64
/*
* Section header.
*/
type ElfShdr struct {
- name uint32
- type_ uint32
- flags uint64
- addr uint64
- off uint64
- size uint64
- link uint32
- info uint32
- addralign uint64
- entsize uint64
- shnum int
+ elf.Section64
+ shnum elf.SectionIndex
}
/*
* Program header.
*/
-type ElfPhdr struct {
- type_ uint32
- flags uint32
- off uint64
- vaddr uint64
- paddr uint64
- filesz uint64
- memsz uint64
- align uint64
-}
+type ElfPhdr elf.ProgHeader
/* For accessing the fields of r_info. */
@@ -497,22 +216,25 @@ func Elfinit(ctxt *Link) {
// 64-bit architectures
case sys.PPC64, sys.S390X:
if ctxt.Arch.ByteOrder == binary.BigEndian {
- ehdr.flags = 1 /* Version 1 ABI */
+ ehdr.Flags = 1 /* Version 1 ABI */
} else {
- ehdr.flags = 2 /* Version 2 ABI */
+ ehdr.Flags = 2 /* Version 2 ABI */
}
fallthrough
case sys.AMD64, sys.ARM64, sys.MIPS64, sys.RISCV64:
if ctxt.Arch.Family == sys.MIPS64 {
- ehdr.flags = 0x20000004 /* MIPS 3 CPIC */
+ ehdr.Flags = 0x20000004 /* MIPS 3 CPIC */
+ }
+ if ctxt.Arch.Family == sys.RISCV64 {
+ ehdr.Flags = 0x4 /* RISCV Float ABI Double */
}
elf64 = true
- ehdr.phoff = ELF64HDRSIZE /* Must be ELF64HDRSIZE: first PHdr must follow ELF header */
- ehdr.shoff = ELF64HDRSIZE /* Will move as we add PHeaders */
- ehdr.ehsize = ELF64HDRSIZE /* Must be ELF64HDRSIZE */
- ehdr.phentsize = ELF64PHDRSIZE /* Must be ELF64PHDRSIZE */
- ehdr.shentsize = ELF64SHDRSIZE /* Must be ELF64SHDRSIZE */
+ ehdr.Phoff = ELF64HDRSIZE /* Must be ELF64HDRSIZE: first PHdr must follow ELF header */
+ ehdr.Shoff = ELF64HDRSIZE /* Will move as we add PHeaders */
+ ehdr.Ehsize = ELF64HDRSIZE /* Must be ELF64HDRSIZE */
+ ehdr.Phentsize = ELF64PHDRSIZE /* Must be ELF64PHDRSIZE */
+ ehdr.Shentsize = ELF64SHDRSIZE /* Must be ELF64SHDRSIZE */
// 32-bit architectures
case sys.ARM, sys.MIPS:
@@ -527,19 +249,19 @@ func Elfinit(ctxt *Link) {
// produced by the host C compiler. parseArmAttributes in
// ldelf.go reads that information and updates this field as
// appropriate.
- ehdr.flags = 0x5000002 // has entry point, Version5 EABI
+ ehdr.Flags = 0x5000002 // has entry point, Version5 EABI
}
} else if ctxt.Arch.Family == sys.MIPS {
- ehdr.flags = 0x50001004 /* MIPS 32 CPIC O32*/
+ ehdr.Flags = 0x50001004 /* MIPS 32 CPIC O32*/
}
fallthrough
default:
- ehdr.phoff = ELF32HDRSIZE
+ ehdr.Phoff = ELF32HDRSIZE
/* Must be ELF32HDRSIZE: first PHdr must follow ELF header */
- ehdr.shoff = ELF32HDRSIZE /* Will move as we add PHeaders */
- ehdr.ehsize = ELF32HDRSIZE /* Must be ELF32HDRSIZE */
- ehdr.phentsize = ELF32PHDRSIZE /* Must be ELF32PHDRSIZE */
- ehdr.shentsize = ELF32SHDRSIZE /* Must be ELF32SHDRSIZE */
+ ehdr.Shoff = ELF32HDRSIZE /* Will move as we add PHeaders */
+ ehdr.Ehsize = ELF32HDRSIZE /* Must be ELF32HDRSIZE */
+ ehdr.Phentsize = ELF32PHDRSIZE /* Must be ELF32PHDRSIZE */
+ ehdr.Shentsize = ELF32SHDRSIZE /* Must be ELF32SHDRSIZE */
}
}
@@ -549,83 +271,83 @@ func Elfinit(ctxt *Link) {
// but buggy ELF loaders like the one in some
// versions of QEMU and UPX won't.
func fixElfPhdr(e *ElfPhdr) {
- frag := int(e.vaddr & (e.align - 1))
+ frag := int(e.Vaddr & (e.Align - 1))
- e.off -= uint64(frag)
- e.vaddr -= uint64(frag)
- e.paddr -= uint64(frag)
- e.filesz += uint64(frag)
- e.memsz += uint64(frag)
+ e.Off -= uint64(frag)
+ e.Vaddr -= uint64(frag)
+ e.Paddr -= uint64(frag)
+ e.Filesz += uint64(frag)
+ e.Memsz += uint64(frag)
}
func elf64phdr(out *OutBuf, e *ElfPhdr) {
- if e.type_ == PT_LOAD {
+ if e.Type == elf.PT_LOAD {
fixElfPhdr(e)
}
- out.Write32(e.type_)
- out.Write32(e.flags)
- out.Write64(e.off)
- out.Write64(e.vaddr)
- out.Write64(e.paddr)
- out.Write64(e.filesz)
- out.Write64(e.memsz)
- out.Write64(e.align)
+ out.Write32(uint32(e.Type))
+ out.Write32(uint32(e.Flags))
+ out.Write64(e.Off)
+ out.Write64(e.Vaddr)
+ out.Write64(e.Paddr)
+ out.Write64(e.Filesz)
+ out.Write64(e.Memsz)
+ out.Write64(e.Align)
}
func elf32phdr(out *OutBuf, e *ElfPhdr) {
- if e.type_ == PT_LOAD {
+ if e.Type == elf.PT_LOAD {
fixElfPhdr(e)
}
- out.Write32(e.type_)
- out.Write32(uint32(e.off))
- out.Write32(uint32(e.vaddr))
- out.Write32(uint32(e.paddr))
- out.Write32(uint32(e.filesz))
- out.Write32(uint32(e.memsz))
- out.Write32(e.flags)
- out.Write32(uint32(e.align))
+ out.Write32(uint32(e.Type))
+ out.Write32(uint32(e.Off))
+ out.Write32(uint32(e.Vaddr))
+ out.Write32(uint32(e.Paddr))
+ out.Write32(uint32(e.Filesz))
+ out.Write32(uint32(e.Memsz))
+ out.Write32(uint32(e.Flags))
+ out.Write32(uint32(e.Align))
}
func elf64shdr(out *OutBuf, e *ElfShdr) {
- out.Write32(e.name)
- out.Write32(e.type_)
- out.Write64(e.flags)
- out.Write64(e.addr)
- out.Write64(e.off)
- out.Write64(e.size)
- out.Write32(e.link)
- out.Write32(e.info)
- out.Write64(e.addralign)
- out.Write64(e.entsize)
+ out.Write32(e.Name)
+ out.Write32(uint32(e.Type))
+ out.Write64(uint64(e.Flags))
+ out.Write64(e.Addr)
+ out.Write64(e.Off)
+ out.Write64(e.Size)
+ out.Write32(e.Link)
+ out.Write32(e.Info)
+ out.Write64(e.Addralign)
+ out.Write64(e.Entsize)
}
func elf32shdr(out *OutBuf, e *ElfShdr) {
- out.Write32(e.name)
- out.Write32(e.type_)
- out.Write32(uint32(e.flags))
- out.Write32(uint32(e.addr))
- out.Write32(uint32(e.off))
- out.Write32(uint32(e.size))
- out.Write32(e.link)
- out.Write32(e.info)
- out.Write32(uint32(e.addralign))
- out.Write32(uint32(e.entsize))
+ out.Write32(e.Name)
+ out.Write32(uint32(e.Type))
+ out.Write32(uint32(e.Flags))
+ out.Write32(uint32(e.Addr))
+ out.Write32(uint32(e.Off))
+ out.Write32(uint32(e.Size))
+ out.Write32(e.Link)
+ out.Write32(e.Info)
+ out.Write32(uint32(e.Addralign))
+ out.Write32(uint32(e.Entsize))
}
func elfwriteshdrs(out *OutBuf) uint32 {
if elf64 {
- for i := 0; i < int(ehdr.shnum); i++ {
+ for i := 0; i < int(ehdr.Shnum); i++ {
elf64shdr(out, shdr[i])
}
- return uint32(ehdr.shnum) * ELF64SHDRSIZE
+ return uint32(ehdr.Shnum) * ELF64SHDRSIZE
}
- for i := 0; i < int(ehdr.shnum); i++ {
+ for i := 0; i < int(ehdr.Shnum); i++ {
elf32shdr(out, shdr[i])
}
- return uint32(ehdr.shnum) * ELF32SHDRSIZE
+ return uint32(ehdr.Shnum) * ELF32SHDRSIZE
}
func elfsetstring(ctxt *Link, s loader.Sym, str string, off int) {
@@ -641,43 +363,43 @@ func elfsetstring(ctxt *Link, s loader.Sym, str string, off int) {
func elfwritephdrs(out *OutBuf) uint32 {
if elf64 {
- for i := 0; i < int(ehdr.phnum); i++ {
+ for i := 0; i < int(ehdr.Phnum); i++ {
elf64phdr(out, phdr[i])
}
- return uint32(ehdr.phnum) * ELF64PHDRSIZE
+ return uint32(ehdr.Phnum) * ELF64PHDRSIZE
}
- for i := 0; i < int(ehdr.phnum); i++ {
+ for i := 0; i < int(ehdr.Phnum); i++ {
elf32phdr(out, phdr[i])
}
- return uint32(ehdr.phnum) * ELF32PHDRSIZE
+ return uint32(ehdr.Phnum) * ELF32PHDRSIZE
}
func newElfPhdr() *ElfPhdr {
e := new(ElfPhdr)
- if ehdr.phnum >= NSECT {
+ if ehdr.Phnum >= NSECT {
Errorf(nil, "too many phdrs")
} else {
- phdr[ehdr.phnum] = e
- ehdr.phnum++
+ phdr[ehdr.Phnum] = e
+ ehdr.Phnum++
}
if elf64 {
- ehdr.shoff += ELF64PHDRSIZE
+ ehdr.Shoff += ELF64PHDRSIZE
} else {
- ehdr.shoff += ELF32PHDRSIZE
+ ehdr.Shoff += ELF32PHDRSIZE
}
return e
}
func newElfShdr(name int64) *ElfShdr {
e := new(ElfShdr)
- e.name = uint32(name)
- e.shnum = int(ehdr.shnum)
- if ehdr.shnum >= NSECT {
+ e.Name = uint32(name)
+ e.shnum = elf.SectionIndex(ehdr.Shnum)
+ if ehdr.Shnum >= NSECT {
Errorf(nil, "too many shdrs")
} else {
- shdr[ehdr.shnum] = e
- ehdr.shnum++
+ shdr[ehdr.Shnum] = e
+ ehdr.Shnum++
}
return e
@@ -688,38 +410,38 @@ func getElfEhdr() *ElfEhdr {
}
func elf64writehdr(out *OutBuf) uint32 {
- out.Write(ehdr.ident[:])
- out.Write16(ehdr.type_)
- out.Write16(ehdr.machine)
- out.Write32(ehdr.version)
- out.Write64(ehdr.entry)
- out.Write64(ehdr.phoff)
- out.Write64(ehdr.shoff)
- out.Write32(ehdr.flags)
- out.Write16(ehdr.ehsize)
- out.Write16(ehdr.phentsize)
- out.Write16(ehdr.phnum)
- out.Write16(ehdr.shentsize)
- out.Write16(ehdr.shnum)
- out.Write16(ehdr.shstrndx)
+ out.Write(ehdr.Ident[:])
+ out.Write16(uint16(ehdr.Type))
+ out.Write16(uint16(ehdr.Machine))
+ out.Write32(uint32(ehdr.Version))
+ out.Write64(ehdr.Entry)
+ out.Write64(ehdr.Phoff)
+ out.Write64(ehdr.Shoff)
+ out.Write32(ehdr.Flags)
+ out.Write16(ehdr.Ehsize)
+ out.Write16(ehdr.Phentsize)
+ out.Write16(ehdr.Phnum)
+ out.Write16(ehdr.Shentsize)
+ out.Write16(ehdr.Shnum)
+ out.Write16(ehdr.Shstrndx)
return ELF64HDRSIZE
}
func elf32writehdr(out *OutBuf) uint32 {
- out.Write(ehdr.ident[:])
- out.Write16(ehdr.type_)
- out.Write16(ehdr.machine)
- out.Write32(ehdr.version)
- out.Write32(uint32(ehdr.entry))
- out.Write32(uint32(ehdr.phoff))
- out.Write32(uint32(ehdr.shoff))
- out.Write32(ehdr.flags)
- out.Write16(ehdr.ehsize)
- out.Write16(ehdr.phentsize)
- out.Write16(ehdr.phnum)
- out.Write16(ehdr.shentsize)
- out.Write16(ehdr.shnum)
- out.Write16(ehdr.shstrndx)
+ out.Write(ehdr.Ident[:])
+ out.Write16(uint16(ehdr.Type))
+ out.Write16(uint16(ehdr.Machine))
+ out.Write32(uint32(ehdr.Version))
+ out.Write32(uint32(ehdr.Entry))
+ out.Write32(uint32(ehdr.Phoff))
+ out.Write32(uint32(ehdr.Shoff))
+ out.Write32(ehdr.Flags)
+ out.Write16(ehdr.Ehsize)
+ out.Write16(ehdr.Phentsize)
+ out.Write16(ehdr.Phnum)
+ out.Write16(ehdr.Shentsize)
+ out.Write16(ehdr.Shnum)
+ out.Write16(ehdr.Shstrndx)
return ELF32HDRSIZE
}
@@ -743,11 +465,11 @@ func elfhash(name string) uint32 {
return h
}
-func elfWriteDynEntSym(ctxt *Link, s *loader.SymbolBuilder, tag int, t loader.Sym) {
+func elfWriteDynEntSym(ctxt *Link, s *loader.SymbolBuilder, tag elf.DynTag, t loader.Sym) {
Elfwritedynentsymplus(ctxt, s, tag, t, 0)
}
-func Elfwritedynent(arch *sys.Arch, s *loader.SymbolBuilder, tag int, val uint64) {
+func Elfwritedynent(arch *sys.Arch, s *loader.SymbolBuilder, tag elf.DynTag, val uint64) {
if elf64 {
s.AddUint64(arch, uint64(tag))
s.AddUint64(arch, val)
@@ -757,11 +479,11 @@ func Elfwritedynent(arch *sys.Arch, s *loader.SymbolBuilder, tag int, val uint64
}
}
-func elfwritedynentsym(ctxt *Link, s *loader.SymbolBuilder, tag int, t loader.Sym) {
+func elfwritedynentsym(ctxt *Link, s *loader.SymbolBuilder, tag elf.DynTag, t loader.Sym) {
Elfwritedynentsymplus(ctxt, s, tag, t, 0)
}
-func Elfwritedynentsymplus(ctxt *Link, s *loader.SymbolBuilder, tag int, t loader.Sym, add int64) {
+func Elfwritedynentsymplus(ctxt *Link, s *loader.SymbolBuilder, tag elf.DynTag, t loader.Sym, add int64) {
if elf64 {
s.AddUint64(ctxt.Arch, uint64(tag))
} else {
@@ -770,7 +492,7 @@ func Elfwritedynentsymplus(ctxt *Link, s *loader.SymbolBuilder, tag int, t loade
s.AddAddrPlus(ctxt.Arch, t, add)
}
-func elfwritedynentsymsize(ctxt *Link, s *loader.SymbolBuilder, tag int, t loader.Sym) {
+func elfwritedynentsymsize(ctxt *Link, s *loader.SymbolBuilder, tag elf.DynTag, t loader.Sym) {
if elf64 {
s.AddUint64(ctxt.Arch, uint64(tag))
} else {
@@ -782,30 +504,30 @@ func elfwritedynentsymsize(ctxt *Link, s *loader.SymbolBuilder, tag int, t loade
func elfinterp(sh *ElfShdr, startva uint64, resoff uint64, p string) int {
interp = p
n := len(interp) + 1
- sh.addr = startva + resoff - uint64(n)
- sh.off = resoff - uint64(n)
- sh.size = uint64(n)
+ sh.Addr = startva + resoff - uint64(n)
+ sh.Off = resoff - uint64(n)
+ sh.Size = uint64(n)
return n
}
func elfwriteinterp(out *OutBuf) int {
sh := elfshname(".interp")
- out.SeekSet(int64(sh.off))
+ out.SeekSet(int64(sh.Off))
out.WriteString(interp)
out.Write8(0)
- return int(sh.size)
+ return int(sh.Size)
}
func elfnote(sh *ElfShdr, startva uint64, resoff uint64, sz int) int {
n := 3*4 + uint64(sz) + resoff%4
- sh.type_ = SHT_NOTE
- sh.flags = SHF_ALLOC
- sh.addralign = 4
- sh.addr = startva + resoff - n
- sh.off = resoff - n
- sh.size = n - resoff%4
+ sh.Type = uint32(elf.SHT_NOTE)
+ sh.Flags = uint64(elf.SHF_ALLOC)
+ sh.Addralign = 4
+ sh.Addr = startva + resoff - n
+ sh.Off = resoff - n
+ sh.Size = n - resoff%4
return int(n)
}
@@ -814,7 +536,7 @@ func elfwritenotehdr(out *OutBuf, str string, namesz uint32, descsz uint32, tag
sh := elfshname(str)
// Write Elf_Note header.
- out.SeekSet(int64(sh.off))
+ out.SeekSet(int64(sh.Off))
out.Write32(namesz)
out.Write32(descsz)
@@ -851,7 +573,7 @@ func elfwritenetbsdsig(out *OutBuf) int {
out.Write8(0)
out.Write32(ELF_NOTE_NETBSD_VERSION)
- return int(sh.size)
+ return int(sh.Size)
}
// The race detector can't handle ASLR (address space layout randomization).
@@ -870,7 +592,7 @@ func elfwritenetbsdpax(out *OutBuf) int {
}
out.Write([]byte("PaX\x00"))
out.Write32(0x20) // 0x20 = Force disable ASLR
- return int(sh.size)
+ return int(sh.Size)
}
// OpenBSD Signature
@@ -901,7 +623,7 @@ func elfwriteopenbsdsig(out *OutBuf) int {
out.Write32(ELF_NOTE_OPENBSD_VERSION)
- return int(sh.size)
+ return int(sh.Size)
}
func addbuildinfo(val string) {
@@ -960,7 +682,7 @@ func elfwritebuildinfo(out *OutBuf) int {
var zero = make([]byte, 4)
out.Write(zero[:int(Rnd(int64(len(buildinfo)), 4)-int64(len(buildinfo)))])
- return int(sh.size)
+ return int(sh.Size)
}
func elfwritegobuildid(out *OutBuf) int {
@@ -974,7 +696,7 @@ func elfwritegobuildid(out *OutBuf) int {
var zero = make([]byte, 4)
out.Write(zero[:int(Rnd(int64(len(*flagBuildid)), 4)-int64(len(*flagBuildid)))])
- return int(sh.size)
+ return int(sh.Size)
}
// Go specific notes
@@ -1145,56 +867,56 @@ func elfdynhash(ctxt *Link) {
s = ldr.CreateSymForUpdate(".dynamic", 0)
elfverneed = nfile
if elfverneed != 0 {
- elfWriteDynEntSym(ctxt, s, DT_VERNEED, gnuVersionR.Sym())
- Elfwritedynent(ctxt.Arch, s, DT_VERNEEDNUM, uint64(nfile))
- elfWriteDynEntSym(ctxt, s, DT_VERSYM, gnuVersion.Sym())
+ elfWriteDynEntSym(ctxt, s, elf.DT_VERNEED, gnuVersionR.Sym())
+ Elfwritedynent(ctxt.Arch, s, elf.DT_VERNEEDNUM, uint64(nfile))
+ elfWriteDynEntSym(ctxt, s, elf.DT_VERSYM, gnuVersion.Sym())
}
sy := ldr.CreateSymForUpdate(elfRelType+".plt", 0)
if sy.Size() > 0 {
if elfRelType == ".rela" {
- Elfwritedynent(ctxt.Arch, s, DT_PLTREL, DT_RELA)
+ Elfwritedynent(ctxt.Arch, s, elf.DT_PLTREL, uint64(elf.DT_RELA))
} else {
- Elfwritedynent(ctxt.Arch, s, DT_PLTREL, DT_REL)
+ Elfwritedynent(ctxt.Arch, s, elf.DT_PLTREL, uint64(elf.DT_REL))
}
- elfwritedynentsymsize(ctxt, s, DT_PLTRELSZ, sy.Sym())
- elfWriteDynEntSym(ctxt, s, DT_JMPREL, sy.Sym())
+ elfwritedynentsymsize(ctxt, s, elf.DT_PLTRELSZ, sy.Sym())
+ elfWriteDynEntSym(ctxt, s, elf.DT_JMPREL, sy.Sym())
}
- Elfwritedynent(ctxt.Arch, s, DT_NULL, 0)
+ Elfwritedynent(ctxt.Arch, s, elf.DT_NULL, 0)
}
func elfphload(seg *sym.Segment) *ElfPhdr {
ph := newElfPhdr()
- ph.type_ = PT_LOAD
+ ph.Type = elf.PT_LOAD
if seg.Rwx&4 != 0 {
- ph.flags |= PF_R
+ ph.Flags |= elf.PF_R
}
if seg.Rwx&2 != 0 {
- ph.flags |= PF_W
+ ph.Flags |= elf.PF_W
}
if seg.Rwx&1 != 0 {
- ph.flags |= PF_X
+ ph.Flags |= elf.PF_X
}
- ph.vaddr = seg.Vaddr
- ph.paddr = seg.Vaddr
- ph.memsz = seg.Length
- ph.off = seg.Fileoff
- ph.filesz = seg.Filelen
- ph.align = uint64(*FlagRound)
+ ph.Vaddr = seg.Vaddr
+ ph.Paddr = seg.Vaddr
+ ph.Memsz = seg.Length
+ ph.Off = seg.Fileoff
+ ph.Filesz = seg.Filelen
+ ph.Align = uint64(*FlagRound)
return ph
}
func elfphrelro(seg *sym.Segment) {
ph := newElfPhdr()
- ph.type_ = PT_GNU_RELRO
- ph.vaddr = seg.Vaddr
- ph.paddr = seg.Vaddr
- ph.memsz = seg.Length
- ph.off = seg.Fileoff
- ph.filesz = seg.Filelen
- ph.align = uint64(*FlagRound)
+ ph.Type = elf.PT_GNU_RELRO
+ ph.Vaddr = seg.Vaddr
+ ph.Paddr = seg.Vaddr
+ ph.Memsz = seg.Length
+ ph.Off = seg.Fileoff
+ ph.Filesz = seg.Filelen
+ ph.Align = uint64(*FlagRound)
}
func elfshname(name string) *ElfShdr {
@@ -1203,9 +925,9 @@ func elfshname(name string) *ElfShdr {
continue
}
off := elfstr[i].off
- for i = 0; i < int(ehdr.shnum); i++ {
+ for i = 0; i < int(ehdr.Shnum); i++ {
sh := shdr[i]
- if sh.name == uint32(off) {
+ if sh.Name == uint32(off) {
return sh
}
}
@@ -1250,7 +972,7 @@ func elfshbits(linkmode LinkMode, sect *sym.Section) *ElfShdr {
// If this section has already been set up as a note, we assume type_ and
// flags are already correct, but the other fields still need filling in.
- if sh.type_ == SHT_NOTE {
+ if sh.Type == uint32(elf.SHT_NOTE) {
if linkmode != LinkExternal {
// TODO(mwhudson): the approach here will work OK when
// linking internally for notes that we want to be included
@@ -1259,44 +981,44 @@ func elfshbits(linkmode LinkMode, sect *sym.Section) *ElfShdr {
// list note). The real fix is probably to define new values
// for Symbol.Type corresponding to mapped and unmapped notes
// and handle them in dodata().
- Errorf(nil, "sh.type_ == SHT_NOTE in elfshbits when linking internally")
+ Errorf(nil, "sh.Type == SHT_NOTE in elfshbits when linking internally")
}
- sh.addralign = uint64(sect.Align)
- sh.size = sect.Length
- sh.off = sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr
+ sh.Addralign = uint64(sect.Align)
+ sh.Size = sect.Length
+ sh.Off = sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr
return sh
}
- if sh.type_ > 0 {
+ if sh.Type > 0 {
return sh
}
if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
- sh.type_ = SHT_PROGBITS
+ sh.Type = uint32(elf.SHT_PROGBITS)
} else {
- sh.type_ = SHT_NOBITS
+ sh.Type = uint32(elf.SHT_NOBITS)
}
- sh.flags = SHF_ALLOC
+ sh.Flags = uint64(elf.SHF_ALLOC)
if sect.Rwx&1 != 0 {
- sh.flags |= SHF_EXECINSTR
+ sh.Flags |= uint64(elf.SHF_EXECINSTR)
}
if sect.Rwx&2 != 0 {
- sh.flags |= SHF_WRITE
+ sh.Flags |= uint64(elf.SHF_WRITE)
}
if sect.Name == ".tbss" {
- sh.flags |= SHF_TLS
- sh.type_ = SHT_NOBITS
+ sh.Flags |= uint64(elf.SHF_TLS)
+ sh.Type = uint32(elf.SHT_NOBITS)
}
if strings.HasPrefix(sect.Name, ".debug") || strings.HasPrefix(sect.Name, ".zdebug") {
- sh.flags = 0
+ sh.Flags = 0
}
if linkmode != LinkExternal {
- sh.addr = sect.Vaddr
+ sh.Addr = sect.Vaddr
}
- sh.addralign = uint64(sect.Align)
- sh.size = sect.Length
+ sh.Addralign = uint64(sect.Align)
+ sh.Size = sect.Length
if sect.Name != ".tbss" {
- sh.off = sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr
+ sh.Off = sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr
}
return sh
@@ -1311,13 +1033,13 @@ func elfshreloc(arch *sys.Arch, sect *sym.Section) *ElfShdr {
if sect.Name == ".shstrtab" || sect.Name == ".tbss" {
return nil
}
- if sect.Elfsect.(*ElfShdr).type_ == SHT_NOTE {
+ if sect.Elfsect.(*ElfShdr).Type == uint32(elf.SHT_NOTE) {
return nil
}
- typ := SHT_REL
+ typ := elf.SHT_REL
if elfRelType == ".rela" {
- typ = SHT_RELA
+ typ = elf.SHT_RELA
}
sh := elfshname(elfRelType + sect.Name)
@@ -1325,21 +1047,21 @@ func elfshreloc(arch *sys.Arch, sect *sym.Section) *ElfShdr {
// its own .rela.text.
if sect.Name == ".text" {
- if sh.info != 0 && sh.info != uint32(sect.Elfsect.(*ElfShdr).shnum) {
+ if sh.Info != 0 && sh.Info != uint32(sect.Elfsect.(*ElfShdr).shnum) {
sh = elfshnamedup(elfRelType + sect.Name)
}
}
- sh.type_ = uint32(typ)
- sh.entsize = uint64(arch.RegSize) * 2
- if typ == SHT_RELA {
- sh.entsize += uint64(arch.RegSize)
+ sh.Type = uint32(typ)
+ sh.Entsize = uint64(arch.RegSize) * 2
+ if typ == elf.SHT_RELA {
+ sh.Entsize += uint64(arch.RegSize)
}
- sh.link = uint32(elfshname(".symtab").shnum)
- sh.info = uint32(sect.Elfsect.(*ElfShdr).shnum)
- sh.off = sect.Reloff
- sh.size = sect.Rellen
- sh.addralign = uint64(arch.RegSize)
+ sh.Link = uint32(elfshname(".symtab").shnum)
+ sh.Info = uint32(sect.Elfsect.(*ElfShdr).shnum)
+ sh.Off = sect.Reloff
+ sh.Size = sect.Rellen
+ sh.Addralign = uint64(arch.RegSize)
return sh
}
@@ -1652,47 +1374,47 @@ func (ctxt *Link) doelf() {
/*
* .dynamic table
*/
- elfwritedynentsym(ctxt, dynamic, DT_HASH, hash.Sym())
+ elfwritedynentsym(ctxt, dynamic, elf.DT_HASH, hash.Sym())
- elfwritedynentsym(ctxt, dynamic, DT_SYMTAB, dynsym.Sym())
+ elfwritedynentsym(ctxt, dynamic, elf.DT_SYMTAB, dynsym.Sym())
if elf64 {
- Elfwritedynent(ctxt.Arch, dynamic, DT_SYMENT, ELF64SYMSIZE)
+ Elfwritedynent(ctxt.Arch, dynamic, elf.DT_SYMENT, ELF64SYMSIZE)
} else {
- Elfwritedynent(ctxt.Arch, dynamic, DT_SYMENT, ELF32SYMSIZE)
+ Elfwritedynent(ctxt.Arch, dynamic, elf.DT_SYMENT, ELF32SYMSIZE)
}
- elfwritedynentsym(ctxt, dynamic, DT_STRTAB, dynstr.Sym())
- elfwritedynentsymsize(ctxt, dynamic, DT_STRSZ, dynstr.Sym())
+ elfwritedynentsym(ctxt, dynamic, elf.DT_STRTAB, dynstr.Sym())
+ elfwritedynentsymsize(ctxt, dynamic, elf.DT_STRSZ, dynstr.Sym())
if elfRelType == ".rela" {
rela := ldr.LookupOrCreateSym(".rela", 0)
- elfwritedynentsym(ctxt, dynamic, DT_RELA, rela)
- elfwritedynentsymsize(ctxt, dynamic, DT_RELASZ, rela)
- Elfwritedynent(ctxt.Arch, dynamic, DT_RELAENT, ELF64RELASIZE)
+ elfwritedynentsym(ctxt, dynamic, elf.DT_RELA, rela)
+ elfwritedynentsymsize(ctxt, dynamic, elf.DT_RELASZ, rela)
+ Elfwritedynent(ctxt.Arch, dynamic, elf.DT_RELAENT, ELF64RELASIZE)
} else {
rel := ldr.LookupOrCreateSym(".rel", 0)
- elfwritedynentsym(ctxt, dynamic, DT_REL, rel)
- elfwritedynentsymsize(ctxt, dynamic, DT_RELSZ, rel)
- Elfwritedynent(ctxt.Arch, dynamic, DT_RELENT, ELF32RELSIZE)
+ elfwritedynentsym(ctxt, dynamic, elf.DT_REL, rel)
+ elfwritedynentsymsize(ctxt, dynamic, elf.DT_RELSZ, rel)
+ Elfwritedynent(ctxt.Arch, dynamic, elf.DT_RELENT, ELF32RELSIZE)
}
if rpath.val != "" {
- Elfwritedynent(ctxt.Arch, dynamic, DT_RUNPATH, uint64(dynstr.Addstring(rpath.val)))
+ Elfwritedynent(ctxt.Arch, dynamic, elf.DT_RUNPATH, uint64(dynstr.Addstring(rpath.val)))
}
if ctxt.IsPPC64() {
- elfwritedynentsym(ctxt, dynamic, DT_PLTGOT, plt.Sym())
+ elfwritedynentsym(ctxt, dynamic, elf.DT_PLTGOT, plt.Sym())
} else {
- elfwritedynentsym(ctxt, dynamic, DT_PLTGOT, gotplt.Sym())
+ elfwritedynentsym(ctxt, dynamic, elf.DT_PLTGOT, gotplt.Sym())
}
if ctxt.IsPPC64() {
- Elfwritedynent(ctxt.Arch, dynamic, DT_PPC64_OPT, 0)
+ Elfwritedynent(ctxt.Arch, dynamic, elf.DT_PPC64_OPT, 0)
}
// Solaris dynamic linker can't handle an empty .rela.plt if
- // DT_JMPREL is emitted so we have to defer generation of DT_PLTREL,
- // DT_PLTRELSZ, and DT_JMPREL dynamic entries until after we know the
+ // DT_JMPREL is emitted so we have to defer generation of elf.DT_PLTREL,
+ // DT_PLTRELSZ, and elf.DT_JMPREL dynamic entries until after we know the
// size of .rel(a).plt section.
- Elfwritedynent(ctxt.Arch, dynamic, DT_DEBUG, 0)
+ Elfwritedynent(ctxt.Arch, dynamic, elf.DT_DEBUG, 0)
}
if ctxt.IsShared() {
@@ -1731,20 +1453,20 @@ func shsym(sh *ElfShdr, ldr *loader.Loader, s loader.Sym) {
panic("bad symbol in shsym2")
}
addr := ldr.SymValue(s)
- if sh.flags&SHF_ALLOC != 0 {
- sh.addr = uint64(addr)
+ if sh.Flags&uint64(elf.SHF_ALLOC) != 0 {
+ sh.Addr = uint64(addr)
}
- sh.off = uint64(datoff(ldr, s, addr))
- sh.size = uint64(ldr.SymSize(s))
+ sh.Off = uint64(datoff(ldr, s, addr))
+ sh.Size = uint64(ldr.SymSize(s))
}
func phsh(ph *ElfPhdr, sh *ElfShdr) {
- ph.vaddr = sh.addr
- ph.paddr = ph.vaddr
- ph.off = sh.off
- ph.filesz = sh.size
- ph.memsz = sh.size
- ph.align = sh.addralign
+ ph.Vaddr = sh.Addr
+ ph.Paddr = ph.Vaddr
+ ph.Off = sh.Off
+ ph.Filesz = sh.Size
+ ph.Memsz = sh.Size
+ ph.Align = sh.Addralign
}
func Asmbelfsetup() {
@@ -1796,21 +1518,21 @@ func asmbElf(ctxt *Link) {
default:
Exitf("unknown architecture in asmbelf: %v", ctxt.Arch.Family)
case sys.MIPS, sys.MIPS64:
- eh.machine = EM_MIPS
+ eh.Machine = uint16(elf.EM_MIPS)
case sys.ARM:
- eh.machine = EM_ARM
+ eh.Machine = uint16(elf.EM_ARM)
case sys.AMD64:
- eh.machine = EM_X86_64
+ eh.Machine = uint16(elf.EM_X86_64)
case sys.ARM64:
- eh.machine = EM_AARCH64
+ eh.Machine = uint16(elf.EM_AARCH64)
case sys.I386:
- eh.machine = EM_386
+ eh.Machine = uint16(elf.EM_386)
case sys.PPC64:
- eh.machine = EM_PPC64
+ eh.Machine = uint16(elf.EM_PPC64)
case sys.RISCV64:
- eh.machine = EM_RISCV
+ eh.Machine = uint16(elf.EM_RISCV)
case sys.S390X:
- eh.machine = EM_S390
+ eh.Machine = uint16(elf.EM_S390)
}
elfreserve := int64(ELFRESERVE)
@@ -1840,30 +1562,30 @@ func asmbElf(ctxt *Link) {
sh := elfshname(".note.netbsd.pax")
resoff -= int64(elfnetbsdpax(sh, uint64(startva), uint64(resoff)))
pnote = newElfPhdr()
- pnote.type_ = PT_NOTE
- pnote.flags = PF_R
+ pnote.Type = elf.PT_NOTE
+ pnote.Flags = elf.PF_R
phsh(pnote, sh)
}
if ctxt.LinkMode == LinkExternal {
/* skip program headers */
- eh.phoff = 0
+ eh.Phoff = 0
- eh.phentsize = 0
+ eh.Phentsize = 0
if ctxt.BuildMode == BuildModeShared {
sh := elfshname(".note.go.pkg-list")
- sh.type_ = SHT_NOTE
+ sh.Type = uint32(elf.SHT_NOTE)
sh = elfshname(".note.go.abihash")
- sh.type_ = SHT_NOTE
- sh.flags = SHF_ALLOC
+ sh.Type = uint32(elf.SHT_NOTE)
+ sh.Flags = uint64(elf.SHF_ALLOC)
sh = elfshname(".note.go.deps")
- sh.type_ = SHT_NOTE
+ sh.Type = uint32(elf.SHT_NOTE)
}
if *flagBuildid != "" {
sh := elfshname(".note.go.buildid")
- sh.type_ = SHT_NOTE
- sh.flags = SHF_ALLOC
+ sh.Type = uint32(elf.SHT_NOTE)
+ sh.Flags = uint64(elf.SHF_ALLOC)
}
goto elfobj
@@ -1872,22 +1594,22 @@ func asmbElf(ctxt *Link) {
/* program header info */
pph = newElfPhdr()
- pph.type_ = PT_PHDR
- pph.flags = PF_R
- pph.off = uint64(eh.ehsize)
- pph.vaddr = uint64(*FlagTextAddr) - uint64(HEADR) + pph.off
- pph.paddr = uint64(*FlagTextAddr) - uint64(HEADR) + pph.off
- pph.align = uint64(*FlagRound)
+ pph.Type = elf.PT_PHDR
+ pph.Flags = elf.PF_R
+ pph.Off = uint64(eh.Ehsize)
+ pph.Vaddr = uint64(*FlagTextAddr) - uint64(HEADR) + pph.Off
+ pph.Paddr = uint64(*FlagTextAddr) - uint64(HEADR) + pph.Off
+ pph.Align = uint64(*FlagRound)
/*
* PHDR must be in a loaded segment. Adjust the text
* segment boundaries downwards to include it.
*/
{
- o := int64(Segtext.Vaddr - pph.vaddr)
+ o := int64(Segtext.Vaddr - pph.Vaddr)
Segtext.Vaddr -= uint64(o)
Segtext.Length += uint64(o)
- o = int64(Segtext.Fileoff - pph.off)
+ o = int64(Segtext.Fileoff - pph.Off)
Segtext.Fileoff -= uint64(o)
Segtext.Filelen += uint64(o)
}
@@ -1896,9 +1618,9 @@ func asmbElf(ctxt *Link) {
/* interpreter */
sh := elfshname(".interp")
- sh.type_ = SHT_PROGBITS
- sh.flags = SHF_ALLOC
- sh.addralign = 1
+ sh.Type = uint32(elf.SHT_PROGBITS)
+ sh.Flags = uint64(elf.SHF_ALLOC)
+ sh.Addralign = 1
if interpreter == "" && objabi.GO_LDSO != "" {
interpreter = objabi.GO_LDSO
@@ -1936,8 +1658,8 @@ func asmbElf(ctxt *Link) {
resoff -= int64(elfinterp(sh, uint64(startva), uint64(resoff), interpreter))
ph := newElfPhdr()
- ph.type_ = PT_INTERP
- ph.flags = PF_R
+ ph.Type = elf.PT_INTERP
+ ph.Flags = elf.PF_R
phsh(ph, sh)
}
@@ -1955,8 +1677,8 @@ func asmbElf(ctxt *Link) {
}
pnote = newElfPhdr()
- pnote.type_ = PT_NOTE
- pnote.flags = PF_R
+ pnote.Type = elf.PT_NOTE
+ pnote.Flags = elf.PF_R
phsh(pnote, sh)
}
@@ -1966,8 +1688,8 @@ func asmbElf(ctxt *Link) {
if pnote == nil {
pnote = newElfPhdr()
- pnote.type_ = PT_NOTE
- pnote.flags = PF_R
+ pnote.Type = elf.PT_NOTE
+ pnote.Flags = elf.PF_R
}
phsh(pnote, sh)
@@ -1978,8 +1700,8 @@ func asmbElf(ctxt *Link) {
resoff -= int64(elfgobuildid(sh, uint64(startva), uint64(resoff)))
pnote := newElfPhdr()
- pnote.type_ = PT_NOTE
- pnote.flags = PF_R
+ pnote.Type = elf.PT_NOTE
+ pnote.Flags = elf.PF_R
phsh(pnote, sh)
}
@@ -1998,15 +1720,15 @@ func asmbElf(ctxt *Link) {
/* Dynamic linking sections */
if !*FlagD {
sh := elfshname(".dynsym")
- sh.type_ = SHT_DYNSYM
- sh.flags = SHF_ALLOC
+ sh.Type = uint32(elf.SHT_DYNSYM)
+ sh.Flags = uint64(elf.SHF_ALLOC)
if elf64 {
- sh.entsize = ELF64SYMSIZE
+ sh.Entsize = ELF64SYMSIZE
} else {
- sh.entsize = ELF32SYMSIZE
+ sh.Entsize = ELF32SYMSIZE
}
- sh.addralign = uint64(ctxt.Arch.RegSize)
- sh.link = uint32(elfshname(".dynstr").shnum)
+ sh.Addralign = uint64(ctxt.Arch.RegSize)
+ sh.Link = uint32(elfshname(".dynstr").shnum)
// sh.info is the index of first non-local symbol (number of local symbols)
s := ldr.Lookup(".dynsym", 0)
@@ -2017,134 +1739,134 @@ func asmbElf(ctxt *Link) {
break
}
}
- sh.info = i
+ sh.Info = i
shsym(sh, ldr, s)
sh = elfshname(".dynstr")
- sh.type_ = SHT_STRTAB
- sh.flags = SHF_ALLOC
- sh.addralign = 1
+ sh.Type = uint32(elf.SHT_STRTAB)
+ sh.Flags = uint64(elf.SHF_ALLOC)
+ sh.Addralign = 1
shsym(sh, ldr, ldr.Lookup(".dynstr", 0))
if elfverneed != 0 {
sh := elfshname(".gnu.version")
- sh.type_ = SHT_GNU_VERSYM
- sh.flags = SHF_ALLOC
- sh.addralign = 2
- sh.link = uint32(elfshname(".dynsym").shnum)
- sh.entsize = 2
+ sh.Type = uint32(elf.SHT_GNU_VERSYM)
+ sh.Flags = uint64(elf.SHF_ALLOC)
+ sh.Addralign = 2
+ sh.Link = uint32(elfshname(".dynsym").shnum)
+ sh.Entsize = 2
shsym(sh, ldr, ldr.Lookup(".gnu.version", 0))
sh = elfshname(".gnu.version_r")
- sh.type_ = SHT_GNU_VERNEED
- sh.flags = SHF_ALLOC
- sh.addralign = uint64(ctxt.Arch.RegSize)
- sh.info = uint32(elfverneed)
- sh.link = uint32(elfshname(".dynstr").shnum)
+ sh.Type = uint32(elf.SHT_GNU_VERNEED)
+ sh.Flags = uint64(elf.SHF_ALLOC)
+ sh.Addralign = uint64(ctxt.Arch.RegSize)
+ sh.Info = uint32(elfverneed)
+ sh.Link = uint32(elfshname(".dynstr").shnum)
shsym(sh, ldr, ldr.Lookup(".gnu.version_r", 0))
}
if elfRelType == ".rela" {
sh := elfshname(".rela.plt")
- sh.type_ = SHT_RELA
- sh.flags = SHF_ALLOC
- sh.entsize = ELF64RELASIZE
- sh.addralign = uint64(ctxt.Arch.RegSize)
- sh.link = uint32(elfshname(".dynsym").shnum)
- sh.info = uint32(elfshname(".plt").shnum)
+ sh.Type = uint32(elf.SHT_RELA)
+ sh.Flags = uint64(elf.SHF_ALLOC)
+ sh.Entsize = ELF64RELASIZE
+ sh.Addralign = uint64(ctxt.Arch.RegSize)
+ sh.Link = uint32(elfshname(".dynsym").shnum)
+ sh.Info = uint32(elfshname(".plt").shnum)
shsym(sh, ldr, ldr.Lookup(".rela.plt", 0))
sh = elfshname(".rela")
- sh.type_ = SHT_RELA
- sh.flags = SHF_ALLOC
- sh.entsize = ELF64RELASIZE
- sh.addralign = 8
- sh.link = uint32(elfshname(".dynsym").shnum)
+ sh.Type = uint32(elf.SHT_RELA)
+ sh.Flags = uint64(elf.SHF_ALLOC)
+ sh.Entsize = ELF64RELASIZE
+ sh.Addralign = 8
+ sh.Link = uint32(elfshname(".dynsym").shnum)
shsym(sh, ldr, ldr.Lookup(".rela", 0))
} else {
sh := elfshname(".rel.plt")
- sh.type_ = SHT_REL
- sh.flags = SHF_ALLOC
- sh.entsize = ELF32RELSIZE
- sh.addralign = 4
- sh.link = uint32(elfshname(".dynsym").shnum)
+ sh.Type = uint32(elf.SHT_REL)
+ sh.Flags = uint64(elf.SHF_ALLOC)
+ sh.Entsize = ELF32RELSIZE
+ sh.Addralign = 4
+ sh.Link = uint32(elfshname(".dynsym").shnum)
shsym(sh, ldr, ldr.Lookup(".rel.plt", 0))
sh = elfshname(".rel")
- sh.type_ = SHT_REL
- sh.flags = SHF_ALLOC
- sh.entsize = ELF32RELSIZE
- sh.addralign = 4
- sh.link = uint32(elfshname(".dynsym").shnum)
+ sh.Type = uint32(elf.SHT_REL)
+ sh.Flags = uint64(elf.SHF_ALLOC)
+ sh.Entsize = ELF32RELSIZE
+ sh.Addralign = 4
+ sh.Link = uint32(elfshname(".dynsym").shnum)
shsym(sh, ldr, ldr.Lookup(".rel", 0))
}
- if eh.machine == EM_PPC64 {
+ if elf.Machine(eh.Machine) == elf.EM_PPC64 {
sh := elfshname(".glink")
- sh.type_ = SHT_PROGBITS
- sh.flags = SHF_ALLOC + SHF_EXECINSTR
- sh.addralign = 4
+ sh.Type = uint32(elf.SHT_PROGBITS)
+ sh.Flags = uint64(elf.SHF_ALLOC + elf.SHF_EXECINSTR)
+ sh.Addralign = 4
shsym(sh, ldr, ldr.Lookup(".glink", 0))
}
sh = elfshname(".plt")
- sh.type_ = SHT_PROGBITS
- sh.flags = SHF_ALLOC + SHF_EXECINSTR
- if eh.machine == EM_X86_64 {
- sh.entsize = 16
- } else if eh.machine == EM_S390 {
- sh.entsize = 32
- } else if eh.machine == EM_PPC64 {
+ sh.Type = uint32(elf.SHT_PROGBITS)
+ sh.Flags = uint64(elf.SHF_ALLOC + elf.SHF_EXECINSTR)
+ if elf.Machine(eh.Machine) == elf.EM_X86_64 {
+ sh.Entsize = 16
+ } else if elf.Machine(eh.Machine) == elf.EM_S390 {
+ sh.Entsize = 32
+ } else if elf.Machine(eh.Machine) == elf.EM_PPC64 {
// On ppc64, this is just a table of addresses
// filled by the dynamic linker
- sh.type_ = SHT_NOBITS
+ sh.Type = uint32(elf.SHT_NOBITS)
- sh.flags = SHF_ALLOC + SHF_WRITE
- sh.entsize = 8
+ sh.Flags = uint64(elf.SHF_ALLOC + elf.SHF_WRITE)
+ sh.Entsize = 8
} else {
- sh.entsize = 4
+ sh.Entsize = 4
}
- sh.addralign = sh.entsize
+ sh.Addralign = sh.Entsize
shsym(sh, ldr, ldr.Lookup(".plt", 0))
// On ppc64, .got comes from the input files, so don't
// create it here, and .got.plt is not used.
- if eh.machine != EM_PPC64 {
+ if elf.Machine(eh.Machine) != elf.EM_PPC64 {
sh := elfshname(".got")
- sh.type_ = SHT_PROGBITS
- sh.flags = SHF_ALLOC + SHF_WRITE
- sh.entsize = uint64(ctxt.Arch.RegSize)
- sh.addralign = uint64(ctxt.Arch.RegSize)
+ sh.Type = uint32(elf.SHT_PROGBITS)
+ sh.Flags = uint64(elf.SHF_ALLOC + elf.SHF_WRITE)
+ sh.Entsize = uint64(ctxt.Arch.RegSize)
+ sh.Addralign = uint64(ctxt.Arch.RegSize)
shsym(sh, ldr, ldr.Lookup(".got", 0))
sh = elfshname(".got.plt")
- sh.type_ = SHT_PROGBITS
- sh.flags = SHF_ALLOC + SHF_WRITE
- sh.entsize = uint64(ctxt.Arch.RegSize)
- sh.addralign = uint64(ctxt.Arch.RegSize)
+ sh.Type = uint32(elf.SHT_PROGBITS)
+ sh.Flags = uint64(elf.SHF_ALLOC + elf.SHF_WRITE)
+ sh.Entsize = uint64(ctxt.Arch.RegSize)
+ sh.Addralign = uint64(ctxt.Arch.RegSize)
shsym(sh, ldr, ldr.Lookup(".got.plt", 0))
}
sh = elfshname(".hash")
- sh.type_ = SHT_HASH
- sh.flags = SHF_ALLOC
- sh.entsize = 4
- sh.addralign = uint64(ctxt.Arch.RegSize)
- sh.link = uint32(elfshname(".dynsym").shnum)
+ sh.Type = uint32(elf.SHT_HASH)
+ sh.Flags = uint64(elf.SHF_ALLOC)
+ sh.Entsize = 4
+ sh.Addralign = uint64(ctxt.Arch.RegSize)
+ sh.Link = uint32(elfshname(".dynsym").shnum)
shsym(sh, ldr, ldr.Lookup(".hash", 0))
- /* sh and PT_DYNAMIC for .dynamic section */
+ /* sh and elf.PT_DYNAMIC for .dynamic section */
sh = elfshname(".dynamic")
- sh.type_ = SHT_DYNAMIC
- sh.flags = SHF_ALLOC + SHF_WRITE
- sh.entsize = 2 * uint64(ctxt.Arch.RegSize)
- sh.addralign = uint64(ctxt.Arch.RegSize)
- sh.link = uint32(elfshname(".dynstr").shnum)
+ sh.Type = uint32(elf.SHT_DYNAMIC)
+ sh.Flags = uint64(elf.SHF_ALLOC + elf.SHF_WRITE)
+ sh.Entsize = 2 * uint64(ctxt.Arch.RegSize)
+ sh.Addralign = uint64(ctxt.Arch.RegSize)
+ sh.Link = uint32(elfshname(".dynstr").shnum)
shsym(sh, ldr, ldr.Lookup(".dynamic", 0))
ph := newElfPhdr()
- ph.type_ = PT_DYNAMIC
- ph.flags = PF_R + PF_W
+ ph.Type = elf.PT_DYNAMIC
+ ph.Flags = elf.PF_R + elf.PF_W
phsh(ph, sh)
/*
@@ -2158,35 +1880,35 @@ func asmbElf(ctxt *Link) {
}
if tlssize != 0 {
ph := newElfPhdr()
- ph.type_ = PT_TLS
- ph.flags = PF_R
- ph.memsz = tlssize
- ph.align = uint64(ctxt.Arch.RegSize)
+ ph.Type = elf.PT_TLS
+ ph.Flags = elf.PF_R
+ ph.Memsz = tlssize
+ ph.Align = uint64(ctxt.Arch.RegSize)
}
}
if ctxt.HeadType == objabi.Hlinux {
ph := newElfPhdr()
- ph.type_ = PT_GNU_STACK
- ph.flags = PF_W + PF_R
- ph.align = uint64(ctxt.Arch.RegSize)
+ ph.Type = elf.PT_GNU_STACK
+ ph.Flags = elf.PF_W + elf.PF_R
+ ph.Align = uint64(ctxt.Arch.RegSize)
ph = newElfPhdr()
- ph.type_ = PT_PAX_FLAGS
- ph.flags = 0x2a00 // mprotect, randexec, emutramp disabled
- ph.align = uint64(ctxt.Arch.RegSize)
+ ph.Type = elf.PT_PAX_FLAGS
+ ph.Flags = 0x2a00 // mprotect, randexec, emutramp disabled
+ ph.Align = uint64(ctxt.Arch.RegSize)
} else if ctxt.HeadType == objabi.Hsolaris {
ph := newElfPhdr()
- ph.type_ = PT_SUNWSTACK
- ph.flags = PF_W + PF_R
+ ph.Type = elf.PT_SUNWSTACK
+ ph.Flags = elf.PF_W + elf.PF_R
}
elfobj:
sh := elfshname(".shstrtab")
- sh.type_ = SHT_STRTAB
- sh.addralign = 1
+ sh.Type = uint32(elf.SHT_STRTAB)
+ sh.Addralign = 1
shsym(sh, ldr, ldr.Lookup(".shstrtab", 0))
- eh.shstrndx = uint16(sh.shnum)
+ eh.Shstrndx = uint16(sh.shnum)
// put these sections early in the list
if !*FlagS {
@@ -2230,72 +1952,73 @@ elfobj:
// add a .note.GNU-stack section to mark the stack as non-executable
sh := elfshname(".note.GNU-stack")
- sh.type_ = SHT_PROGBITS
- sh.addralign = 1
- sh.flags = 0
+ sh.Type = uint32(elf.SHT_PROGBITS)
+ sh.Addralign = 1
+ sh.Flags = 0
}
if !*FlagS {
sh := elfshname(".symtab")
- sh.type_ = SHT_SYMTAB
- sh.off = uint64(symo)
- sh.size = uint64(symSize)
- sh.addralign = uint64(ctxt.Arch.RegSize)
- sh.entsize = 8 + 2*uint64(ctxt.Arch.RegSize)
- sh.link = uint32(elfshname(".strtab").shnum)
- sh.info = uint32(elfglobalsymndx)
+ sh.Type = uint32(elf.SHT_SYMTAB)
+ sh.Off = uint64(symo)
+ sh.Size = uint64(symSize)
+ sh.Addralign = uint64(ctxt.Arch.RegSize)
+ sh.Entsize = 8 + 2*uint64(ctxt.Arch.RegSize)
+ sh.Link = uint32(elfshname(".strtab").shnum)
+ sh.Info = uint32(elfglobalsymndx)
sh = elfshname(".strtab")
- sh.type_ = SHT_STRTAB
- sh.off = uint64(symo) + uint64(symSize)
- sh.size = uint64(len(Elfstrdat))
- sh.addralign = 1
+ sh.Type = uint32(elf.SHT_STRTAB)
+ sh.Off = uint64(symo) + uint64(symSize)
+ sh.Size = uint64(len(Elfstrdat))
+ sh.Addralign = 1
}
/* Main header */
- eh.ident[EI_MAG0] = '\177'
-
- eh.ident[EI_MAG1] = 'E'
- eh.ident[EI_MAG2] = 'L'
- eh.ident[EI_MAG3] = 'F'
- if ctxt.HeadType == objabi.Hfreebsd {
- eh.ident[EI_OSABI] = ELFOSABI_FREEBSD
- } else if ctxt.HeadType == objabi.Hnetbsd {
- eh.ident[EI_OSABI] = ELFOSABI_NETBSD
- } else if ctxt.HeadType == objabi.Hopenbsd {
- eh.ident[EI_OSABI] = ELFOSABI_OPENBSD
- } else if ctxt.HeadType == objabi.Hdragonfly {
- eh.ident[EI_OSABI] = ELFOSABI_NONE
+ copy(eh.Ident[:], elf.ELFMAG)
+
+ var osabi elf.OSABI
+ switch ctxt.HeadType {
+ case objabi.Hfreebsd:
+ osabi = elf.ELFOSABI_FREEBSD
+ case objabi.Hnetbsd:
+ osabi = elf.ELFOSABI_NETBSD
+ case objabi.Hopenbsd:
+ osabi = elf.ELFOSABI_OPENBSD
+ case objabi.Hdragonfly:
+ osabi = elf.ELFOSABI_NONE
}
+ eh.Ident[elf.EI_OSABI] = byte(osabi)
+
if elf64 {
- eh.ident[EI_CLASS] = ELFCLASS64
+ eh.Ident[elf.EI_CLASS] = byte(elf.ELFCLASS64)
} else {
- eh.ident[EI_CLASS] = ELFCLASS32
+ eh.Ident[elf.EI_CLASS] = byte(elf.ELFCLASS32)
}
if ctxt.Arch.ByteOrder == binary.BigEndian {
- eh.ident[EI_DATA] = ELFDATA2MSB
+ eh.Ident[elf.EI_DATA] = byte(elf.ELFDATA2MSB)
} else {
- eh.ident[EI_DATA] = ELFDATA2LSB
+ eh.Ident[elf.EI_DATA] = byte(elf.ELFDATA2LSB)
}
- eh.ident[EI_VERSION] = EV_CURRENT
+ eh.Ident[elf.EI_VERSION] = byte(elf.EV_CURRENT)
if ctxt.LinkMode == LinkExternal {
- eh.type_ = ET_REL
+ eh.Type = uint16(elf.ET_REL)
} else if ctxt.BuildMode == BuildModePIE {
- eh.type_ = ET_DYN
+ eh.Type = uint16(elf.ET_DYN)
} else {
- eh.type_ = ET_EXEC
+ eh.Type = uint16(elf.ET_EXEC)
}
if ctxt.LinkMode != LinkExternal {
- eh.entry = uint64(Entryvalue(ctxt))
+ eh.Entry = uint64(Entryvalue(ctxt))
}
- eh.version = EV_CURRENT
+ eh.Version = uint32(elf.EV_CURRENT)
if pph != nil {
- pph.filesz = uint64(eh.phnum) * uint64(eh.phentsize)
- pph.memsz = pph.filesz
+ pph.Filesz = uint64(eh.Phnum) * uint64(eh.Phentsize)
+ pph.Memsz = pph.Filesz
}
ctxt.Out.SeekSet(0)
@@ -2345,21 +2068,21 @@ func elfadddynsym(ldr *loader.Loader, target *Target, syms *ArchSyms, s loader.S
if elf64 {
/* type */
- t := STB_GLOBAL << 4
+ var t uint8
if cgoexp && st == sym.STEXT {
- t |= STT_FUNC
+ t = elf.ST_INFO(elf.STB_GLOBAL, elf.STT_FUNC)
} else {
- t |= STT_OBJECT
+ t = elf.ST_INFO(elf.STB_GLOBAL, elf.STT_OBJECT)
}
- d.AddUint8(uint8(t))
+ d.AddUint8(t)
/* reserved */
d.AddUint8(0)
/* section where symbol is defined */
if st == sym.SDYNIMPORT {
- d.AddUint16(target.Arch, SHN_UNDEF)
+ d.AddUint16(target.Arch, uint16(elf.SHN_UNDEF))
} else {
d.AddUint16(target.Arch, 1)
}
@@ -2378,7 +2101,7 @@ func elfadddynsym(ldr *loader.Loader, target *Target, syms *ArchSyms, s loader.S
if target.Arch.Family == sys.AMD64 && !cgoeDynamic && dil != "" && !seenlib[dil] {
du := ldr.MakeSymbolUpdater(syms.Dynamic)
- Elfwritedynent(target.Arch, du, DT_NEEDED, uint64(dstru.Addstring(dil)))
+ Elfwritedynent(target.Arch, du, elf.DT_NEEDED, uint64(dstru.Addstring(dil)))
seenlib[dil] = true
}
} else {
@@ -2394,80 +2117,24 @@ func elfadddynsym(ldr *loader.Loader, target *Target, syms *ArchSyms, s loader.S
d.AddUint32(target.Arch, uint32(len(ldr.Data(s))))
/* type */
- t := STB_GLOBAL << 4
+ var t uint8
// TODO(mwhudson): presumably the behavior should actually be the same on both arm and 386.
if target.Arch.Family == sys.I386 && cgoexp && st == sym.STEXT {
- t |= STT_FUNC
+ t = elf.ST_INFO(elf.STB_GLOBAL, elf.STT_FUNC)
} else if target.Arch.Family == sys.ARM && cgoeDynamic && st == sym.STEXT {
- t |= STT_FUNC
+ t = elf.ST_INFO(elf.STB_GLOBAL, elf.STT_FUNC)
} else {
- t |= STT_OBJECT
+ t = elf.ST_INFO(elf.STB_GLOBAL, elf.STT_OBJECT)
}
- d.AddUint8(uint8(t))
+ d.AddUint8(t)
d.AddUint8(0)
/* shndx */
if st == sym.SDYNIMPORT {
- d.AddUint16(target.Arch, SHN_UNDEF)
+ d.AddUint16(target.Arch, uint16(elf.SHN_UNDEF))
} else {
d.AddUint16(target.Arch, 1)
}
}
}
-
-func ELF32_R_SYM(info uint32) uint32 {
- return info >> 8
-}
-
-func ELF32_R_TYPE(info uint32) uint32 {
- return uint32(uint8(info))
-}
-
-func ELF32_R_INFO(sym uint32, type_ uint32) uint32 {
- return sym<<8 | type_
-}
-
-func ELF32_ST_BIND(info uint8) uint8 {
- return info >> 4
-}
-
-func ELF32_ST_TYPE(info uint8) uint8 {
- return info & 0xf
-}
-
-func ELF32_ST_INFO(bind uint8, type_ uint8) uint8 {
- return bind<<4 | type_&0xf
-}
-
-func ELF32_ST_VISIBILITY(oth uint8) uint8 {
- return oth & 3
-}
-
-func ELF64_R_SYM(info uint64) uint32 {
- return uint32(info >> 32)
-}
-
-func ELF64_R_TYPE(info uint64) uint32 {
- return uint32(info)
-}
-
-func ELF64_R_INFO(sym uint32, type_ uint32) uint64 {
- return uint64(sym)<<32 | uint64(type_)
-}
-
-func ELF64_ST_BIND(info uint8) uint8 {
- return info >> 4
-}
-
-func ELF64_ST_TYPE(info uint8) uint8 {
- return info & 0xf
-}
-
-func ELF64_ST_INFO(bind uint8, type_ uint8) uint8 {
- return bind<<4 | type_&0xf
-}
-
-func ELF64_ST_VISIBILITY(oth uint8) uint8 {
- return oth & 3
-}
diff --git a/src/cmd/link/internal/ld/go.go b/src/cmd/link/internal/ld/go.go
index b3541c46c0..a6cd4c0541 100644
--- a/src/cmd/link/internal/ld/go.go
+++ b/src/cmd/link/internal/ld/go.go
@@ -13,6 +13,7 @@ import (
"cmd/internal/sys"
"cmd/link/internal/loader"
"cmd/link/internal/sym"
+ "debug/elf"
"encoding/json"
"fmt"
"io"
@@ -302,7 +303,7 @@ func adddynlib(ctxt *Link, lib string) {
dsu.Addstring("")
}
du := ctxt.loader.MakeSymbolUpdater(ctxt.Dynamic)
- Elfwritedynent(ctxt.Arch, du, DT_NEEDED, uint64(dsu.Addstring(lib)))
+ Elfwritedynent(ctxt.Arch, du, elf.DT_NEEDED, uint64(dsu.Addstring(lib)))
} else {
Errorf(nil, "adddynlib: unsupported binary format")
}
diff --git a/src/cmd/link/internal/ld/ld_test.go b/src/cmd/link/internal/ld/ld_test.go
index db339b484d..cdfaadb17d 100644
--- a/src/cmd/link/internal/ld/ld_test.go
+++ b/src/cmd/link/internal/ld/ld_test.go
@@ -5,6 +5,7 @@
package ld
import (
+ "debug/pe"
"fmt"
"internal/testenv"
"io/ioutil"
@@ -17,8 +18,13 @@ import (
)
func TestUndefinedRelocErrors(t *testing.T) {
- t.Parallel()
testenv.MustHaveGoBuild(t)
+
+ // When external linking, symbols may be defined externally, so we allow
+ // undefined symbols and let external linker resolve. Skip the test.
+ testenv.MustInternalLink(t)
+
+ t.Parallel()
dir, err := ioutil.TempDir("", "go-build")
if err != nil {
t.Fatal(err)
@@ -167,3 +173,72 @@ func TestPPC64LargeTextSectionSplitting(t *testing.T) {
t.Fatal(err)
}
}
+
+func TestWindowsBuildmodeCSharedASLR(t *testing.T) {
+ platform := fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)
+ switch platform {
+ case "windows/amd64", "windows/386":
+ default:
+ t.Skip("skipping windows amd64/386 only test")
+ }
+
+ t.Run("aslr", func(t *testing.T) {
+ testWindowsBuildmodeCSharedASLR(t, true)
+ })
+ t.Run("no-aslr", func(t *testing.T) {
+ testWindowsBuildmodeCSharedASLR(t, false)
+ })
+}
+
+func testWindowsBuildmodeCSharedASLR(t *testing.T, useASLR bool) {
+ t.Parallel()
+ testenv.MustHaveGoBuild(t)
+
+ dir, err := ioutil.TempDir("", "go-build")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+
+ srcfile := filepath.Join(dir, "test.go")
+ objfile := filepath.Join(dir, "test.dll")
+ if err := ioutil.WriteFile(srcfile, []byte(`package main; func main() { print("hello") }`), 0666); err != nil {
+ t.Fatal(err)
+ }
+ argv := []string{"build", "-buildmode=c-shared"}
+ if !useASLR {
+ argv = append(argv, "-ldflags", "-aslr=false")
+ }
+ argv = append(argv, "-o", objfile, srcfile)
+ out, err := exec.Command(testenv.GoToolPath(t), argv...).CombinedOutput()
+ if err != nil {
+ t.Fatalf("build failure: %s\n%s\n", err, string(out))
+ }
+
+ f, err := pe.Open(objfile)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer f.Close()
+ var dc uint16
+ switch oh := f.OptionalHeader.(type) {
+ case *pe.OptionalHeader32:
+ dc = oh.DllCharacteristics
+ case *pe.OptionalHeader64:
+ dc = oh.DllCharacteristics
+ hasHEVA := (dc & pe.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA) != 0
+ if useASLR && !hasHEVA {
+ t.Error("IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA flag is not set")
+ } else if !useASLR && hasHEVA {
+ t.Error("IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA flag should not be set")
+ }
+ default:
+ t.Fatalf("unexpected optional header type of %T", f.OptionalHeader)
+ }
+ hasASLR := (dc & pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) != 0
+ if useASLR && !hasASLR {
+ t.Error("IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE flag is not set")
+ } else if !useASLR && hasASLR {
+ t.Error("IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE flag should not be set")
+ }
+}
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index f5d41a0b4a..73e0b35bc0 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -247,12 +247,16 @@ type Arch struct {
Elfreloc1 func(*Link, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int, int64) bool
ElfrelocSize uint32 // size of an ELF relocation record, must match Elfreloc1.
Elfsetupplt func(ctxt *Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym)
- Gentext func(*Link, *loader.Loader)
+ Gentext func(*Link, *loader.Loader) // Generate text before addressing has been performed.
Machoreloc1 func(*sys.Arch, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool
MachorelocSize uint32 // size of an Mach-O relocation record, must match Machoreloc1.
PEreloc1 func(*sys.Arch, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool
Xcoffreloc1 func(*sys.Arch, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool
+ // Generate additional symbols for the native symbol table just prior to
+ // code generation.
+ GenSymsLate func(*Link, *loader.Loader)
+
// TLSIEtoLE converts a TLS Initial Executable relocation to
// a TLS Local Executable relocation.
//
@@ -1254,7 +1258,9 @@ func (ctxt *Link) hostlink() {
// -headerpad is incompatible with -fembed-bitcode.
argv = append(argv, "-Wl,-headerpad,1144")
}
- if ctxt.DynlinkingGo() && !ctxt.Arch.InFamily(sys.ARM, sys.ARM64) {
+ if ctxt.DynlinkingGo() && objabi.GOOS != "ios" {
+ // -flat_namespace is deprecated on iOS.
+ // It is useful for supporting plugins. We don't support plugins on iOS.
argv = append(argv, "-Wl,-flat_namespace")
}
if !combineDwarf {
@@ -1290,6 +1296,17 @@ func (ctxt *Link) hostlink() {
argv = append(argv, "-Wl,-bbigtoc")
}
+ // Enable ASLR on Windows.
+ addASLRargs := func(argv []string) []string {
+ // Enable ASLR.
+ argv = append(argv, "-Wl,--dynamicbase")
+ // enable high-entropy ASLR on 64-bit.
+ if ctxt.Arch.PtrSize >= 8 {
+ argv = append(argv, "-Wl,--high-entropy-va")
+ }
+ return argv
+ }
+
switch ctxt.BuildMode {
case BuildModeExe:
if ctxt.HeadType == objabi.Hdarwin {
@@ -1302,12 +1319,7 @@ func (ctxt *Link) hostlink() {
switch ctxt.HeadType {
case objabi.Hdarwin, objabi.Haix:
case objabi.Hwindows:
- // Enable ASLR.
- argv = append(argv, "-Wl,--dynamicbase")
- // enable high-entropy ASLR on 64-bit.
- if ctxt.Arch.PtrSize >= 8 {
- argv = append(argv, "-Wl,--high-entropy-va")
- }
+ argv = addASLRargs(argv)
// Work around binutils limitation that strips relocation table for dynamicbase.
// See https://sourceware.org/bugzilla/show_bug.cgi?id=19011
argv = append(argv, "-Wl,--export-all-symbols")
@@ -1321,9 +1333,6 @@ func (ctxt *Link) hostlink() {
case BuildModeCShared:
if ctxt.HeadType == objabi.Hdarwin {
argv = append(argv, "-dynamiclib")
- if ctxt.Arch.Family != sys.AMD64 {
- argv = append(argv, "-Wl,-read_only_relocs,suppress")
- }
} else {
// ELF.
argv = append(argv, "-Wl,-Bsymbolic")
@@ -1331,7 +1340,11 @@ func (ctxt *Link) hostlink() {
argv = append(argv, "-Wl,-z,relro")
}
argv = append(argv, "-shared")
- if ctxt.HeadType != objabi.Hwindows {
+ if ctxt.HeadType == objabi.Hwindows {
+ if *flagAslr {
+ argv = addASLRargs(argv)
+ }
+ } else {
// Pass -z nodelete to mark the shared library as
// non-closeable: a dlclose will do nothing.
argv = append(argv, "-Wl,-z,nodelete")
@@ -1601,12 +1614,12 @@ func (ctxt *Link) hostlink() {
if combineDwarf {
dsym := filepath.Join(*flagTmpdir, "go.dwarf")
- if out, err := exec.Command("dsymutil", "-f", *flagOutfile, "-o", dsym).CombinedOutput(); err != nil {
+ if out, err := exec.Command("xcrun", "dsymutil", "-f", *flagOutfile, "-o", dsym).CombinedOutput(); err != nil {
Exitf("%s: running dsymutil failed: %v\n%s", os.Args[0], err, out)
}
// Remove STAB (symbolic debugging) symbols after we are done with them (by dsymutil).
// They contain temporary file paths and make the build not reproducible.
- if out, err := exec.Command("strip", "-S", *flagOutfile).CombinedOutput(); err != nil {
+ if out, err := exec.Command("xcrun", "strip", "-S", *flagOutfile).CombinedOutput(); err != nil {
Exitf("%s: running strip failed: %v\n%s", os.Args[0], err, out)
}
// Skip combining if `dsymutil` didn't generate a file. See #11994.
@@ -1757,12 +1770,12 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
if magic == 0x7f454c46 { // \x7F E L F
ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
- textp, flags, err := loadelf.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn, ehdr.flags)
+ textp, flags, err := loadelf.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn, ehdr.Flags)
if err != nil {
Errorf(nil, "%v", err)
return
}
- ehdr.flags = flags
+ ehdr.Flags = flags
ctxt.Textp = append(ctxt.Textp, textp...)
}
return ldhostobj(ldelf, ctxt.HeadType, f, pkg, length, pn, file)
@@ -2507,16 +2520,22 @@ func AddGotSym(target *Target, ldr *loader.Loader, syms *ArchSyms, s loader.Sym,
if target.Arch.PtrSize == 8 {
rela := ldr.MakeSymbolUpdater(syms.Rela)
rela.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
- rela.AddUint64(target.Arch, ELF64_R_INFO(uint32(ldr.SymDynid(s)), elfRelocTyp))
+ rela.AddUint64(target.Arch, elf.R_INFO(uint32(ldr.SymDynid(s)), elfRelocTyp))
rela.AddUint64(target.Arch, 0)
} else {
rel := ldr.MakeSymbolUpdater(syms.Rel)
rel.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
- rel.AddUint32(target.Arch, ELF32_R_INFO(uint32(ldr.SymDynid(s)), elfRelocTyp))
+ rel.AddUint32(target.Arch, elf.R_INFO32(uint32(ldr.SymDynid(s)), elfRelocTyp))
}
} else if target.IsDarwin() {
leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT)
leg.AddUint32(target.Arch, uint32(ldr.SymDynid(s)))
+ if target.IsPIE() && target.IsInternal() {
+ // Mach-O relocations are a royal pain to lay out.
+ // They use a compact stateful bytecode representation.
+ // Here we record what are needed and encode them later.
+ MachoAddBind(int64(ldr.SymGot(s)), s)
+ }
} else {
ldr.Errorf(s, "addgotsym: unsupported binary format")
}
diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go
index 9765ce18d3..155769c48f 100644
--- a/src/cmd/link/internal/ld/macho.go
+++ b/src/cmd/link/internal/ld/macho.go
@@ -76,36 +76,38 @@ const (
)
const (
- MACHO_CPU_AMD64 = 1<<24 | 7
- MACHO_CPU_386 = 7
- MACHO_SUBCPU_X86 = 3
- MACHO_CPU_ARM = 12
- MACHO_SUBCPU_ARM = 0
- MACHO_SUBCPU_ARMV7 = 9
- MACHO_CPU_ARM64 = 1<<24 | 12
- MACHO_SUBCPU_ARM64_ALL = 0
- MACHO32SYMSIZE = 12
- MACHO64SYMSIZE = 16
- MACHO_X86_64_RELOC_UNSIGNED = 0
- MACHO_X86_64_RELOC_SIGNED = 1
- MACHO_X86_64_RELOC_BRANCH = 2
- MACHO_X86_64_RELOC_GOT_LOAD = 3
- MACHO_X86_64_RELOC_GOT = 4
- MACHO_X86_64_RELOC_SUBTRACTOR = 5
- MACHO_X86_64_RELOC_SIGNED_1 = 6
- MACHO_X86_64_RELOC_SIGNED_2 = 7
- MACHO_X86_64_RELOC_SIGNED_4 = 8
- MACHO_ARM_RELOC_VANILLA = 0
- MACHO_ARM_RELOC_PAIR = 1
- MACHO_ARM_RELOC_SECTDIFF = 2
- MACHO_ARM_RELOC_BR24 = 5
- MACHO_ARM64_RELOC_UNSIGNED = 0
- MACHO_ARM64_RELOC_BRANCH26 = 2
- MACHO_ARM64_RELOC_PAGE21 = 3
- MACHO_ARM64_RELOC_PAGEOFF12 = 4
- MACHO_ARM64_RELOC_ADDEND = 10
- MACHO_GENERIC_RELOC_VANILLA = 0
- MACHO_FAKE_GOTPCREL = 100
+ MACHO_CPU_AMD64 = 1<<24 | 7
+ MACHO_CPU_386 = 7
+ MACHO_SUBCPU_X86 = 3
+ MACHO_CPU_ARM = 12
+ MACHO_SUBCPU_ARM = 0
+ MACHO_SUBCPU_ARMV7 = 9
+ MACHO_CPU_ARM64 = 1<<24 | 12
+ MACHO_SUBCPU_ARM64_ALL = 0
+ MACHO32SYMSIZE = 12
+ MACHO64SYMSIZE = 16
+ MACHO_X86_64_RELOC_UNSIGNED = 0
+ MACHO_X86_64_RELOC_SIGNED = 1
+ MACHO_X86_64_RELOC_BRANCH = 2
+ MACHO_X86_64_RELOC_GOT_LOAD = 3
+ MACHO_X86_64_RELOC_GOT = 4
+ MACHO_X86_64_RELOC_SUBTRACTOR = 5
+ MACHO_X86_64_RELOC_SIGNED_1 = 6
+ MACHO_X86_64_RELOC_SIGNED_2 = 7
+ MACHO_X86_64_RELOC_SIGNED_4 = 8
+ MACHO_ARM_RELOC_VANILLA = 0
+ MACHO_ARM_RELOC_PAIR = 1
+ MACHO_ARM_RELOC_SECTDIFF = 2
+ MACHO_ARM_RELOC_BR24 = 5
+ MACHO_ARM64_RELOC_UNSIGNED = 0
+ MACHO_ARM64_RELOC_BRANCH26 = 2
+ MACHO_ARM64_RELOC_PAGE21 = 3
+ MACHO_ARM64_RELOC_PAGEOFF12 = 4
+ MACHO_ARM64_RELOC_GOT_LOAD_PAGE21 = 5
+ MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12 = 6
+ MACHO_ARM64_RELOC_ADDEND = 10
+ MACHO_GENERIC_RELOC_VANILLA = 0
+ MACHO_FAKE_GOTPCREL = 100
)
const (
@@ -116,6 +118,8 @@ const (
MH_EXECUTE = 0x2
MH_NOUNDEFS = 0x1
+ MH_DYLDLINK = 0x4
+ MH_PIE = 0x200000
)
const (
@@ -191,6 +195,56 @@ const (
PLATFORM_BRIDGEOS MachoPlatform = 5
)
+// rebase table opcode
+const (
+ REBASE_TYPE_POINTER = 1
+ REBASE_TYPE_TEXT_ABSOLUTE32 = 2
+ REBASE_TYPE_TEXT_PCREL32 = 3
+
+ REBASE_OPCODE_MASK = 0xF0
+ REBASE_IMMEDIATE_MASK = 0x0F
+ REBASE_OPCODE_DONE = 0x00
+ REBASE_OPCODE_SET_TYPE_IMM = 0x10
+ REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB = 0x20
+ REBASE_OPCODE_ADD_ADDR_ULEB = 0x30
+ REBASE_OPCODE_ADD_ADDR_IMM_SCALED = 0x40
+ REBASE_OPCODE_DO_REBASE_IMM_TIMES = 0x50
+ REBASE_OPCODE_DO_REBASE_ULEB_TIMES = 0x60
+ REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB = 0x70
+ REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB = 0x80
+)
+
+// bind table opcode
+const (
+ BIND_TYPE_POINTER = 1
+ BIND_TYPE_TEXT_ABSOLUTE32 = 2
+ BIND_TYPE_TEXT_PCREL32 = 3
+
+ BIND_SPECIAL_DYLIB_SELF = 0
+ BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE = -1
+ BIND_SPECIAL_DYLIB_FLAT_LOOKUP = -2
+ BIND_SPECIAL_DYLIB_WEAK_LOOKUP = -3
+
+ BIND_OPCODE_MASK = 0xF0
+ BIND_IMMEDIATE_MASK = 0x0F
+ BIND_OPCODE_DONE = 0x00
+ BIND_OPCODE_SET_DYLIB_ORDINAL_IMM = 0x10
+ BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB = 0x20
+ BIND_OPCODE_SET_DYLIB_SPECIAL_IMM = 0x30
+ BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM = 0x40
+ BIND_OPCODE_SET_TYPE_IMM = 0x50
+ BIND_OPCODE_SET_ADDEND_SLEB = 0x60
+ BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB = 0x70
+ BIND_OPCODE_ADD_ADDR_ULEB = 0x80
+ BIND_OPCODE_DO_BIND = 0x90
+ BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB = 0xA0
+ BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED = 0xB0
+ BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB = 0xC0
+ BIND_OPCODE_THREADED = 0xD0
+ BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB = 0x00
+ BIND_SUBOPCODE_THREADED_APPLY = 0x01
+)
+
// Mach-O file writing
// https://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
@@ -277,7 +331,7 @@ var dylib []string
var linkoff int64
-func machowrite(arch *sys.Arch, out *OutBuf, linkmode LinkMode) int {
+func machowrite(ctxt *Link, arch *sys.Arch, out *OutBuf, linkmode LinkMode) int {
o1 := out.Offset()
loadsize := 4 * 4 * ndebug
@@ -306,11 +360,14 @@ func machowrite(arch *sys.Arch, out *OutBuf, linkmode LinkMode) int {
}
out.Write32(uint32(len(load)) + uint32(nseg) + uint32(ndebug))
out.Write32(uint32(loadsize))
+ flags := uint32(0)
if nkind[SymKindUndef] == 0 {
- out.Write32(MH_NOUNDEFS) /* flags - no undefines */
- } else {
- out.Write32(0) /* flags */
+ flags |= MH_NOUNDEFS
+ }
+ if ctxt.IsPIE() && linkmode == LinkInternal {
+ flags |= MH_PIE | MH_DYLDLINK
}
+ out.Write32(flags) /* flags */
if arch.PtrSize == 8 {
out.Write32(0) /* reserved */
}
@@ -473,6 +530,18 @@ func (ctxt *Link) domacho() {
sb.SetReachable(true)
sb.AddUint8(0)
}
+
+ // Do not export C symbols dynamically in plugins, as runtime C symbols like crosscall2
+ // are in pclntab and end up pointing at the host binary, breaking unwinding.
+ // See Issue #18190.
+ if ctxt.BuildMode == BuildModePlugin {
+ for _, name := range []string{"_cgo_topofstack", "__cgo_topofstack", "_cgo_panic", "crosscall2"} {
+ s := ctxt.loader.Lookup(name, 0)
+ if s != 0 {
+ ctxt.loader.SetAttrCgoExportDynamic(s, false)
+ }
+ }
+ }
}
func machoadddynlib(lib string, linkmode LinkMode) {
@@ -682,11 +751,9 @@ func asmbMacho(ctxt *Link) {
ml.data[2+32+1] = uint32(Entryvalue(ctxt) >> 32)
case sys.ARM64:
- ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 68+2)
- ml.data[0] = 6 /* thread type */
- ml.data[1] = 68 /* word count */
- ml.data[2+64] = uint32(Entryvalue(ctxt)) /* start pc */
- ml.data[2+64+1] = uint32(Entryvalue(ctxt) >> 32)
+ ml := newMachoLoad(ctxt.Arch, LC_MAIN, 4)
+ ml.data[0] = uint32(uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR)))
+ ml.data[1] = uint32((uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR))) >> 32)
}
}
@@ -698,15 +765,17 @@ func asmbMacho(ctxt *Link) {
s2 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT)
s3 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT)
s4 := ldr.SymSize(ldr.Lookup(".machosymstr", 0))
+ s5 := ldr.SymSize(ldr.Lookup(".machorebase", 0))
+ s6 := ldr.SymSize(ldr.Lookup(".machobind", 0))
if ctxt.LinkMode != LinkExternal {
ms := newMachoSeg("__LINKEDIT", 0)
ms.vaddr = uint64(Rnd(int64(Segdata.Vaddr+Segdata.Length), int64(*FlagRound)))
- ms.vsize = uint64(s1) + uint64(s2) + uint64(s3) + uint64(s4)
+ ms.vsize = uint64(s1 + s2 + s3 + s4 + s5 + s6)
ms.fileoffset = uint64(linkoff)
ms.filesize = ms.vsize
- ms.prot1 = 7
- ms.prot2 = 3
+ ms.prot1 = 1
+ ms.prot2 = 1
}
ml := newMachoLoad(ctxt.Arch, LC_SYMTAB, 4)
@@ -731,9 +800,23 @@ func asmbMacho(ctxt *Link) {
stringtouint32(ml.data[4:], lib)
}
}
+
+ if ctxt.LinkMode != LinkExternal && ctxt.IsPIE() {
+ ml := newMachoLoad(ctxt.Arch, LC_DYLD_INFO_ONLY, 10)
+ ml.data[0] = uint32(linkoff + s1 + s2 + s3 + s4) // rebase off
+ ml.data[1] = uint32(s5) // rebase size
+ ml.data[2] = uint32(linkoff + s1 + s2 + s3 + s4 + s5) // bind off
+ ml.data[3] = uint32(s6) // bind size
+ ml.data[4] = 0 // weak bind off
+ ml.data[5] = 0 // weak bind size
+ ml.data[6] = 0 // lazy bind off
+ ml.data[7] = 0 // lazy bind size
+ ml.data[8] = 0 // export
+ ml.data[9] = 0 // export size
+ }
}
- a := machowrite(ctxt.Arch, ctxt.Out, ctxt.LinkMode)
+ a := machowrite(ctxt, ctxt.Arch, ctxt.Out, ctxt.LinkMode)
if int32(a) > HEADR {
Exitf("HEADR too small: %d > %d", a, HEADR)
}
@@ -818,12 +901,10 @@ func collectmachosyms(ctxt *Link) {
switch objabi.GOARCH {
case "amd64":
ldr.SetSymExtname(s, n+"$INODE64")
- case "386":
- ldr.SetSymExtname(s, n+"$INODE64$UNIX2003")
}
case "readdir_r", "getfsstat":
switch objabi.GOARCH {
- case "amd64", "386":
+ case "amd64":
ldr.SetSymExtname(s, n+"$INODE64")
}
}
@@ -897,19 +978,12 @@ func machosymtab(ctxt *Link) {
symtab.AddUint32(ctxt.Arch, uint32(symstr.Size()))
export := machoShouldExport(ctxt, ldr, s)
- isGoSymbol := strings.Contains(ldr.SymExtname(s), ".")
-
- // In normal buildmodes, only add _ to C symbols, as
- // Go symbols have dot in the name.
- //
- // Do not export C symbols in plugins, as runtime C
- // symbols like crosscall2 are in pclntab and end up
- // pointing at the host binary, breaking unwinding.
- // See Issue #18190.
- cexport := !isGoSymbol && (ctxt.BuildMode != BuildModePlugin || onlycsymbol(ldr.SymName(s)))
- if cexport || export || isGoSymbol {
- symstr.AddUint8('_')
- }
+
+ // Prefix symbol names with "_" to match the system toolchain.
+ // (We used to only prefix C symbols, which is all required for the build.
+ // But some tools don't recognize Go symbols as symbols, so we prefix them
+ // as well.)
+ symstr.AddUint8('_')
// replace "ยท" as ".", because DTrace cannot handle it.
symstr.Addstring(strings.Replace(ldr.SymExtname(s), "ยท", ".", -1))
@@ -920,10 +994,13 @@ func machosymtab(ctxt *Link) {
symtab.AddUint16(ctxt.Arch, 0) // desc
symtab.AddUintXX(ctxt.Arch, 0, ctxt.Arch.PtrSize) // no value
} else {
- if ldr.AttrCgoExport(s) || export {
- symtab.AddUint8(0x0f)
+ if export || ldr.AttrCgoExportDynamic(s) {
+ symtab.AddUint8(0x0f) // N_SECT | N_EXT
+ } else if ldr.AttrCgoExportStatic(s) {
+ // Only export statically, not dynamically. (N_PEXT is like hidden visibility)
+ symtab.AddUint8(0x1f) // N_SECT | N_EXT | N_PEXT
} else {
- symtab.AddUint8(0x0e)
+ symtab.AddUint8(0x0e) // N_SECT
}
o := s
if outer := ldr.OuterSym(o); outer != 0 {
@@ -981,6 +1058,8 @@ func machodysymtab(ctxt *Link) {
func doMachoLink(ctxt *Link) int64 {
machosymtab(ctxt)
+ machoDyldInfo(ctxt)
+
ldr := ctxt.loader
// write data that will be linkedit section
@@ -988,6 +1067,8 @@ func doMachoLink(ctxt *Link) int64 {
s2 := ctxt.ArchSyms.LinkEditPLT
s3 := ctxt.ArchSyms.LinkEditGOT
s4 := ldr.Lookup(".machosymstr", 0)
+ s5 := ldr.Lookup(".machorebase", 0)
+ s6 := ldr.Lookup(".machobind", 0)
// Force the linkedit section to end on a 16-byte
// boundary. This allows pure (non-cgo) Go binaries
@@ -1011,7 +1092,7 @@ func doMachoLink(ctxt *Link) int64 {
s4b.AddUint8(0)
}
- size := int(ldr.SymSize(s1) + ldr.SymSize(s2) + ldr.SymSize(s3) + ldr.SymSize(s4))
+ size := int(ldr.SymSize(s1) + ldr.SymSize(s2) + ldr.SymSize(s3) + ldr.SymSize(s4) + ldr.SymSize(s5) + ldr.SymSize(s6))
if size > 0 {
linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound)) + Rnd(int64(Segrelrodata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdwarf.Filelen), int64(*FlagRound))
@@ -1021,6 +1102,8 @@ func doMachoLink(ctxt *Link) int64 {
ctxt.Out.Write(ldr.Data(s2))
ctxt.Out.Write(ldr.Data(s3))
ctxt.Out.Write(ldr.Data(s4))
+ ctxt.Out.Write(ldr.Data(s5))
+ ctxt.Out.Write(ldr.Data(s6))
}
return Rnd(int64(size), int64(*FlagRound))
@@ -1164,3 +1247,134 @@ func peekMachoPlatform(m *macho.File) (*MachoPlatformLoad, error) {
}
return nil, nil
}
+
+// A rebase entry tells the dynamic linker the data at sym+off needs to be
+// relocated when the in-memory image moves. (This is somewhat like, say,
+// ELF R_X86_64_RELATIVE).
+// For now, the only kind of entry we support is that the data is an absolute
+// address. That seems all we need.
+// In the binary it uses a compact stateful bytecode encoding. So we record
+// entries as we go and build the table at the end.
+type machoRebaseRecord struct {
+ sym loader.Sym
+ off int64
+}
+
+var machorebase []machoRebaseRecord
+
+func MachoAddRebase(s loader.Sym, off int64) {
+ machorebase = append(machorebase, machoRebaseRecord{s, off})
+}
+
+// A bind entry tells the dynamic linker the data at GOT+off should be bound
+// to the address of the target symbol, which is a dynamic import.
+// For now, the only kind of entry we support is that the data is an absolute
+// address, and the source symbol is always the GOT. That seems all we need.
+// In the binary it uses a compact stateful bytecode encoding. So we record
+// entries as we go and build the table at the end.
+type machoBindRecord struct {
+ off int64
+ targ loader.Sym
+}
+
+var machobind []machoBindRecord
+
+func MachoAddBind(off int64, targ loader.Sym) {
+ machobind = append(machobind, machoBindRecord{off, targ})
+}
+
+// Generate data for the dynamic linker, used in LC_DYLD_INFO_ONLY load command.
+// See mach-o/loader.h, struct dyld_info_command, for the encoding.
+// e.g. https://opensource.apple.com/source/xnu/xnu-6153.81.5/EXTERNAL_HEADERS/mach-o/loader.h
+func machoDyldInfo(ctxt *Link) {
+ ldr := ctxt.loader
+ rebase := ldr.CreateSymForUpdate(".machorebase", 0)
+ bind := ldr.CreateSymForUpdate(".machobind", 0)
+
+ if !(ctxt.IsPIE() && ctxt.IsInternal()) {
+ return
+ }
+
+ segId := func(seg *sym.Segment) uint8 {
+ switch seg {
+ case &Segtext:
+ return 1
+ case &Segrelrodata:
+ return 2
+ case &Segdata:
+ if Segrelrodata.Length > 0 {
+ return 3
+ }
+ return 2
+ }
+ panic("unknown segment")
+ }
+
+ dylibId := func(s loader.Sym) int {
+ slib := ldr.SymDynimplib(s)
+ for i, lib := range dylib {
+ if lib == slib {
+ return i + 1
+ }
+ }
+ return BIND_SPECIAL_DYLIB_FLAT_LOOKUP // don't know where it is from
+ }
+
+ // Rebase table.
+ // TODO: use more compact encoding. The encoding is stateful, and
+ // we can use delta encoding.
+ rebase.AddUint8(REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER)
+ for _, r := range machorebase {
+ seg := ldr.SymSect(r.sym).Seg
+ off := uint64(ldr.SymValue(r.sym)+r.off) - seg.Vaddr
+ rebase.AddUint8(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg))
+ rebase.AddUleb(off)
+
+ rebase.AddUint8(REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1)
+ }
+ rebase.AddUint8(REBASE_OPCODE_DONE)
+ sz := Rnd(rebase.Size(), 8)
+ rebase.Grow(sz)
+ rebase.SetSize(sz)
+
+ // Bind table.
+ // TODO: compact encoding, as above.
+ // TODO: lazy binding?
+ got := ctxt.GOT
+ seg := ldr.SymSect(got).Seg
+ gotAddr := ldr.SymValue(got)
+ bind.AddUint8(BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER)
+ for _, r := range machobind {
+ off := uint64(gotAddr+r.off) - seg.Vaddr
+ bind.AddUint8(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg))
+ bind.AddUleb(off)
+
+ d := dylibId(r.targ)
+ if d > 0 && d < 128 {
+ bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | uint8(d)&0xf)
+ } else if d >= 128 {
+ bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB)
+ bind.AddUleb(uint64(d))
+ } else { // d <= 0
+ bind.AddUint8(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | uint8(d)&0xf)
+ }
+
+ bind.AddUint8(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM)
+ // target symbol name as a C string, with _ prefix
+ bind.AddUint8('_')
+ bind.Addstring(ldr.SymExtname(r.targ))
+
+ bind.AddUint8(BIND_OPCODE_DO_BIND)
+ }
+ bind.AddUint8(BIND_OPCODE_DONE)
+ sz = Rnd(bind.Size(), 16) // make it 16-byte aligned, see the comment in doMachoLink
+ bind.Grow(sz)
+ bind.SetSize(sz)
+
+ // TODO: export table.
+ // The symbols names are encoded as a trie. I'm really too lazy to do that
+ // for now.
+ // Without it, the symbols are not dynamically exported, so they cannot be
+ // e.g. dlsym'd. But internal linking is not the default in that case, so
+ // it is fine.
+}
diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go
index 778b0e9245..5c8293810f 100644
--- a/src/cmd/link/internal/ld/main.go
+++ b/src/cmd/link/internal/ld/main.go
@@ -36,14 +36,12 @@ import (
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/benchmark"
- "cmd/link/internal/loader"
"flag"
"log"
"os"
"runtime"
"runtime/pprof"
"strings"
- "sync"
)
var (
@@ -67,6 +65,7 @@ var (
flagDumpDep = flag.Bool("dumpdep", false, "dump symbol dependency graph")
flagRace = flag.Bool("race", false, "enable race detector")
flagMsan = flag.Bool("msan", false, "enable MSan interface")
+ flagAslr = flag.Bool("aslr", true, "enable ASLR for buildmode=c-shared on windows")
flagFieldTrack = flag.String("k", "", "set field tracking `symbol`")
flagLibGCC = flag.String("libgcc", "", "compiler support lib for internal linking; use \"none\" to disable")
@@ -159,11 +158,16 @@ func Main(arch *sys.Arch, theArch Arch) {
ctxt.HeadType.Set(objabi.GOOS)
}
+ if !*flagAslr && ctxt.BuildMode != BuildModeCShared {
+ Errorf(nil, "-aslr=false is only allowed for -buildmode=c-shared")
+ usage()
+ }
+
checkStrictDups = *FlagStrictDups
startProfile()
if ctxt.BuildMode == BuildModeUnset {
- ctxt.BuildMode = BuildModeExe
+ ctxt.BuildMode.Set("exe")
}
if ctxt.BuildMode != BuildModeShared && flag.NArg() != 1 {
@@ -325,16 +329,14 @@ func Main(arch *sys.Arch, theArch Arch) {
// will be applied directly there.
bench.Start("Asmb")
asmb(ctxt)
- // Generate large symbols.
- var wg sync.WaitGroup
- for s, f := range ctxt.generatorSyms {
- wg.Add(1)
- go func(f generatorFunc, s loader.Sym) {
- defer wg.Done()
- f(ctxt, s)
- }(f, s)
+
+ // Generate additional symbols for the native symbol table just prior
+ // to code generation.
+ bench.Start("GenSymsLate")
+ if thearch.GenSymsLate != nil {
+ thearch.GenSymsLate(ctxt, ctxt.loader)
}
- wg.Wait()
+
bench.Start("Asmb2")
asmb2(ctxt)
diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go
index 75e63248df..facb30fe15 100644
--- a/src/cmd/link/internal/ld/pcln.go
+++ b/src/cmd/link/internal/ld/pcln.go
@@ -13,7 +13,6 @@ import (
"fmt"
"os"
"path/filepath"
- "strings"
)
// pclntab holds the state needed for pclntab generation.
@@ -113,23 +112,7 @@ func makePclntab(ctxt *Link, container loader.Bitmap) (*pclntab, []*sym.Compilat
return state, compUnits, funcs
}
-// onlycsymbol looks at a symbol's name to report whether this is a
-// symbol that is referenced by C code
-func onlycsymbol(sname string) bool {
- switch sname {
- case "_cgo_topofstack", "__cgo_topofstack", "_cgo_panic", "crosscall2":
- return true
- }
- if strings.HasPrefix(sname, "_cgoexp_") {
- return true
- }
- return false
-}
-
func emitPcln(ctxt *Link, s loader.Sym, container loader.Bitmap) bool {
- if ctxt.BuildMode == BuildModePlugin && ctxt.HeadType == objabi.Hdarwin && onlycsymbol(ctxt.loader.SymName(s)) {
- return false
- }
// We want to generate func table entries only for the "lowest
// level" symbols, not containers of subsymbols.
return !container.Has(s)
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
index dd82963a41..2e2e392c59 100644
--- a/src/cmd/link/internal/ld/symtab.go
+++ b/src/cmd/link/internal/ld/symtab.go
@@ -34,6 +34,7 @@ import (
"cmd/internal/objabi"
"cmd/link/internal/loader"
"cmd/link/internal/sym"
+ "debug/elf"
"fmt"
"path/filepath"
"strings"
@@ -53,10 +54,10 @@ func putelfstr(s string) int {
return off
}
-func putelfsyment(out *OutBuf, off int, addr int64, size int64, info int, shndx int, other int) {
+func putelfsyment(out *OutBuf, off int, addr int64, size int64, info uint8, shndx elf.SectionIndex, other int) {
if elf64 {
out.Write32(uint32(off))
- out.Write8(uint8(info))
+ out.Write8(info)
out.Write8(uint8(other))
out.Write16(uint16(shndx))
out.Write64(uint64(addr))
@@ -66,14 +67,14 @@ func putelfsyment(out *OutBuf, off int, addr int64, size int64, info int, shndx
out.Write32(uint32(off))
out.Write32(uint32(addr))
out.Write32(uint32(size))
- out.Write8(uint8(info))
+ out.Write8(info)
out.Write8(uint8(other))
out.Write16(uint16(shndx))
symSize += ELF32SYMSIZE
}
}
-func putelfsym(ctxt *Link, x loader.Sym, typ int, curbind int) {
+func putelfsym(ctxt *Link, x loader.Sym, typ elf.SymType, curbind elf.SymBind) {
ldr := ctxt.loader
addr := ldr.SymValue(x)
size := ldr.SymSize(x)
@@ -85,9 +86,9 @@ func putelfsym(ctxt *Link, x loader.Sym, typ int, curbind int) {
xot := ldr.SymType(xo)
xosect := ldr.SymSect(xo)
- var elfshnum int
+ var elfshnum elf.SectionIndex
if xot == sym.SDYNIMPORT || xot == sym.SHOSTOBJ || xot == sym.SUNDEFEXT {
- elfshnum = SHN_UNDEF
+ elfshnum = elf.SHN_UNDEF
size = 0
} else {
if xosect == nil {
@@ -101,11 +102,11 @@ func putelfsym(ctxt *Link, x loader.Sym, typ int, curbind int) {
elfshnum = xosect.Elfsect.(*ElfShdr).shnum
}
- // One pass for each binding: STB_LOCAL, STB_GLOBAL,
- // maybe one day STB_WEAK.
- bind := STB_GLOBAL
+ // One pass for each binding: elf.STB_LOCAL, elf.STB_GLOBAL,
+ // maybe one day elf.STB_WEAK.
+ bind := elf.STB_GLOBAL
if ldr.IsFileLocal(x) || ldr.AttrVisibilityHidden(x) || ldr.AttrLocal(x) {
- bind = STB_LOCAL
+ bind = elf.STB_LOCAL
}
// In external linking mode, we have to invoke gcc with -rdynamic
@@ -113,23 +114,23 @@ func putelfsym(ctxt *Link, x loader.Sym, typ int, curbind int) {
// To avoid filling the dynamic table with lots of unnecessary symbols,
// mark all Go symbols local (not global) in the final executable.
// But when we're dynamically linking, we need all those global symbols.
- if !ctxt.DynlinkingGo() && ctxt.IsExternal() && !ldr.AttrCgoExportStatic(x) && elfshnum != SHN_UNDEF {
- bind = STB_LOCAL
+ if !ctxt.DynlinkingGo() && ctxt.IsExternal() && !ldr.AttrCgoExportStatic(x) && elfshnum != elf.SHN_UNDEF {
+ bind = elf.STB_LOCAL
}
- if ctxt.LinkMode == LinkExternal && elfshnum != SHN_UNDEF {
+ if ctxt.LinkMode == LinkExternal && elfshnum != elf.SHN_UNDEF {
addr -= int64(xosect.Vaddr)
}
- other := STV_DEFAULT
+ other := int(elf.STV_DEFAULT)
if ldr.AttrVisibilityHidden(x) {
// TODO(mwhudson): We only set AttrVisibilityHidden in ldelf, i.e. when
// internally linking. But STV_HIDDEN visibility only matters in object
// files and shared libraries, and as we are a long way from implementing
// internal linking for shared libraries and only create object files when
// externally linking, I don't think this makes a lot of sense.
- other = STV_HIDDEN
+ other = int(elf.STV_HIDDEN)
}
- if ctxt.IsPPC64() && typ == STT_FUNC && ldr.AttrShared(x) && ldr.SymName(x) != "runtime.duffzero" && ldr.SymName(x) != "runtime.duffcopy" {
+ if ctxt.IsPPC64() && typ == elf.STT_FUNC && ldr.AttrShared(x) && ldr.SymName(x) != "runtime.duffzero" && ldr.SymName(x) != "runtime.duffcopy" {
// On ppc64 the top three bits of the st_other field indicate how
// many instructions separate the global and local entry points. In
// our case it is two instructions, indicated by the value 3.
@@ -149,7 +150,7 @@ func putelfsym(ctxt *Link, x loader.Sym, typ int, curbind int) {
sname = strings.Replace(sname, "ยท", ".", -1)
}
- if ctxt.DynlinkingGo() && bind == STB_GLOBAL && curbind == STB_LOCAL && ldr.SymType(x) == sym.STEXT {
+ if ctxt.DynlinkingGo() && bind == elf.STB_GLOBAL && curbind == elf.STB_LOCAL && ldr.SymType(x) == sym.STEXT {
// When dynamically linking, we want references to functions defined
// in this module to always be to the function object, not to the
// PLT. We force this by writing an additional local symbol for every
@@ -158,7 +159,7 @@ func putelfsym(ctxt *Link, x loader.Sym, typ int, curbind int) {
// (*sym.Symbol).ElfsymForReloc). This is approximately equivalent to the
// ELF linker -Bsymbolic-functions option, but that is buggy on
// several platforms.
- putelfsyment(ctxt.Out, putelfstr("local."+sname), addr, size, STB_LOCAL<<4|typ&0xf, elfshnum, other)
+ putelfsyment(ctxt.Out, putelfstr("local."+sname), addr, size, elf.ST_INFO(elf.STB_LOCAL, typ), elfshnum, other)
ldr.SetSymLocalElfSym(x, int32(ctxt.numelfsym))
ctxt.numelfsym++
return
@@ -166,23 +167,23 @@ func putelfsym(ctxt *Link, x loader.Sym, typ int, curbind int) {
return
}
- putelfsyment(ctxt.Out, putelfstr(sname), addr, size, bind<<4|typ&0xf, elfshnum, other)
+ putelfsyment(ctxt.Out, putelfstr(sname), addr, size, elf.ST_INFO(bind, typ), elfshnum, other)
ldr.SetSymElfSym(x, int32(ctxt.numelfsym))
ctxt.numelfsym++
}
-func putelfsectionsym(ctxt *Link, out *OutBuf, s loader.Sym, shndx int) {
- putelfsyment(out, 0, 0, 0, STB_LOCAL<<4|STT_SECTION, shndx, 0)
+func putelfsectionsym(ctxt *Link, out *OutBuf, s loader.Sym, shndx elf.SectionIndex) {
+ putelfsyment(out, 0, 0, 0, elf.ST_INFO(elf.STB_LOCAL, elf.STT_SECTION), shndx, 0)
ctxt.loader.SetSymElfSym(s, int32(ctxt.numelfsym))
ctxt.numelfsym++
}
-func genelfsym(ctxt *Link, elfbind int) {
+func genelfsym(ctxt *Link, elfbind elf.SymBind) {
ldr := ctxt.loader
// runtime.text marker symbol(s).
s := ldr.Lookup("runtime.text", 0)
- putelfsym(ctxt, s, STT_FUNC, elfbind)
+ putelfsym(ctxt, s, elf.STT_FUNC, elfbind)
for k, sect := range Segtext.Sections[1:] {
n := k + 1
if sect.Name != ".text" || (ctxt.IsAIX() && ctxt.IsExternal()) {
@@ -196,18 +197,18 @@ func genelfsym(ctxt *Link, elfbind int) {
if ldr.SymType(s) != sym.STEXT {
panic("unexpected type for runtime.text symbol")
}
- putelfsym(ctxt, s, STT_FUNC, elfbind)
+ putelfsym(ctxt, s, elf.STT_FUNC, elfbind)
}
// Text symbols.
for _, s := range ctxt.Textp {
- putelfsym(ctxt, s, STT_FUNC, elfbind)
+ putelfsym(ctxt, s, elf.STT_FUNC, elfbind)
}
// runtime.etext marker symbol.
s = ldr.Lookup("runtime.etext", 0)
if ldr.SymType(s) == sym.STEXT {
- putelfsym(ctxt, s, STT_FUNC, elfbind)
+ putelfsym(ctxt, s, elf.STT_FUNC, elfbind)
}
shouldBeInSymbolTable := func(s loader.Sym) bool {
@@ -236,12 +237,12 @@ func genelfsym(ctxt *Link, elfbind int) {
}
st := ldr.SymType(s)
if st >= sym.SELFRXSECT && st < sym.SXREF {
- typ := STT_OBJECT
+ typ := elf.STT_OBJECT
if st == sym.STLSBSS {
if ctxt.IsInternal() {
continue
}
- typ = STT_TLS
+ typ = elf.STT_TLS
}
if !shouldBeInSymbolTable(s) {
continue
@@ -250,7 +251,7 @@ func genelfsym(ctxt *Link, elfbind int) {
continue
}
if st == sym.SHOSTOBJ || st == sym.SDYNIMPORT || st == sym.SUNDEFEXT {
- putelfsym(ctxt, s, int(ldr.SymElfType(s)), elfbind)
+ putelfsym(ctxt, s, ldr.SymElfType(s), elfbind)
}
}
}
@@ -258,7 +259,7 @@ func genelfsym(ctxt *Link, elfbind int) {
func asmElfSym(ctxt *Link) {
// the first symbol entry is reserved
- putelfsyment(ctxt.Out, 0, 0, 0, STB_LOCAL<<4|STT_NOTYPE, 0, 0)
+ putelfsyment(ctxt.Out, 0, 0, 0, elf.ST_INFO(elf.STB_LOCAL, elf.STT_NOTYPE), 0, 0)
dwarfaddelfsectionsyms(ctxt)
@@ -266,12 +267,12 @@ func asmElfSym(ctxt *Link) {
// Avoid having the working directory inserted into the symbol table.
// It is added with a name to avoid problems with external linking
// encountered on some versions of Solaris. See issue #14957.
- putelfsyment(ctxt.Out, putelfstr("go.go"), 0, 0, STB_LOCAL<<4|STT_FILE, SHN_ABS, 0)
+ putelfsyment(ctxt.Out, putelfstr("go.go"), 0, 0, elf.ST_INFO(elf.STB_LOCAL, elf.STT_FILE), elf.SHN_ABS, 0)
ctxt.numelfsym++
- bindings := []int{STB_LOCAL, STB_GLOBAL}
+ bindings := []elf.SymBind{elf.STB_LOCAL, elf.STB_GLOBAL}
for _, elfbind := range bindings {
- if elfbind == STB_GLOBAL {
+ if elfbind == elf.STB_GLOBAL {
elfglobalsymndx = ctxt.numelfsym
}
genelfsym(ctxt, elfbind)
@@ -580,8 +581,12 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind {
symGroupType[s] = sym.SGOFUNC
ldr.SetAttrNotInSymbolTable(s, true)
ldr.SetCarrierSym(s, symgofunc)
- const align = 4
- ldr.SetSymAlign(s, align)
+ align := int32(4)
+ if a := ldr.SymAlign(s); a < align {
+ ldr.SetSymAlign(s, align)
+ } else {
+ align = a
+ }
liveness += (ldr.SymSize(s) + int64(align) - 1) &^ (int64(align) - 1)
}
}
diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go
index 19d8d98b1e..d861efcb13 100644
--- a/src/cmd/link/internal/loader/loader.go
+++ b/src/cmd/link/internal/loader/loader.go
@@ -1791,6 +1791,11 @@ func (l *Loader) SortSub(s Sym) Sym {
return sl[0].s
}
+// SortSyms sorts a list of symbols by their value.
+func (l *Loader) SortSyms(ss []Sym) {
+ sort.SliceStable(ss, func(i, j int) bool { return l.SymValue(ss[i]) < l.SymValue(ss[j]) })
+}
+
// Insure that reachable bitmap and its siblings have enough size.
func (l *Loader) growAttrBitmaps(reqLen int) {
if reqLen > l.attrReachable.Len() {
@@ -2617,11 +2622,15 @@ func (l *Loader) Dump() {
fmt.Println("Nsyms:", len(l.objSyms))
fmt.Println("syms")
for i := Sym(1); i < Sym(len(l.objSyms)); i++ {
- pi := interface{}("")
+ pi := ""
if l.IsExternal(i) {
pi = fmt.Sprintf("<ext %d>", l.extIndex(i))
}
- fmt.Println(i, l.SymName(i), l.SymType(i), pi)
+ sect := ""
+ if l.SymSect(i) != nil {
+ sect = l.SymSect(i).Name
+ }
+ fmt.Printf("%v %v %v %v %x %v\n", i, l.SymName(i), l.SymType(i), pi, l.SymValue(i), sect)
}
fmt.Println("symsByName")
for name, i := range l.symsByName[0] {
diff --git a/src/cmd/link/internal/loader/symbolbuilder.go b/src/cmd/link/internal/loader/symbolbuilder.go
index c0c723d7f0..5d37da8ac6 100644
--- a/src/cmd/link/internal/loader/symbolbuilder.go
+++ b/src/cmd/link/internal/loader/symbolbuilder.go
@@ -420,3 +420,21 @@ func (sb *SymbolBuilder) MakeWritable() {
sb.l.SetAttrReadOnly(sb.symIdx, false)
}
}
+
+func (sb *SymbolBuilder) AddUleb(v uint64) {
+ if v < 128 { // common case: 1 byte
+ sb.AddUint8(uint8(v))
+ return
+ }
+ for {
+ c := uint8(v & 0x7f)
+ v >>= 7
+ if v != 0 {
+ c |= 0x80
+ }
+ sb.AddUint8(c)
+ if c&0x80 == 0 {
+ break
+ }
+ }
+}
diff --git a/src/cmd/link/internal/loadmacho/ldmacho.go b/src/cmd/link/internal/loadmacho/ldmacho.go
index 864d80835b..d12f2bc2ac 100644
--- a/src/cmd/link/internal/loadmacho/ldmacho.go
+++ b/src/cmd/link/internal/loadmacho/ldmacho.go
@@ -43,7 +43,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
-// TODO(crawshaw): de-duplicate these symbols with cmd/internal/ld
+// TODO(crawshaw): de-duplicate these symbols with cmd/link/internal/ld
const (
MACHO_X86_64_RELOC_UNSIGNED = 0
MACHO_X86_64_RELOC_SIGNED = 1
@@ -172,11 +172,12 @@ const (
LdMachoCpuVax = 1
LdMachoCpu68000 = 6
LdMachoCpu386 = 7
- LdMachoCpuAmd64 = 0x1000007
+ LdMachoCpuAmd64 = 1<<24 | 7
LdMachoCpuMips = 8
LdMachoCpu98000 = 10
LdMachoCpuHppa = 11
LdMachoCpuArm = 12
+ LdMachoCpuArm64 = 1<<24 | 12
LdMachoCpu88000 = 13
LdMachoCpuSparc = 14
LdMachoCpu860 = 15
@@ -471,11 +472,14 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader,
switch arch.Family {
default:
return errorf("mach-o %s unimplemented", arch.Name)
-
case sys.AMD64:
if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 {
return errorf("mach-o object but not amd64")
}
+ case sys.ARM64:
+ if e != binary.LittleEndian || m.cputype != LdMachoCpuArm64 {
+ return errorf("mach-o object but not arm64")
+ }
}
m.cmd = make([]ldMachoCmd, ncmd)
@@ -633,7 +637,9 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader,
}
bld.SetType(l.SymType(outer))
- l.AddInteriorSym(outer, s)
+ if l.SymSize(outer) != 0 { // skip empty section (0-sized symbol)
+ l.AddInteriorSym(outer, s)
+ }
bld.SetValue(int64(machsym.value - sect.addr))
if !l.AttrCgoExportDynamic(s) {
@@ -722,27 +728,28 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader,
// Handle X86_64_RELOC_SIGNED referencing a section (rel.extrn == 0).
p := l.Data(s)
- if arch.Family == sys.AMD64 && rel.extrn == 0 && rel.type_ == MACHO_X86_64_RELOC_SIGNED {
- // Calculate the addend as the offset into the section.
- //
- // The rip-relative offset stored in the object file is encoded
- // as follows:
- //
- // movsd 0x00000360(%rip),%xmm0
- //
- // To get the absolute address of the value this rip-relative address is pointing
- // to, we must add the address of the next instruction to it. This is done by
- // taking the address of the relocation and adding 4 to it (since the rip-relative
- // offset can at most be 32 bits long). To calculate the offset into the section the
- // relocation is referencing, we subtract the vaddr of the start of the referenced
- // section found in the original object file.
- //
- // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
- secaddr := c.seg.sect[rel.symnum-1].addr
-
- rAdd = int64(uint64(int64(int32(e.Uint32(p[rOff:])))+int64(rOff)+4) - secaddr)
- } else {
- rAdd = int64(int32(e.Uint32(p[rOff:])))
+ if arch.Family == sys.AMD64 {
+ if rel.extrn == 0 && rel.type_ == MACHO_X86_64_RELOC_SIGNED {
+ // Calculate the addend as the offset into the section.
+ //
+ // The rip-relative offset stored in the object file is encoded
+ // as follows:
+ //
+ // movsd 0x00000360(%rip),%xmm0
+ //
+ // To get the absolute address of the value this rip-relative address is pointing
+ // to, we must add the address of the next instruction to it. This is done by
+ // taking the address of the relocation and adding 4 to it (since the rip-relative
+ // offset can at most be 32 bits long). To calculate the offset into the section the
+ // relocation is referencing, we subtract the vaddr of the start of the referenced
+ // section found in the original object file.
+ //
+ // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
+ secaddr := c.seg.sect[rel.symnum-1].addr
+ rAdd = int64(uint64(int64(int32(e.Uint32(p[rOff:])))+int64(rOff)+4) - secaddr)
+ } else {
+ rAdd = int64(int32(e.Uint32(p[rOff:])))
+ }
}
// An unsigned internal relocation has a value offset
diff --git a/src/cmd/link/internal/mips64/obj.go b/src/cmd/link/internal/mips64/obj.go
index d2dc20f5c1..01d89a209c 100644
--- a/src/cmd/link/internal/mips64/obj.go
+++ b/src/cmd/link/internal/mips64/obj.go
@@ -60,7 +60,7 @@ func Init() (*sys.Arch, ld.Arch) {
Linuxdynld: "/lib64/ld64.so.1",
Freebsddynld: "XXX",
- Openbsddynld: "XXX",
+ Openbsddynld: "/usr/libexec/ld.so",
Netbsddynld: "XXX",
Dragonflydynld: "XXX",
Solarisdynld: "XXX",
@@ -84,7 +84,8 @@ func archinit(ctxt *ld.Link) {
*ld.FlagRound = 16 * 1024
}
- case objabi.Hlinux: /* mips64 elf */
+ case objabi.Hlinux, /* mips64 elf */
+ objabi.Hopenbsd:
ld.Elfinit(ctxt)
ld.HEADR = ld.ELFRESERVE
if *ld.FlagTextAddr == -1 {
diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go
index dc522e6a38..5bf3898eb9 100644
--- a/src/cmd/link/internal/ppc64/asm.go
+++ b/src/cmd/link/internal/ppc64/asm.go
@@ -313,7 +313,7 @@ func addelfdynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s lo
rela := ldr.MakeSymbolUpdater(syms.Rela)
rela.AddAddrPlus(target.Arch, s, int64(r.Off()))
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(ldr.SymDynid(targ)), uint32(elf.R_PPC64_ADDR64)))
+ rela.AddUint64(target.Arch, elf.R_INFO(uint32(ldr.SymDynid(targ)), uint32(elf.R_PPC64_ADDR64)))
rela.AddUint64(target.Arch, uint64(r.Add()))
su.SetRelocType(rIdx, objabi.ElfRelocOffset) // ignore during relocsym
}
@@ -994,9 +994,10 @@ func addpltsym(ctxt *ld.Link, ldr *loader.Loader, s loader.Sym) {
ldr.SetPlt(s, int32(plt.Size()))
plt.Grow(plt.Size() + 8)
+ plt.SetSize(plt.Size() + 8)
rela.AddAddrPlus(ctxt.Arch, plt.Sym(), int64(ldr.SymPlt(s)))
- rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_PPC64_JMP_SLOT)))
+ rela.AddUint64(ctxt.Arch, elf.R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_PPC64_JMP_SLOT)))
rela.AddUint64(ctxt.Arch, 0)
} else {
ctxt.Errorf(s, "addpltsym: unsupported binary format")
@@ -1052,7 +1053,7 @@ func ensureglinkresolver(ctxt *ld.Link, ldr *loader.Loader) *loader.SymbolBuilde
// Add DT_PPC64_GLINK .dynamic entry, which points to 32 bytes
// before the first symbol resolver stub.
du := ldr.MakeSymbolUpdater(ctxt.Dynamic)
- ld.Elfwritedynentsymplus(ctxt, du, ld.DT_PPC64_GLINK, glink.Sym(), glink.Size()-32)
+ ld.Elfwritedynentsymplus(ctxt, du, elf.DT_PPC64_GLINK, glink.Sym(), glink.Size()-32)
return glink
}
diff --git a/src/cmd/link/internal/riscv64/asm.go b/src/cmd/link/internal/riscv64/asm.go
index 1236145fb1..c18e0540d8 100644
--- a/src/cmd/link/internal/riscv64/asm.go
+++ b/src/cmd/link/internal/riscv64/asm.go
@@ -11,20 +11,143 @@ import (
"cmd/link/internal/ld"
"cmd/link/internal/loader"
"cmd/link/internal/sym"
+ "debug/elf"
"fmt"
"log"
+ "sort"
)
+// fakeLabelName matches the RISCV_FAKE_LABEL_NAME from binutils.
+const fakeLabelName = ".L0 "
+
func gentext(ctxt *ld.Link, ldr *loader.Loader) {
}
+func genSymsLate(ctxt *ld.Link, ldr *loader.Loader) {
+ if ctxt.LinkMode != ld.LinkExternal {
+ return
+ }
+
+ // Generate a local text symbol for each relocation target, as the
+ // R_RISCV_PCREL_LO12_* relocations generated by elfreloc1 need it.
+ if ctxt.Textp == nil {
+ log.Fatal("genSymsLate called before Textp has been assigned")
+ }
+ var hi20Syms []loader.Sym
+ for _, s := range ctxt.Textp {
+ relocs := ldr.Relocs(s)
+ for ri := 0; ri < relocs.Count(); ri++ {
+ r := relocs.At(ri)
+ if r.Type() != objabi.R_RISCV_PCREL_ITYPE && r.Type() != objabi.R_RISCV_PCREL_STYPE &&
+ r.Type() != objabi.R_RISCV_TLS_IE_ITYPE && r.Type() != objabi.R_RISCV_TLS_IE_STYPE {
+ continue
+ }
+ if r.Off() == 0 && ldr.SymType(s) == sym.STEXT {
+ // Use the symbol for the function instead of creating
+ // an overlapping symbol.
+ continue
+ }
+
+ // TODO(jsing): Consider generating ELF symbols without needing
+ // loader symbols, in order to reduce memory consumption. This
+ // would require changes to genelfsym so that it called
+ // putelfsym and putelfsyment as appropriate.
+ sb := ldr.MakeSymbolBuilder(fakeLabelName)
+ sb.SetType(sym.STEXT)
+ sb.SetValue(ldr.SymValue(s) + int64(r.Off()))
+ sb.SetLocal(true)
+ sb.SetReachable(true)
+ sb.SetVisibilityHidden(true)
+ sb.SetSect(ldr.SymSect(s))
+ if outer := ldr.OuterSym(s); outer != 0 {
+ ldr.AddInteriorSym(outer, sb.Sym())
+ }
+ hi20Syms = append(hi20Syms, sb.Sym())
+ }
+ }
+ ctxt.Textp = append(ctxt.Textp, hi20Syms...)
+ ldr.SortSyms(ctxt.Textp)
+}
+
+func findHI20Symbol(ctxt *ld.Link, ldr *loader.Loader, val int64) loader.Sym {
+ idx := sort.Search(len(ctxt.Textp), func(i int) bool { return ldr.SymValue(ctxt.Textp[i]) >= val })
+ if idx >= len(ctxt.Textp) {
+ return 0
+ }
+ if s := ctxt.Textp[idx]; ldr.SymValue(s) == val && ldr.SymType(s) == sym.STEXT {
+ return s
+ }
+ return 0
+}
+
func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
- log.Fatalf("elfreloc1")
- return false
+ elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
+ switch r.Type {
+ case objabi.R_ADDR, objabi.R_DWARFSECREF:
+ out.Write64(uint64(sectoff))
+ switch r.Size {
+ case 4:
+ out.Write64(uint64(elf.R_RISCV_32) | uint64(elfsym)<<32)
+ case 8:
+ out.Write64(uint64(elf.R_RISCV_64) | uint64(elfsym)<<32)
+ default:
+ ld.Errorf(nil, "unknown size %d for %v relocation", r.Size, r.Type)
+ return false
+ }
+ out.Write64(uint64(r.Xadd))
+
+ case objabi.R_CALLRISCV:
+ // Call relocations are currently handled via R_RISCV_PCREL_ITYPE.
+ // TODO(jsing): Consider generating elf.R_RISCV_CALL instead of a
+ // HI20/LO12_I pair.
+
+ case objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE_ITYPE, objabi.R_RISCV_TLS_IE_STYPE:
+ // Find the text symbol for the AUIPC instruction targeted
+ // by this relocation.
+ relocs := ldr.Relocs(s)
+ offset := int64(relocs.At(ri).Off())
+ hi20Sym := findHI20Symbol(ctxt, ldr, ldr.SymValue(s)+offset)
+ if hi20Sym == 0 {
+ ld.Errorf(nil, "failed to find text symbol for HI20 relocation at %d (%x)", sectoff, ldr.SymValue(s)+offset)
+ return false
+ }
+ hi20ElfSym := ld.ElfSymForReloc(ctxt, hi20Sym)
+
+ // Emit two relocations - a R_RISCV_PCREL_HI20 relocation and a
+ // corresponding R_RISCV_PCREL_LO12_I or R_RISCV_PCREL_LO12_S relocation.
+ // Note that the LO12 relocation must point to a target that has a valid
+ // HI20 PC-relative relocation text symbol, which in turn points to the
+ // given symbol. For further details see the ELF specification for RISC-V:
+ //
+ // https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#pc-relative-symbol-addresses
+ //
+ var hiRel, loRel elf.R_RISCV
+ switch r.Type {
+ case objabi.R_RISCV_PCREL_ITYPE:
+ hiRel, loRel = elf.R_RISCV_PCREL_HI20, elf.R_RISCV_PCREL_LO12_I
+ case objabi.R_RISCV_PCREL_STYPE:
+ hiRel, loRel = elf.R_RISCV_PCREL_HI20, elf.R_RISCV_PCREL_LO12_S
+ case objabi.R_RISCV_TLS_IE_ITYPE:
+ hiRel, loRel = elf.R_RISCV_TLS_GOT_HI20, elf.R_RISCV_PCREL_LO12_I
+ case objabi.R_RISCV_TLS_IE_STYPE:
+ hiRel, loRel = elf.R_RISCV_TLS_GOT_HI20, elf.R_RISCV_PCREL_LO12_S
+ }
+ out.Write64(uint64(sectoff))
+ out.Write64(uint64(hiRel) | uint64(elfsym)<<32)
+ out.Write64(uint64(r.Xadd))
+ out.Write64(uint64(sectoff + 4))
+ out.Write64(uint64(loRel) | uint64(hi20ElfSym)<<32)
+ out.Write64(uint64(0))
+
+ default:
+ return false
+ }
+
+ return true
}
func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
- log.Fatalf("elfsetuplt")
+ log.Fatalf("elfsetupplt")
}
func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool {
@@ -33,13 +156,35 @@ func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtRe
}
func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loader.Reloc, s loader.Sym, val int64) (o int64, nExtReloc int, ok bool) {
- rs := r.Sym()
- rs = ldr.ResolveABIAlias(rs)
+ if target.IsExternal() {
+ switch r.Type() {
+ case objabi.R_CALLRISCV:
+ return val, 0, true
+
+ case objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE_ITYPE, objabi.R_RISCV_TLS_IE_STYPE:
+ return val, 2, true
+ }
+
+ return val, 0, false
+ }
+
+ rs := ldr.ResolveABIAlias(r.Sym())
+
switch r.Type() {
case objabi.R_CALLRISCV:
// Nothing to do.
return val, 0, true
+ case objabi.R_RISCV_TLS_IE_ITYPE, objabi.R_RISCV_TLS_IE_STYPE:
+ // TLS relocations are not currently handled for internal linking.
+ // For now, TLS is only used when cgo is in use and cgo currently
+ // requires external linking. However, we need to accept these
+ // relocations so that code containing TLS variables will link,
+ // even when they're not being used. For now, replace these
+ // instructions with EBREAK to detect accidental use.
+ const ebreakIns = 0x00100073
+ return ebreakIns<<32 | ebreakIns, 0, true
+
case objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE:
pc := ldr.SymValue(s) + int64(r.Off())
off := ldr.SymValue(rs) + r.Add() - pc
@@ -89,3 +234,11 @@ func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant
log.Fatalf("archrelocvariant")
return -1
}
+
+func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc, s loader.Sym) (loader.ExtReloc, bool) {
+ switch r.Type() {
+ case objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE_ITYPE, objabi.R_RISCV_TLS_IE_STYPE:
+ return ld.ExtrelocViaOuterSym(ldr, r, s), true
+ }
+ return loader.ExtReloc{}, false
+}
diff --git a/src/cmd/link/internal/riscv64/obj.go b/src/cmd/link/internal/riscv64/obj.go
index e66d3cd856..917324d922 100644
--- a/src/cmd/link/internal/riscv64/obj.go
+++ b/src/cmd/link/internal/riscv64/obj.go
@@ -23,9 +23,12 @@ func Init() (*sys.Arch, ld.Arch) {
Archinit: archinit,
Archreloc: archreloc,
Archrelocvariant: archrelocvariant,
+ Extreloc: extreloc,
Elfreloc1: elfreloc1,
+ ElfrelocSize: 24,
Elfsetupplt: elfsetupplt,
Gentext: gentext,
+ GenSymsLate: genSymsLate,
Machoreloc1: machoreloc1,
Linuxdynld: "/lib/ld.so.1",
diff --git a/src/cmd/link/internal/s390x/asm.go b/src/cmd/link/internal/s390x/asm.go
index 645b7d4e28..78d2cc81e4 100644
--- a/src/cmd/link/internal/s390x/asm.go
+++ b/src/cmd/link/internal/s390x/asm.go
@@ -444,7 +444,7 @@ func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
rela.AddAddrPlus(target.Arch, got.Sym(), got.Size()-8)
sDynid := ldr.SymDynid(s)
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(sDynid), uint32(elf.R_390_JMP_SLOT)))
+ rela.AddUint64(target.Arch, elf.R_INFO(uint32(sDynid), uint32(elf.R_390_JMP_SLOT)))
rela.AddUint64(target.Arch, 0)
ldr.SetPlt(s, int32(plt.Size()-32))
diff --git a/src/cmd/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go
index 9b949ebbf8..af0ce11255 100644
--- a/src/cmd/link/internal/x86/asm.go
+++ b/src/cmd/link/internal/x86/asm.go
@@ -303,7 +303,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
ld.Adddynsym(ldr, target, syms, targ)
rel := ldr.MakeSymbolUpdater(syms.Rel)
rel.AddAddrPlus(target.Arch, s, int64(r.Off()))
- rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(targ)), uint32(elf.R_386_32)))
+ rel.AddUint32(target.Arch, elf.R_INFO32(uint32(ldr.SymDynid(targ)), uint32(elf.R_386_32)))
su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_CONST) // write r->add during relocsym
su.SetRelocSym(rIdx, 0)
@@ -483,7 +483,7 @@ func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
rel.AddAddrPlus(target.Arch, got.Sym(), got.Size()-4)
sDynid := ldr.SymDynid(s)
- rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(sDynid), uint32(elf.R_386_JMP_SLOT)))
+ rel.AddUint32(target.Arch, elf.R_INFO32(uint32(sDynid), uint32(elf.R_386_JMP_SLOT)))
ldr.SetPlt(s, int32(plt.Size()-16))
} else {
diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go
index b7611f207c..204410e976 100644
--- a/src/cmd/link/link_test.go
+++ b/src/cmd/link/link_test.go
@@ -181,6 +181,7 @@ main.x: relocation target main.zero not defined
func TestIssue33979(t *testing.T) {
testenv.MustHaveGoBuild(t)
testenv.MustHaveCGO(t)
+ testenv.MustInternalLink(t)
// Skip test on platforms that do not support cgo internal linking.
switch runtime.GOARCH {
@@ -308,7 +309,7 @@ func TestBuildForTvOS(t *testing.T) {
cmd := exec.Command(testenv.GoToolPath(t), "build", "-buildmode=c-archive", "-o", ar, lib)
cmd.Env = append(os.Environ(),
"CGO_ENABLED=1",
- "GOOS=darwin",
+ "GOOS=ios",
"GOARCH=arm64",
"CC="+strings.Join(CC, " "),
"CGO_CFLAGS=", // ensure CGO_CFLAGS does not contain any flags. Issue #35459
@@ -819,3 +820,56 @@ func TestReadOnly(t *testing.T) {
t.Errorf("running test program did not fail. output:\n%s", out)
}
}
+
+const testIssue38554Src = `
+package main
+
+type T [10<<20]byte
+
+//go:noinline
+func f() T {
+ return T{} // compiler will make a large stmp symbol, but not used.
+}
+
+func main() {
+ x := f()
+ println(x[1])
+}
+`
+
+func TestIssue38554(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+
+ t.Parallel()
+
+ tmpdir, err := ioutil.TempDir("", "TestIssue38554")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ src := filepath.Join(tmpdir, "x.go")
+ err = ioutil.WriteFile(src, []byte(testIssue38554Src), 0666)
+ if err != nil {
+ t.Fatalf("failed to write source file: %v", err)
+ }
+ exe := filepath.Join(tmpdir, "x.exe")
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe, src)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("build failed: %v\n%s", err, out)
+ }
+
+ fi, err := os.Stat(exe)
+ if err != nil {
+ t.Fatalf("failed to stat output file: %v", err)
+ }
+
+ // The test program is not much different from a helloworld, which is
+ // typically a little over 1 MB. We allow 5 MB. If the bad stmp is live,
+ // it will be over 10 MB.
+ const want = 5 << 20
+ if got := fi.Size(); got > want {
+ t.Errorf("binary too big: got %d, want < %d", got, want)
+ }
+}