| |
| |
| |
|
|
| package ld |
|
|
| import ( |
| "cmd/internal/hash" |
| "cmd/internal/objabi" |
| "cmd/internal/sys" |
| "cmd/link/internal/loader" |
| "cmd/link/internal/sym" |
| "cmp" |
| "debug/elf" |
| "encoding/binary" |
| "encoding/hex" |
| "fmt" |
| "internal/buildcfg" |
| "os" |
| "path/filepath" |
| "runtime" |
| "slices" |
| "strings" |
| ) |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
|
|
| |
| |
| |
|
|
| |
| type ElfEhdr elf.Header64 |
|
|
| |
| type ElfShdr struct { |
| elf.Section64 |
|
|
| |
| |
| |
| nameString string |
|
|
| |
| |
| shnum elf.SectionIndex |
|
|
| |
| |
| |
| |
| link *ElfShdr |
| info *ElfShdr |
|
|
| |
| |
| |
| relocSect *sym.Section |
| } |
|
|
| |
| type ElfPhdr elf.ProgHeader |
|
|
| const ( |
| ELF64HDRSIZE = 64 |
| ELF64PHDRSIZE = 56 |
| ELF64SHDRSIZE = 64 |
| ELF64RELSIZE = 16 |
| ELF64RELASIZE = 24 |
| ELF64SYMSIZE = 24 |
| ELF32HDRSIZE = 52 |
| ELF32PHDRSIZE = 32 |
| ELF32SHDRSIZE = 40 |
| ELF32SYMSIZE = 16 |
| ELF32RELSIZE = 8 |
| ) |
|
|
| var elfstrdat []byte |
|
|
| |
| |
| |
| |
| const ELFRESERVE = 4096 |
|
|
| var ( |
| Nelfsym = 1 |
|
|
| elf64 bool |
| |
| |
| elfRelType string |
|
|
| ehdr ElfEhdr |
| phdr = make([]*ElfPhdr, 0, 8) |
| shdr = make([]*ElfShdr, 0, 64) |
| shdrSorted bool |
|
|
| interp string |
| ) |
|
|
| |
| |
| |
| type ELFArch struct { |
| |
|
|
| Androiddynld string |
| Linuxdynld string |
| LinuxdynldMusl string |
| Freebsddynld string |
| Netbsddynld string |
| Openbsddynld string |
| Dragonflydynld string |
| Solarisdynld string |
|
|
| Reloc1 func(*Link, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int, int64) bool |
| RelocSize uint32 |
| SetupPLT func(ctxt *Link, ldr *loader.Loader, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) |
|
|
| |
| |
| |
| DynamicReadOnly bool |
| } |
|
|
| var buildinfo []byte |
|
|
| |
| |
| func Elfinit(ctxt *Link) { |
| ctxt.IsELF = true |
|
|
| if ctxt.Arch.InFamily(sys.AMD64, sys.ARM64, sys.Loong64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X) { |
| elfRelType = ".rela" |
| } else { |
| elfRelType = ".rel" |
| } |
|
|
| switch ctxt.Arch.Family { |
| |
| case sys.PPC64, sys.S390X: |
| if ctxt.Arch.ByteOrder == binary.BigEndian && ctxt.HeadType != objabi.Hopenbsd { |
| ehdr.Flags = 1 |
| } else { |
| ehdr.Flags = 2 |
| } |
| fallthrough |
| case sys.AMD64, sys.ARM64, sys.Loong64, sys.MIPS64, sys.RISCV64: |
| if ctxt.Arch.Family == sys.MIPS64 { |
| ehdr.Flags = 0x20000004 |
| } |
| if ctxt.Arch.Family == sys.Loong64 { |
| ehdr.Flags = 0x43 |
| } |
| if ctxt.Arch.Family == sys.RISCV64 { |
| ehdr.Flags = 0x4 |
| } |
| elf64 = true |
|
|
| ehdr.Phoff = ELF64HDRSIZE |
| ehdr.Shoff = ELF64HDRSIZE |
| ehdr.Ehsize = ELF64HDRSIZE |
| ehdr.Phentsize = ELF64PHDRSIZE |
| ehdr.Shentsize = ELF64SHDRSIZE |
|
|
| |
| case sys.ARM, sys.MIPS: |
| if ctxt.Arch.Family == sys.ARM { |
| |
| if ctxt.HeadType == objabi.Hlinux || ctxt.HeadType == objabi.Hfreebsd || ctxt.HeadType == objabi.Hnetbsd { |
| |
| |
| |
| |
| |
| |
| |
| |
| ehdr.Flags = 0x5000002 |
| } |
| } else if ctxt.Arch.Family == sys.MIPS { |
| ehdr.Flags = 0x50001004 |
| } |
| fallthrough |
| default: |
| ehdr.Phoff = ELF32HDRSIZE |
| |
| ehdr.Shoff = ELF32HDRSIZE |
| ehdr.Ehsize = ELF32HDRSIZE |
| ehdr.Phentsize = ELF32PHDRSIZE |
| ehdr.Shentsize = ELF32SHDRSIZE |
| } |
| } |
|
|
| |
| |
| |
| |
| func fixElfPhdr(e *ElfPhdr) { |
| 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) |
| } |
|
|
| func elf64phdr(out *OutBuf, e *ElfPhdr) { |
| if e.Type == elf.PT_LOAD { |
| fixElfPhdr(e) |
| } |
|
|
| 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 == elf.PT_LOAD { |
| fixElfPhdr(e) |
| } |
|
|
| 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 elfShdrShnum(e *ElfShdr) elf.SectionIndex { |
| if e.shnum == -1 { |
| Errorf("internal error: retrieved section index before it is set") |
| errorexit() |
| } |
| return e.shnum |
| } |
|
|
| |
| func elfShdrOff(e *ElfShdr) uint64 { |
| if e.relocSect != nil { |
| if e.Off != 0 { |
| Errorf("internal error: ElfShdr relocSect == %p Off == %d", e.relocSect, e.Off) |
| errorexit() |
| } |
| return e.relocSect.Reloff |
| } |
| return e.Off |
| } |
|
|
| |
| func elfShdrSize(e *ElfShdr) uint64 { |
| if e.relocSect != nil { |
| if e.Size != 0 { |
| Errorf("internal error: ElfShdr relocSect == %p Size == %d", e.relocSect, e.Size) |
| errorexit() |
| } |
| return e.relocSect.Rellen |
| } |
| return e.Size |
| } |
|
|
| |
| func elfShdrLink(e *ElfShdr) uint32 { |
| if e.link != nil { |
| if e.Link != 0 { |
| Errorf("internal error: ElfShdr link == %p Link == %d", e.link, e.Link) |
| errorexit() |
| } |
| return uint32(elfShdrShnum(e.link)) |
| } |
| return e.Link |
| } |
|
|
| |
| func elfShdrInfo(e *ElfShdr) uint32 { |
| if e.info != nil { |
| if e.Info != 0 { |
| Errorf("internal error: ElfShdr info == %p Info == %d", e.info, e.Info) |
| errorexit() |
| } |
| return uint32(elfShdrShnum(e.info)) |
| } |
| return e.Info |
| } |
|
|
| func elf64shdr(out *OutBuf, e *ElfShdr) { |
| out.Write32(e.Name) |
| out.Write32(e.Type) |
| out.Write64(e.Flags) |
| out.Write64(e.Addr) |
| out.Write64(elfShdrOff(e)) |
| out.Write64(elfShdrSize(e)) |
| out.Write32(elfShdrLink(e)) |
| out.Write32(elfShdrInfo(e)) |
| 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(elfShdrOff(e))) |
| out.Write32(uint32(elfShdrSize(e))) |
| out.Write32(elfShdrLink(e)) |
| out.Write32(elfShdrInfo(e)) |
| out.Write32(uint32(e.Addralign)) |
| out.Write32(uint32(e.Entsize)) |
| } |
|
|
| func elfwriteshdrs(out *OutBuf) uint32 { |
| if elf64 { |
| for _, sh := range shdr { |
| elf64shdr(out, sh) |
| } |
| return uint32(len(shdr)) * ELF64SHDRSIZE |
| } |
|
|
| for _, sh := range shdr { |
| elf32shdr(out, sh) |
| } |
| return uint32(len(shdr)) * ELF32SHDRSIZE |
| } |
|
|
| |
| |
| |
| |
| func elfSortShdrs(ctxt *Link) { |
| if ctxt.LinkMode != LinkExternal { |
| |
| slices.SortStableFunc(shdr[1:], func(a, b *ElfShdr) int { |
| isAllocated := func(h *ElfShdr) bool { |
| return elf.SectionFlag(h.Flags)&elf.SHF_ALLOC != 0 |
| } |
| if isAllocated(a) { |
| if isAllocated(b) { |
| if r := cmp.Compare(a.Addr, b.Addr); r != 0 { |
| return r |
| } |
| |
| |
| return cmp.Compare(a.Size, b.Size) |
| } |
| |
| return -1 |
| } |
| if isAllocated(b) { |
| |
| return 1 |
| } |
| return 0 |
| }) |
| } |
| for i, h := range shdr { |
| h.shnum = elf.SectionIndex(i) |
| } |
| shdrSorted = true |
| } |
|
|
| |
| |
| |
| func elfWriteShstrtab(ctxt *Link) uint32 { |
| |
| m := make(map[string]uint32, len(shdr)) |
|
|
| m[""] = 0 |
| ctxt.Out.WriteByte(0) |
| off := uint32(1) |
|
|
| writeString := func(s string) { |
| m[s] = off |
| ctxt.Out.WriteString(s) |
| ctxt.Out.WriteByte(0) |
| off += uint32(len(s)) + 1 |
| } |
|
|
| |
| |
| |
| |
| |
| for _, sh := range shdr { |
| if suffix, ok := strings.CutPrefix(sh.nameString, elfRelType); ok { |
| if _, found := m[suffix]; !found { |
| m[suffix] = off + uint32(len(elfRelType)) |
| } |
| writeString(sh.nameString) |
| } |
| } |
|
|
| for _, sh := range shdr { |
| if shOff, ok := m[sh.nameString]; ok { |
| sh.Name = shOff |
| } else { |
| sh.Name = off |
| writeString(sh.nameString) |
| } |
| } |
|
|
| return off |
| } |
|
|
| func elfwritephdrs(out *OutBuf) uint32 { |
| if elf64 { |
| for i := 0; i < int(ehdr.Phnum); i++ { |
| elf64phdr(out, phdr[i]) |
| } |
| return uint32(ehdr.Phnum) * ELF64PHDRSIZE |
| } |
|
|
| for i := 0; i < int(ehdr.Phnum); i++ { |
| elf32phdr(out, phdr[i]) |
| } |
| return uint32(ehdr.Phnum) * ELF32PHDRSIZE |
| } |
|
|
| func newElfPhdr() *ElfPhdr { |
| e := new(ElfPhdr) |
| phdr = append(phdr, e) |
| ehdr.Phnum++ |
| if elf64 { |
| ehdr.Shoff += ELF64PHDRSIZE |
| } else { |
| ehdr.Shoff += ELF32PHDRSIZE |
| } |
| return e |
| } |
|
|
| func newElfShdr(name string) *ElfShdr { |
| if shdrSorted { |
| Errorf("internal error: creating a section header after they were sorted") |
| errorexit() |
| } |
|
|
| e := &ElfShdr{ |
| nameString: name, |
| shnum: -1, |
| } |
| shdr = append(shdr, e) |
| return e |
| } |
|
|
| func getElfEhdr() *ElfEhdr { |
| return &ehdr |
| } |
|
|
| 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) |
| 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) |
| return ELF32HDRSIZE |
| } |
|
|
| func elfwritehdr(out *OutBuf) uint32 { |
| if elf64 { |
| return elf64writehdr(out) |
| } |
| return elf32writehdr(out) |
| } |
|
|
| |
| |
| |
| |
| func elfhash(name string) uint32 { |
| var h uint32 |
| for i := 0; i < len(name); i++ { |
| h = (h << 4) + uint32(name[i]) |
| if g := h & 0xf0000000; g != 0 { |
| h ^= g >> 24 |
| } |
| h &= 0x0fffffff |
| } |
| return h |
| } |
|
|
| 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 elf.DynTag, val uint64) { |
| if elf64 { |
| s.AddUint64(arch, uint64(tag)) |
| s.AddUint64(arch, val) |
| } else { |
| s.AddUint32(arch, uint32(tag)) |
| s.AddUint32(arch, uint32(val)) |
| } |
| } |
|
|
| func Elfwritedynentsymplus(ctxt *Link, s *loader.SymbolBuilder, tag elf.DynTag, t loader.Sym, add int64) { |
| if elf64 { |
| s.AddUint64(ctxt.Arch, uint64(tag)) |
| } else { |
| s.AddUint32(ctxt.Arch, uint32(tag)) |
| } |
| s.AddAddrPlus(ctxt.Arch, t, add) |
| } |
|
|
| func elfwritedynentsymsize(ctxt *Link, s *loader.SymbolBuilder, tag elf.DynTag, t loader.Sym) { |
| if elf64 { |
| s.AddUint64(ctxt.Arch, uint64(tag)) |
| } else { |
| s.AddUint32(ctxt.Arch, uint32(tag)) |
| } |
| s.AddSize(ctxt.Arch, t) |
| } |
|
|
| 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) |
|
|
| return n |
| } |
|
|
| func elfwriteinterp(out *OutBuf) int { |
| sh := elfshname(".interp") |
| out.SeekSet(int64(sh.Off)) |
| out.WriteString(interp) |
| out.Write8(0) |
| return int(sh.Size) |
| } |
|
|
| |
| const ( |
| |
| MIPS_FPABI_NONE = 0 |
| |
| MIPS_FPABI_ANY = 1 |
| |
| MIPS_FPABI_SINGLE = 2 |
| |
| MIPS_FPABI_SOFT = 3 |
| |
| |
| MIPS_FPABI_HIST = 4 |
| |
| MIPS_FPABI_FPXX = 5 |
| |
| MIPS_FPABI_FP64 = 6 |
| |
| MIPS_FPABI_FP64A = 7 |
| ) |
|
|
| func elfMipsAbiFlags(sh *ElfShdr, startva uint64, resoff uint64) int { |
| n := 24 |
| sh.Addr = startva + resoff - uint64(n) |
| sh.Off = resoff - uint64(n) |
| sh.Size = uint64(n) |
| sh.Type = uint32(elf.SHT_MIPS_ABIFLAGS) |
| sh.Flags = uint64(elf.SHF_ALLOC) |
|
|
| return n |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| func elfWriteMipsAbiFlags(ctxt *Link) int { |
| sh := elfshname(".MIPS.abiflags") |
| ctxt.Out.SeekSet(int64(sh.Off)) |
| ctxt.Out.Write16(0) |
| ctxt.Out.Write8(32) |
| ctxt.Out.Write8(1) |
| ctxt.Out.Write8(1) |
| ctxt.Out.Write8(1) |
| ctxt.Out.Write8(0) |
| if buildcfg.GOMIPS == "softfloat" { |
| ctxt.Out.Write8(MIPS_FPABI_SOFT) |
| } else { |
| |
| |
| |
| |
| |
| |
| |
| ctxt.Out.Write8(MIPS_FPABI_ANY) |
| } |
| ctxt.Out.Write32(0) |
| ctxt.Out.Write32(0) |
| ctxt.Out.Write32(0) |
| ctxt.Out.Write32(0) |
| return int(sh.Size) |
| } |
|
|
| func elfnote(sh *ElfShdr, startva uint64, resoff uint64, sizes ...int) int { |
| n := resoff % 4 |
| |
| |
| for _, sz := range sizes { |
| n += 3*4 + uint64(sz) |
| } |
|
|
| 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) |
| } |
|
|
| func elfwritenotehdr(out *OutBuf, str string, namesz uint32, descsz uint32, tag uint32) *ElfShdr { |
| sh := elfshname(str) |
|
|
| |
| out.SeekSet(int64(sh.Off)) |
|
|
| out.Write32(namesz) |
| out.Write32(descsz) |
| out.Write32(tag) |
|
|
| return sh |
| } |
|
|
| |
| const ( |
| ELF_NOTE_NETBSD_NAMESZ = 7 |
| ELF_NOTE_NETBSD_DESCSZ = 4 |
| ELF_NOTE_NETBSD_TAG = 1 |
| ELF_NOTE_NETBSD_VERSION = 700000000 |
| ) |
|
|
| var ELF_NOTE_NETBSD_NAME = []byte("NetBSD\x00") |
|
|
| func elfnetbsdsig(sh *ElfShdr, startva uint64, resoff uint64) int { |
| n := int(Rnd(ELF_NOTE_NETBSD_NAMESZ, 4) + Rnd(ELF_NOTE_NETBSD_DESCSZ, 4)) |
| return elfnote(sh, startva, resoff, n) |
| } |
|
|
| func elfwritenetbsdsig(out *OutBuf) int { |
| |
| sh := elfwritenotehdr(out, ".note.netbsd.ident", ELF_NOTE_NETBSD_NAMESZ, ELF_NOTE_NETBSD_DESCSZ, ELF_NOTE_NETBSD_TAG) |
|
|
| if sh == nil { |
| return 0 |
| } |
|
|
| |
| out.Write(ELF_NOTE_NETBSD_NAME) |
| out.Write8(0) |
| out.Write32(ELF_NOTE_NETBSD_VERSION) |
|
|
| return int(sh.Size) |
| } |
|
|
| |
| |
| |
|
|
| func elfnetbsdpax(sh *ElfShdr, startva uint64, resoff uint64) int { |
| n := int(Rnd(4, 4) + Rnd(4, 4)) |
| return elfnote(sh, startva, resoff, n) |
| } |
|
|
| func elfwritenetbsdpax(out *OutBuf) int { |
| sh := elfwritenotehdr(out, ".note.netbsd.pax", 4 , 4 , 0x03 ) |
| if sh == nil { |
| return 0 |
| } |
| out.Write([]byte("PaX\x00")) |
| out.Write32(0x20) |
| return int(sh.Size) |
| } |
|
|
| |
| const ( |
| ELF_NOTE_OPENBSD_NAMESZ = 8 |
| ELF_NOTE_OPENBSD_DESCSZ = 4 |
| ELF_NOTE_OPENBSD_TAG = 1 |
| ELF_NOTE_OPENBSD_VERSION = 0 |
| ) |
|
|
| var ELF_NOTE_OPENBSD_NAME = []byte("OpenBSD\x00") |
|
|
| func elfopenbsdsig(sh *ElfShdr, startva uint64, resoff uint64) int { |
| n := ELF_NOTE_OPENBSD_NAMESZ + ELF_NOTE_OPENBSD_DESCSZ |
| return elfnote(sh, startva, resoff, n) |
| } |
|
|
| func elfwriteopenbsdsig(out *OutBuf) int { |
| |
| sh := elfwritenotehdr(out, ".note.openbsd.ident", ELF_NOTE_OPENBSD_NAMESZ, ELF_NOTE_OPENBSD_DESCSZ, ELF_NOTE_OPENBSD_TAG) |
|
|
| if sh == nil { |
| return 0 |
| } |
|
|
| |
| out.Write(ELF_NOTE_OPENBSD_NAME) |
|
|
| out.Write32(ELF_NOTE_OPENBSD_VERSION) |
|
|
| return int(sh.Size) |
| } |
|
|
| |
| const ( |
| ELF_NOTE_FREEBSD_NAMESZ = 8 |
| ELF_NOTE_FREEBSD_DESCSZ = 4 |
| ELF_NOTE_FREEBSD_ABI_TAG = 1 |
| ELF_NOTE_FREEBSD_NOINIT_TAG = 2 |
| ELF_NOTE_FREEBSD_FEATURE_CTL_TAG = 4 |
| ELF_NOTE_FREEBSD_VERSION = 1203000 |
| ELF_NOTE_FREEBSD_FCTL_ASLR_DISABLE = 0x1 |
| ) |
|
|
| const ELF_NOTE_FREEBSD_NAME = "FreeBSD\x00" |
|
|
| func elffreebsdsig(sh *ElfShdr, startva uint64, resoff uint64) int { |
| n := ELF_NOTE_FREEBSD_NAMESZ + ELF_NOTE_FREEBSD_DESCSZ |
| |
| return elfnote(sh, startva, resoff, n, n, n) |
| } |
|
|
| |
| |
| |
| |
| |
| |
| func elfwritefreebsdsig(out *OutBuf) int { |
| sh := elfshname(".note.tag") |
| if sh == nil { |
| return 0 |
| } |
| out.SeekSet(int64(sh.Off)) |
|
|
| |
| out.Write32(ELF_NOTE_FREEBSD_NAMESZ) |
| out.Write32(ELF_NOTE_FREEBSD_DESCSZ) |
| out.Write32(ELF_NOTE_FREEBSD_ABI_TAG) |
| out.WriteString(ELF_NOTE_FREEBSD_NAME) |
| out.Write32(ELF_NOTE_FREEBSD_VERSION) |
|
|
| |
| out.Write32(ELF_NOTE_FREEBSD_NAMESZ) |
| out.Write32(ELF_NOTE_FREEBSD_DESCSZ) |
| out.Write32(ELF_NOTE_FREEBSD_NOINIT_TAG) |
| out.WriteString(ELF_NOTE_FREEBSD_NAME) |
| out.Write32(0) |
|
|
| |
| out.Write32(ELF_NOTE_FREEBSD_NAMESZ) |
| out.Write32(ELF_NOTE_FREEBSD_DESCSZ) |
| out.Write32(ELF_NOTE_FREEBSD_FEATURE_CTL_TAG) |
| out.WriteString(ELF_NOTE_FREEBSD_NAME) |
| if *flagRace { |
| |
| out.Write32(ELF_NOTE_FREEBSD_FCTL_ASLR_DISABLE) |
| } else { |
| out.Write32(0) |
| } |
|
|
| return int(sh.Size) |
| } |
|
|
| func addbuildinfo(ctxt *Link) { |
| val := *flagHostBuildid |
| if val == "" || val == "none" { |
| return |
| } |
| if val == "gobuildid" { |
| buildID := *flagBuildid |
| if buildID == "" { |
| Exitf("-B gobuildid requires a Go build ID supplied via -buildid") |
| } |
|
|
| if ctxt.IsDarwin() { |
| buildinfo = uuidFromGoBuildId(buildID) |
| return |
| } |
|
|
| hashedBuildID := hash.Sum32([]byte(buildID)) |
| buildinfo = hashedBuildID[:20] |
|
|
| return |
| } |
|
|
| if !strings.HasPrefix(val, "0x") { |
| Exitf("-B argument must start with 0x: %s", val) |
| } |
| ov := val |
| val = val[2:] |
|
|
| maxLen := 32 |
| if ctxt.IsDarwin() { |
| maxLen = 16 |
| } |
| if hex.DecodedLen(len(val)) > maxLen { |
| Exitf("-B option too long (max %d digits): %s", maxLen, ov) |
| } |
|
|
| b, err := hex.DecodeString(val) |
| if err != nil { |
| if err == hex.ErrLength { |
| Exitf("-B argument must have even number of digits: %s", ov) |
| } |
| if inv, ok := err.(hex.InvalidByteError); ok { |
| Exitf("-B argument contains invalid hex digit %c: %s", byte(inv), ov) |
| } |
| Exitf("-B argument contains invalid hex: %s", ov) |
| } |
|
|
| buildinfo = b |
| } |
|
|
| |
| const ( |
| ELF_NOTE_BUILDINFO_NAMESZ = 4 |
| ELF_NOTE_BUILDINFO_TAG = 3 |
| ) |
|
|
| var ELF_NOTE_BUILDINFO_NAME = []byte("GNU\x00") |
|
|
| func elfbuildinfo(sh *ElfShdr, startva uint64, resoff uint64) int { |
| n := int(ELF_NOTE_BUILDINFO_NAMESZ + Rnd(int64(len(buildinfo)), 4)) |
| return elfnote(sh, startva, resoff, n) |
| } |
|
|
| func elfgobuildid(sh *ElfShdr, startva uint64, resoff uint64) int { |
| n := len(ELF_NOTE_GO_NAME) + int(Rnd(int64(len(*flagBuildid)), 4)) |
| return elfnote(sh, startva, resoff, n) |
| } |
|
|
| func elfwritebuildinfo(out *OutBuf) int { |
| sh := elfwritenotehdr(out, ".note.gnu.build-id", ELF_NOTE_BUILDINFO_NAMESZ, uint32(len(buildinfo)), ELF_NOTE_BUILDINFO_TAG) |
| if sh == nil { |
| return 0 |
| } |
|
|
| out.Write(ELF_NOTE_BUILDINFO_NAME) |
| out.Write(buildinfo) |
| var zero = make([]byte, 4) |
| out.Write(zero[:int(Rnd(int64(len(buildinfo)), 4)-int64(len(buildinfo)))]) |
|
|
| return int(sh.Size) |
| } |
|
|
| func elfwritegobuildid(out *OutBuf) int { |
| sh := elfwritenotehdr(out, ".note.go.buildid", uint32(len(ELF_NOTE_GO_NAME)), uint32(len(*flagBuildid)), ELF_NOTE_GOBUILDID_TAG) |
| if sh == nil { |
| return 0 |
| } |
|
|
| out.Write(ELF_NOTE_GO_NAME) |
| out.Write([]byte(*flagBuildid)) |
| var zero = make([]byte, 4) |
| out.Write(zero[:int(Rnd(int64(len(*flagBuildid)), 4)-int64(len(*flagBuildid)))]) |
|
|
| return int(sh.Size) |
| } |
|
|
| |
| const ( |
| ELF_NOTE_GOPKGLIST_TAG = 1 |
| ELF_NOTE_GOABIHASH_TAG = 2 |
| ELF_NOTE_GODEPS_TAG = 3 |
| ELF_NOTE_GOBUILDID_TAG = 4 |
| ) |
|
|
| var ELF_NOTE_GO_NAME = []byte("Go\x00\x00") |
|
|
| var elfverneed int |
|
|
| type Elfaux struct { |
| next *Elfaux |
| num int |
| vers string |
| } |
|
|
| type Elflib struct { |
| next *Elflib |
| aux *Elfaux |
| file string |
| } |
|
|
| func addelflib(list **Elflib, file string, vers string) *Elfaux { |
| var lib *Elflib |
|
|
| for lib = *list; lib != nil; lib = lib.next { |
| if lib.file == file { |
| goto havelib |
| } |
| } |
| lib = new(Elflib) |
| lib.next = *list |
| lib.file = file |
| *list = lib |
|
|
| havelib: |
| for aux := lib.aux; aux != nil; aux = aux.next { |
| if aux.vers == vers { |
| return aux |
| } |
| } |
| aux := new(Elfaux) |
| aux.next = lib.aux |
| aux.vers = vers |
| lib.aux = aux |
|
|
| return aux |
| } |
|
|
| func elfdynhash(ctxt *Link) { |
| if !ctxt.IsELF { |
| return |
| } |
|
|
| nsym := Nelfsym |
| ldr := ctxt.loader |
| s := ldr.CreateSymForUpdate(".hash", 0) |
| s.SetType(sym.SELFROSECT) |
|
|
| i := nsym |
| nbucket := 1 |
| for i > 0 { |
| nbucket++ |
| i >>= 1 |
| } |
|
|
| var needlib *Elflib |
| need := make([]*Elfaux, nsym) |
| chain := make([]uint32, nsym) |
| buckets := make([]uint32, nbucket) |
|
|
| for _, sy := range ldr.DynidSyms() { |
|
|
| dynid := ldr.SymDynid(sy) |
| if ldr.SymDynimpvers(sy) != "" { |
| need[dynid] = addelflib(&needlib, ldr.SymDynimplib(sy), ldr.SymDynimpvers(sy)) |
| } |
|
|
| name := ldr.SymExtname(sy) |
| hc := elfhash(name) |
|
|
| b := hc % uint32(nbucket) |
| chain[dynid] = buckets[b] |
| buckets[b] = uint32(dynid) |
| } |
|
|
| |
| if ctxt.Arch.Family == sys.S390X { |
| s.AddUint64(ctxt.Arch, uint64(nbucket)) |
| s.AddUint64(ctxt.Arch, uint64(nsym)) |
| for i := 0; i < nbucket; i++ { |
| s.AddUint64(ctxt.Arch, uint64(buckets[i])) |
| } |
| for i := 0; i < nsym; i++ { |
| s.AddUint64(ctxt.Arch, uint64(chain[i])) |
| } |
| } else { |
| s.AddUint32(ctxt.Arch, uint32(nbucket)) |
| s.AddUint32(ctxt.Arch, uint32(nsym)) |
| for i := 0; i < nbucket; i++ { |
| s.AddUint32(ctxt.Arch, buckets[i]) |
| } |
| for i := 0; i < nsym; i++ { |
| s.AddUint32(ctxt.Arch, chain[i]) |
| } |
| } |
|
|
| dynstr := ldr.CreateSymForUpdate(".dynstr", 0) |
|
|
| |
| gnuVersionR := ldr.CreateSymForUpdate(".gnu.version_r", 0) |
| s = gnuVersionR |
| i = 2 |
| nfile := 0 |
| for l := needlib; l != nil; l = l.next { |
| nfile++ |
|
|
| |
| s.AddUint16(ctxt.Arch, 1) |
| j := 0 |
| for x := l.aux; x != nil; x = x.next { |
| j++ |
| } |
| s.AddUint16(ctxt.Arch, uint16(j)) |
| s.AddUint32(ctxt.Arch, uint32(dynstr.Addstring(l.file))) |
| s.AddUint32(ctxt.Arch, 16) |
| if l.next != nil { |
| s.AddUint32(ctxt.Arch, 16+uint32(j)*16) |
| } else { |
| s.AddUint32(ctxt.Arch, 0) |
| } |
|
|
| for x := l.aux; x != nil; x = x.next { |
| x.num = i |
| i++ |
|
|
| |
| s.AddUint32(ctxt.Arch, elfhash(x.vers)) |
| s.AddUint16(ctxt.Arch, 0) |
| s.AddUint16(ctxt.Arch, uint16(x.num)) |
| s.AddUint32(ctxt.Arch, uint32(dynstr.Addstring(x.vers))) |
| if x.next != nil { |
| s.AddUint32(ctxt.Arch, 16) |
| } else { |
| s.AddUint32(ctxt.Arch, 0) |
| } |
| } |
| } |
|
|
| |
| gnuVersion := ldr.CreateSymForUpdate(".gnu.version", 0) |
| s = gnuVersion |
|
|
| for i := 0; i < nsym; i++ { |
| if i == 0 { |
| s.AddUint16(ctxt.Arch, 0) |
| } else if need[i] == nil { |
| s.AddUint16(ctxt.Arch, 1) |
| } else { |
| s.AddUint16(ctxt.Arch, uint16(need[i].num)) |
| } |
| } |
|
|
| s = ldr.CreateSymForUpdate(".dynamic", 0) |
|
|
| var dtFlags1 elf.DynFlag1 |
| if *flagBindNow { |
| dtFlags1 |= elf.DF_1_NOW |
| Elfwritedynent(ctxt.Arch, s, elf.DT_FLAGS, uint64(elf.DF_BIND_NOW)) |
| } |
| if ctxt.BuildMode == BuildModePIE { |
| dtFlags1 |= elf.DF_1_PIE |
| } |
| Elfwritedynent(ctxt.Arch, s, elf.DT_FLAGS_1, uint64(dtFlags1)) |
|
|
| elfverneed = nfile |
| if elfverneed != 0 { |
| 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, elf.DT_PLTREL, uint64(elf.DT_RELA)) |
| } else { |
| Elfwritedynent(ctxt.Arch, s, elf.DT_PLTREL, uint64(elf.DT_REL)) |
| } |
| elfwritedynentsymsize(ctxt, s, elf.DT_PLTRELSZ, sy.Sym()) |
| elfWriteDynEntSym(ctxt, s, elf.DT_JMPREL, sy.Sym()) |
| } |
|
|
| Elfwritedynent(ctxt.Arch, s, elf.DT_NULL, 0) |
| } |
|
|
| func elfphload(seg *sym.Segment) *ElfPhdr { |
| ph := newElfPhdr() |
| ph.Type = elf.PT_LOAD |
| if seg.Rwx&4 != 0 { |
| ph.Flags |= elf.PF_R |
| } |
| if seg.Rwx&2 != 0 { |
| ph.Flags |= elf.PF_W |
| } |
| if seg.Rwx&1 != 0 { |
| 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) |
|
|
| return ph |
| } |
|
|
| func elfphrelro(seg *sym.Segment) { |
| ph := newElfPhdr() |
| ph.Type = elf.PT_GNU_RELRO |
| ph.Flags = elf.PF_R |
| 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 { |
| for _, sh := range shdr { |
| if sh.nameString == name { |
| return sh |
| } |
| } |
| return newElfShdr(name) |
| } |
|
|
| |
| |
| func elfshnamedup(name string) *ElfShdr { |
| return newElfShdr(name) |
| } |
|
|
| func elfshalloc(sect *sym.Section) *ElfShdr { |
| sh := elfshname(sect.Name) |
| sect.Elfsect = sh |
| return sh |
| } |
|
|
| func elfshbits(linkmode LinkMode, sect *sym.Section) *ElfShdr { |
| var sh *ElfShdr |
|
|
| if sect.Name == ".text" { |
| if sect.Elfsect == nil { |
| sect.Elfsect = elfshnamedup(sect.Name) |
| } |
| sh = sect.Elfsect.(*ElfShdr) |
| } else { |
| sh = elfshalloc(sect) |
| } |
|
|
| |
| |
| if sh.Type == uint32(elf.SHT_NOTE) { |
| if linkmode != LinkExternal { |
| |
| |
| |
| |
| |
| |
| |
| Errorf("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 |
| return sh |
| } |
| if sh.Type > 0 { |
| return sh |
| } |
|
|
| if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen { |
| switch sect.Name { |
| case ".init_array": |
| sh.Type = uint32(elf.SHT_INIT_ARRAY) |
| default: |
| sh.Type = uint32(elf.SHT_PROGBITS) |
| } |
| } else { |
| sh.Type = uint32(elf.SHT_NOBITS) |
| } |
| sh.Flags = uint64(elf.SHF_ALLOC) |
| if sect.Rwx&1 != 0 { |
| sh.Flags |= uint64(elf.SHF_EXECINSTR) |
| } |
| if sect.Rwx&2 != 0 { |
| sh.Flags |= uint64(elf.SHF_WRITE) |
| } |
| if sect.Name == ".tbss" { |
| sh.Flags |= uint64(elf.SHF_TLS) |
| sh.Type = uint32(elf.SHT_NOBITS) |
| } |
| if linkmode != LinkExternal { |
| sh.Addr = sect.Vaddr |
| } |
|
|
| if strings.HasPrefix(sect.Name, ".debug") || strings.HasPrefix(sect.Name, ".zdebug") { |
| sh.Flags = 0 |
| sh.Addr = 0 |
| if sect.Compressed { |
| sh.Flags |= uint64(elf.SHF_COMPRESSED) |
| } |
| } |
|
|
| sh.Addralign = uint64(sect.Align) |
| sh.Size = sect.Length |
| if sect.Name != ".tbss" { |
| sh.Off = sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr |
| } |
|
|
| return sh |
| } |
|
|
| func elfshreloc(arch *sys.Arch, sect *sym.Section) *ElfShdr { |
| |
| |
| if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen { |
| return nil |
| } |
| switch sect.Name { |
| case ".shstrtab", ".tbss", ".gopclntab": |
| return nil |
| } |
| if sect.Elfsect.(*ElfShdr).Type == uint32(elf.SHT_NOTE) { |
| return nil |
| } |
|
|
| typ := elf.SHT_REL |
| if elfRelType == ".rela" { |
| typ = elf.SHT_RELA |
| } |
|
|
| sh := elfshname(elfRelType + sect.Name) |
| |
| |
|
|
| if sect.Name == ".text" { |
| if sh.info != nil && sh.info != sect.Elfsect.(*ElfShdr) { |
| sh = elfshnamedup(elfRelType + sect.Name) |
| } |
| } |
|
|
| sh.Type = uint32(typ) |
| sh.Entsize = uint64(arch.RegSize) * 2 |
| if typ == elf.SHT_RELA { |
| sh.Entsize += uint64(arch.RegSize) |
| } |
| sh.link = elfshname(".symtab") |
| sh.info = sect.Elfsect.(*ElfShdr) |
| sh.relocSect = sect |
| sh.Addralign = uint64(arch.RegSize) |
| return sh |
| } |
|
|
| func elfrelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sym) { |
| |
| |
| if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen { |
| return |
| } |
| if sect.Name == ".shstrtab" { |
| return |
| } |
|
|
| ldr := ctxt.loader |
| for i, s := range syms { |
| if !ldr.AttrReachable(s) { |
| panic("should never happen") |
| } |
| if uint64(ldr.SymValue(s)) >= sect.Vaddr { |
| syms = syms[i:] |
| break |
| } |
| } |
|
|
| eaddr := sect.Vaddr + sect.Length |
| for _, s := range syms { |
| if !ldr.AttrReachable(s) { |
| continue |
| } |
| if ldr.SymValue(s) >= int64(eaddr) { |
| break |
| } |
|
|
| |
| |
| relocs := ldr.Relocs(s) |
| for ri := 0; ri < relocs.Count(); ri++ { |
| r := relocs.At(ri) |
| rr, ok := extreloc(ctxt, ldr, s, r) |
| if !ok { |
| continue |
| } |
| if rr.Xsym == 0 { |
| ldr.Errorf(s, "missing xsym in relocation") |
| continue |
| } |
| esr := ElfSymForReloc(ctxt, rr.Xsym) |
| if esr == 0 { |
| ldr.Errorf(s, "reloc %d (%s) to non-elf symbol %s (outer=%s) %d (%s)", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.SymName(r.Sym()), ldr.SymName(rr.Xsym), ldr.SymType(r.Sym()), ldr.SymType(r.Sym()).String()) |
| } |
| if !ldr.AttrReachable(rr.Xsym) { |
| ldr.Errorf(s, "unreachable reloc %d (%s) target %v", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.SymName(rr.Xsym)) |
| } |
| if !thearch.ELF.Reloc1(ctxt, out, ldr, s, rr, ri, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-sect.Vaddr)) { |
| ldr.Errorf(s, "unsupported obj reloc %d (%s)/%d to %s", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), r.Siz(), ldr.SymName(r.Sym())) |
| } |
| } |
| } |
|
|
| |
| if uint64(out.Offset()) != sect.Reloff+sect.Rellen { |
| panic(fmt.Sprintf("elfrelocsect: size mismatch %d != %d + %d", out.Offset(), sect.Reloff, sect.Rellen)) |
| } |
| } |
|
|
| func elfEmitReloc(ctxt *Link) { |
| for ctxt.Out.Offset()&7 != 0 { |
| ctxt.Out.Write8(0) |
| } |
|
|
| sizeExtRelocs(ctxt, thearch.ELF.RelocSize) |
| relocSect, wg := relocSectFn(ctxt, elfrelocsect) |
|
|
| for _, sect := range Segtext.Sections { |
| if sect.Name == ".text" { |
| relocSect(ctxt, sect, ctxt.Textp) |
| } else { |
| relocSect(ctxt, sect, ctxt.datap) |
| } |
| } |
|
|
| for _, sect := range Segrodata.Sections { |
| relocSect(ctxt, sect, ctxt.datap) |
| } |
| for _, sect := range Segrelrodata.Sections { |
| relocSect(ctxt, sect, ctxt.datap) |
| } |
| for _, sect := range Segdata.Sections { |
| relocSect(ctxt, sect, ctxt.datap) |
| } |
| for i := 0; i < len(Segdwarf.Sections); i++ { |
| sect := Segdwarf.Sections[i] |
| si := dwarfp[i] |
| if si.secSym() != sect.Sym || |
| ctxt.loader.SymSect(si.secSym()) != sect { |
| panic("inconsistency between dwarfp and Segdwarf") |
| } |
| relocSect(ctxt, sect, si.syms) |
| } |
| wg.Wait() |
| } |
|
|
| func addgonote(ctxt *Link, sectionName string, tag uint32, desc []byte) { |
| ldr := ctxt.loader |
| s := ldr.CreateSymForUpdate(sectionName, 0) |
| s.SetType(sym.SELFROSECT) |
| |
| s.AddUint32(ctxt.Arch, uint32(len(ELF_NOTE_GO_NAME))) |
| |
| s.AddUint32(ctxt.Arch, uint32(len(desc))) |
| |
| s.AddUint32(ctxt.Arch, tag) |
| |
| s.AddBytes(ELF_NOTE_GO_NAME) |
| for len(s.Data())%4 != 0 { |
| s.AddUint8(0) |
| } |
| |
| s.AddBytes(desc) |
| for len(s.Data())%4 != 0 { |
| s.AddUint8(0) |
| } |
| s.SetSize(int64(len(s.Data()))) |
| s.SetAlign(4) |
| } |
|
|
| func (ctxt *Link) doelf() { |
| ldr := ctxt.loader |
|
|
| if ctxt.IsExternal() { |
| *FlagD = true |
| } |
|
|
| if !*FlagD { |
| |
| dynsym := ldr.CreateSymForUpdate(".dynsym", 0) |
|
|
| dynsym.SetType(sym.SELFROSECT) |
| if elf64 { |
| dynsym.SetSize(dynsym.Size() + ELF64SYMSIZE) |
| } else { |
| dynsym.SetSize(dynsym.Size() + ELF32SYMSIZE) |
| } |
|
|
| |
| dynstr := ldr.CreateSymForUpdate(".dynstr", 0) |
|
|
| dynstr.SetType(sym.SELFROSECT) |
| if dynstr.Size() == 0 { |
| dynstr.Addstring("") |
| } |
|
|
| |
| s := ldr.CreateSymForUpdate(elfRelType, 0) |
| s.SetType(sym.SELFROSECT) |
|
|
| |
| got := ldr.CreateSymForUpdate(".got", 0) |
| if ctxt.UseRelro() { |
| got.SetType(sym.SELFRELROSECT) |
| } else { |
| got.SetType(sym.SELFGOT) |
| } |
|
|
| |
| if ctxt.IsPPC64() { |
| s := ldr.CreateSymForUpdate(".glink", 0) |
| s.SetType(sym.SELFRXSECT) |
| } |
|
|
| |
| hash := ldr.CreateSymForUpdate(".hash", 0) |
| hash.SetType(sym.SELFROSECT) |
|
|
| gotplt := ldr.CreateSymForUpdate(".got.plt", 0) |
| if ctxt.UseRelro() && *flagBindNow { |
| gotplt.SetType(sym.SELFRELROSECT) |
| } else { |
| gotplt.SetType(sym.SELFSECT) |
| } |
|
|
| plt := ldr.CreateSymForUpdate(".plt", 0) |
| if ctxt.IsPPC64() { |
| |
| |
| plt.SetType(sym.SELFSECT) |
| } else { |
| plt.SetType(sym.SELFRXSECT) |
| } |
|
|
| s = ldr.CreateSymForUpdate(elfRelType+".plt", 0) |
| s.SetType(sym.SELFROSECT) |
|
|
| s = ldr.CreateSymForUpdate(".gnu.version", 0) |
| s.SetType(sym.SELFROSECT) |
|
|
| s = ldr.CreateSymForUpdate(".gnu.version_r", 0) |
| s.SetType(sym.SELFROSECT) |
|
|
| |
| dynamic := ldr.CreateSymForUpdate(".dynamic", 0) |
| switch { |
| case thearch.ELF.DynamicReadOnly: |
| dynamic.SetType(sym.SELFROSECT) |
| case ctxt.UseRelro(): |
| dynamic.SetType(sym.SELFRELROSECT) |
| default: |
| dynamic.SetType(sym.SELFSECT) |
| } |
|
|
| if ctxt.IsS390X() { |
| |
| gotplt = got |
| } |
| thearch.ELF.SetupPLT(ctxt, ctxt.loader, plt, gotplt, dynamic.Sym()) |
|
|
| |
| elfWriteDynEntSym(ctxt, dynamic, elf.DT_HASH, hash.Sym()) |
|
|
| elfWriteDynEntSym(ctxt, dynamic, elf.DT_SYMTAB, dynsym.Sym()) |
| if elf64 { |
| Elfwritedynent(ctxt.Arch, dynamic, elf.DT_SYMENT, ELF64SYMSIZE) |
| } else { |
| Elfwritedynent(ctxt.Arch, dynamic, elf.DT_SYMENT, ELF32SYMSIZE) |
| } |
| 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, 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, 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, elf.DT_RUNPATH, uint64(dynstr.Addstring(rpath.val))) |
| } |
|
|
| if ctxt.IsPPC64() { |
| elfWriteDynEntSym(ctxt, dynamic, elf.DT_PLTGOT, plt.Sym()) |
| } else { |
| elfWriteDynEntSym(ctxt, dynamic, elf.DT_PLTGOT, gotplt.Sym()) |
| } |
|
|
| if ctxt.IsPPC64() { |
| Elfwritedynent(ctxt.Arch, dynamic, elf.DT_PPC64_OPT, 0) |
| } |
|
|
| |
| |
| |
| |
|
|
| Elfwritedynent(ctxt.Arch, dynamic, elf.DT_DEBUG, 0) |
| } |
|
|
| if ctxt.IsShared() { |
| |
| |
| s := ldr.LookupOrCreateSym("go:link.abihashbytes", 0) |
| sb := ldr.MakeSymbolUpdater(s) |
| ldr.SetAttrLocal(s, true) |
| sb.SetType(sym.SRODATA) |
| ldr.SetAttrSpecial(s, true) |
| sb.SetReachable(true) |
| sb.SetSize(hash.Size32) |
| slices.SortFunc(ctxt.Library, func(a, b *sym.Library) int { |
| return strings.Compare(a.Pkg, b.Pkg) |
| }) |
| h := hash.New32() |
| for _, l := range ctxt.Library { |
| h.Write(l.Fingerprint[:]) |
| } |
| addgonote(ctxt, ".note.go.abihash", ELF_NOTE_GOABIHASH_TAG, h.Sum([]byte{})) |
| addgonote(ctxt, ".note.go.pkg-list", ELF_NOTE_GOPKGLIST_TAG, pkglistfornote) |
| var deplist []string |
| for _, shlib := range ctxt.Shlibs { |
| deplist = append(deplist, filepath.Base(shlib.Path)) |
| } |
| addgonote(ctxt, ".note.go.deps", ELF_NOTE_GODEPS_TAG, []byte(strings.Join(deplist, "\n"))) |
| } |
|
|
| if ctxt.LinkMode == LinkExternal && *flagBuildid != "" { |
| addgonote(ctxt, ".note.go.buildid", ELF_NOTE_GOBUILDID_TAG, []byte(*flagBuildid)) |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| if ctxt.IsMIPS() { |
| gnuattributes := ldr.CreateSymForUpdate(".gnu.attributes", 0) |
| gnuattributes.SetType(sym.SELFROSECT) |
| gnuattributes.SetReachable(true) |
| gnuattributes.AddUint8('A') |
| gnuattributes.AddUint32(ctxt.Arch, 15) |
| gnuattributes.AddBytes([]byte("gnu\x00")) |
| gnuattributes.AddUint8(1) |
| gnuattributes.AddUint32(ctxt.Arch, 7) |
| gnuattributes.AddUint8(4) |
| if buildcfg.GOMIPS == "softfloat" { |
| gnuattributes.AddUint8(MIPS_FPABI_SOFT) |
| } else { |
| |
| |
| |
| gnuattributes.AddUint8(MIPS_FPABI_ANY) |
| } |
| } |
| } |
|
|
| |
| func shsym(sh *ElfShdr, ldr *loader.Loader, s loader.Sym) { |
| if s == 0 { |
| panic("bad symbol in shsym2") |
| } |
| addr := ldr.SymValue(s) |
| 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)) |
| } |
|
|
| 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 |
| } |
|
|
| func Asmbelfsetup() { |
| |
| elfshname("") |
|
|
| for _, sect := range Segtext.Sections { |
| |
| |
| if sect.Name == ".text" { |
| if sect.Elfsect == nil { |
| sect.Elfsect = elfshnamedup(sect.Name) |
| } |
| } else { |
| elfshalloc(sect) |
| } |
| } |
| for _, sect := range Segrodata.Sections { |
| elfshalloc(sect) |
| } |
| for _, sect := range Segrelrodata.Sections { |
| elfshalloc(sect) |
| } |
| for _, sect := range Segdata.Sections { |
| elfshalloc(sect) |
| } |
| for _, sect := range Segdwarf.Sections { |
| elfshalloc(sect) |
| } |
| } |
|
|
| func asmbElf(ctxt *Link) { |
| var symo int64 |
| symo = int64(Segdwarf.Fileoff + Segdwarf.Filelen) |
| symo = Rnd(symo, int64(ctxt.Arch.PtrSize)) |
|
|
| ldr := ctxt.loader |
| eh := getElfEhdr() |
| switch ctxt.Arch.Family { |
| default: |
| Exitf("unknown architecture in asmbelf: %v", ctxt.Arch.Family) |
| case sys.MIPS, sys.MIPS64: |
| eh.Machine = uint16(elf.EM_MIPS) |
| case sys.Loong64: |
| eh.Machine = uint16(elf.EM_LOONGARCH) |
| case sys.ARM: |
| eh.Machine = uint16(elf.EM_ARM) |
| case sys.AMD64: |
| eh.Machine = uint16(elf.EM_X86_64) |
| case sys.ARM64: |
| eh.Machine = uint16(elf.EM_AARCH64) |
| case sys.I386: |
| eh.Machine = uint16(elf.EM_386) |
| case sys.PPC64: |
| eh.Machine = uint16(elf.EM_PPC64) |
| case sys.RISCV64: |
| eh.Machine = uint16(elf.EM_RISCV) |
| case sys.S390X: |
| eh.Machine = uint16(elf.EM_S390) |
| } |
|
|
| elfreserve := int64(ELFRESERVE) |
|
|
| numtext := int64(0) |
| for _, sect := range Segtext.Sections { |
| if sect.Name == ".text" { |
| numtext++ |
| } |
| } |
|
|
| |
| |
| |
| |
|
|
| if numtext > 4 { |
| elfreserve += elfreserve + numtext*64*2 |
| } |
|
|
| startva := *FlagTextAddr - int64(HEADR) |
| resoff := elfreserve |
|
|
| var pph *ElfPhdr |
| var pnote *ElfPhdr |
| getpnote := func() *ElfPhdr { |
| if pnote == nil { |
| pnote = newElfPhdr() |
| pnote.Type = elf.PT_NOTE |
| pnote.Flags = elf.PF_R |
| } |
| return pnote |
| } |
| if *flagRace && ctxt.IsNetbsd() { |
| sh := elfshname(".note.netbsd.pax") |
| resoff -= int64(elfnetbsdpax(sh, uint64(startva), uint64(resoff))) |
| phsh(getpnote(), sh) |
| } |
| if ctxt.LinkMode == LinkExternal { |
| |
| eh.Phoff = 0 |
|
|
| eh.Phentsize = 0 |
|
|
| if ctxt.BuildMode == BuildModeShared { |
| sh := elfshname(".note.go.pkg-list") |
| sh.Type = uint32(elf.SHT_NOTE) |
| sh = elfshname(".note.go.abihash") |
| sh.Type = uint32(elf.SHT_NOTE) |
| sh.Flags = uint64(elf.SHF_ALLOC) |
| sh = elfshname(".note.go.deps") |
| sh.Type = uint32(elf.SHT_NOTE) |
| } |
|
|
| if *flagBuildid != "" { |
| sh := elfshname(".note.go.buildid") |
| sh.Type = uint32(elf.SHT_NOTE) |
| sh.Flags = uint64(elf.SHF_ALLOC) |
| } |
|
|
| goto elfobj |
| } |
|
|
| |
| pph = newElfPhdr() |
|
|
| 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) |
|
|
| |
| |
| { |
| o := int64(Segtext.Vaddr - pph.Vaddr) |
| Segtext.Vaddr -= uint64(o) |
| Segtext.Length += uint64(o) |
| o = int64(Segtext.Fileoff - pph.Off) |
| Segtext.Fileoff -= uint64(o) |
| Segtext.Filelen += uint64(o) |
| } |
|
|
| if !*FlagD { |
| |
| sh := elfshname(".interp") |
|
|
| sh.Type = uint32(elf.SHT_PROGBITS) |
| sh.Flags = uint64(elf.SHF_ALLOC) |
| sh.Addralign = 1 |
|
|
| if interpreter == "" && buildcfg.GOOS == runtime.GOOS && buildcfg.GOARCH == runtime.GOARCH && buildcfg.GO_LDSO != "" { |
| interpreter = buildcfg.GO_LDSO |
| } |
|
|
| if interpreter == "" { |
| switch ctxt.HeadType { |
| case objabi.Hlinux: |
| if buildcfg.GOOS == "android" { |
| interpreter = thearch.ELF.Androiddynld |
| if interpreter == "" { |
| Exitf("ELF interpreter not set") |
| } |
| } else { |
| interpreter = thearch.ELF.Linuxdynld |
| |
| |
| |
| if _, err := os.Stat(interpreter); err != nil { |
| if musl := thearch.ELF.LinuxdynldMusl; musl != "" { |
| if _, err := os.Stat(musl); err == nil { |
| interpreter = musl |
| } |
| } |
| } |
| } |
|
|
| case objabi.Hfreebsd: |
| interpreter = thearch.ELF.Freebsddynld |
|
|
| case objabi.Hnetbsd: |
| interpreter = thearch.ELF.Netbsddynld |
|
|
| case objabi.Hopenbsd: |
| interpreter = thearch.ELF.Openbsddynld |
|
|
| case objabi.Hdragonfly: |
| interpreter = thearch.ELF.Dragonflydynld |
|
|
| case objabi.Hsolaris: |
| interpreter = thearch.ELF.Solarisdynld |
| } |
| } |
|
|
| resoff -= int64(elfinterp(sh, uint64(startva), uint64(resoff), interpreter)) |
|
|
| ph := newElfPhdr() |
| ph.Type = elf.PT_INTERP |
| ph.Flags = elf.PF_R |
| phsh(ph, sh) |
| } |
|
|
| if ctxt.HeadType == objabi.Hnetbsd || ctxt.HeadType == objabi.Hopenbsd || ctxt.HeadType == objabi.Hfreebsd { |
| var sh *ElfShdr |
| switch ctxt.HeadType { |
| case objabi.Hnetbsd: |
| sh = elfshname(".note.netbsd.ident") |
| resoff -= int64(elfnetbsdsig(sh, uint64(startva), uint64(resoff))) |
|
|
| case objabi.Hopenbsd: |
| sh = elfshname(".note.openbsd.ident") |
| resoff -= int64(elfopenbsdsig(sh, uint64(startva), uint64(resoff))) |
|
|
| case objabi.Hfreebsd: |
| sh = elfshname(".note.tag") |
| resoff -= int64(elffreebsdsig(sh, uint64(startva), uint64(resoff))) |
| } |
| |
| pnotei := newElfPhdr() |
| pnotei.Type = elf.PT_NOTE |
| pnotei.Flags = elf.PF_R |
| phsh(pnotei, sh) |
| } |
|
|
| if len(buildinfo) > 0 { |
| sh := elfshname(".note.gnu.build-id") |
| resoff -= int64(elfbuildinfo(sh, uint64(startva), uint64(resoff))) |
| phsh(getpnote(), sh) |
| } |
|
|
| if *flagBuildid != "" { |
| sh := elfshname(".note.go.buildid") |
| resoff -= int64(elfgobuildid(sh, uint64(startva), uint64(resoff))) |
| phsh(getpnote(), sh) |
| } |
|
|
| |
|
|
| elfphload(&Segtext) |
| if len(Segrodata.Sections) > 0 { |
| elfphload(&Segrodata) |
| } |
| if len(Segrelrodata.Sections) > 0 { |
| elfphload(&Segrelrodata) |
| elfphrelro(&Segrelrodata) |
| } |
| elfphload(&Segdata) |
|
|
| |
| if !*FlagD { |
| sh := elfshname(".dynsym") |
| sh.Type = uint32(elf.SHT_DYNSYM) |
| sh.Flags = uint64(elf.SHF_ALLOC) |
| if elf64 { |
| sh.Entsize = ELF64SYMSIZE |
| } else { |
| sh.Entsize = ELF32SYMSIZE |
| } |
| sh.Addralign = uint64(ctxt.Arch.RegSize) |
| sh.link = elfshname(".dynstr") |
|
|
| |
| s := ldr.Lookup(".dynsym", 0) |
| i := uint32(0) |
| for sub := s; sub != 0; sub = ldr.SubSym(sub) { |
| i++ |
| if !ldr.AttrLocal(sub) { |
| break |
| } |
| } |
| sh.Info = i |
| shsym(sh, ldr, s) |
|
|
| sh = elfshname(".dynstr") |
| 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 = uint32(elf.SHT_GNU_VERSYM) |
| sh.Flags = uint64(elf.SHF_ALLOC) |
| sh.Addralign = 2 |
| sh.link = elfshname(".dynsym") |
| sh.Entsize = 2 |
| shsym(sh, ldr, ldr.Lookup(".gnu.version", 0)) |
|
|
| sh = elfshname(".gnu.version_r") |
| 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 = elfshname(".dynstr") |
| shsym(sh, ldr, ldr.Lookup(".gnu.version_r", 0)) |
| } |
|
|
| if elfRelType == ".rela" { |
| sh := elfshname(".rela.plt") |
| sh.Type = uint32(elf.SHT_RELA) |
| sh.Flags = uint64(elf.SHF_ALLOC) |
| sh.Entsize = ELF64RELASIZE |
| sh.Addralign = uint64(ctxt.Arch.RegSize) |
| sh.link = elfshname(".dynsym") |
| sh.info = elfshname(".plt") |
| shsym(sh, ldr, ldr.Lookup(".rela.plt", 0)) |
|
|
| sh = elfshname(".rela") |
| sh.Type = uint32(elf.SHT_RELA) |
| sh.Flags = uint64(elf.SHF_ALLOC) |
| sh.Entsize = ELF64RELASIZE |
| sh.Addralign = 8 |
| sh.link = elfshname(".dynsym") |
| shsym(sh, ldr, ldr.Lookup(".rela", 0)) |
| } else { |
| sh := elfshname(".rel.plt") |
| sh.Type = uint32(elf.SHT_REL) |
| sh.Flags = uint64(elf.SHF_ALLOC) |
| sh.Entsize = ELF32RELSIZE |
| sh.Addralign = 4 |
| sh.link = elfshname(".dynsym") |
| shsym(sh, ldr, ldr.Lookup(".rel.plt", 0)) |
|
|
| sh = elfshname(".rel") |
| sh.Type = uint32(elf.SHT_REL) |
| sh.Flags = uint64(elf.SHF_ALLOC) |
| sh.Entsize = ELF32RELSIZE |
| sh.Addralign = 4 |
| sh.link = elfshname(".dynsym") |
| shsym(sh, ldr, ldr.Lookup(".rel", 0)) |
| } |
|
|
| if elf.Machine(eh.Machine) == elf.EM_PPC64 { |
| sh := elfshname(".glink") |
| 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 = 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 { |
| |
| |
| sh.Type = uint32(elf.SHT_NOBITS) |
|
|
| sh.Flags = uint64(elf.SHF_ALLOC + elf.SHF_WRITE) |
| sh.Entsize = 8 |
| } else { |
| sh.Entsize = 4 |
| } |
| sh.Addralign = sh.Entsize |
| shsym(sh, ldr, ldr.Lookup(".plt", 0)) |
|
|
| |
| |
| if elf.Machine(eh.Machine) != elf.EM_PPC64 { |
| sh := elfshname(".got") |
| 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 = 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 = uint32(elf.SHT_HASH) |
| sh.Flags = uint64(elf.SHF_ALLOC) |
| sh.Entsize = 4 |
| sh.Addralign = uint64(ctxt.Arch.RegSize) |
| sh.link = elfshname(".dynsym") |
| shsym(sh, ldr, ldr.Lookup(".hash", 0)) |
|
|
| |
| sh = elfshname(".dynamic") |
|
|
| 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 = elfshname(".dynstr") |
| shsym(sh, ldr, ldr.Lookup(".dynamic", 0)) |
| ph := newElfPhdr() |
| ph.Type = elf.PT_DYNAMIC |
| ph.Flags = elf.PF_R + elf.PF_W |
| phsh(ph, sh) |
|
|
| |
| tlssize := uint64(0) |
| for _, sect := range Segdata.Sections { |
| if sect.Name == ".tbss" { |
| tlssize = sect.Length |
| } |
| } |
| if tlssize != 0 { |
| ph := newElfPhdr() |
| ph.Type = elf.PT_TLS |
| ph.Flags = elf.PF_R |
| ph.Memsz = tlssize |
| ph.Align = uint64(ctxt.Arch.RegSize) |
| } |
| } |
|
|
| if ctxt.HeadType == objabi.Hlinux || ctxt.HeadType == objabi.Hfreebsd { |
| ph := newElfPhdr() |
| ph.Type = elf.PT_GNU_STACK |
| ph.Flags = elf.PF_W + elf.PF_R |
| ph.Align = uint64(ctxt.Arch.RegSize) |
| } else if ctxt.HeadType == objabi.Hopenbsd { |
| ph := newElfPhdr() |
| ph.Type = elf.PT_OPENBSD_NOBTCFI |
| ph.Flags = elf.PF_X |
| } else if ctxt.HeadType == objabi.Hsolaris { |
| ph := newElfPhdr() |
| ph.Type = elf.PT_SUNWSTACK |
| ph.Flags = elf.PF_W + elf.PF_R |
| } |
|
|
| elfobj: |
| if ctxt.IsMIPS() { |
| sh := elfshname(".MIPS.abiflags") |
| sh.Type = uint32(elf.SHT_MIPS_ABIFLAGS) |
| sh.Flags = uint64(elf.SHF_ALLOC) |
| sh.Addralign = 8 |
| resoff -= int64(elfMipsAbiFlags(sh, uint64(startva), uint64(resoff))) |
|
|
| ph := newElfPhdr() |
| ph.Type = elf.PT_MIPS_ABIFLAGS |
| ph.Flags = elf.PF_R |
| phsh(ph, sh) |
|
|
| sh = elfshname(".gnu.attributes") |
| sh.Type = uint32(elf.SHT_GNU_ATTRIBUTES) |
| sh.Addralign = 1 |
| ldr := ctxt.loader |
| shsym(sh, ldr, ldr.Lookup(".gnu.attributes", 0)) |
| } |
|
|
| |
| if !*FlagS { |
| elfshname(".symtab") |
| elfshname(".strtab") |
| } |
| elfshname(".shstrtab") |
|
|
| for _, sect := range Segtext.Sections { |
| elfshbits(ctxt.LinkMode, sect) |
| } |
| for _, sect := range Segrodata.Sections { |
| elfshbits(ctxt.LinkMode, sect) |
| } |
| for _, sect := range Segrelrodata.Sections { |
| elfshbits(ctxt.LinkMode, sect) |
| } |
| for _, sect := range Segdata.Sections { |
| elfshbits(ctxt.LinkMode, sect) |
| } |
| for _, sect := range Segdwarf.Sections { |
| elfshbits(ctxt.LinkMode, sect) |
| } |
|
|
| if ctxt.LinkMode == LinkExternal { |
| for _, sect := range Segtext.Sections { |
| elfshreloc(ctxt.Arch, sect) |
| } |
| for _, sect := range Segrodata.Sections { |
| elfshreloc(ctxt.Arch, sect) |
| } |
| for _, sect := range Segrelrodata.Sections { |
| elfshreloc(ctxt.Arch, sect) |
| } |
| for _, sect := range Segdata.Sections { |
| elfshreloc(ctxt.Arch, sect) |
| } |
| for _, si := range dwarfp { |
| sect := ldr.SymSect(si.secSym()) |
| elfshreloc(ctxt.Arch, sect) |
| } |
| |
| sh := elfshname(".note.GNU-stack") |
|
|
| sh.Type = uint32(elf.SHT_PROGBITS) |
| sh.Addralign = 1 |
| sh.Flags = 0 |
| } |
|
|
| elfSortShdrs(ctxt) |
|
|
| sh := elfshname(".shstrtab") |
| eh.Shstrndx = uint16(elfShdrShnum(sh)) |
|
|
| var shstrtabLen uint32 |
| ctxt.Out.SeekSet(symo) |
| if *FlagS { |
| shstrtabLen = elfWriteShstrtab(ctxt) |
| } else { |
| asmElfSym(ctxt) |
| ctxt.Out.Write(elfstrdat) |
| shstrtabLen = elfWriteShstrtab(ctxt) |
| if ctxt.IsExternal() { |
| elfEmitReloc(ctxt) |
| } |
| } |
| ctxt.Out.SeekSet(0) |
|
|
| var shstroff uint64 |
| if !*FlagS { |
| sh := elfshname(".symtab") |
| 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 = elfshname(".strtab") |
| sh.Info = uint32(elfglobalsymndx) |
|
|
| sh = elfshname(".strtab") |
| sh.Type = uint32(elf.SHT_STRTAB) |
| sh.Off = uint64(symo) + uint64(symSize) |
| sh.Size = uint64(len(elfstrdat)) |
| sh.Addralign = 1 |
| shstroff = sh.Off + sh.Size |
| } else { |
| shstroff = uint64(symo) |
| } |
|
|
| sh = elfshname(".shstrtab") |
| sh.Type = uint32(elf.SHT_STRTAB) |
| sh.Off = shstroff |
| sh.Size = uint64(shstrtabLen) |
| sh.Addralign = 1 |
|
|
| |
| 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[elf.EI_CLASS] = byte(elf.ELFCLASS64) |
| } else { |
| eh.Ident[elf.EI_CLASS] = byte(elf.ELFCLASS32) |
| } |
| if ctxt.Arch.ByteOrder == binary.BigEndian { |
| eh.Ident[elf.EI_DATA] = byte(elf.ELFDATA2MSB) |
| } else { |
| eh.Ident[elf.EI_DATA] = byte(elf.ELFDATA2LSB) |
| } |
| eh.Ident[elf.EI_VERSION] = byte(elf.EV_CURRENT) |
|
|
| if ctxt.LinkMode == LinkExternal { |
| eh.Type = uint16(elf.ET_REL) |
| } else if ctxt.BuildMode == BuildModePIE { |
| eh.Type = uint16(elf.ET_DYN) |
| } else { |
| eh.Type = uint16(elf.ET_EXEC) |
| } |
|
|
| if ctxt.LinkMode != LinkExternal { |
| eh.Entry = uint64(Entryvalue(ctxt)) |
| } |
|
|
| eh.Version = uint32(elf.EV_CURRENT) |
|
|
| if pph != nil { |
| pph.Filesz = uint64(eh.Phnum) * uint64(eh.Phentsize) |
| pph.Memsz = pph.Filesz |
| } |
|
|
| if len(shdr) >= 0xffff { |
| Errorf("too many ELF sections") |
| } |
| eh.Shnum = uint16(len(shdr)) |
|
|
| ctxt.Out.SeekSet(0) |
| a := int64(0) |
| a += int64(elfwritehdr(ctxt.Out)) |
| a += int64(elfwritephdrs(ctxt.Out)) |
| a += int64(elfwriteshdrs(ctxt.Out)) |
| if !*FlagD { |
| a += int64(elfwriteinterp(ctxt.Out)) |
| } |
| if ctxt.IsMIPS() { |
| a += int64(elfWriteMipsAbiFlags(ctxt)) |
| } |
|
|
| if ctxt.LinkMode != LinkExternal { |
| if ctxt.HeadType == objabi.Hnetbsd { |
| a += int64(elfwritenetbsdsig(ctxt.Out)) |
| } |
| if ctxt.HeadType == objabi.Hopenbsd { |
| a += int64(elfwriteopenbsdsig(ctxt.Out)) |
| } |
| if ctxt.HeadType == objabi.Hfreebsd { |
| a += int64(elfwritefreebsdsig(ctxt.Out)) |
| } |
| if len(buildinfo) > 0 { |
| a += int64(elfwritebuildinfo(ctxt.Out)) |
| } |
| if *flagBuildid != "" { |
| a += int64(elfwritegobuildid(ctxt.Out)) |
| } |
| } |
| if *flagRace && ctxt.IsNetbsd() { |
| a += int64(elfwritenetbsdpax(ctxt.Out)) |
| } |
|
|
| if a > elfreserve { |
| Errorf("ELFRESERVE too small: %d > %d with %d text sections", a, elfreserve, numtext) |
| } |
|
|
| |
| |
| if a > int64(HEADR) { |
| Errorf("HEADR too small: %d > %d with %d text sections", a, HEADR, numtext) |
| } |
| } |
|
|
| func elfadddynsym(ldr *loader.Loader, target *Target, syms *ArchSyms, s loader.Sym) { |
| ldr.SetSymDynid(s, int32(Nelfsym)) |
| Nelfsym++ |
| d := ldr.MakeSymbolUpdater(syms.DynSym) |
| name := ldr.SymExtname(s) |
| dstru := ldr.MakeSymbolUpdater(syms.DynStr) |
| st := ldr.SymType(s) |
| cgoeStatic := ldr.AttrCgoExportStatic(s) |
| cgoeDynamic := ldr.AttrCgoExportDynamic(s) |
| cgoexp := (cgoeStatic || cgoeDynamic) |
|
|
| d.AddUint32(target.Arch, uint32(dstru.Addstring(name))) |
|
|
| if elf64 { |
| |
| var t uint8 |
|
|
| if cgoexp && st.IsText() { |
| t = elf.ST_INFO(elf.STB_GLOBAL, elf.STT_FUNC) |
| } else { |
| t = elf.ST_INFO(elf.STB_GLOBAL, elf.STT_OBJECT) |
| } |
| d.AddUint8(t) |
|
|
| |
| d.AddUint8(0) |
|
|
| |
| if st == sym.SDYNIMPORT { |
| d.AddUint16(target.Arch, uint16(elf.SHN_UNDEF)) |
| } else { |
| d.AddUint16(target.Arch, 1) |
| } |
|
|
| |
| if st == sym.SDYNIMPORT { |
| d.AddUint64(target.Arch, 0) |
| } else { |
| d.AddAddrPlus(target.Arch, s, 0) |
| } |
|
|
| |
| d.AddUint64(target.Arch, uint64(len(ldr.Data(s)))) |
|
|
| dil := ldr.SymDynimplib(s) |
|
|
| if !cgoeDynamic && dil != "" && !seenlib[dil] { |
| du := ldr.MakeSymbolUpdater(syms.Dynamic) |
| Elfwritedynent(target.Arch, du, elf.DT_NEEDED, uint64(dstru.Addstring(dil))) |
| seenlib[dil] = true |
| } |
| } else { |
|
|
| |
| if st == sym.SDYNIMPORT { |
| d.AddUint32(target.Arch, 0) |
| } else { |
| d.AddAddrPlus(target.Arch, s, 0) |
| } |
|
|
| |
| d.AddUint32(target.Arch, uint32(len(ldr.Data(s)))) |
|
|
| |
| var t uint8 |
|
|
| |
| if target.Arch.Family == sys.I386 && cgoexp && st.IsText() { |
| t = elf.ST_INFO(elf.STB_GLOBAL, elf.STT_FUNC) |
| } else if target.Arch.Family == sys.ARM && cgoeDynamic && st.IsText() { |
| t = elf.ST_INFO(elf.STB_GLOBAL, elf.STT_FUNC) |
| } else { |
| t = elf.ST_INFO(elf.STB_GLOBAL, elf.STT_OBJECT) |
| } |
| d.AddUint8(t) |
| d.AddUint8(0) |
|
|
| |
| if st == sym.SDYNIMPORT { |
| d.AddUint16(target.Arch, uint16(elf.SHN_UNDEF)) |
| } else { |
| d.AddUint16(target.Arch, 1) |
| } |
| } |
| } |
|
|