• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package ld
6
7import (
8	"cmd/internal/notsha256"
9	"cmd/internal/objabi"
10	"cmd/internal/sys"
11	"cmd/link/internal/loader"
12	"cmd/link/internal/sym"
13	"debug/elf"
14	"encoding/binary"
15	"encoding/hex"
16	"fmt"
17	"internal/buildcfg"
18	"os"
19	"path/filepath"
20	"runtime"
21	"sort"
22	"strings"
23)
24
25/*
26 * Derived from:
27 * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.1 2005/12/30 22:13:58 marcel Exp $
28 * $FreeBSD: src/sys/sys/elf64.h,v 1.10.14.1 2005/12/30 22:13:58 marcel Exp $
29 * $FreeBSD: src/sys/sys/elf_common.h,v 1.15.8.1 2005/12/30 22:13:58 marcel Exp $
30 * $FreeBSD: src/sys/alpha/include/elf.h,v 1.14 2003/09/25 01:10:22 peter Exp $
31 * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $
32 * $FreeBSD: src/sys/arm/include/elf.h,v 1.5.2.1 2006/06/30 21:42:52 cognet Exp $
33 * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $
34 * $FreeBSD: src/sys/powerpc/include/elf.h,v 1.7 2004/11/02 09:47:01 ssouhlal Exp $
35 * $FreeBSD: src/sys/sparc64/include/elf.h,v 1.12 2003/09/25 01:10:26 peter Exp $
36 *
37 * Copyright (c) 1996-1998 John D. Polstra.  All rights reserved.
38 * Copyright (c) 2001 David E. O'Brien
39 * Portions Copyright 2009 The Go Authors. All rights reserved.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 *    notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 *    notice, this list of conditions and the following disclaimer in the
48 *    documentation and/or other materials provided with the distribution.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * SUCH DAMAGE.
61 *
62 */
63
64/*
65 * ELF definitions that are independent of architecture or word size.
66 */
67
68/*
69 * Note header.  The ".note" section contains an array of notes.  Each
70 * begins with this header, aligned to a word boundary.  Immediately
71 * following the note header is n_namesz bytes of name, padded to the
72 * next word boundary.  Then comes n_descsz bytes of descriptor, again
73 * padded to a word boundary.  The values of n_namesz and n_descsz do
74 * not include the padding.
75 */
76type elfNote struct {
77	nNamesz uint32
78	nDescsz uint32
79	nType   uint32
80}
81
82/* For accessing the fields of r_info. */
83
84/* For constructing r_info from field values. */
85
86/*
87 * Relocation types.
88 */
89const (
90	ARM_MAGIC_TRAMP_NUMBER = 0x5c000003
91)
92
93/*
94 * Symbol table entries.
95 */
96
97/* For accessing the fields of st_info. */
98
99/* For constructing st_info from field values. */
100
101/* For accessing the fields of st_other. */
102
103/*
104 * ELF header.
105 */
106type ElfEhdr elf.Header64
107
108/*
109 * Section header.
110 */
111type ElfShdr struct {
112	elf.Section64
113	shnum elf.SectionIndex
114}
115
116/*
117 * Program header.
118 */
119type ElfPhdr elf.ProgHeader
120
121/* For accessing the fields of r_info. */
122
123/* For constructing r_info from field values. */
124
125/*
126 * Symbol table entries.
127 */
128
129/* For accessing the fields of st_info. */
130
131/* For constructing st_info from field values. */
132
133/* For accessing the fields of st_other. */
134
135/*
136 * Go linker interface
137 */
138const (
139	ELF64HDRSIZE  = 64
140	ELF64PHDRSIZE = 56
141	ELF64SHDRSIZE = 64
142	ELF64RELSIZE  = 16
143	ELF64RELASIZE = 24
144	ELF64SYMSIZE  = 24
145	ELF32HDRSIZE  = 52
146	ELF32PHDRSIZE = 32
147	ELF32SHDRSIZE = 40
148	ELF32SYMSIZE  = 16
149	ELF32RELSIZE  = 8
150)
151
152/*
153 * The interface uses the 64-bit structures always,
154 * to avoid code duplication.  The writers know how to
155 * marshal a 32-bit representation from the 64-bit structure.
156 */
157
158var elfstrdat, elfshstrdat []byte
159
160/*
161 * Total amount of space to reserve at the start of the file
162 * for Header, PHeaders, SHeaders, and interp.
163 * May waste some.
164 * On FreeBSD, cannot be larger than a page.
165 */
166const (
167	ELFRESERVE = 4096
168)
169
170/*
171 * We use the 64-bit data structures on both 32- and 64-bit machines
172 * in order to write the code just once.  The 64-bit data structure is
173 * written in the 32-bit format on the 32-bit machines.
174 */
175const (
176	NSECT = 400
177)
178
179var (
180	Nelfsym = 1
181
182	elf64 bool
183	// Either ".rel" or ".rela" depending on which type of relocation the
184	// target platform uses.
185	elfRelType string
186
187	ehdr ElfEhdr
188	phdr [NSECT]*ElfPhdr
189	shdr [NSECT]*ElfShdr
190
191	interp string
192)
193
194// ELFArch includes target-specific hooks for ELF targets.
195// This is initialized by the target-specific Init function
196// called by the linker's main function in cmd/link/main.go.
197type ELFArch struct {
198	// TODO: Document these fields.
199
200	Androiddynld   string
201	Linuxdynld     string
202	LinuxdynldMusl string
203	Freebsddynld   string
204	Netbsddynld    string
205	Openbsddynld   string
206	Dragonflydynld string
207	Solarisdynld   string
208
209	Reloc1    func(*Link, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int, int64) bool
210	RelocSize uint32 // size of an ELF relocation record, must match Reloc1.
211	SetupPLT  func(ctxt *Link, ldr *loader.Loader, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym)
212
213	// DynamicReadOnly can be set to true to make the .dynamic
214	// section read-only. By default it is writable.
215	// This is used by MIPS targets.
216	DynamicReadOnly bool
217}
218
219type Elfstring struct {
220	s   string
221	off int
222}
223
224var elfstr [100]Elfstring
225
226var nelfstr int
227
228var buildinfo []byte
229
230/*
231Initialize the global variable that describes the ELF header. It will be updated as
232we write section and prog headers.
233*/
234func Elfinit(ctxt *Link) {
235	ctxt.IsELF = true
236
237	if ctxt.Arch.InFamily(sys.AMD64, sys.ARM64, sys.Loong64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X) {
238		elfRelType = ".rela"
239	} else {
240		elfRelType = ".rel"
241	}
242
243	switch ctxt.Arch.Family {
244	// 64-bit architectures
245	case sys.PPC64, sys.S390X:
246		if ctxt.Arch.ByteOrder == binary.BigEndian && ctxt.HeadType != objabi.Hopenbsd {
247			ehdr.Flags = 1 /* Version 1 ABI */
248		} else {
249			ehdr.Flags = 2 /* Version 2 ABI */
250		}
251		fallthrough
252	case sys.AMD64, sys.ARM64, sys.Loong64, sys.MIPS64, sys.RISCV64:
253		if ctxt.Arch.Family == sys.MIPS64 {
254			ehdr.Flags = 0x20000004 /* MIPS 3 CPIC */
255		}
256		if ctxt.Arch.Family == sys.Loong64 {
257			ehdr.Flags = 0x43 /* DOUBLE_FLOAT, OBJABI_V1 */
258		}
259		if ctxt.Arch.Family == sys.RISCV64 {
260			ehdr.Flags = 0x4 /* RISCV Float ABI Double */
261		}
262		elf64 = true
263
264		ehdr.Phoff = ELF64HDRSIZE      /* Must be ELF64HDRSIZE: first PHdr must follow ELF header */
265		ehdr.Shoff = ELF64HDRSIZE      /* Will move as we add PHeaders */
266		ehdr.Ehsize = ELF64HDRSIZE     /* Must be ELF64HDRSIZE */
267		ehdr.Phentsize = ELF64PHDRSIZE /* Must be ELF64PHDRSIZE */
268		ehdr.Shentsize = ELF64SHDRSIZE /* Must be ELF64SHDRSIZE */
269
270	// 32-bit architectures
271	case sys.ARM, sys.MIPS:
272		if ctxt.Arch.Family == sys.ARM {
273			// we use EABI on linux/arm, freebsd/arm, netbsd/arm.
274			if ctxt.HeadType == objabi.Hlinux || ctxt.HeadType == objabi.Hfreebsd || ctxt.HeadType == objabi.Hnetbsd {
275				// We set a value here that makes no indication of which
276				// float ABI the object uses, because this is information
277				// used by the dynamic linker to compare executables and
278				// shared libraries -- so it only matters for cgo calls, and
279				// the information properly comes from the object files
280				// produced by the host C compiler. parseArmAttributes in
281				// ldelf.go reads that information and updates this field as
282				// appropriate.
283				ehdr.Flags = 0x5000002 // has entry point, Version5 EABI
284			}
285		} else if ctxt.Arch.Family == sys.MIPS {
286			ehdr.Flags = 0x50001004 /* MIPS 32 CPIC O32*/
287		}
288		fallthrough
289	default:
290		ehdr.Phoff = ELF32HDRSIZE
291		/* Must be ELF32HDRSIZE: first PHdr must follow ELF header */
292		ehdr.Shoff = ELF32HDRSIZE      /* Will move as we add PHeaders */
293		ehdr.Ehsize = ELF32HDRSIZE     /* Must be ELF32HDRSIZE */
294		ehdr.Phentsize = ELF32PHDRSIZE /* Must be ELF32PHDRSIZE */
295		ehdr.Shentsize = ELF32SHDRSIZE /* Must be ELF32SHDRSIZE */
296	}
297}
298
299// Make sure PT_LOAD is aligned properly and
300// that there is no gap,
301// correct ELF loaders will do this implicitly,
302// but buggy ELF loaders like the one in some
303// versions of QEMU and UPX won't.
304func fixElfPhdr(e *ElfPhdr) {
305	frag := int(e.Vaddr & (e.Align - 1))
306
307	e.Off -= uint64(frag)
308	e.Vaddr -= uint64(frag)
309	e.Paddr -= uint64(frag)
310	e.Filesz += uint64(frag)
311	e.Memsz += uint64(frag)
312}
313
314func elf64phdr(out *OutBuf, e *ElfPhdr) {
315	if e.Type == elf.PT_LOAD {
316		fixElfPhdr(e)
317	}
318
319	out.Write32(uint32(e.Type))
320	out.Write32(uint32(e.Flags))
321	out.Write64(e.Off)
322	out.Write64(e.Vaddr)
323	out.Write64(e.Paddr)
324	out.Write64(e.Filesz)
325	out.Write64(e.Memsz)
326	out.Write64(e.Align)
327}
328
329func elf32phdr(out *OutBuf, e *ElfPhdr) {
330	if e.Type == elf.PT_LOAD {
331		fixElfPhdr(e)
332	}
333
334	out.Write32(uint32(e.Type))
335	out.Write32(uint32(e.Off))
336	out.Write32(uint32(e.Vaddr))
337	out.Write32(uint32(e.Paddr))
338	out.Write32(uint32(e.Filesz))
339	out.Write32(uint32(e.Memsz))
340	out.Write32(uint32(e.Flags))
341	out.Write32(uint32(e.Align))
342}
343
344func elf64shdr(out *OutBuf, e *ElfShdr) {
345	out.Write32(e.Name)
346	out.Write32(uint32(e.Type))
347	out.Write64(uint64(e.Flags))
348	out.Write64(e.Addr)
349	out.Write64(e.Off)
350	out.Write64(e.Size)
351	out.Write32(e.Link)
352	out.Write32(e.Info)
353	out.Write64(e.Addralign)
354	out.Write64(e.Entsize)
355}
356
357func elf32shdr(out *OutBuf, e *ElfShdr) {
358	out.Write32(e.Name)
359	out.Write32(uint32(e.Type))
360	out.Write32(uint32(e.Flags))
361	out.Write32(uint32(e.Addr))
362	out.Write32(uint32(e.Off))
363	out.Write32(uint32(e.Size))
364	out.Write32(e.Link)
365	out.Write32(e.Info)
366	out.Write32(uint32(e.Addralign))
367	out.Write32(uint32(e.Entsize))
368}
369
370func elfwriteshdrs(out *OutBuf) uint32 {
371	if elf64 {
372		for i := 0; i < int(ehdr.Shnum); i++ {
373			elf64shdr(out, shdr[i])
374		}
375		return uint32(ehdr.Shnum) * ELF64SHDRSIZE
376	}
377
378	for i := 0; i < int(ehdr.Shnum); i++ {
379		elf32shdr(out, shdr[i])
380	}
381	return uint32(ehdr.Shnum) * ELF32SHDRSIZE
382}
383
384func elfsetstring(ctxt *Link, s loader.Sym, str string, off int) {
385	if nelfstr >= len(elfstr) {
386		ctxt.Errorf(s, "too many elf strings")
387		errorexit()
388	}
389
390	elfstr[nelfstr].s = str
391	elfstr[nelfstr].off = off
392	nelfstr++
393}
394
395func elfwritephdrs(out *OutBuf) uint32 {
396	if elf64 {
397		for i := 0; i < int(ehdr.Phnum); i++ {
398			elf64phdr(out, phdr[i])
399		}
400		return uint32(ehdr.Phnum) * ELF64PHDRSIZE
401	}
402
403	for i := 0; i < int(ehdr.Phnum); i++ {
404		elf32phdr(out, phdr[i])
405	}
406	return uint32(ehdr.Phnum) * ELF32PHDRSIZE
407}
408
409func newElfPhdr() *ElfPhdr {
410	e := new(ElfPhdr)
411	if ehdr.Phnum >= NSECT {
412		Errorf(nil, "too many phdrs")
413	} else {
414		phdr[ehdr.Phnum] = e
415		ehdr.Phnum++
416	}
417	if elf64 {
418		ehdr.Shoff += ELF64PHDRSIZE
419	} else {
420		ehdr.Shoff += ELF32PHDRSIZE
421	}
422	return e
423}
424
425func newElfShdr(name int64) *ElfShdr {
426	e := new(ElfShdr)
427	e.Name = uint32(name)
428	e.shnum = elf.SectionIndex(ehdr.Shnum)
429	if ehdr.Shnum >= NSECT {
430		Errorf(nil, "too many shdrs")
431	} else {
432		shdr[ehdr.Shnum] = e
433		ehdr.Shnum++
434	}
435
436	return e
437}
438
439func getElfEhdr() *ElfEhdr {
440	return &ehdr
441}
442
443func elf64writehdr(out *OutBuf) uint32 {
444	out.Write(ehdr.Ident[:])
445	out.Write16(uint16(ehdr.Type))
446	out.Write16(uint16(ehdr.Machine))
447	out.Write32(uint32(ehdr.Version))
448	out.Write64(ehdr.Entry)
449	out.Write64(ehdr.Phoff)
450	out.Write64(ehdr.Shoff)
451	out.Write32(ehdr.Flags)
452	out.Write16(ehdr.Ehsize)
453	out.Write16(ehdr.Phentsize)
454	out.Write16(ehdr.Phnum)
455	out.Write16(ehdr.Shentsize)
456	out.Write16(ehdr.Shnum)
457	out.Write16(ehdr.Shstrndx)
458	return ELF64HDRSIZE
459}
460
461func elf32writehdr(out *OutBuf) uint32 {
462	out.Write(ehdr.Ident[:])
463	out.Write16(uint16(ehdr.Type))
464	out.Write16(uint16(ehdr.Machine))
465	out.Write32(uint32(ehdr.Version))
466	out.Write32(uint32(ehdr.Entry))
467	out.Write32(uint32(ehdr.Phoff))
468	out.Write32(uint32(ehdr.Shoff))
469	out.Write32(ehdr.Flags)
470	out.Write16(ehdr.Ehsize)
471	out.Write16(ehdr.Phentsize)
472	out.Write16(ehdr.Phnum)
473	out.Write16(ehdr.Shentsize)
474	out.Write16(ehdr.Shnum)
475	out.Write16(ehdr.Shstrndx)
476	return ELF32HDRSIZE
477}
478
479func elfwritehdr(out *OutBuf) uint32 {
480	if elf64 {
481		return elf64writehdr(out)
482	}
483	return elf32writehdr(out)
484}
485
486/* Taken directly from the definition document for ELF64. */
487func elfhash(name string) uint32 {
488	var h uint32
489	for i := 0; i < len(name); i++ {
490		h = (h << 4) + uint32(name[i])
491		if g := h & 0xf0000000; g != 0 {
492			h ^= g >> 24
493		}
494		h &= 0x0fffffff
495	}
496	return h
497}
498
499func elfWriteDynEntSym(ctxt *Link, s *loader.SymbolBuilder, tag elf.DynTag, t loader.Sym) {
500	Elfwritedynentsymplus(ctxt, s, tag, t, 0)
501}
502
503func Elfwritedynent(arch *sys.Arch, s *loader.SymbolBuilder, tag elf.DynTag, val uint64) {
504	if elf64 {
505		s.AddUint64(arch, uint64(tag))
506		s.AddUint64(arch, val)
507	} else {
508		s.AddUint32(arch, uint32(tag))
509		s.AddUint32(arch, uint32(val))
510	}
511}
512
513func Elfwritedynentsymplus(ctxt *Link, s *loader.SymbolBuilder, tag elf.DynTag, t loader.Sym, add int64) {
514	if elf64 {
515		s.AddUint64(ctxt.Arch, uint64(tag))
516	} else {
517		s.AddUint32(ctxt.Arch, uint32(tag))
518	}
519	s.AddAddrPlus(ctxt.Arch, t, add)
520}
521
522func elfwritedynentsymsize(ctxt *Link, s *loader.SymbolBuilder, tag elf.DynTag, t loader.Sym) {
523	if elf64 {
524		s.AddUint64(ctxt.Arch, uint64(tag))
525	} else {
526		s.AddUint32(ctxt.Arch, uint32(tag))
527	}
528	s.AddSize(ctxt.Arch, t)
529}
530
531func elfinterp(sh *ElfShdr, startva uint64, resoff uint64, p string) int {
532	interp = p
533	n := len(interp) + 1
534	sh.Addr = startva + resoff - uint64(n)
535	sh.Off = resoff - uint64(n)
536	sh.Size = uint64(n)
537
538	return n
539}
540
541func elfwriteinterp(out *OutBuf) int {
542	sh := elfshname(".interp")
543	out.SeekSet(int64(sh.Off))
544	out.WriteString(interp)
545	out.Write8(0)
546	return int(sh.Size)
547}
548
549// member of .gnu.attributes of MIPS for fpAbi
550const (
551	// No floating point is present in the module (default)
552	MIPS_FPABI_NONE = 0
553	// FP code in the module uses the FP32 ABI for a 32-bit ABI
554	MIPS_FPABI_ANY = 1
555	// FP code in the module only uses single precision ABI
556	MIPS_FPABI_SINGLE = 2
557	// FP code in the module uses soft-float ABI
558	MIPS_FPABI_SOFT = 3
559	// FP code in the module assumes an FPU with FR=1 and has 12
560	// callee-saved doubles. Historic, no longer supported.
561	MIPS_FPABI_HIST = 4
562	// FP code in the module uses the FPXX  ABI
563	MIPS_FPABI_FPXX = 5
564	// FP code in the module uses the FP64  ABI
565	MIPS_FPABI_FP64 = 6
566	// FP code in the module uses the FP64A ABI
567	MIPS_FPABI_FP64A = 7
568)
569
570func elfMipsAbiFlags(sh *ElfShdr, startva uint64, resoff uint64) int {
571	n := 24
572	sh.Addr = startva + resoff - uint64(n)
573	sh.Off = resoff - uint64(n)
574	sh.Size = uint64(n)
575	sh.Type = uint32(elf.SHT_MIPS_ABIFLAGS)
576	sh.Flags = uint64(elf.SHF_ALLOC)
577
578	return n
579}
580
581// Layout is given by this C definition:
582//
583//	typedef struct
584//	{
585//	  /* Version of flags structure.  */
586//	  uint16_t version;
587//	  /* The level of the ISA: 1-5, 32, 64.  */
588//	  uint8_t isa_level;
589//	  /* The revision of ISA: 0 for MIPS V and below, 1-n otherwise.  */
590//	  uint8_t isa_rev;
591//	  /* The size of general purpose registers.  */
592//	  uint8_t gpr_size;
593//	  /* The size of co-processor 1 registers.  */
594//	  uint8_t cpr1_size;
595//	  /* The size of co-processor 2 registers.  */
596//	  uint8_t cpr2_size;
597//	  /* The floating-point ABI.  */
598//	  uint8_t fp_abi;
599//	  /* Processor-specific extension.  */
600//	  uint32_t isa_ext;
601//	  /* Mask of ASEs used.  */
602//	  uint32_t ases;
603//	  /* Mask of general flags.  */
604//	  uint32_t flags1;
605//	  uint32_t flags2;
606//	} Elf_Internal_ABIFlags_v0;
607func elfWriteMipsAbiFlags(ctxt *Link) int {
608	sh := elfshname(".MIPS.abiflags")
609	ctxt.Out.SeekSet(int64(sh.Off))
610	ctxt.Out.Write16(0) // version
611	ctxt.Out.Write8(32) // isaLevel
612	ctxt.Out.Write8(1)  // isaRev
613	ctxt.Out.Write8(1)  // gprSize
614	ctxt.Out.Write8(1)  // cpr1Size
615	ctxt.Out.Write8(0)  // cpr2Size
616	if buildcfg.GOMIPS == "softfloat" {
617		ctxt.Out.Write8(MIPS_FPABI_SOFT) // fpAbi
618	} else {
619		// Go cannot make sure non odd-number-fpr is used (ie, in load a double from memory).
620		// So, we mark the object is MIPS I style paired float/double register scheme,
621		// aka MIPS_FPABI_ANY. If we mark the object as FPXX, the kernel may use FR=1 mode,
622		// then we meet some problem.
623		// Note: MIPS_FPABI_ANY is bad naming: in fact it is MIPS I style FPR usage.
624		//       It is not for 'ANY'.
625		// TODO: switch to FPXX after be sure that no odd-number-fpr is used.
626		ctxt.Out.Write8(MIPS_FPABI_ANY) // fpAbi
627	}
628	ctxt.Out.Write32(0) // isaExt
629	ctxt.Out.Write32(0) // ases
630	ctxt.Out.Write32(0) // flags1
631	ctxt.Out.Write32(0) // flags2
632	return int(sh.Size)
633}
634
635func elfnote(sh *ElfShdr, startva uint64, resoff uint64, sizes ...int) int {
636	n := resoff % 4
637	// if section contains multiple notes (as is the case with FreeBSD signature),
638	// multiple note sizes can be specified
639	for _, sz := range sizes {
640		n += 3*4 + uint64(sz)
641	}
642
643	sh.Type = uint32(elf.SHT_NOTE)
644	sh.Flags = uint64(elf.SHF_ALLOC)
645	sh.Addralign = 4
646	sh.Addr = startva + resoff - n
647	sh.Off = resoff - n
648	sh.Size = n - resoff%4
649
650	return int(n)
651}
652
653func elfwritenotehdr(out *OutBuf, str string, namesz uint32, descsz uint32, tag uint32) *ElfShdr {
654	sh := elfshname(str)
655
656	// Write Elf_Note header.
657	out.SeekSet(int64(sh.Off))
658
659	out.Write32(namesz)
660	out.Write32(descsz)
661	out.Write32(tag)
662
663	return sh
664}
665
666// NetBSD Signature (as per sys/exec_elf.h)
667const (
668	ELF_NOTE_NETBSD_NAMESZ  = 7
669	ELF_NOTE_NETBSD_DESCSZ  = 4
670	ELF_NOTE_NETBSD_TAG     = 1
671	ELF_NOTE_NETBSD_VERSION = 700000000 /* NetBSD 7.0 */
672)
673
674var ELF_NOTE_NETBSD_NAME = []byte("NetBSD\x00")
675
676func elfnetbsdsig(sh *ElfShdr, startva uint64, resoff uint64) int {
677	n := int(Rnd(ELF_NOTE_NETBSD_NAMESZ, 4) + Rnd(ELF_NOTE_NETBSD_DESCSZ, 4))
678	return elfnote(sh, startva, resoff, n)
679}
680
681func elfwritenetbsdsig(out *OutBuf) int {
682	// Write Elf_Note header.
683	sh := elfwritenotehdr(out, ".note.netbsd.ident", ELF_NOTE_NETBSD_NAMESZ, ELF_NOTE_NETBSD_DESCSZ, ELF_NOTE_NETBSD_TAG)
684
685	if sh == nil {
686		return 0
687	}
688
689	// Followed by NetBSD string and version.
690	out.Write(ELF_NOTE_NETBSD_NAME)
691	out.Write8(0)
692	out.Write32(ELF_NOTE_NETBSD_VERSION)
693
694	return int(sh.Size)
695}
696
697// The race detector can't handle ASLR (address space layout randomization).
698// ASLR is on by default for NetBSD, so we turn the ASLR off explicitly
699// using a magic elf Note when building race binaries.
700
701func elfnetbsdpax(sh *ElfShdr, startva uint64, resoff uint64) int {
702	n := int(Rnd(4, 4) + Rnd(4, 4))
703	return elfnote(sh, startva, resoff, n)
704}
705
706func elfwritenetbsdpax(out *OutBuf) int {
707	sh := elfwritenotehdr(out, ".note.netbsd.pax", 4 /* length of PaX\x00 */, 4 /* length of flags */, 0x03 /* PaX type */)
708	if sh == nil {
709		return 0
710	}
711	out.Write([]byte("PaX\x00"))
712	out.Write32(0x20) // 0x20 = Force disable ASLR
713	return int(sh.Size)
714}
715
716// OpenBSD Signature
717const (
718	ELF_NOTE_OPENBSD_NAMESZ  = 8
719	ELF_NOTE_OPENBSD_DESCSZ  = 4
720	ELF_NOTE_OPENBSD_TAG     = 1
721	ELF_NOTE_OPENBSD_VERSION = 0
722)
723
724var ELF_NOTE_OPENBSD_NAME = []byte("OpenBSD\x00")
725
726func elfopenbsdsig(sh *ElfShdr, startva uint64, resoff uint64) int {
727	n := ELF_NOTE_OPENBSD_NAMESZ + ELF_NOTE_OPENBSD_DESCSZ
728	return elfnote(sh, startva, resoff, n)
729}
730
731func elfwriteopenbsdsig(out *OutBuf) int {
732	// Write Elf_Note header.
733	sh := elfwritenotehdr(out, ".note.openbsd.ident", ELF_NOTE_OPENBSD_NAMESZ, ELF_NOTE_OPENBSD_DESCSZ, ELF_NOTE_OPENBSD_TAG)
734
735	if sh == nil {
736		return 0
737	}
738
739	// Followed by OpenBSD string and version.
740	out.Write(ELF_NOTE_OPENBSD_NAME)
741
742	out.Write32(ELF_NOTE_OPENBSD_VERSION)
743
744	return int(sh.Size)
745}
746
747// FreeBSD Signature (as per sys/elf_common.h)
748const (
749	ELF_NOTE_FREEBSD_NAMESZ            = 8
750	ELF_NOTE_FREEBSD_DESCSZ            = 4
751	ELF_NOTE_FREEBSD_ABI_TAG           = 1
752	ELF_NOTE_FREEBSD_NOINIT_TAG        = 2
753	ELF_NOTE_FREEBSD_FEATURE_CTL_TAG   = 4
754	ELF_NOTE_FREEBSD_VERSION           = 1203000 // 12.3-RELEASE
755	ELF_NOTE_FREEBSD_FCTL_ASLR_DISABLE = 0x1
756)
757
758const ELF_NOTE_FREEBSD_NAME = "FreeBSD\x00"
759
760func elffreebsdsig(sh *ElfShdr, startva uint64, resoff uint64) int {
761	n := ELF_NOTE_FREEBSD_NAMESZ + ELF_NOTE_FREEBSD_DESCSZ
762	// FreeBSD signature section contains 3 equally sized notes
763	return elfnote(sh, startva, resoff, n, n, n)
764}
765
766// elfwritefreebsdsig writes FreeBSD .note section.
767//
768// See https://www.netbsd.org/docs/kernel/elf-notes.html for the description of
769// a Note element format and
770// https://github.com/freebsd/freebsd-src/blob/main/sys/sys/elf_common.h#L790
771// for the FreeBSD-specific values.
772func elfwritefreebsdsig(out *OutBuf) int {
773	sh := elfshname(".note.tag")
774	if sh == nil {
775		return 0
776	}
777	out.SeekSet(int64(sh.Off))
778
779	// NT_FREEBSD_ABI_TAG
780	out.Write32(ELF_NOTE_FREEBSD_NAMESZ)
781	out.Write32(ELF_NOTE_FREEBSD_DESCSZ)
782	out.Write32(ELF_NOTE_FREEBSD_ABI_TAG)
783	out.WriteString(ELF_NOTE_FREEBSD_NAME)
784	out.Write32(ELF_NOTE_FREEBSD_VERSION)
785
786	// NT_FREEBSD_NOINIT_TAG
787	out.Write32(ELF_NOTE_FREEBSD_NAMESZ)
788	out.Write32(ELF_NOTE_FREEBSD_DESCSZ)
789	out.Write32(ELF_NOTE_FREEBSD_NOINIT_TAG)
790	out.WriteString(ELF_NOTE_FREEBSD_NAME)
791	out.Write32(0)
792
793	// NT_FREEBSD_FEATURE_CTL
794	out.Write32(ELF_NOTE_FREEBSD_NAMESZ)
795	out.Write32(ELF_NOTE_FREEBSD_DESCSZ)
796	out.Write32(ELF_NOTE_FREEBSD_FEATURE_CTL_TAG)
797	out.WriteString(ELF_NOTE_FREEBSD_NAME)
798	if *flagRace {
799		// The race detector can't handle ASLR, turn the ASLR off when compiling with -race.
800		out.Write32(ELF_NOTE_FREEBSD_FCTL_ASLR_DISABLE)
801	} else {
802		out.Write32(0)
803	}
804
805	return int(sh.Size)
806}
807
808func addbuildinfo(ctxt *Link) {
809	val := *flagHostBuildid
810	if val == "gobuildid" {
811		buildID := *flagBuildid
812		if buildID == "" {
813			Exitf("-B gobuildid requires a Go build ID supplied via -buildid")
814		}
815
816		if ctxt.IsDarwin() {
817			buildinfo = uuidFromGoBuildId(buildID)
818			return
819		}
820
821		hashedBuildID := notsha256.Sum256([]byte(buildID))
822		buildinfo = hashedBuildID[:20]
823
824		return
825	}
826
827	if !strings.HasPrefix(val, "0x") {
828		Exitf("-B argument must start with 0x: %s", val)
829	}
830	ov := val
831	val = val[2:]
832
833	maxLen := 32
834	if ctxt.IsDarwin() {
835		maxLen = 16
836	}
837	if hex.DecodedLen(len(val)) > maxLen {
838		Exitf("-B option too long (max %d digits): %s", maxLen, ov)
839	}
840
841	b, err := hex.DecodeString(val)
842	if err != nil {
843		if err == hex.ErrLength {
844			Exitf("-B argument must have even number of digits: %s", ov)
845		}
846		if inv, ok := err.(hex.InvalidByteError); ok {
847			Exitf("-B argument contains invalid hex digit %c: %s", byte(inv), ov)
848		}
849		Exitf("-B argument contains invalid hex: %s", ov)
850	}
851
852	buildinfo = b
853}
854
855// Build info note
856const (
857	ELF_NOTE_BUILDINFO_NAMESZ = 4
858	ELF_NOTE_BUILDINFO_TAG    = 3
859)
860
861var ELF_NOTE_BUILDINFO_NAME = []byte("GNU\x00")
862
863func elfbuildinfo(sh *ElfShdr, startva uint64, resoff uint64) int {
864	n := int(ELF_NOTE_BUILDINFO_NAMESZ + Rnd(int64(len(buildinfo)), 4))
865	return elfnote(sh, startva, resoff, n)
866}
867
868func elfgobuildid(sh *ElfShdr, startva uint64, resoff uint64) int {
869	n := len(ELF_NOTE_GO_NAME) + int(Rnd(int64(len(*flagBuildid)), 4))
870	return elfnote(sh, startva, resoff, n)
871}
872
873func elfwritebuildinfo(out *OutBuf) int {
874	sh := elfwritenotehdr(out, ".note.gnu.build-id", ELF_NOTE_BUILDINFO_NAMESZ, uint32(len(buildinfo)), ELF_NOTE_BUILDINFO_TAG)
875	if sh == nil {
876		return 0
877	}
878
879	out.Write(ELF_NOTE_BUILDINFO_NAME)
880	out.Write(buildinfo)
881	var zero = make([]byte, 4)
882	out.Write(zero[:int(Rnd(int64(len(buildinfo)), 4)-int64(len(buildinfo)))])
883
884	return int(sh.Size)
885}
886
887func elfwritegobuildid(out *OutBuf) int {
888	sh := elfwritenotehdr(out, ".note.go.buildid", uint32(len(ELF_NOTE_GO_NAME)), uint32(len(*flagBuildid)), ELF_NOTE_GOBUILDID_TAG)
889	if sh == nil {
890		return 0
891	}
892
893	out.Write(ELF_NOTE_GO_NAME)
894	out.Write([]byte(*flagBuildid))
895	var zero = make([]byte, 4)
896	out.Write(zero[:int(Rnd(int64(len(*flagBuildid)), 4)-int64(len(*flagBuildid)))])
897
898	return int(sh.Size)
899}
900
901// Go specific notes
902const (
903	ELF_NOTE_GOPKGLIST_TAG = 1
904	ELF_NOTE_GOABIHASH_TAG = 2
905	ELF_NOTE_GODEPS_TAG    = 3
906	ELF_NOTE_GOBUILDID_TAG = 4
907)
908
909var ELF_NOTE_GO_NAME = []byte("Go\x00\x00")
910
911var elfverneed int
912
913type Elfaux struct {
914	next *Elfaux
915	num  int
916	vers string
917}
918
919type Elflib struct {
920	next *Elflib
921	aux  *Elfaux
922	file string
923}
924
925func addelflib(list **Elflib, file string, vers string) *Elfaux {
926	var lib *Elflib
927
928	for lib = *list; lib != nil; lib = lib.next {
929		if lib.file == file {
930			goto havelib
931		}
932	}
933	lib = new(Elflib)
934	lib.next = *list
935	lib.file = file
936	*list = lib
937
938havelib:
939	for aux := lib.aux; aux != nil; aux = aux.next {
940		if aux.vers == vers {
941			return aux
942		}
943	}
944	aux := new(Elfaux)
945	aux.next = lib.aux
946	aux.vers = vers
947	lib.aux = aux
948
949	return aux
950}
951
952func elfdynhash(ctxt *Link) {
953	if !ctxt.IsELF {
954		return
955	}
956
957	nsym := Nelfsym
958	ldr := ctxt.loader
959	s := ldr.CreateSymForUpdate(".hash", 0)
960	s.SetType(sym.SELFROSECT)
961
962	i := nsym
963	nbucket := 1
964	for i > 0 {
965		nbucket++
966		i >>= 1
967	}
968
969	var needlib *Elflib
970	need := make([]*Elfaux, nsym)
971	chain := make([]uint32, nsym)
972	buckets := make([]uint32, nbucket)
973
974	for _, sy := range ldr.DynidSyms() {
975
976		dynid := ldr.SymDynid(sy)
977		if ldr.SymDynimpvers(sy) != "" {
978			need[dynid] = addelflib(&needlib, ldr.SymDynimplib(sy), ldr.SymDynimpvers(sy))
979		}
980
981		name := ldr.SymExtname(sy)
982		hc := elfhash(name)
983
984		b := hc % uint32(nbucket)
985		chain[dynid] = buckets[b]
986		buckets[b] = uint32(dynid)
987	}
988
989	// s390x (ELF64) hash table entries are 8 bytes
990	if ctxt.Arch.Family == sys.S390X {
991		s.AddUint64(ctxt.Arch, uint64(nbucket))
992		s.AddUint64(ctxt.Arch, uint64(nsym))
993		for i := 0; i < nbucket; i++ {
994			s.AddUint64(ctxt.Arch, uint64(buckets[i]))
995		}
996		for i := 0; i < nsym; i++ {
997			s.AddUint64(ctxt.Arch, uint64(chain[i]))
998		}
999	} else {
1000		s.AddUint32(ctxt.Arch, uint32(nbucket))
1001		s.AddUint32(ctxt.Arch, uint32(nsym))
1002		for i := 0; i < nbucket; i++ {
1003			s.AddUint32(ctxt.Arch, buckets[i])
1004		}
1005		for i := 0; i < nsym; i++ {
1006			s.AddUint32(ctxt.Arch, chain[i])
1007		}
1008	}
1009
1010	dynstr := ldr.CreateSymForUpdate(".dynstr", 0)
1011
1012	// version symbols
1013	gnuVersionR := ldr.CreateSymForUpdate(".gnu.version_r", 0)
1014	s = gnuVersionR
1015	i = 2
1016	nfile := 0
1017	for l := needlib; l != nil; l = l.next {
1018		nfile++
1019
1020		// header
1021		s.AddUint16(ctxt.Arch, 1) // table version
1022		j := 0
1023		for x := l.aux; x != nil; x = x.next {
1024			j++
1025		}
1026		s.AddUint16(ctxt.Arch, uint16(j))                        // aux count
1027		s.AddUint32(ctxt.Arch, uint32(dynstr.Addstring(l.file))) // file string offset
1028		s.AddUint32(ctxt.Arch, 16)                               // offset from header to first aux
1029		if l.next != nil {
1030			s.AddUint32(ctxt.Arch, 16+uint32(j)*16) // offset from this header to next
1031		} else {
1032			s.AddUint32(ctxt.Arch, 0)
1033		}
1034
1035		for x := l.aux; x != nil; x = x.next {
1036			x.num = i
1037			i++
1038
1039			// aux struct
1040			s.AddUint32(ctxt.Arch, elfhash(x.vers))                  // hash
1041			s.AddUint16(ctxt.Arch, 0)                                // flags
1042			s.AddUint16(ctxt.Arch, uint16(x.num))                    // other - index we refer to this by
1043			s.AddUint32(ctxt.Arch, uint32(dynstr.Addstring(x.vers))) // version string offset
1044			if x.next != nil {
1045				s.AddUint32(ctxt.Arch, 16) // offset from this aux to next
1046			} else {
1047				s.AddUint32(ctxt.Arch, 0)
1048			}
1049		}
1050	}
1051
1052	// version references
1053	gnuVersion := ldr.CreateSymForUpdate(".gnu.version", 0)
1054	s = gnuVersion
1055
1056	for i := 0; i < nsym; i++ {
1057		if i == 0 {
1058			s.AddUint16(ctxt.Arch, 0) // first entry - no symbol
1059		} else if need[i] == nil {
1060			s.AddUint16(ctxt.Arch, 1) // global
1061		} else {
1062			s.AddUint16(ctxt.Arch, uint16(need[i].num))
1063		}
1064	}
1065
1066	s = ldr.CreateSymForUpdate(".dynamic", 0)
1067
1068	var dtFlags1 elf.DynFlag1
1069	if *flagBindNow {
1070		dtFlags1 |= elf.DF_1_NOW
1071		Elfwritedynent(ctxt.Arch, s, elf.DT_FLAGS, uint64(elf.DF_BIND_NOW))
1072	}
1073	if ctxt.BuildMode == BuildModePIE {
1074		dtFlags1 |= elf.DF_1_PIE
1075	}
1076	Elfwritedynent(ctxt.Arch, s, elf.DT_FLAGS_1, uint64(dtFlags1))
1077
1078	elfverneed = nfile
1079	if elfverneed != 0 {
1080		elfWriteDynEntSym(ctxt, s, elf.DT_VERNEED, gnuVersionR.Sym())
1081		Elfwritedynent(ctxt.Arch, s, elf.DT_VERNEEDNUM, uint64(nfile))
1082		elfWriteDynEntSym(ctxt, s, elf.DT_VERSYM, gnuVersion.Sym())
1083	}
1084
1085	sy := ldr.CreateSymForUpdate(elfRelType+".plt", 0)
1086	if sy.Size() > 0 {
1087		if elfRelType == ".rela" {
1088			Elfwritedynent(ctxt.Arch, s, elf.DT_PLTREL, uint64(elf.DT_RELA))
1089		} else {
1090			Elfwritedynent(ctxt.Arch, s, elf.DT_PLTREL, uint64(elf.DT_REL))
1091		}
1092		elfwritedynentsymsize(ctxt, s, elf.DT_PLTRELSZ, sy.Sym())
1093		elfWriteDynEntSym(ctxt, s, elf.DT_JMPREL, sy.Sym())
1094	}
1095
1096	Elfwritedynent(ctxt.Arch, s, elf.DT_NULL, 0)
1097}
1098
1099func elfphload(seg *sym.Segment) *ElfPhdr {
1100	ph := newElfPhdr()
1101	ph.Type = elf.PT_LOAD
1102	if seg.Rwx&4 != 0 {
1103		ph.Flags |= elf.PF_R
1104	}
1105	if seg.Rwx&2 != 0 {
1106		ph.Flags |= elf.PF_W
1107	}
1108	if seg.Rwx&1 != 0 {
1109		ph.Flags |= elf.PF_X
1110	}
1111	ph.Vaddr = seg.Vaddr
1112	ph.Paddr = seg.Vaddr
1113	ph.Memsz = seg.Length
1114	ph.Off = seg.Fileoff
1115	ph.Filesz = seg.Filelen
1116	ph.Align = uint64(*FlagRound)
1117
1118	return ph
1119}
1120
1121func elfphrelro(seg *sym.Segment) {
1122	ph := newElfPhdr()
1123	ph.Type = elf.PT_GNU_RELRO
1124	ph.Flags = elf.PF_R
1125	ph.Vaddr = seg.Vaddr
1126	ph.Paddr = seg.Vaddr
1127	ph.Memsz = seg.Length
1128	ph.Off = seg.Fileoff
1129	ph.Filesz = seg.Filelen
1130	ph.Align = uint64(*FlagRound)
1131}
1132
1133func elfshname(name string) *ElfShdr {
1134	for i := 0; i < nelfstr; i++ {
1135		if name != elfstr[i].s {
1136			continue
1137		}
1138		off := elfstr[i].off
1139		for i = 0; i < int(ehdr.Shnum); i++ {
1140			sh := shdr[i]
1141			if sh.Name == uint32(off) {
1142				return sh
1143			}
1144		}
1145		return newElfShdr(int64(off))
1146	}
1147	Exitf("cannot find elf name %s", name)
1148	return nil
1149}
1150
1151// Create an ElfShdr for the section with name.
1152// Create a duplicate if one already exists with that name.
1153func elfshnamedup(name string) *ElfShdr {
1154	for i := 0; i < nelfstr; i++ {
1155		if name == elfstr[i].s {
1156			off := elfstr[i].off
1157			return newElfShdr(int64(off))
1158		}
1159	}
1160
1161	Errorf(nil, "cannot find elf name %s", name)
1162	errorexit()
1163	return nil
1164}
1165
1166func elfshalloc(sect *sym.Section) *ElfShdr {
1167	sh := elfshname(sect.Name)
1168	sect.Elfsect = sh
1169	return sh
1170}
1171
1172func elfshbits(linkmode LinkMode, sect *sym.Section) *ElfShdr {
1173	var sh *ElfShdr
1174
1175	if sect.Name == ".text" {
1176		if sect.Elfsect == nil {
1177			sect.Elfsect = elfshnamedup(sect.Name)
1178		}
1179		sh = sect.Elfsect.(*ElfShdr)
1180	} else {
1181		sh = elfshalloc(sect)
1182	}
1183
1184	// If this section has already been set up as a note, we assume type_ and
1185	// flags are already correct, but the other fields still need filling in.
1186	if sh.Type == uint32(elf.SHT_NOTE) {
1187		if linkmode != LinkExternal {
1188			// TODO(mwhudson): the approach here will work OK when
1189			// linking internally for notes that we want to be included
1190			// in a loadable segment (e.g. the abihash note) but not for
1191			// notes that we do not want to be mapped (e.g. the package
1192			// list note). The real fix is probably to define new values
1193			// for Symbol.Type corresponding to mapped and unmapped notes
1194			// and handle them in dodata().
1195			Errorf(nil, "sh.Type == SHT_NOTE in elfshbits when linking internally")
1196		}
1197		sh.Addralign = uint64(sect.Align)
1198		sh.Size = sect.Length
1199		sh.Off = sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr
1200		return sh
1201	}
1202	if sh.Type > 0 {
1203		return sh
1204	}
1205
1206	if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
1207		switch sect.Name {
1208		case ".init_array":
1209			sh.Type = uint32(elf.SHT_INIT_ARRAY)
1210		default:
1211			sh.Type = uint32(elf.SHT_PROGBITS)
1212		}
1213	} else {
1214		sh.Type = uint32(elf.SHT_NOBITS)
1215	}
1216	sh.Flags = uint64(elf.SHF_ALLOC)
1217	if sect.Rwx&1 != 0 {
1218		sh.Flags |= uint64(elf.SHF_EXECINSTR)
1219	}
1220	if sect.Rwx&2 != 0 {
1221		sh.Flags |= uint64(elf.SHF_WRITE)
1222	}
1223	if sect.Name == ".tbss" {
1224		sh.Flags |= uint64(elf.SHF_TLS)
1225		sh.Type = uint32(elf.SHT_NOBITS)
1226	}
1227	if linkmode != LinkExternal {
1228		sh.Addr = sect.Vaddr
1229	}
1230
1231	if strings.HasPrefix(sect.Name, ".debug") || strings.HasPrefix(sect.Name, ".zdebug") {
1232		sh.Flags = 0
1233		sh.Addr = 0
1234		if sect.Compressed {
1235			sh.Flags |= uint64(elf.SHF_COMPRESSED)
1236		}
1237	}
1238
1239	sh.Addralign = uint64(sect.Align)
1240	sh.Size = sect.Length
1241	if sect.Name != ".tbss" {
1242		sh.Off = sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr
1243	}
1244
1245	return sh
1246}
1247
1248func elfshreloc(arch *sys.Arch, sect *sym.Section) *ElfShdr {
1249	// If main section is SHT_NOBITS, nothing to relocate.
1250	// Also nothing to relocate in .shstrtab or notes.
1251	if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
1252		return nil
1253	}
1254	if sect.Name == ".shstrtab" || sect.Name == ".tbss" {
1255		return nil
1256	}
1257	if sect.Elfsect.(*ElfShdr).Type == uint32(elf.SHT_NOTE) {
1258		return nil
1259	}
1260
1261	typ := elf.SHT_REL
1262	if elfRelType == ".rela" {
1263		typ = elf.SHT_RELA
1264	}
1265
1266	sh := elfshname(elfRelType + sect.Name)
1267	// There could be multiple text sections but each needs
1268	// its own .rela.text.
1269
1270	if sect.Name == ".text" {
1271		if sh.Info != 0 && sh.Info != uint32(sect.Elfsect.(*ElfShdr).shnum) {
1272			sh = elfshnamedup(elfRelType + sect.Name)
1273		}
1274	}
1275
1276	sh.Type = uint32(typ)
1277	sh.Entsize = uint64(arch.RegSize) * 2
1278	if typ == elf.SHT_RELA {
1279		sh.Entsize += uint64(arch.RegSize)
1280	}
1281	sh.Link = uint32(elfshname(".symtab").shnum)
1282	sh.Info = uint32(sect.Elfsect.(*ElfShdr).shnum)
1283	sh.Off = sect.Reloff
1284	sh.Size = sect.Rellen
1285	sh.Addralign = uint64(arch.RegSize)
1286	return sh
1287}
1288
1289func elfrelocsect(ctxt *Link, out *OutBuf, sect *sym.Section, syms []loader.Sym) {
1290	// If main section is SHT_NOBITS, nothing to relocate.
1291	// Also nothing to relocate in .shstrtab.
1292	if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
1293		return
1294	}
1295	if sect.Name == ".shstrtab" {
1296		return
1297	}
1298
1299	ldr := ctxt.loader
1300	for i, s := range syms {
1301		if !ldr.AttrReachable(s) {
1302			panic("should never happen")
1303		}
1304		if uint64(ldr.SymValue(s)) >= sect.Vaddr {
1305			syms = syms[i:]
1306			break
1307		}
1308	}
1309
1310	eaddr := sect.Vaddr + sect.Length
1311	for _, s := range syms {
1312		if !ldr.AttrReachable(s) {
1313			continue
1314		}
1315		if ldr.SymValue(s) >= int64(eaddr) {
1316			break
1317		}
1318
1319		// Compute external relocations on the go, and pass to
1320		// ELF.Reloc1 to stream out.
1321		relocs := ldr.Relocs(s)
1322		for ri := 0; ri < relocs.Count(); ri++ {
1323			r := relocs.At(ri)
1324			rr, ok := extreloc(ctxt, ldr, s, r)
1325			if !ok {
1326				continue
1327			}
1328			if rr.Xsym == 0 {
1329				ldr.Errorf(s, "missing xsym in relocation")
1330				continue
1331			}
1332			esr := ElfSymForReloc(ctxt, rr.Xsym)
1333			if esr == 0 {
1334				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())
1335			}
1336			if !ldr.AttrReachable(rr.Xsym) {
1337				ldr.Errorf(s, "unreachable reloc %d (%s) target %v", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.SymName(rr.Xsym))
1338			}
1339			if !thearch.ELF.Reloc1(ctxt, out, ldr, s, rr, ri, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-sect.Vaddr)) {
1340				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()))
1341			}
1342		}
1343	}
1344
1345	// sanity check
1346	if uint64(out.Offset()) != sect.Reloff+sect.Rellen {
1347		panic(fmt.Sprintf("elfrelocsect: size mismatch %d != %d + %d", out.Offset(), sect.Reloff, sect.Rellen))
1348	}
1349}
1350
1351func elfEmitReloc(ctxt *Link) {
1352	for ctxt.Out.Offset()&7 != 0 {
1353		ctxt.Out.Write8(0)
1354	}
1355
1356	sizeExtRelocs(ctxt, thearch.ELF.RelocSize)
1357	relocSect, wg := relocSectFn(ctxt, elfrelocsect)
1358
1359	for _, sect := range Segtext.Sections {
1360		if sect.Name == ".text" {
1361			relocSect(ctxt, sect, ctxt.Textp)
1362		} else {
1363			relocSect(ctxt, sect, ctxt.datap)
1364		}
1365	}
1366
1367	for _, sect := range Segrodata.Sections {
1368		relocSect(ctxt, sect, ctxt.datap)
1369	}
1370	for _, sect := range Segrelrodata.Sections {
1371		relocSect(ctxt, sect, ctxt.datap)
1372	}
1373	for _, sect := range Segdata.Sections {
1374		relocSect(ctxt, sect, ctxt.datap)
1375	}
1376	for i := 0; i < len(Segdwarf.Sections); i++ {
1377		sect := Segdwarf.Sections[i]
1378		si := dwarfp[i]
1379		if si.secSym() != loader.Sym(sect.Sym) ||
1380			ctxt.loader.SymSect(si.secSym()) != sect {
1381			panic("inconsistency between dwarfp and Segdwarf")
1382		}
1383		relocSect(ctxt, sect, si.syms)
1384	}
1385	wg.Wait()
1386}
1387
1388func addgonote(ctxt *Link, sectionName string, tag uint32, desc []byte) {
1389	ldr := ctxt.loader
1390	s := ldr.CreateSymForUpdate(sectionName, 0)
1391	s.SetType(sym.SELFROSECT)
1392	// namesz
1393	s.AddUint32(ctxt.Arch, uint32(len(ELF_NOTE_GO_NAME)))
1394	// descsz
1395	s.AddUint32(ctxt.Arch, uint32(len(desc)))
1396	// tag
1397	s.AddUint32(ctxt.Arch, tag)
1398	// name + padding
1399	s.AddBytes(ELF_NOTE_GO_NAME)
1400	for len(s.Data())%4 != 0 {
1401		s.AddUint8(0)
1402	}
1403	// desc + padding
1404	s.AddBytes(desc)
1405	for len(s.Data())%4 != 0 {
1406		s.AddUint8(0)
1407	}
1408	s.SetSize(int64(len(s.Data())))
1409	s.SetAlign(4)
1410}
1411
1412func (ctxt *Link) doelf() {
1413	ldr := ctxt.loader
1414
1415	/* predefine strings we need for section headers */
1416
1417	addshstr := func(s string) int {
1418		off := len(elfshstrdat)
1419		elfshstrdat = append(elfshstrdat, s...)
1420		elfshstrdat = append(elfshstrdat, 0)
1421		return off
1422	}
1423
1424	shstrtabAddstring := func(s string) {
1425		off := addshstr(s)
1426		elfsetstring(ctxt, 0, s, int(off))
1427	}
1428
1429	shstrtabAddstring("")
1430	shstrtabAddstring(".text")
1431	shstrtabAddstring(".noptrdata")
1432	shstrtabAddstring(".data")
1433	shstrtabAddstring(".bss")
1434	shstrtabAddstring(".noptrbss")
1435	shstrtabAddstring(".go.fuzzcntrs")
1436	shstrtabAddstring(".go.buildinfo")
1437	if ctxt.IsMIPS() {
1438		shstrtabAddstring(".MIPS.abiflags")
1439		shstrtabAddstring(".gnu.attributes")
1440	}
1441
1442	// generate .tbss section for dynamic internal linker or external
1443	// linking, so that various binutils could correctly calculate
1444	// PT_TLS size. See https://golang.org/issue/5200.
1445	if !*FlagD || ctxt.IsExternal() {
1446		shstrtabAddstring(".tbss")
1447	}
1448	if ctxt.IsNetbsd() {
1449		shstrtabAddstring(".note.netbsd.ident")
1450		if *flagRace {
1451			shstrtabAddstring(".note.netbsd.pax")
1452		}
1453	}
1454	if ctxt.IsOpenbsd() {
1455		shstrtabAddstring(".note.openbsd.ident")
1456	}
1457	if ctxt.IsFreebsd() {
1458		shstrtabAddstring(".note.tag")
1459	}
1460	if len(buildinfo) > 0 {
1461		shstrtabAddstring(".note.gnu.build-id")
1462	}
1463	if *flagBuildid != "" {
1464		shstrtabAddstring(".note.go.buildid")
1465	}
1466	shstrtabAddstring(".elfdata")
1467	shstrtabAddstring(".rodata")
1468	// See the comment about data.rel.ro.FOO section names in data.go.
1469	relro_prefix := ""
1470	if ctxt.UseRelro() {
1471		shstrtabAddstring(".data.rel.ro")
1472		relro_prefix = ".data.rel.ro"
1473	}
1474	shstrtabAddstring(relro_prefix + ".typelink")
1475	shstrtabAddstring(relro_prefix + ".itablink")
1476	shstrtabAddstring(relro_prefix + ".gosymtab")
1477	shstrtabAddstring(relro_prefix + ".gopclntab")
1478
1479	if ctxt.IsExternal() {
1480		*FlagD = true
1481
1482		shstrtabAddstring(elfRelType + ".text")
1483		shstrtabAddstring(elfRelType + ".rodata")
1484		shstrtabAddstring(elfRelType + relro_prefix + ".typelink")
1485		shstrtabAddstring(elfRelType + relro_prefix + ".itablink")
1486		shstrtabAddstring(elfRelType + relro_prefix + ".gosymtab")
1487		shstrtabAddstring(elfRelType + relro_prefix + ".gopclntab")
1488		shstrtabAddstring(elfRelType + ".noptrdata")
1489		shstrtabAddstring(elfRelType + ".data")
1490		if ctxt.UseRelro() {
1491			shstrtabAddstring(elfRelType + ".data.rel.ro")
1492		}
1493		shstrtabAddstring(elfRelType + ".go.buildinfo")
1494		if ctxt.IsMIPS() {
1495			shstrtabAddstring(elfRelType + ".MIPS.abiflags")
1496			shstrtabAddstring(elfRelType + ".gnu.attributes")
1497		}
1498
1499		// add a .note.GNU-stack section to mark the stack as non-executable
1500		shstrtabAddstring(".note.GNU-stack")
1501
1502		if ctxt.IsShared() {
1503			shstrtabAddstring(".note.go.abihash")
1504			shstrtabAddstring(".note.go.pkg-list")
1505			shstrtabAddstring(".note.go.deps")
1506		}
1507	}
1508
1509	hasinitarr := ctxt.linkShared
1510
1511	/* shared library initializer */
1512	switch ctxt.BuildMode {
1513	case BuildModeCArchive, BuildModeCShared, BuildModeShared, BuildModePlugin:
1514		hasinitarr = true
1515	}
1516
1517	if hasinitarr {
1518		shstrtabAddstring(".init_array")
1519		shstrtabAddstring(elfRelType + ".init_array")
1520	}
1521
1522	if !*FlagS {
1523		shstrtabAddstring(".symtab")
1524		shstrtabAddstring(".strtab")
1525	}
1526	if !*FlagW {
1527		dwarfaddshstrings(ctxt, shstrtabAddstring)
1528	}
1529
1530	shstrtabAddstring(".shstrtab")
1531
1532	if !*FlagD { /* -d suppresses dynamic loader format */
1533		shstrtabAddstring(".interp")
1534		shstrtabAddstring(".hash")
1535		shstrtabAddstring(".got")
1536		if ctxt.IsPPC64() {
1537			shstrtabAddstring(".glink")
1538		}
1539		shstrtabAddstring(".got.plt")
1540		shstrtabAddstring(".dynamic")
1541		shstrtabAddstring(".dynsym")
1542		shstrtabAddstring(".dynstr")
1543		shstrtabAddstring(elfRelType)
1544		shstrtabAddstring(elfRelType + ".plt")
1545
1546		shstrtabAddstring(".plt")
1547		shstrtabAddstring(".gnu.version")
1548		shstrtabAddstring(".gnu.version_r")
1549
1550		/* dynamic symbol table - first entry all zeros */
1551		dynsym := ldr.CreateSymForUpdate(".dynsym", 0)
1552
1553		dynsym.SetType(sym.SELFROSECT)
1554		if elf64 {
1555			dynsym.SetSize(dynsym.Size() + ELF64SYMSIZE)
1556		} else {
1557			dynsym.SetSize(dynsym.Size() + ELF32SYMSIZE)
1558		}
1559
1560		/* dynamic string table */
1561		dynstr := ldr.CreateSymForUpdate(".dynstr", 0)
1562
1563		dynstr.SetType(sym.SELFROSECT)
1564		if dynstr.Size() == 0 {
1565			dynstr.Addstring("")
1566		}
1567
1568		/* relocation table */
1569		s := ldr.CreateSymForUpdate(elfRelType, 0)
1570		s.SetType(sym.SELFROSECT)
1571
1572		/* global offset table */
1573		got := ldr.CreateSymForUpdate(".got", 0)
1574		if ctxt.UseRelro() {
1575			got.SetType(sym.SELFRELROSECT)
1576		} else {
1577			got.SetType(sym.SELFGOT) // writable
1578		}
1579
1580		/* ppc64 glink resolver */
1581		if ctxt.IsPPC64() {
1582			s := ldr.CreateSymForUpdate(".glink", 0)
1583			s.SetType(sym.SELFRXSECT)
1584		}
1585
1586		/* hash */
1587		hash := ldr.CreateSymForUpdate(".hash", 0)
1588		hash.SetType(sym.SELFROSECT)
1589
1590		gotplt := ldr.CreateSymForUpdate(".got.plt", 0)
1591		if ctxt.UseRelro() && *flagBindNow {
1592			gotplt.SetType(sym.SELFRELROSECT)
1593		} else {
1594			gotplt.SetType(sym.SELFSECT) // writable
1595		}
1596
1597		plt := ldr.CreateSymForUpdate(".plt", 0)
1598		if ctxt.IsPPC64() {
1599			// In the ppc64 ABI, .plt is a data section
1600			// written by the dynamic linker.
1601			plt.SetType(sym.SELFSECT)
1602		} else {
1603			plt.SetType(sym.SELFRXSECT)
1604		}
1605
1606		s = ldr.CreateSymForUpdate(elfRelType+".plt", 0)
1607		s.SetType(sym.SELFROSECT)
1608
1609		s = ldr.CreateSymForUpdate(".gnu.version", 0)
1610		s.SetType(sym.SELFROSECT)
1611
1612		s = ldr.CreateSymForUpdate(".gnu.version_r", 0)
1613		s.SetType(sym.SELFROSECT)
1614
1615		/* define dynamic elf table */
1616		dynamic := ldr.CreateSymForUpdate(".dynamic", 0)
1617		switch {
1618		case thearch.ELF.DynamicReadOnly:
1619			dynamic.SetType(sym.SELFROSECT)
1620		case ctxt.UseRelro():
1621			dynamic.SetType(sym.SELFRELROSECT)
1622		default:
1623			dynamic.SetType(sym.SELFSECT)
1624		}
1625
1626		if ctxt.IsS390X() {
1627			// S390X uses .got instead of .got.plt
1628			gotplt = got
1629		}
1630		thearch.ELF.SetupPLT(ctxt, ctxt.loader, plt, gotplt, dynamic.Sym())
1631
1632		/*
1633		 * .dynamic table
1634		 */
1635		elfWriteDynEntSym(ctxt, dynamic, elf.DT_HASH, hash.Sym())
1636
1637		elfWriteDynEntSym(ctxt, dynamic, elf.DT_SYMTAB, dynsym.Sym())
1638		if elf64 {
1639			Elfwritedynent(ctxt.Arch, dynamic, elf.DT_SYMENT, ELF64SYMSIZE)
1640		} else {
1641			Elfwritedynent(ctxt.Arch, dynamic, elf.DT_SYMENT, ELF32SYMSIZE)
1642		}
1643		elfWriteDynEntSym(ctxt, dynamic, elf.DT_STRTAB, dynstr.Sym())
1644		elfwritedynentsymsize(ctxt, dynamic, elf.DT_STRSZ, dynstr.Sym())
1645		if elfRelType == ".rela" {
1646			rela := ldr.LookupOrCreateSym(".rela", 0)
1647			elfWriteDynEntSym(ctxt, dynamic, elf.DT_RELA, rela)
1648			elfwritedynentsymsize(ctxt, dynamic, elf.DT_RELASZ, rela)
1649			Elfwritedynent(ctxt.Arch, dynamic, elf.DT_RELAENT, ELF64RELASIZE)
1650		} else {
1651			rel := ldr.LookupOrCreateSym(".rel", 0)
1652			elfWriteDynEntSym(ctxt, dynamic, elf.DT_REL, rel)
1653			elfwritedynentsymsize(ctxt, dynamic, elf.DT_RELSZ, rel)
1654			Elfwritedynent(ctxt.Arch, dynamic, elf.DT_RELENT, ELF32RELSIZE)
1655		}
1656
1657		if rpath.val != "" {
1658			Elfwritedynent(ctxt.Arch, dynamic, elf.DT_RUNPATH, uint64(dynstr.Addstring(rpath.val)))
1659		}
1660
1661		if ctxt.IsPPC64() {
1662			elfWriteDynEntSym(ctxt, dynamic, elf.DT_PLTGOT, plt.Sym())
1663		} else {
1664			elfWriteDynEntSym(ctxt, dynamic, elf.DT_PLTGOT, gotplt.Sym())
1665		}
1666
1667		if ctxt.IsPPC64() {
1668			Elfwritedynent(ctxt.Arch, dynamic, elf.DT_PPC64_OPT, 0)
1669		}
1670
1671		// Solaris dynamic linker can't handle an empty .rela.plt if
1672		// DT_JMPREL is emitted so we have to defer generation of elf.DT_PLTREL,
1673		// DT_PLTRELSZ, and elf.DT_JMPREL dynamic entries until after we know the
1674		// size of .rel(a).plt section.
1675
1676		Elfwritedynent(ctxt.Arch, dynamic, elf.DT_DEBUG, 0)
1677	}
1678
1679	if ctxt.IsShared() {
1680		// The go.link.abihashbytes symbol will be pointed at the appropriate
1681		// part of the .note.go.abihash section in data.go:func address().
1682		s := ldr.LookupOrCreateSym("go:link.abihashbytes", 0)
1683		sb := ldr.MakeSymbolUpdater(s)
1684		ldr.SetAttrLocal(s, true)
1685		sb.SetType(sym.SRODATA)
1686		ldr.SetAttrSpecial(s, true)
1687		sb.SetReachable(true)
1688		sb.SetSize(notsha256.Size)
1689
1690		sort.Sort(byPkg(ctxt.Library))
1691		h := notsha256.New()
1692		for _, l := range ctxt.Library {
1693			h.Write(l.Fingerprint[:])
1694		}
1695		addgonote(ctxt, ".note.go.abihash", ELF_NOTE_GOABIHASH_TAG, h.Sum([]byte{}))
1696		addgonote(ctxt, ".note.go.pkg-list", ELF_NOTE_GOPKGLIST_TAG, pkglistfornote)
1697		var deplist []string
1698		for _, shlib := range ctxt.Shlibs {
1699			deplist = append(deplist, filepath.Base(shlib.Path))
1700		}
1701		addgonote(ctxt, ".note.go.deps", ELF_NOTE_GODEPS_TAG, []byte(strings.Join(deplist, "\n")))
1702	}
1703
1704	if ctxt.LinkMode == LinkExternal && *flagBuildid != "" {
1705		addgonote(ctxt, ".note.go.buildid", ELF_NOTE_GOBUILDID_TAG, []byte(*flagBuildid))
1706	}
1707
1708	//type mipsGnuAttributes struct {
1709	//	version uint8   // 'A'
1710	//	length  uint32  // 15 including itself
1711	//	gnu     [4]byte // "gnu\0"
1712	//	tag     uint8   // 1:file, 2: section, 3: symbol, 1 here
1713	//	taglen  uint32  // tag length, including tag, 7 here
1714	//	tagfp   uint8   // 4
1715	//	fpAbi  uint8    // see .MIPS.abiflags
1716	//}
1717	if ctxt.IsMIPS() {
1718		gnuattributes := ldr.CreateSymForUpdate(".gnu.attributes", 0)
1719		gnuattributes.SetType(sym.SELFROSECT)
1720		gnuattributes.SetReachable(true)
1721		gnuattributes.AddUint8('A')               // version 'A'
1722		gnuattributes.AddUint32(ctxt.Arch, 15)    // length 15 including itself
1723		gnuattributes.AddBytes([]byte("gnu\x00")) // "gnu\0"
1724		gnuattributes.AddUint8(1)                 // 1:file, 2: section, 3: symbol, 1 here
1725		gnuattributes.AddUint32(ctxt.Arch, 7)     // tag length, including tag, 7 here
1726		gnuattributes.AddUint8(4)                 // 4 for FP, 8 for MSA
1727		if buildcfg.GOMIPS == "softfloat" {
1728			gnuattributes.AddUint8(MIPS_FPABI_SOFT)
1729		} else {
1730			// Note: MIPS_FPABI_ANY is bad naming: in fact it is MIPS I style FPR usage.
1731			//       It is not for 'ANY'.
1732			// TODO: switch to FPXX after be sure that no odd-number-fpr is used.
1733			gnuattributes.AddUint8(MIPS_FPABI_ANY)
1734		}
1735	}
1736}
1737
1738// Do not write DT_NULL.  elfdynhash will finish it.
1739func shsym(sh *ElfShdr, ldr *loader.Loader, s loader.Sym) {
1740	if s == 0 {
1741		panic("bad symbol in shsym2")
1742	}
1743	addr := ldr.SymValue(s)
1744	if sh.Flags&uint64(elf.SHF_ALLOC) != 0 {
1745		sh.Addr = uint64(addr)
1746	}
1747	sh.Off = uint64(datoff(ldr, s, addr))
1748	sh.Size = uint64(ldr.SymSize(s))
1749}
1750
1751func phsh(ph *ElfPhdr, sh *ElfShdr) {
1752	ph.Vaddr = sh.Addr
1753	ph.Paddr = ph.Vaddr
1754	ph.Off = sh.Off
1755	ph.Filesz = sh.Size
1756	ph.Memsz = sh.Size
1757	ph.Align = sh.Addralign
1758}
1759
1760func Asmbelfsetup() {
1761	/* This null SHdr must appear before all others */
1762	elfshname("")
1763
1764	for _, sect := range Segtext.Sections {
1765		// There could be multiple .text sections. Instead check the Elfsect
1766		// field to determine if already has an ElfShdr and if not, create one.
1767		if sect.Name == ".text" {
1768			if sect.Elfsect == nil {
1769				sect.Elfsect = elfshnamedup(sect.Name)
1770			}
1771		} else {
1772			elfshalloc(sect)
1773		}
1774	}
1775	for _, sect := range Segrodata.Sections {
1776		elfshalloc(sect)
1777	}
1778	for _, sect := range Segrelrodata.Sections {
1779		elfshalloc(sect)
1780	}
1781	for _, sect := range Segdata.Sections {
1782		elfshalloc(sect)
1783	}
1784	for _, sect := range Segdwarf.Sections {
1785		elfshalloc(sect)
1786	}
1787}
1788
1789func asmbElf(ctxt *Link) {
1790	var symo int64
1791	symo = int64(Segdwarf.Fileoff + Segdwarf.Filelen)
1792	symo = Rnd(symo, int64(ctxt.Arch.PtrSize))
1793	ctxt.Out.SeekSet(symo)
1794	if *FlagS {
1795		ctxt.Out.Write(elfshstrdat)
1796	} else {
1797		ctxt.Out.SeekSet(symo)
1798		asmElfSym(ctxt)
1799		ctxt.Out.Write(elfstrdat)
1800		ctxt.Out.Write(elfshstrdat)
1801		if ctxt.IsExternal() {
1802			elfEmitReloc(ctxt)
1803		}
1804	}
1805	ctxt.Out.SeekSet(0)
1806
1807	ldr := ctxt.loader
1808	eh := getElfEhdr()
1809	switch ctxt.Arch.Family {
1810	default:
1811		Exitf("unknown architecture in asmbelf: %v", ctxt.Arch.Family)
1812	case sys.MIPS, sys.MIPS64:
1813		eh.Machine = uint16(elf.EM_MIPS)
1814	case sys.Loong64:
1815		eh.Machine = uint16(elf.EM_LOONGARCH)
1816	case sys.ARM:
1817		eh.Machine = uint16(elf.EM_ARM)
1818	case sys.AMD64:
1819		eh.Machine = uint16(elf.EM_X86_64)
1820	case sys.ARM64:
1821		eh.Machine = uint16(elf.EM_AARCH64)
1822	case sys.I386:
1823		eh.Machine = uint16(elf.EM_386)
1824	case sys.PPC64:
1825		eh.Machine = uint16(elf.EM_PPC64)
1826	case sys.RISCV64:
1827		eh.Machine = uint16(elf.EM_RISCV)
1828	case sys.S390X:
1829		eh.Machine = uint16(elf.EM_S390)
1830	}
1831
1832	elfreserve := int64(ELFRESERVE)
1833
1834	numtext := int64(0)
1835	for _, sect := range Segtext.Sections {
1836		if sect.Name == ".text" {
1837			numtext++
1838		}
1839	}
1840
1841	// If there are multiple text sections, extra space is needed
1842	// in the elfreserve for the additional .text and .rela.text
1843	// section headers.  It can handle 4 extra now. Headers are
1844	// 64 bytes.
1845
1846	if numtext > 4 {
1847		elfreserve += elfreserve + numtext*64*2
1848	}
1849
1850	startva := *FlagTextAddr - int64(HEADR)
1851	resoff := elfreserve
1852
1853	var pph *ElfPhdr
1854	var pnote *ElfPhdr
1855	getpnote := func() *ElfPhdr {
1856		if pnote == nil {
1857			pnote = newElfPhdr()
1858			pnote.Type = elf.PT_NOTE
1859			pnote.Flags = elf.PF_R
1860		}
1861		return pnote
1862	}
1863	if *flagRace && ctxt.IsNetbsd() {
1864		sh := elfshname(".note.netbsd.pax")
1865		resoff -= int64(elfnetbsdpax(sh, uint64(startva), uint64(resoff)))
1866		phsh(getpnote(), sh)
1867	}
1868	if ctxt.LinkMode == LinkExternal {
1869		/* skip program headers */
1870		eh.Phoff = 0
1871
1872		eh.Phentsize = 0
1873
1874		if ctxt.BuildMode == BuildModeShared {
1875			sh := elfshname(".note.go.pkg-list")
1876			sh.Type = uint32(elf.SHT_NOTE)
1877			sh = elfshname(".note.go.abihash")
1878			sh.Type = uint32(elf.SHT_NOTE)
1879			sh.Flags = uint64(elf.SHF_ALLOC)
1880			sh = elfshname(".note.go.deps")
1881			sh.Type = uint32(elf.SHT_NOTE)
1882		}
1883
1884		if *flagBuildid != "" {
1885			sh := elfshname(".note.go.buildid")
1886			sh.Type = uint32(elf.SHT_NOTE)
1887			sh.Flags = uint64(elf.SHF_ALLOC)
1888		}
1889
1890		goto elfobj
1891	}
1892
1893	/* program header info */
1894	pph = newElfPhdr()
1895
1896	pph.Type = elf.PT_PHDR
1897	pph.Flags = elf.PF_R
1898	pph.Off = uint64(eh.Ehsize)
1899	pph.Vaddr = uint64(*FlagTextAddr) - uint64(HEADR) + pph.Off
1900	pph.Paddr = uint64(*FlagTextAddr) - uint64(HEADR) + pph.Off
1901	pph.Align = uint64(*FlagRound)
1902
1903	/*
1904	 * PHDR must be in a loaded segment. Adjust the text
1905	 * segment boundaries downwards to include it.
1906	 */
1907	{
1908		o := int64(Segtext.Vaddr - pph.Vaddr)
1909		Segtext.Vaddr -= uint64(o)
1910		Segtext.Length += uint64(o)
1911		o = int64(Segtext.Fileoff - pph.Off)
1912		Segtext.Fileoff -= uint64(o)
1913		Segtext.Filelen += uint64(o)
1914	}
1915
1916	if !*FlagD { /* -d suppresses dynamic loader format */
1917		/* interpreter */
1918		sh := elfshname(".interp")
1919
1920		sh.Type = uint32(elf.SHT_PROGBITS)
1921		sh.Flags = uint64(elf.SHF_ALLOC)
1922		sh.Addralign = 1
1923
1924		if interpreter == "" && buildcfg.GOOS == runtime.GOOS && buildcfg.GOARCH == runtime.GOARCH && buildcfg.GO_LDSO != "" {
1925			interpreter = buildcfg.GO_LDSO
1926		}
1927
1928		if interpreter == "" {
1929			switch ctxt.HeadType {
1930			case objabi.Hlinux:
1931				if buildcfg.GOOS == "android" {
1932					interpreter = thearch.ELF.Androiddynld
1933					if interpreter == "" {
1934						Exitf("ELF interpreter not set")
1935					}
1936				} else {
1937					interpreter = thearch.ELF.Linuxdynld
1938					// If interpreter does not exist, try musl instead.
1939					// This lets the same cmd/link binary work on
1940					// both glibc-based and musl-based systems.
1941					if _, err := os.Stat(interpreter); err != nil {
1942						if musl := thearch.ELF.LinuxdynldMusl; musl != "" {
1943							if _, err := os.Stat(musl); err == nil {
1944								interpreter = musl
1945							}
1946						}
1947					}
1948				}
1949
1950			case objabi.Hfreebsd:
1951				interpreter = thearch.ELF.Freebsddynld
1952
1953			case objabi.Hnetbsd:
1954				interpreter = thearch.ELF.Netbsddynld
1955
1956			case objabi.Hopenbsd:
1957				interpreter = thearch.ELF.Openbsddynld
1958
1959			case objabi.Hdragonfly:
1960				interpreter = thearch.ELF.Dragonflydynld
1961
1962			case objabi.Hsolaris:
1963				interpreter = thearch.ELF.Solarisdynld
1964			}
1965		}
1966
1967		resoff -= int64(elfinterp(sh, uint64(startva), uint64(resoff), interpreter))
1968
1969		ph := newElfPhdr()
1970		ph.Type = elf.PT_INTERP
1971		ph.Flags = elf.PF_R
1972		phsh(ph, sh)
1973	}
1974
1975	if ctxt.HeadType == objabi.Hnetbsd || ctxt.HeadType == objabi.Hopenbsd || ctxt.HeadType == objabi.Hfreebsd {
1976		var sh *ElfShdr
1977		switch ctxt.HeadType {
1978		case objabi.Hnetbsd:
1979			sh = elfshname(".note.netbsd.ident")
1980			resoff -= int64(elfnetbsdsig(sh, uint64(startva), uint64(resoff)))
1981
1982		case objabi.Hopenbsd:
1983			sh = elfshname(".note.openbsd.ident")
1984			resoff -= int64(elfopenbsdsig(sh, uint64(startva), uint64(resoff)))
1985
1986		case objabi.Hfreebsd:
1987			sh = elfshname(".note.tag")
1988			resoff -= int64(elffreebsdsig(sh, uint64(startva), uint64(resoff)))
1989		}
1990		// NetBSD, OpenBSD and FreeBSD require ident in an independent segment.
1991		pnotei := newElfPhdr()
1992		pnotei.Type = elf.PT_NOTE
1993		pnotei.Flags = elf.PF_R
1994		phsh(pnotei, sh)
1995	}
1996
1997	if len(buildinfo) > 0 {
1998		sh := elfshname(".note.gnu.build-id")
1999		resoff -= int64(elfbuildinfo(sh, uint64(startva), uint64(resoff)))
2000		phsh(getpnote(), sh)
2001	}
2002
2003	if *flagBuildid != "" {
2004		sh := elfshname(".note.go.buildid")
2005		resoff -= int64(elfgobuildid(sh, uint64(startva), uint64(resoff)))
2006		phsh(getpnote(), sh)
2007	}
2008
2009	// Additions to the reserved area must be above this line.
2010
2011	elfphload(&Segtext)
2012	if len(Segrodata.Sections) > 0 {
2013		elfphload(&Segrodata)
2014	}
2015	if len(Segrelrodata.Sections) > 0 {
2016		elfphload(&Segrelrodata)
2017		elfphrelro(&Segrelrodata)
2018	}
2019	elfphload(&Segdata)
2020
2021	/* Dynamic linking sections */
2022	if !*FlagD {
2023		sh := elfshname(".dynsym")
2024		sh.Type = uint32(elf.SHT_DYNSYM)
2025		sh.Flags = uint64(elf.SHF_ALLOC)
2026		if elf64 {
2027			sh.Entsize = ELF64SYMSIZE
2028		} else {
2029			sh.Entsize = ELF32SYMSIZE
2030		}
2031		sh.Addralign = uint64(ctxt.Arch.RegSize)
2032		sh.Link = uint32(elfshname(".dynstr").shnum)
2033
2034		// sh.info is the index of first non-local symbol (number of local symbols)
2035		s := ldr.Lookup(".dynsym", 0)
2036		i := uint32(0)
2037		for sub := s; sub != 0; sub = ldr.SubSym(sub) {
2038			i++
2039			if !ldr.AttrLocal(sub) {
2040				break
2041			}
2042		}
2043		sh.Info = i
2044		shsym(sh, ldr, s)
2045
2046		sh = elfshname(".dynstr")
2047		sh.Type = uint32(elf.SHT_STRTAB)
2048		sh.Flags = uint64(elf.SHF_ALLOC)
2049		sh.Addralign = 1
2050		shsym(sh, ldr, ldr.Lookup(".dynstr", 0))
2051
2052		if elfverneed != 0 {
2053			sh := elfshname(".gnu.version")
2054			sh.Type = uint32(elf.SHT_GNU_VERSYM)
2055			sh.Flags = uint64(elf.SHF_ALLOC)
2056			sh.Addralign = 2
2057			sh.Link = uint32(elfshname(".dynsym").shnum)
2058			sh.Entsize = 2
2059			shsym(sh, ldr, ldr.Lookup(".gnu.version", 0))
2060
2061			sh = elfshname(".gnu.version_r")
2062			sh.Type = uint32(elf.SHT_GNU_VERNEED)
2063			sh.Flags = uint64(elf.SHF_ALLOC)
2064			sh.Addralign = uint64(ctxt.Arch.RegSize)
2065			sh.Info = uint32(elfverneed)
2066			sh.Link = uint32(elfshname(".dynstr").shnum)
2067			shsym(sh, ldr, ldr.Lookup(".gnu.version_r", 0))
2068		}
2069
2070		if elfRelType == ".rela" {
2071			sh := elfshname(".rela.plt")
2072			sh.Type = uint32(elf.SHT_RELA)
2073			sh.Flags = uint64(elf.SHF_ALLOC)
2074			sh.Entsize = ELF64RELASIZE
2075			sh.Addralign = uint64(ctxt.Arch.RegSize)
2076			sh.Link = uint32(elfshname(".dynsym").shnum)
2077			sh.Info = uint32(elfshname(".plt").shnum)
2078			shsym(sh, ldr, ldr.Lookup(".rela.plt", 0))
2079
2080			sh = elfshname(".rela")
2081			sh.Type = uint32(elf.SHT_RELA)
2082			sh.Flags = uint64(elf.SHF_ALLOC)
2083			sh.Entsize = ELF64RELASIZE
2084			sh.Addralign = 8
2085			sh.Link = uint32(elfshname(".dynsym").shnum)
2086			shsym(sh, ldr, ldr.Lookup(".rela", 0))
2087		} else {
2088			sh := elfshname(".rel.plt")
2089			sh.Type = uint32(elf.SHT_REL)
2090			sh.Flags = uint64(elf.SHF_ALLOC)
2091			sh.Entsize = ELF32RELSIZE
2092			sh.Addralign = 4
2093			sh.Link = uint32(elfshname(".dynsym").shnum)
2094			shsym(sh, ldr, ldr.Lookup(".rel.plt", 0))
2095
2096			sh = elfshname(".rel")
2097			sh.Type = uint32(elf.SHT_REL)
2098			sh.Flags = uint64(elf.SHF_ALLOC)
2099			sh.Entsize = ELF32RELSIZE
2100			sh.Addralign = 4
2101			sh.Link = uint32(elfshname(".dynsym").shnum)
2102			shsym(sh, ldr, ldr.Lookup(".rel", 0))
2103		}
2104
2105		if elf.Machine(eh.Machine) == elf.EM_PPC64 {
2106			sh := elfshname(".glink")
2107			sh.Type = uint32(elf.SHT_PROGBITS)
2108			sh.Flags = uint64(elf.SHF_ALLOC + elf.SHF_EXECINSTR)
2109			sh.Addralign = 4
2110			shsym(sh, ldr, ldr.Lookup(".glink", 0))
2111		}
2112
2113		sh = elfshname(".plt")
2114		sh.Type = uint32(elf.SHT_PROGBITS)
2115		sh.Flags = uint64(elf.SHF_ALLOC + elf.SHF_EXECINSTR)
2116		if elf.Machine(eh.Machine) == elf.EM_X86_64 {
2117			sh.Entsize = 16
2118		} else if elf.Machine(eh.Machine) == elf.EM_S390 {
2119			sh.Entsize = 32
2120		} else if elf.Machine(eh.Machine) == elf.EM_PPC64 {
2121			// On ppc64, this is just a table of addresses
2122			// filled by the dynamic linker
2123			sh.Type = uint32(elf.SHT_NOBITS)
2124
2125			sh.Flags = uint64(elf.SHF_ALLOC + elf.SHF_WRITE)
2126			sh.Entsize = 8
2127		} else {
2128			sh.Entsize = 4
2129		}
2130		sh.Addralign = sh.Entsize
2131		shsym(sh, ldr, ldr.Lookup(".plt", 0))
2132
2133		// On ppc64, .got comes from the input files, so don't
2134		// create it here, and .got.plt is not used.
2135		if elf.Machine(eh.Machine) != elf.EM_PPC64 {
2136			sh := elfshname(".got")
2137			sh.Type = uint32(elf.SHT_PROGBITS)
2138			sh.Flags = uint64(elf.SHF_ALLOC + elf.SHF_WRITE)
2139			sh.Entsize = uint64(ctxt.Arch.RegSize)
2140			sh.Addralign = uint64(ctxt.Arch.RegSize)
2141			shsym(sh, ldr, ldr.Lookup(".got", 0))
2142
2143			sh = elfshname(".got.plt")
2144			sh.Type = uint32(elf.SHT_PROGBITS)
2145			sh.Flags = uint64(elf.SHF_ALLOC + elf.SHF_WRITE)
2146			sh.Entsize = uint64(ctxt.Arch.RegSize)
2147			sh.Addralign = uint64(ctxt.Arch.RegSize)
2148			shsym(sh, ldr, ldr.Lookup(".got.plt", 0))
2149		}
2150
2151		sh = elfshname(".hash")
2152		sh.Type = uint32(elf.SHT_HASH)
2153		sh.Flags = uint64(elf.SHF_ALLOC)
2154		sh.Entsize = 4
2155		sh.Addralign = uint64(ctxt.Arch.RegSize)
2156		sh.Link = uint32(elfshname(".dynsym").shnum)
2157		shsym(sh, ldr, ldr.Lookup(".hash", 0))
2158
2159		/* sh and elf.PT_DYNAMIC for .dynamic section */
2160		sh = elfshname(".dynamic")
2161
2162		sh.Type = uint32(elf.SHT_DYNAMIC)
2163		sh.Flags = uint64(elf.SHF_ALLOC + elf.SHF_WRITE)
2164		sh.Entsize = 2 * uint64(ctxt.Arch.RegSize)
2165		sh.Addralign = uint64(ctxt.Arch.RegSize)
2166		sh.Link = uint32(elfshname(".dynstr").shnum)
2167		shsym(sh, ldr, ldr.Lookup(".dynamic", 0))
2168		ph := newElfPhdr()
2169		ph.Type = elf.PT_DYNAMIC
2170		ph.Flags = elf.PF_R + elf.PF_W
2171		phsh(ph, sh)
2172
2173		/*
2174		 * Thread-local storage segment (really just size).
2175		 */
2176		tlssize := uint64(0)
2177		for _, sect := range Segdata.Sections {
2178			if sect.Name == ".tbss" {
2179				tlssize = sect.Length
2180			}
2181		}
2182		if tlssize != 0 {
2183			ph := newElfPhdr()
2184			ph.Type = elf.PT_TLS
2185			ph.Flags = elf.PF_R
2186			ph.Memsz = tlssize
2187			ph.Align = uint64(ctxt.Arch.RegSize)
2188		}
2189	}
2190
2191	if ctxt.HeadType == objabi.Hlinux || ctxt.HeadType == objabi.Hfreebsd {
2192		ph := newElfPhdr()
2193		ph.Type = elf.PT_GNU_STACK
2194		ph.Flags = elf.PF_W + elf.PF_R
2195		ph.Align = uint64(ctxt.Arch.RegSize)
2196	} else if ctxt.HeadType == objabi.Hopenbsd {
2197		ph := newElfPhdr()
2198		ph.Type = elf.PT_OPENBSD_NOBTCFI
2199		ph.Flags = elf.PF_X
2200	} else if ctxt.HeadType == objabi.Hsolaris {
2201		ph := newElfPhdr()
2202		ph.Type = elf.PT_SUNWSTACK
2203		ph.Flags = elf.PF_W + elf.PF_R
2204	}
2205
2206elfobj:
2207	sh := elfshname(".shstrtab")
2208	eh.Shstrndx = uint16(sh.shnum)
2209
2210	if ctxt.IsMIPS() {
2211		sh = elfshname(".MIPS.abiflags")
2212		sh.Type = uint32(elf.SHT_MIPS_ABIFLAGS)
2213		sh.Flags = uint64(elf.SHF_ALLOC)
2214		sh.Addralign = 8
2215		resoff -= int64(elfMipsAbiFlags(sh, uint64(startva), uint64(resoff)))
2216
2217		ph := newElfPhdr()
2218		ph.Type = elf.PT_MIPS_ABIFLAGS
2219		ph.Flags = elf.PF_R
2220		phsh(ph, sh)
2221
2222		sh = elfshname(".gnu.attributes")
2223		sh.Type = uint32(elf.SHT_GNU_ATTRIBUTES)
2224		sh.Addralign = 1
2225		ldr := ctxt.loader
2226		shsym(sh, ldr, ldr.Lookup(".gnu.attributes", 0))
2227	}
2228
2229	// put these sections early in the list
2230	if !*FlagS {
2231		elfshname(".symtab")
2232		elfshname(".strtab")
2233	}
2234	elfshname(".shstrtab")
2235
2236	for _, sect := range Segtext.Sections {
2237		elfshbits(ctxt.LinkMode, sect)
2238	}
2239	for _, sect := range Segrodata.Sections {
2240		elfshbits(ctxt.LinkMode, sect)
2241	}
2242	for _, sect := range Segrelrodata.Sections {
2243		elfshbits(ctxt.LinkMode, sect)
2244	}
2245	for _, sect := range Segdata.Sections {
2246		elfshbits(ctxt.LinkMode, sect)
2247	}
2248	for _, sect := range Segdwarf.Sections {
2249		elfshbits(ctxt.LinkMode, sect)
2250	}
2251
2252	if ctxt.LinkMode == LinkExternal {
2253		for _, sect := range Segtext.Sections {
2254			elfshreloc(ctxt.Arch, sect)
2255		}
2256		for _, sect := range Segrodata.Sections {
2257			elfshreloc(ctxt.Arch, sect)
2258		}
2259		for _, sect := range Segrelrodata.Sections {
2260			elfshreloc(ctxt.Arch, sect)
2261		}
2262		for _, sect := range Segdata.Sections {
2263			elfshreloc(ctxt.Arch, sect)
2264		}
2265		for _, si := range dwarfp {
2266			sect := ldr.SymSect(si.secSym())
2267			elfshreloc(ctxt.Arch, sect)
2268		}
2269		// add a .note.GNU-stack section to mark the stack as non-executable
2270		sh := elfshname(".note.GNU-stack")
2271
2272		sh.Type = uint32(elf.SHT_PROGBITS)
2273		sh.Addralign = 1
2274		sh.Flags = 0
2275	}
2276
2277	var shstroff uint64
2278	if !*FlagS {
2279		sh := elfshname(".symtab")
2280		sh.Type = uint32(elf.SHT_SYMTAB)
2281		sh.Off = uint64(symo)
2282		sh.Size = uint64(symSize)
2283		sh.Addralign = uint64(ctxt.Arch.RegSize)
2284		sh.Entsize = 8 + 2*uint64(ctxt.Arch.RegSize)
2285		sh.Link = uint32(elfshname(".strtab").shnum)
2286		sh.Info = uint32(elfglobalsymndx)
2287
2288		sh = elfshname(".strtab")
2289		sh.Type = uint32(elf.SHT_STRTAB)
2290		sh.Off = uint64(symo) + uint64(symSize)
2291		sh.Size = uint64(len(elfstrdat))
2292		sh.Addralign = 1
2293		shstroff = sh.Off + sh.Size
2294	} else {
2295		shstroff = uint64(symo)
2296	}
2297
2298	sh = elfshname(".shstrtab")
2299	sh.Type = uint32(elf.SHT_STRTAB)
2300	sh.Off = shstroff
2301	sh.Size = uint64(len(elfshstrdat))
2302	sh.Addralign = 1
2303
2304	/* Main header */
2305	copy(eh.Ident[:], elf.ELFMAG)
2306
2307	var osabi elf.OSABI
2308	switch ctxt.HeadType {
2309	case objabi.Hfreebsd:
2310		osabi = elf.ELFOSABI_FREEBSD
2311	case objabi.Hnetbsd:
2312		osabi = elf.ELFOSABI_NETBSD
2313	case objabi.Hopenbsd:
2314		osabi = elf.ELFOSABI_OPENBSD
2315	case objabi.Hdragonfly:
2316		osabi = elf.ELFOSABI_NONE
2317	}
2318	eh.Ident[elf.EI_OSABI] = byte(osabi)
2319
2320	if elf64 {
2321		eh.Ident[elf.EI_CLASS] = byte(elf.ELFCLASS64)
2322	} else {
2323		eh.Ident[elf.EI_CLASS] = byte(elf.ELFCLASS32)
2324	}
2325	if ctxt.Arch.ByteOrder == binary.BigEndian {
2326		eh.Ident[elf.EI_DATA] = byte(elf.ELFDATA2MSB)
2327	} else {
2328		eh.Ident[elf.EI_DATA] = byte(elf.ELFDATA2LSB)
2329	}
2330	eh.Ident[elf.EI_VERSION] = byte(elf.EV_CURRENT)
2331
2332	if ctxt.LinkMode == LinkExternal {
2333		eh.Type = uint16(elf.ET_REL)
2334	} else if ctxt.BuildMode == BuildModePIE {
2335		eh.Type = uint16(elf.ET_DYN)
2336	} else {
2337		eh.Type = uint16(elf.ET_EXEC)
2338	}
2339
2340	if ctxt.LinkMode != LinkExternal {
2341		eh.Entry = uint64(Entryvalue(ctxt))
2342	}
2343
2344	eh.Version = uint32(elf.EV_CURRENT)
2345
2346	if pph != nil {
2347		pph.Filesz = uint64(eh.Phnum) * uint64(eh.Phentsize)
2348		pph.Memsz = pph.Filesz
2349	}
2350
2351	ctxt.Out.SeekSet(0)
2352	a := int64(0)
2353	a += int64(elfwritehdr(ctxt.Out))
2354	a += int64(elfwritephdrs(ctxt.Out))
2355	a += int64(elfwriteshdrs(ctxt.Out))
2356	if !*FlagD {
2357		a += int64(elfwriteinterp(ctxt.Out))
2358	}
2359	if ctxt.IsMIPS() {
2360		a += int64(elfWriteMipsAbiFlags(ctxt))
2361	}
2362
2363	if ctxt.LinkMode != LinkExternal {
2364		if ctxt.HeadType == objabi.Hnetbsd {
2365			a += int64(elfwritenetbsdsig(ctxt.Out))
2366		}
2367		if ctxt.HeadType == objabi.Hopenbsd {
2368			a += int64(elfwriteopenbsdsig(ctxt.Out))
2369		}
2370		if ctxt.HeadType == objabi.Hfreebsd {
2371			a += int64(elfwritefreebsdsig(ctxt.Out))
2372		}
2373		if len(buildinfo) > 0 {
2374			a += int64(elfwritebuildinfo(ctxt.Out))
2375		}
2376		if *flagBuildid != "" {
2377			a += int64(elfwritegobuildid(ctxt.Out))
2378		}
2379	}
2380	if *flagRace && ctxt.IsNetbsd() {
2381		a += int64(elfwritenetbsdpax(ctxt.Out))
2382	}
2383
2384	if a > elfreserve {
2385		Errorf(nil, "ELFRESERVE too small: %d > %d with %d text sections", a, elfreserve, numtext)
2386	}
2387
2388	// Verify the amount of space allocated for the elf header is sufficient.  The file offsets are
2389	// already computed in layout, so we could spill into another section.
2390	if a > int64(HEADR) {
2391		Errorf(nil, "HEADR too small: %d > %d with %d text sections", a, HEADR, numtext)
2392	}
2393}
2394
2395func elfadddynsym(ldr *loader.Loader, target *Target, syms *ArchSyms, s loader.Sym) {
2396	ldr.SetSymDynid(s, int32(Nelfsym))
2397	Nelfsym++
2398	d := ldr.MakeSymbolUpdater(syms.DynSym)
2399	name := ldr.SymExtname(s)
2400	dstru := ldr.MakeSymbolUpdater(syms.DynStr)
2401	st := ldr.SymType(s)
2402	cgoeStatic := ldr.AttrCgoExportStatic(s)
2403	cgoeDynamic := ldr.AttrCgoExportDynamic(s)
2404	cgoexp := (cgoeStatic || cgoeDynamic)
2405
2406	d.AddUint32(target.Arch, uint32(dstru.Addstring(name)))
2407
2408	if elf64 {
2409
2410		/* type */
2411		var t uint8
2412
2413		if cgoexp && st == sym.STEXT {
2414			t = elf.ST_INFO(elf.STB_GLOBAL, elf.STT_FUNC)
2415		} else {
2416			t = elf.ST_INFO(elf.STB_GLOBAL, elf.STT_OBJECT)
2417		}
2418		d.AddUint8(t)
2419
2420		/* reserved */
2421		d.AddUint8(0)
2422
2423		/* section where symbol is defined */
2424		if st == sym.SDYNIMPORT {
2425			d.AddUint16(target.Arch, uint16(elf.SHN_UNDEF))
2426		} else {
2427			d.AddUint16(target.Arch, 1)
2428		}
2429
2430		/* value */
2431		if st == sym.SDYNIMPORT {
2432			d.AddUint64(target.Arch, 0)
2433		} else {
2434			d.AddAddrPlus(target.Arch, s, 0)
2435		}
2436
2437		/* size of object */
2438		d.AddUint64(target.Arch, uint64(len(ldr.Data(s))))
2439
2440		dil := ldr.SymDynimplib(s)
2441
2442		if !cgoeDynamic && dil != "" && !seenlib[dil] {
2443			du := ldr.MakeSymbolUpdater(syms.Dynamic)
2444			Elfwritedynent(target.Arch, du, elf.DT_NEEDED, uint64(dstru.Addstring(dil)))
2445			seenlib[dil] = true
2446		}
2447	} else {
2448
2449		/* value */
2450		if st == sym.SDYNIMPORT {
2451			d.AddUint32(target.Arch, 0)
2452		} else {
2453			d.AddAddrPlus(target.Arch, s, 0)
2454		}
2455
2456		/* size of object */
2457		d.AddUint32(target.Arch, uint32(len(ldr.Data(s))))
2458
2459		/* type */
2460		var t uint8
2461
2462		// TODO(mwhudson): presumably the behavior should actually be the same on both arm and 386.
2463		if target.Arch.Family == sys.I386 && cgoexp && st == sym.STEXT {
2464			t = elf.ST_INFO(elf.STB_GLOBAL, elf.STT_FUNC)
2465		} else if target.Arch.Family == sys.ARM && cgoeDynamic && st == sym.STEXT {
2466			t = elf.ST_INFO(elf.STB_GLOBAL, elf.STT_FUNC)
2467		} else {
2468			t = elf.ST_INFO(elf.STB_GLOBAL, elf.STT_OBJECT)
2469		}
2470		d.AddUint8(t)
2471		d.AddUint8(0)
2472
2473		/* shndx */
2474		if st == sym.SDYNIMPORT {
2475			d.AddUint16(target.Arch, uint16(elf.SHN_UNDEF))
2476		} else {
2477			d.AddUint16(target.Arch, 1)
2478		}
2479	}
2480}
2481