// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ld

import (
	"cmd/internal/obj"
	"cmd/internal/sys"
	"crypto/sha1"
	"encoding/binary"
	"encoding/hex"
	"io"
	"path/filepath"
	"sort"
	"strings"
)

/*
 * Derived from:
 * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.1 2005/12/30 22:13:58 marcel Exp $
 * $FreeBSD: src/sys/sys/elf64.h,v 1.10.14.1 2005/12/30 22:13:58 marcel Exp $
 * $FreeBSD: src/sys/sys/elf_common.h,v 1.15.8.1 2005/12/30 22:13:58 marcel Exp $
 * $FreeBSD: src/sys/alpha/include/elf.h,v 1.14 2003/09/25 01:10:22 peter Exp $
 * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $
 * $FreeBSD: src/sys/arm/include/elf.h,v 1.5.2.1 2006/06/30 21:42:52 cognet Exp $
 * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $
 * $FreeBSD: src/sys/powerpc/include/elf.h,v 1.7 2004/11/02 09:47:01 ssouhlal Exp $
 * $FreeBSD: src/sys/sparc64/include/elf.h,v 1.12 2003/09/25 01:10:26 peter Exp $
 *
 * Copyright (c) 1996-1998 John D. Polstra.  All rights reserved.
 * Copyright (c) 2001 David E. O'Brien
 * Portions Copyright 2009 The Go Authors. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

/*
 * ELF definitions that are independent of architecture or word size.
 */

/*
 * Note header.  The ".note" section contains an array of notes.  Each
 * begins with this header, aligned to a word boundary.  Immediately
 * following the note header is n_namesz bytes of name, padded to the
 * next word boundary.  Then comes n_descsz bytes of descriptor, again
 * padded to a word boundary.  The values of n_namesz and n_descsz do
 * not include the padding.
 */
type elfNote struct {
	nNamesz uint32
	nDescsz uint32
	nType   uint32
}

const (
	EI_MAG0              = 0
	EI_MAG1              = 1
	EI_MAG2              = 2
	EI_MAG3              = 3
	EI_CLASS             = 4
	EI_DATA              = 5
	EI_VERSION           = 6
	EI_OSABI             = 7
	EI_ABIVERSION        = 8
	OLD_EI_BRAND         = 8
	EI_PAD               = 9
	EI_NIDENT            = 16
	ELFMAG0              = 0x7f
	ELFMAG1              = 'E'
	ELFMAG2              = 'L'
	ELFMAG3              = 'F'
	SELFMAG              = 4
	EV_NONE              = 0
	EV_CURRENT           = 1
	ELFCLASSNONE         = 0
	ELFCLASS32           = 1
	ELFCLASS64           = 2
	ELFDATANONE          = 0
	ELFDATA2LSB          = 1
	ELFDATA2MSB          = 2
	ELFOSABI_NONE        = 0
	ELFOSABI_HPUX        = 1
	ELFOSABI_NETBSD      = 2
	ELFOSABI_LINUX       = 3
	ELFOSABI_HURD        = 4
	ELFOSABI_86OPEN      = 5
	ELFOSABI_SOLARIS     = 6
	ELFOSABI_AIX         = 7
	ELFOSABI_IRIX        = 8
	ELFOSABI_FREEBSD     = 9
	ELFOSABI_TRU64       = 10
	ELFOSABI_MODESTO     = 11
	ELFOSABI_OPENBSD     = 12
	ELFOSABI_OPENVMS     = 13
	ELFOSABI_NSK         = 14
	ELFOSABI_ARM         = 97
	ELFOSABI_STANDALONE  = 255
	ELFOSABI_SYSV        = ELFOSABI_NONE
	ELFOSABI_MONTEREY    = ELFOSABI_AIX
	ET_NONE              = 0
	ET_REL               = 1
	ET_EXEC              = 2
	ET_DYN               = 3
	ET_CORE              = 4
	ET_LOOS              = 0xfe00
	ET_HIOS              = 0xfeff
	ET_LOPROC            = 0xff00
	ET_HIPROC            = 0xffff
	EM_NONE              = 0
	EM_M32               = 1
	EM_SPARC             = 2
	EM_386               = 3
	EM_68K               = 4
	EM_88K               = 5
	EM_860               = 7
	EM_MIPS              = 8
	EM_S370              = 9
	EM_MIPS_RS3_LE       = 10
	EM_PARISC            = 15
	EM_VPP500            = 17
	EM_SPARC32PLUS       = 18
	EM_960               = 19
	EM_PPC               = 20
	EM_PPC64             = 21
	EM_S390              = 22
	EM_V800              = 36
	EM_FR20              = 37
	EM_RH32              = 38
	EM_RCE               = 39
	EM_ARM               = 40
	EM_SH                = 42
	EM_SPARCV9           = 43
	EM_TRICORE           = 44
	EM_ARC               = 45
	EM_H8_300            = 46
	EM_H8_300H           = 47
	EM_H8S               = 48
	EM_H8_500            = 49
	EM_IA_64             = 50
	EM_MIPS_X            = 51
	EM_COLDFIRE          = 52
	EM_68HC12            = 53
	EM_MMA               = 54
	EM_PCP               = 55
	EM_NCPU              = 56
	EM_NDR1              = 57
	EM_STARCORE          = 58
	EM_ME16              = 59
	EM_ST100             = 60
	EM_TINYJ             = 61
	EM_X86_64            = 62
	EM_AARCH64           = 183
	EM_486               = 6
	EM_MIPS_RS4_BE       = 10
	EM_ALPHA_STD         = 41
	EM_ALPHA             = 0x9026
	SHN_UNDEF            = 0
	SHN_LORESERVE        = 0xff00
	SHN_LOPROC           = 0xff00
	SHN_HIPROC           = 0xff1f
	SHN_LOOS             = 0xff20
	SHN_HIOS             = 0xff3f
	SHN_ABS              = 0xfff1
	SHN_COMMON           = 0xfff2
	SHN_XINDEX           = 0xffff
	SHN_HIRESERVE        = 0xffff
	SHT_NULL             = 0
	SHT_PROGBITS         = 1
	SHT_SYMTAB           = 2
	SHT_STRTAB           = 3
	SHT_RELA             = 4
	SHT_HASH             = 5
	SHT_DYNAMIC          = 6
	SHT_NOTE             = 7
	SHT_NOBITS           = 8
	SHT_REL              = 9
	SHT_SHLIB            = 10
	SHT_DYNSYM           = 11
	SHT_INIT_ARRAY       = 14
	SHT_FINI_ARRAY       = 15
	SHT_PREINIT_ARRAY    = 16
	SHT_GROUP            = 17
	SHT_SYMTAB_SHNDX     = 18
	SHT_LOOS             = 0x60000000
	SHT_HIOS             = 0x6fffffff
	SHT_GNU_VERDEF       = 0x6ffffffd
	SHT_GNU_VERNEED      = 0x6ffffffe
	SHT_GNU_VERSYM       = 0x6fffffff
	SHT_LOPROC           = 0x70000000
	SHT_ARM_ATTRIBUTES   = 0x70000003
	SHT_HIPROC           = 0x7fffffff
	SHT_LOUSER           = 0x80000000
	SHT_HIUSER           = 0xffffffff
	SHF_WRITE            = 0x1
	SHF_ALLOC            = 0x2
	SHF_EXECINSTR        = 0x4
	SHF_MERGE            = 0x10
	SHF_STRINGS          = 0x20
	SHF_INFO_LINK        = 0x40
	SHF_LINK_ORDER       = 0x80
	SHF_OS_NONCONFORMING = 0x100
	SHF_GROUP            = 0x200
	SHF_TLS              = 0x400
	SHF_MASKOS           = 0x0ff00000
	SHF_MASKPROC         = 0xf0000000
	PT_NULL              = 0
	PT_LOAD              = 1
	PT_DYNAMIC           = 2
	PT_INTERP            = 3
	PT_NOTE              = 4
	PT_SHLIB             = 5
	PT_PHDR              = 6
	PT_TLS               = 7
	PT_LOOS              = 0x60000000
	PT_HIOS              = 0x6fffffff
	PT_LOPROC            = 0x70000000
	PT_HIPROC            = 0x7fffffff
	PT_GNU_STACK         = 0x6474e551
	PT_GNU_RELRO         = 0x6474e552
	PT_PAX_FLAGS         = 0x65041580
	PT_SUNWSTACK         = 0x6ffffffb
	PF_X                 = 0x1
	PF_W                 = 0x2
	PF_R                 = 0x4
	PF_MASKOS            = 0x0ff00000
	PF_MASKPROC          = 0xf0000000
	DT_NULL              = 0
	DT_NEEDED            = 1
	DT_PLTRELSZ          = 2
	DT_PLTGOT            = 3
	DT_HASH              = 4
	DT_STRTAB            = 5
	DT_SYMTAB            = 6
	DT_RELA              = 7
	DT_RELASZ            = 8
	DT_RELAENT           = 9
	DT_STRSZ             = 10
	DT_SYMENT            = 11
	DT_INIT              = 12
	DT_FINI              = 13
	DT_SONAME            = 14
	DT_RPATH             = 15
	DT_SYMBOLIC          = 16
	DT_REL               = 17
	DT_RELSZ             = 18
	DT_RELENT            = 19
	DT_PLTREL            = 20
	DT_DEBUG             = 21
	DT_TEXTREL           = 22
	DT_JMPREL            = 23
	DT_BIND_NOW          = 24
	DT_INIT_ARRAY        = 25
	DT_FINI_ARRAY        = 26
	DT_INIT_ARRAYSZ      = 27
	DT_FINI_ARRAYSZ      = 28
	DT_RUNPATH           = 29
	DT_FLAGS             = 30
	DT_ENCODING          = 32
	DT_PREINIT_ARRAY     = 32
	DT_PREINIT_ARRAYSZ   = 33
	DT_LOOS              = 0x6000000d
	DT_HIOS              = 0x6ffff000
	DT_LOPROC            = 0x70000000
	DT_HIPROC            = 0x7fffffff
	DT_VERNEED           = 0x6ffffffe
	DT_VERNEEDNUM        = 0x6fffffff
	DT_VERSYM            = 0x6ffffff0
	DT_PPC64_GLINK       = DT_LOPROC + 0
	DT_PPC64_OPT         = DT_LOPROC + 3
	DF_ORIGIN            = 0x0001
	DF_SYMBOLIC          = 0x0002
	DF_TEXTREL           = 0x0004
	DF_BIND_NOW          = 0x0008
	DF_STATIC_TLS        = 0x0010
	NT_PRSTATUS          = 1
	NT_FPREGSET          = 2
	NT_PRPSINFO          = 3
	STB_LOCAL            = 0
	STB_GLOBAL           = 1
	STB_WEAK             = 2
	STB_LOOS             = 10
	STB_HIOS             = 12
	STB_LOPROC           = 13
	STB_HIPROC           = 15
	STT_NOTYPE           = 0
	STT_OBJECT           = 1
	STT_FUNC             = 2
	STT_SECTION          = 3
	STT_FILE             = 4
	STT_COMMON           = 5
	STT_TLS              = 6
	STT_LOOS             = 10
	STT_HIOS             = 12
	STT_LOPROC           = 13
	STT_HIPROC           = 15
	STV_DEFAULT          = 0x0
	STV_INTERNAL         = 0x1
	STV_HIDDEN           = 0x2
	STV_PROTECTED        = 0x3
	STN_UNDEF            = 0
)

/* For accessing the fields of r_info. */

/* For constructing r_info from field values. */

/*
 * Relocation types.
 */
const (
	R_X86_64_NONE           = 0
	R_X86_64_64             = 1
	R_X86_64_PC32           = 2
	R_X86_64_GOT32          = 3
	R_X86_64_PLT32          = 4
	R_X86_64_COPY           = 5
	R_X86_64_GLOB_DAT       = 6
	R_X86_64_JMP_SLOT       = 7
	R_X86_64_RELATIVE       = 8
	R_X86_64_GOTPCREL       = 9
	R_X86_64_32             = 10
	R_X86_64_32S            = 11
	R_X86_64_16             = 12
	R_X86_64_PC16           = 13
	R_X86_64_8              = 14
	R_X86_64_PC8            = 15
	R_X86_64_DTPMOD64       = 16
	R_X86_64_DTPOFF64       = 17
	R_X86_64_TPOFF64        = 18
	R_X86_64_TLSGD          = 19
	R_X86_64_TLSLD          = 20
	R_X86_64_DTPOFF32       = 21
	R_X86_64_GOTTPOFF       = 22
	R_X86_64_TPOFF32        = 23
	R_X86_64_PC64           = 24
	R_X86_64_GOTOFF64       = 25
	R_X86_64_GOTPC32        = 26
	R_X86_64_GOT64          = 27
	R_X86_64_GOTPCREL64     = 28
	R_X86_64_GOTPC64        = 29
	R_X86_64_GOTPLT64       = 30
	R_X86_64_PLTOFF64       = 31
	R_X86_64_SIZE32         = 32
	R_X86_64_SIZE64         = 33
	R_X86_64_GOTPC32_TLSDEC = 34
	R_X86_64_TLSDESC_CALL   = 35
	R_X86_64_TLSDESC        = 36
	R_X86_64_IRELATIVE      = 37
	R_X86_64_PC32_BND       = 40
	R_X86_64_GOTPCRELX      = 41
	R_X86_64_REX_GOTPCRELX  = 42

	R_AARCH64_ABS64                       = 257
	R_AARCH64_ABS32                       = 258
	R_AARCH64_CALL26                      = 283
	R_AARCH64_ADR_PREL_PG_HI21            = 275
	R_AARCH64_ADD_ABS_LO12_NC             = 277
	R_AARCH64_LDST8_ABS_LO12_NC           = 278
	R_AARCH64_LDST16_ABS_LO12_NC          = 284
	R_AARCH64_LDST32_ABS_LO12_NC          = 285
	R_AARCH64_LDST64_ABS_LO12_NC          = 286
	R_AARCH64_ADR_GOT_PAGE                = 311
	R_AARCH64_LD64_GOT_LO12_NC            = 312
	R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21   = 541
	R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC = 542
	R_AARCH64_TLSLE_MOVW_TPREL_G0         = 547

	R_ALPHA_NONE           = 0
	R_ALPHA_REFLONG        = 1
	R_ALPHA_REFQUAD        = 2
	R_ALPHA_GPREL32        = 3
	R_ALPHA_LITERAL        = 4
	R_ALPHA_LITUSE         = 5
	R_ALPHA_GPDISP         = 6
	R_ALPHA_BRADDR         = 7
	R_ALPHA_HINT           = 8
	R_ALPHA_SREL16         = 9
	R_ALPHA_SREL32         = 10
	R_ALPHA_SREL64         = 11
	R_ALPHA_OP_PUSH        = 12
	R_ALPHA_OP_STORE       = 13
	R_ALPHA_OP_PSUB        = 14
	R_ALPHA_OP_PRSHIFT     = 15
	R_ALPHA_GPVALUE        = 16
	R_ALPHA_GPRELHIGH      = 17
	R_ALPHA_GPRELLOW       = 18
	R_ALPHA_IMMED_GP_16    = 19
	R_ALPHA_IMMED_GP_HI32  = 20
	R_ALPHA_IMMED_SCN_HI32 = 21
	R_ALPHA_IMMED_BR_HI32  = 22
	R_ALPHA_IMMED_LO32     = 23
	R_ALPHA_COPY           = 24
	R_ALPHA_GLOB_DAT       = 25
	R_ALPHA_JMP_SLOT       = 26
	R_ALPHA_RELATIVE       = 27

	R_ARM_NONE          = 0
	R_ARM_PC24          = 1
	R_ARM_ABS32         = 2
	R_ARM_REL32         = 3
	R_ARM_PC13          = 4
	R_ARM_ABS16         = 5
	R_ARM_ABS12         = 6
	R_ARM_THM_ABS5      = 7
	R_ARM_ABS8          = 8
	R_ARM_SBREL32       = 9
	R_ARM_THM_PC22      = 10
	R_ARM_THM_PC8       = 11
	R_ARM_AMP_VCALL9    = 12
	R_ARM_SWI24         = 13
	R_ARM_THM_SWI8      = 14
	R_ARM_XPC25         = 15
	R_ARM_THM_XPC22     = 16
	R_ARM_COPY          = 20
	R_ARM_GLOB_DAT      = 21
	R_ARM_JUMP_SLOT     = 22
	R_ARM_RELATIVE      = 23
	R_ARM_GOTOFF        = 24
	R_ARM_GOTPC         = 25
	R_ARM_GOT32         = 26
	R_ARM_PLT32         = 27
	R_ARM_CALL          = 28
	R_ARM_JUMP24        = 29
	R_ARM_V4BX          = 40
	R_ARM_GOT_PREL      = 96
	R_ARM_GNU_VTENTRY   = 100
	R_ARM_GNU_VTINHERIT = 101
	R_ARM_TLS_IE32      = 107
	R_ARM_TLS_LE32      = 108
	R_ARM_RSBREL32      = 250
	R_ARM_THM_RPC22     = 251
	R_ARM_RREL32        = 252
	R_ARM_RABS32        = 253
	R_ARM_RPC24         = 254
	R_ARM_RBASE         = 255

	R_386_NONE          = 0
	R_386_32            = 1
	R_386_PC32          = 2
	R_386_GOT32         = 3
	R_386_PLT32         = 4
	R_386_COPY          = 5
	R_386_GLOB_DAT      = 6
	R_386_JMP_SLOT      = 7
	R_386_RELATIVE      = 8
	R_386_GOTOFF        = 9
	R_386_GOTPC         = 10
	R_386_TLS_TPOFF     = 14
	R_386_TLS_IE        = 15
	R_386_TLS_GOTIE     = 16
	R_386_TLS_LE        = 17
	R_386_TLS_GD        = 18
	R_386_TLS_LDM       = 19
	R_386_TLS_GD_32     = 24
	R_386_TLS_GD_PUSH   = 25
	R_386_TLS_GD_CALL   = 26
	R_386_TLS_GD_POP    = 27
	R_386_TLS_LDM_32    = 28
	R_386_TLS_LDM_PUSH  = 29
	R_386_TLS_LDM_CALL  = 30
	R_386_TLS_LDM_POP   = 31
	R_386_TLS_LDO_32    = 32
	R_386_TLS_IE_32     = 33
	R_386_TLS_LE_32     = 34
	R_386_TLS_DTPMOD32  = 35
	R_386_TLS_DTPOFF32  = 36
	R_386_TLS_TPOFF32   = 37
	R_386_TLS_GOTDESC   = 39
	R_386_TLS_DESC_CALL = 40
	R_386_TLS_DESC      = 41
	R_386_IRELATIVE     = 42
	R_386_GOT32X        = 43

	R_MIPS_NONE            = 0
	R_MIPS_16              = 1
	R_MIPS_32              = 2
	R_MIPS_REL32           = 3
	R_MIPS_26              = 4
	R_MIPS_HI16            = 5
	R_MIPS_LO16            = 6
	R_MIPS_GPREL16         = 7
	R_MIPS_LITERAL         = 8
	R_MIPS_GOT16           = 9
	R_MIPS_PC16            = 10
	R_MIPS_CALL16          = 11
	R_MIPS_GPREL32         = 12
	R_MIPS_SHIFT5          = 16
	R_MIPS_SHIFT6          = 17
	R_MIPS_64              = 18
	R_MIPS_GOT_DISP        = 19
	R_MIPS_GOT_PAGE        = 20
	R_MIPS_GOT_OFST        = 21
	R_MIPS_GOT_HI16        = 22
	R_MIPS_GOT_LO16        = 23
	R_MIPS_SUB             = 24
	R_MIPS_INSERT_A        = 25
	R_MIPS_INSERT_B        = 26
	R_MIPS_DELETE          = 27
	R_MIPS_HIGHER          = 28
	R_MIPS_HIGHEST         = 29
	R_MIPS_CALL_HI16       = 30
	R_MIPS_CALL_LO16       = 31
	R_MIPS_SCN_DISP        = 32
	R_MIPS_REL16           = 33
	R_MIPS_ADD_IMMEDIATE   = 34
	R_MIPS_PJUMP           = 35
	R_MIPS_RELGOT          = 36
	R_MIPS_JALR            = 37
	R_MIPS_TLS_DTPMOD32    = 38
	R_MIPS_TLS_DTPREL32    = 39
	R_MIPS_TLS_DTPMOD64    = 40
	R_MIPS_TLS_DTPREL64    = 41
	R_MIPS_TLS_GD          = 42
	R_MIPS_TLS_LDM         = 43
	R_MIPS_TLS_DTPREL_HI16 = 44
	R_MIPS_TLS_DTPREL_LO16 = 45
	R_MIPS_TLS_GOTTPREL    = 46
	R_MIPS_TLS_TPREL32     = 47
	R_MIPS_TLS_TPREL64     = 48
	R_MIPS_TLS_TPREL_HI16  = 49
	R_MIPS_TLS_TPREL_LO16  = 50

	R_PPC_NONE            = 0
	R_PPC_ADDR32          = 1
	R_PPC_ADDR24          = 2
	R_PPC_ADDR16          = 3
	R_PPC_ADDR16_LO       = 4
	R_PPC_ADDR16_HI       = 5
	R_PPC_ADDR16_HA       = 6
	R_PPC_ADDR14          = 7
	R_PPC_ADDR14_BRTAKEN  = 8
	R_PPC_ADDR14_BRNTAKEN = 9
	R_PPC_REL24           = 10
	R_PPC_REL14           = 11
	R_PPC_REL14_BRTAKEN   = 12
	R_PPC_REL14_BRNTAKEN  = 13
	R_PPC_GOT16           = 14
	R_PPC_GOT16_LO        = 15
	R_PPC_GOT16_HI        = 16
	R_PPC_GOT16_HA        = 17
	R_PPC_PLTREL24        = 18
	R_PPC_COPY            = 19
	R_PPC_GLOB_DAT        = 20
	R_PPC_JMP_SLOT        = 21
	R_PPC_RELATIVE        = 22
	R_PPC_LOCAL24PC       = 23
	R_PPC_UADDR32         = 24
	R_PPC_UADDR16         = 25
	R_PPC_REL32           = 26
	R_PPC_PLT32           = 27
	R_PPC_PLTREL32        = 28
	R_PPC_PLT16_LO        = 29
	R_PPC_PLT16_HI        = 30
	R_PPC_PLT16_HA        = 31
	R_PPC_SDAREL16        = 32
	R_PPC_SECTOFF         = 33
	R_PPC_SECTOFF_LO      = 34
	R_PPC_SECTOFF_HI      = 35
	R_PPC_SECTOFF_HA      = 36
	R_PPC_TLS             = 67
	R_PPC_DTPMOD32        = 68
	R_PPC_TPREL16         = 69
	R_PPC_TPREL16_LO      = 70
	R_PPC_TPREL16_HI      = 71
	R_PPC_TPREL16_HA      = 72
	R_PPC_TPREL32         = 73
	R_PPC_DTPREL16        = 74
	R_PPC_DTPREL16_LO     = 75
	R_PPC_DTPREL16_HI     = 76
	R_PPC_DTPREL16_HA     = 77
	R_PPC_DTPREL32        = 78
	R_PPC_GOT_TLSGD16     = 79
	R_PPC_GOT_TLSGD16_LO  = 80
	R_PPC_GOT_TLSGD16_HI  = 81
	R_PPC_GOT_TLSGD16_HA  = 82
	R_PPC_GOT_TLSLD16     = 83
	R_PPC_GOT_TLSLD16_LO  = 84
	R_PPC_GOT_TLSLD16_HI  = 85
	R_PPC_GOT_TLSLD16_HA  = 86
	R_PPC_GOT_TPREL16     = 87
	R_PPC_GOT_TPREL16_LO  = 88
	R_PPC_GOT_TPREL16_HI  = 89
	R_PPC_GOT_TPREL16_HA  = 90
	R_PPC_EMB_NADDR32     = 101
	R_PPC_EMB_NADDR16     = 102
	R_PPC_EMB_NADDR16_LO  = 103
	R_PPC_EMB_NADDR16_HI  = 104
	R_PPC_EMB_NADDR16_HA  = 105
	R_PPC_EMB_SDAI16      = 106
	R_PPC_EMB_SDA2I16     = 107
	R_PPC_EMB_SDA2REL     = 108
	R_PPC_EMB_SDA21       = 109
	R_PPC_EMB_MRKREF      = 110
	R_PPC_EMB_RELSEC16    = 111
	R_PPC_EMB_RELST_LO    = 112
	R_PPC_EMB_RELST_HI    = 113
	R_PPC_EMB_RELST_HA    = 114
	R_PPC_EMB_BIT_FLD     = 115
	R_PPC_EMB_RELSDA      = 116

	R_PPC64_ADDR32            = R_PPC_ADDR32
	R_PPC64_ADDR16_LO         = R_PPC_ADDR16_LO
	R_PPC64_ADDR16_HA         = R_PPC_ADDR16_HA
	R_PPC64_REL24             = R_PPC_REL24
	R_PPC64_GOT16_HA          = R_PPC_GOT16_HA
	R_PPC64_JMP_SLOT          = R_PPC_JMP_SLOT
	R_PPC64_TPREL16           = R_PPC_TPREL16
	R_PPC64_ADDR64            = 38
	R_PPC64_TOC16             = 47
	R_PPC64_TOC16_LO          = 48
	R_PPC64_TOC16_HI          = 49
	R_PPC64_TOC16_HA          = 50
	R_PPC64_ADDR16_LO_DS      = 57
	R_PPC64_GOT16_LO_DS       = 59
	R_PPC64_TOC16_DS          = 63
	R_PPC64_TOC16_LO_DS       = 64
	R_PPC64_TLS               = 67
	R_PPC64_GOT_TPREL16_LO_DS = 88
	R_PPC64_GOT_TPREL16_HA    = 90
	R_PPC64_REL16_LO          = 250
	R_PPC64_REL16_HI          = 251
	R_PPC64_REL16_HA          = 252

	R_SPARC_NONE     = 0
	R_SPARC_8        = 1
	R_SPARC_16       = 2
	R_SPARC_32       = 3
	R_SPARC_DISP8    = 4
	R_SPARC_DISP16   = 5
	R_SPARC_DISP32   = 6
	R_SPARC_WDISP30  = 7
	R_SPARC_WDISP22  = 8
	R_SPARC_HI22     = 9
	R_SPARC_22       = 10
	R_SPARC_13       = 11
	R_SPARC_LO10     = 12
	R_SPARC_GOT10    = 13
	R_SPARC_GOT13    = 14
	R_SPARC_GOT22    = 15
	R_SPARC_PC10     = 16
	R_SPARC_PC22     = 17
	R_SPARC_WPLT30   = 18
	R_SPARC_COPY     = 19
	R_SPARC_GLOB_DAT = 20
	R_SPARC_JMP_SLOT = 21
	R_SPARC_RELATIVE = 22
	R_SPARC_UA32     = 23
	R_SPARC_PLT32    = 24
	R_SPARC_HIPLT22  = 25
	R_SPARC_LOPLT10  = 26
	R_SPARC_PCPLT32  = 27
	R_SPARC_PCPLT22  = 28
	R_SPARC_PCPLT10  = 29
	R_SPARC_10       = 30
	R_SPARC_11       = 31
	R_SPARC_64       = 32
	R_SPARC_OLO10    = 33
	R_SPARC_HH22     = 34
	R_SPARC_HM10     = 35
	R_SPARC_LM22     = 36
	R_SPARC_PC_HH22  = 37
	R_SPARC_PC_HM10  = 38
	R_SPARC_PC_LM22  = 39
	R_SPARC_WDISP16  = 40
	R_SPARC_WDISP19  = 41
	R_SPARC_GLOB_JMP = 42
	R_SPARC_7        = 43
	R_SPARC_5        = 44
	R_SPARC_6        = 45
	R_SPARC_DISP64   = 46
	R_SPARC_PLT64    = 47
	R_SPARC_HIX22    = 48
	R_SPARC_LOX10    = 49
	R_SPARC_H44      = 50
	R_SPARC_M44      = 51
	R_SPARC_L44      = 52
	R_SPARC_REGISTER = 53
	R_SPARC_UA64     = 54
	R_SPARC_UA16     = 55

	R_390_NONE        = 0
	R_390_8           = 1
	R_390_12          = 2
	R_390_16          = 3
	R_390_32          = 4
	R_390_PC32        = 5
	R_390_GOT12       = 6
	R_390_GOT32       = 7
	R_390_PLT32       = 8
	R_390_COPY        = 9
	R_390_GLOB_DAT    = 10
	R_390_JMP_SLOT    = 11
	R_390_RELATIVE    = 12
	R_390_GOTOFF      = 13
	R_390_GOTPC       = 14
	R_390_GOT16       = 15
	R_390_PC16        = 16
	R_390_PC16DBL     = 17
	R_390_PLT16DBL    = 18
	R_390_PC32DBL     = 19
	R_390_PLT32DBL    = 20
	R_390_GOTPCDBL    = 21
	R_390_64          = 22
	R_390_PC64        = 23
	R_390_GOT64       = 24
	R_390_PLT64       = 25
	R_390_GOTENT      = 26
	R_390_GOTOFF16    = 27
	R_390_GOTOFF64    = 28
	R_390_GOTPLT12    = 29
	R_390_GOTPLT16    = 30
	R_390_GOTPLT32    = 31
	R_390_GOTPLT64    = 32
	R_390_GOTPLTENT   = 33
	R_390_GOTPLTOFF16 = 34
	R_390_GOTPLTOFF32 = 35
	R_390_GOTPLTOFF64 = 36
	R_390_TLS_LOAD    = 37
	R_390_TLS_GDCALL  = 38
	R_390_TLS_LDCALL  = 39
	R_390_TLS_GD32    = 40
	R_390_TLS_GD64    = 41
	R_390_TLS_GOTIE12 = 42
	R_390_TLS_GOTIE32 = 43
	R_390_TLS_GOTIE64 = 44
	R_390_TLS_LDM32   = 45
	R_390_TLS_LDM64   = 46
	R_390_TLS_IE32    = 47
	R_390_TLS_IE64    = 48
	R_390_TLS_IEENT   = 49
	R_390_TLS_LE32    = 50
	R_390_TLS_LE64    = 51
	R_390_TLS_LDO32   = 52
	R_390_TLS_LDO64   = 53
	R_390_TLS_DTPMOD  = 54
	R_390_TLS_DTPOFF  = 55
	R_390_TLS_TPOFF   = 56
	R_390_20          = 57
	R_390_GOT20       = 58
	R_390_GOTPLT20    = 59
	R_390_TLS_GOTIE20 = 60

	ARM_MAGIC_TRAMP_NUMBER = 0x5c000003
)

/*
 * Symbol table entries.
 */

/* For accessing the fields of st_info. */

/* For constructing st_info from field values. */

/* For accessing the fields of st_other. */

/*
 * ELF header.
 */
type ElfEhdr struct {
	ident     [EI_NIDENT]uint8
	type_     uint16
	machine   uint16
	version   uint32
	entry     uint64
	phoff     uint64
	shoff     uint64
	flags     uint32
	ehsize    uint16
	phentsize uint16
	phnum     uint16
	shentsize uint16
	shnum     uint16
	shstrndx  uint16
}

/*
 * Section header.
 */
type ElfShdr struct {
	name      uint32
	type_     uint32
	flags     uint64
	addr      uint64
	off       uint64
	size      uint64
	link      uint32
	info      uint32
	addralign uint64
	entsize   uint64
	shnum     int
	secsym    *Symbol
}

/*
 * Program header.
 */
type ElfPhdr struct {
	type_  uint32
	flags  uint32
	off    uint64
	vaddr  uint64
	paddr  uint64
	filesz uint64
	memsz  uint64
	align  uint64
}

/* For accessing the fields of r_info. */

/* For constructing r_info from field values. */

/*
 * Symbol table entries.
 */

/* For accessing the fields of st_info. */

/* For constructing st_info from field values. */

/* For accessing the fields of st_other. */

/*
 * Go linker interface
 */
const (
	ELF64HDRSIZE  = 64
	ELF64PHDRSIZE = 56
	ELF64SHDRSIZE = 64
	ELF64RELSIZE  = 16
	ELF64RELASIZE = 24
	ELF64SYMSIZE  = 24
	ELF32HDRSIZE  = 52
	ELF32PHDRSIZE = 32
	ELF32SHDRSIZE = 40
	ELF32SYMSIZE  = 16
	ELF32RELSIZE  = 8
)

/*
 * The interface uses the 64-bit structures always,
 * to avoid code duplication.  The writers know how to
 * marshal a 32-bit representation from the 64-bit structure.
 */

var Elfstrdat []byte

/*
 * Total amount of space to reserve at the start of the file
 * for Header, PHeaders, SHeaders, and interp.
 * May waste some.
 * On FreeBSD, cannot be larger than a page.
 */
const (
	ELFRESERVE = 4096
)

/*
 * We use the 64-bit data structures on both 32- and 64-bit machines
 * in order to write the code just once.  The 64-bit data structure is
 * written in the 32-bit format on the 32-bit machines.
 */
const (
	NSECT = 400
)

var (
	Iself bool

	Nelfsym int = 1

	elf64 bool
	// Either ".rel" or ".rela" depending on which type of relocation the
	// target platform uses.
	elfRelType string

	ehdr ElfEhdr
	phdr [NSECT]*ElfPhdr
	shdr [NSECT]*ElfShdr

	interp string
)

type Elfstring struct {
	s   string
	off int
}

var elfstr [100]Elfstring

var nelfstr int

var buildinfo []byte

/*
 Initialize the global variable that describes the ELF header. It will be updated as
 we write section and prog headers.
*/
func Elfinit(ctxt *Link) {
	Iself = true

	if SysArch.InFamily(sys.AMD64, sys.ARM64, sys.MIPS64, sys.PPC64, sys.S390X) {
		elfRelType = ".rela"
	} else {
		elfRelType = ".rel"
	}

	switch SysArch.Family {
	// 64-bit architectures
	case sys.PPC64, sys.S390X:
		if ctxt.Arch.ByteOrder == binary.BigEndian {
			ehdr.flags = 1 /* Version 1 ABI */
		} else {
			ehdr.flags = 2 /* Version 2 ABI */
		}
		fallthrough
	case sys.AMD64, sys.ARM64, sys.MIPS64:
		if SysArch.Family == sys.MIPS64 {
			ehdr.flags = 0x20000000 /* MIPS 3 */
		}
		elf64 = true

		ehdr.phoff = ELF64HDRSIZE      /* Must be be ELF64HDRSIZE: first PHdr must follow ELF header */
		ehdr.shoff = ELF64HDRSIZE      /* Will move as we add PHeaders */
		ehdr.ehsize = ELF64HDRSIZE     /* Must be ELF64HDRSIZE */
		ehdr.phentsize = ELF64PHDRSIZE /* Must be ELF64PHDRSIZE */
		ehdr.shentsize = ELF64SHDRSIZE /* Must be ELF64SHDRSIZE */

	// 32-bit architectures
	case sys.ARM, sys.MIPS:
		if SysArch.Family == sys.ARM {
			// we use EABI on linux/arm, freebsd/arm, netbsd/arm.
			if Headtype == obj.Hlinux || Headtype == obj.Hfreebsd || Headtype == obj.Hnetbsd {
				// We set a value here that makes no indication of which
				// float ABI the object uses, because this is information
				// used by the dynamic linker to compare executables and
				// shared libraries -- so it only matters for cgo calls, and
				// the information properly comes from the object files
				// produced by the host C compiler. parseArmAttributes in
				// ldelf.go reads that information and updates this field as
				// appropriate.
				ehdr.flags = 0x5000002 // has entry point, Version5 EABI
			}
		} else if SysArch.Family == sys.MIPS {
			ehdr.flags = 0x50001004 /* MIPS 32 CPIC O32*/
		}
		fallthrough
	default:
		ehdr.phoff = ELF32HDRSIZE
		/* Must be be ELF32HDRSIZE: first PHdr must follow ELF header */
		ehdr.shoff = ELF32HDRSIZE      /* Will move as we add PHeaders */
		ehdr.ehsize = ELF32HDRSIZE     /* Must be ELF32HDRSIZE */
		ehdr.phentsize = ELF32PHDRSIZE /* Must be ELF32PHDRSIZE */
		ehdr.shentsize = ELF32SHDRSIZE /* Must be ELF32SHDRSIZE */
	}
}

// Make sure PT_LOAD is aligned properly and
// that there is no gap,
// correct ELF loaders will do this implicitly,
// but buggy ELF loaders like the one in some
// versions of QEMU and UPX won't.
func fixElfPhdr(e *ElfPhdr) {
	frag := int(e.vaddr & (e.align - 1))

	e.off -= uint64(frag)
	e.vaddr -= uint64(frag)
	e.paddr -= uint64(frag)
	e.filesz += uint64(frag)
	e.memsz += uint64(frag)
}

func elf64phdr(e *ElfPhdr) {
	if e.type_ == PT_LOAD {
		fixElfPhdr(e)
	}

	Thearch.Lput(e.type_)
	Thearch.Lput(e.flags)
	Thearch.Vput(e.off)
	Thearch.Vput(e.vaddr)
	Thearch.Vput(e.paddr)
	Thearch.Vput(e.filesz)
	Thearch.Vput(e.memsz)
	Thearch.Vput(e.align)
}

func elf32phdr(e *ElfPhdr) {
	if e.type_ == PT_LOAD {
		fixElfPhdr(e)
	}

	Thearch.Lput(e.type_)
	Thearch.Lput(uint32(e.off))
	Thearch.Lput(uint32(e.vaddr))
	Thearch.Lput(uint32(e.paddr))
	Thearch.Lput(uint32(e.filesz))
	Thearch.Lput(uint32(e.memsz))
	Thearch.Lput(e.flags)
	Thearch.Lput(uint32(e.align))
}

func elf64shdr(e *ElfShdr) {
	Thearch.Lput(e.name)
	Thearch.Lput(e.type_)
	Thearch.Vput(e.flags)
	Thearch.Vput(e.addr)
	Thearch.Vput(e.off)
	Thearch.Vput(e.size)
	Thearch.Lput(e.link)
	Thearch.Lput(e.info)
	Thearch.Vput(e.addralign)
	Thearch.Vput(e.entsize)
}

func elf32shdr(e *ElfShdr) {
	Thearch.Lput(e.name)
	Thearch.Lput(e.type_)
	Thearch.Lput(uint32(e.flags))
	Thearch.Lput(uint32(e.addr))
	Thearch.Lput(uint32(e.off))
	Thearch.Lput(uint32(e.size))
	Thearch.Lput(e.link)
	Thearch.Lput(e.info)
	Thearch.Lput(uint32(e.addralign))
	Thearch.Lput(uint32(e.entsize))
}

func elfwriteshdrs() uint32 {
	if elf64 {
		for i := 0; i < int(ehdr.shnum); i++ {
			elf64shdr(shdr[i])
		}
		return uint32(ehdr.shnum) * ELF64SHDRSIZE
	}

	for i := 0; i < int(ehdr.shnum); i++ {
		elf32shdr(shdr[i])
	}
	return uint32(ehdr.shnum) * ELF32SHDRSIZE
}

func elfsetstring(s *Symbol, str string, off int) {
	if nelfstr >= len(elfstr) {
		Errorf(s, "too many elf strings")
		errorexit()
	}

	elfstr[nelfstr].s = str
	elfstr[nelfstr].off = off
	nelfstr++
}

func elfwritephdrs() uint32 {
	if elf64 {
		for i := 0; i < int(ehdr.phnum); i++ {
			elf64phdr(phdr[i])
		}
		return uint32(ehdr.phnum) * ELF64PHDRSIZE
	}

	for i := 0; i < int(ehdr.phnum); i++ {
		elf32phdr(phdr[i])
	}
	return uint32(ehdr.phnum) * ELF32PHDRSIZE
}

func newElfPhdr() *ElfPhdr {
	e := new(ElfPhdr)
	if ehdr.phnum >= NSECT {
		Errorf(nil, "too many phdrs")
	} else {
		phdr[ehdr.phnum] = e
		ehdr.phnum++
	}
	if elf64 {
		ehdr.shoff += ELF64PHDRSIZE
	} else {
		ehdr.shoff += ELF32PHDRSIZE
	}
	return e
}

func newElfShdr(name int64) *ElfShdr {
	e := new(ElfShdr)
	e.name = uint32(name)
	e.shnum = int(ehdr.shnum)
	if ehdr.shnum >= NSECT {
		Errorf(nil, "too many shdrs")
	} else {
		shdr[ehdr.shnum] = e
		ehdr.shnum++
	}

	return e
}

func getElfEhdr() *ElfEhdr {
	return &ehdr
}

func elf64writehdr() uint32 {
	for i := 0; i < EI_NIDENT; i++ {
		Cput(ehdr.ident[i])
	}
	Thearch.Wput(ehdr.type_)
	Thearch.Wput(ehdr.machine)
	Thearch.Lput(ehdr.version)
	Thearch.Vput(ehdr.entry)
	Thearch.Vput(ehdr.phoff)
	Thearch.Vput(ehdr.shoff)
	Thearch.Lput(ehdr.flags)
	Thearch.Wput(ehdr.ehsize)
	Thearch.Wput(ehdr.phentsize)
	Thearch.Wput(ehdr.phnum)
	Thearch.Wput(ehdr.shentsize)
	Thearch.Wput(ehdr.shnum)
	Thearch.Wput(ehdr.shstrndx)
	return ELF64HDRSIZE
}

func elf32writehdr() uint32 {
	for i := 0; i < EI_NIDENT; i++ {
		Cput(ehdr.ident[i])
	}
	Thearch.Wput(ehdr.type_)
	Thearch.Wput(ehdr.machine)
	Thearch.Lput(ehdr.version)
	Thearch.Lput(uint32(ehdr.entry))
	Thearch.Lput(uint32(ehdr.phoff))
	Thearch.Lput(uint32(ehdr.shoff))
	Thearch.Lput(ehdr.flags)
	Thearch.Wput(ehdr.ehsize)
	Thearch.Wput(ehdr.phentsize)
	Thearch.Wput(ehdr.phnum)
	Thearch.Wput(ehdr.shentsize)
	Thearch.Wput(ehdr.shnum)
	Thearch.Wput(ehdr.shstrndx)
	return ELF32HDRSIZE
}

func elfwritehdr() uint32 {
	if elf64 {
		return elf64writehdr()
	}
	return elf32writehdr()
}

/* Taken directly from the definition document for ELF64 */
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 Elfwritedynent(ctxt *Link, s *Symbol, tag int, val uint64) {
	if elf64 {
		Adduint64(ctxt, s, uint64(tag))
		Adduint64(ctxt, s, val)
	} else {
		Adduint32(ctxt, s, uint32(tag))
		Adduint32(ctxt, s, uint32(val))
	}
}

func elfwritedynentsym(ctxt *Link, s *Symbol, tag int, t *Symbol) {
	Elfwritedynentsymplus(ctxt, s, tag, t, 0)
}

func Elfwritedynentsymplus(ctxt *Link, s *Symbol, tag int, t *Symbol, add int64) {
	if elf64 {
		Adduint64(ctxt, s, uint64(tag))
	} else {
		Adduint32(ctxt, s, uint32(tag))
	}
	Addaddrplus(ctxt, s, t, add)
}

func elfwritedynentsymsize(ctxt *Link, s *Symbol, tag int, t *Symbol) {
	if elf64 {
		Adduint64(ctxt, s, uint64(tag))
	} else {
		Adduint32(ctxt, s, uint32(tag))
	}
	addsize(ctxt, s, 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() int {
	sh := elfshname(".interp")
	Cseek(int64(sh.off))
	coutbuf.WriteString(interp)
	Cput(0)
	return int(sh.size)
}

func elfnote(sh *ElfShdr, startva uint64, resoff uint64, sz int, alloc bool) int {
	n := 3*4 + uint64(sz) + resoff%4

	sh.type_ = SHT_NOTE
	if alloc {
		sh.flags = SHF_ALLOC
	}
	sh.addralign = 4
	sh.addr = startva + resoff - n
	sh.off = resoff - n
	sh.size = n - resoff%4

	return int(n)
}

func elfwritenotehdr(str string, namesz uint32, descsz uint32, tag uint32) *ElfShdr {
	sh := elfshname(str)

	// Write Elf_Note header.
	Cseek(int64(sh.off))

	Thearch.Lput(namesz)
	Thearch.Lput(descsz)
	Thearch.Lput(tag)

	return sh
}

// NetBSD Signature (as per sys/exec_elf.h)
const (
	ELF_NOTE_NETBSD_NAMESZ  = 7
	ELF_NOTE_NETBSD_DESCSZ  = 4
	ELF_NOTE_NETBSD_TAG     = 1
	ELF_NOTE_NETBSD_VERSION = 599000000 /* NetBSD 5.99 */
)

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, true)
}

func elfwritenetbsdsig() int {
	// Write Elf_Note header.
	sh := elfwritenotehdr(".note.netbsd.ident", ELF_NOTE_NETBSD_NAMESZ, ELF_NOTE_NETBSD_DESCSZ, ELF_NOTE_NETBSD_TAG)

	if sh == nil {
		return 0
	}

	// Followed by NetBSD string and version.
	Cwrite(ELF_NOTE_NETBSD_NAME)
	Cput(0)

	Thearch.Lput(ELF_NOTE_NETBSD_VERSION)

	return int(sh.size)
}

// OpenBSD Signature
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, true)
}

func elfwriteopenbsdsig() int {
	// Write Elf_Note header.
	sh := elfwritenotehdr(".note.openbsd.ident", ELF_NOTE_OPENBSD_NAMESZ, ELF_NOTE_OPENBSD_DESCSZ, ELF_NOTE_OPENBSD_TAG)

	if sh == nil {
		return 0
	}

	// Followed by OpenBSD string and version.
	Cwrite(ELF_NOTE_OPENBSD_NAME)

	Thearch.Lput(ELF_NOTE_OPENBSD_VERSION)

	return int(sh.size)
}

func addbuildinfo(val string) {
	if !strings.HasPrefix(val, "0x") {
		Exitf("-B argument must start with 0x: %s", val)
	}

	ov := val
	val = val[2:]

	const maxLen = 32
	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
}

// Build info note
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, true)
}

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, true)
}

func elfwritebuildinfo() int {
	sh := elfwritenotehdr(".note.gnu.build-id", ELF_NOTE_BUILDINFO_NAMESZ, uint32(len(buildinfo)), ELF_NOTE_BUILDINFO_TAG)
	if sh == nil {
		return 0
	}

	Cwrite(ELF_NOTE_BUILDINFO_NAME)
	Cwrite(buildinfo)
	var zero = make([]byte, 4)
	Cwrite(zero[:int(Rnd(int64(len(buildinfo)), 4)-int64(len(buildinfo)))])

	return int(sh.size)
}

func elfwritegobuildid() int {
	sh := elfwritenotehdr(".note.go.buildid", uint32(len(ELF_NOTE_GO_NAME)), uint32(len(*flagBuildid)), ELF_NOTE_GOBUILDID_TAG)
	if sh == nil {
		return 0
	}

	Cwrite(ELF_NOTE_GO_NAME)
	Cwrite([]byte(*flagBuildid))
	var zero = make([]byte, 4)
	Cwrite(zero[:int(Rnd(int64(len(*flagBuildid)), 4)-int64(len(*flagBuildid)))])

	return int(sh.size)
}

// Go specific notes
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 !Iself {
		return
	}

	nsym := Nelfsym
	s := ctxt.Syms.Lookup(".hash", 0)
	s.Type = obj.SELFROSECT
	s.Attr |= AttrReachable

	i := nsym
	nbucket := 1
	for i > 0 {
		nbucket++
		i >>= 1
	}

	var needlib *Elflib
	need := make([]*Elfaux, nsym)
	chain := make([]uint32, nsym)
	buckets := make([]uint32, nbucket)

	var b int
	for _, sy := range ctxt.Syms.Allsym {
		if sy.Dynid <= 0 {
			continue
		}

		if sy.Dynimpvers != "" {
			need[sy.Dynid] = addelflib(&needlib, sy.Dynimplib, sy.Dynimpvers)
		}

		name := sy.Extname
		hc := elfhash(name)

		b = int(hc % uint32(nbucket))
		chain[sy.Dynid] = buckets[b]
		buckets[b] = uint32(sy.Dynid)
	}

	// s390x (ELF64) hash table entries are 8 bytes
	if SysArch.Family == sys.S390X {
		Adduint64(ctxt, s, uint64(nbucket))
		Adduint64(ctxt, s, uint64(nsym))
		for i := 0; i < nbucket; i++ {
			Adduint64(ctxt, s, uint64(buckets[i]))
		}
		for i := 0; i < nsym; i++ {
			Adduint64(ctxt, s, uint64(chain[i]))
		}
	} else {
		Adduint32(ctxt, s, uint32(nbucket))
		Adduint32(ctxt, s, uint32(nsym))
		for i := 0; i < nbucket; i++ {
			Adduint32(ctxt, s, buckets[i])
		}
		for i := 0; i < nsym; i++ {
			Adduint32(ctxt, s, chain[i])
		}
	}

	// version symbols
	dynstr := ctxt.Syms.Lookup(".dynstr", 0)

	s = ctxt.Syms.Lookup(".gnu.version_r", 0)
	i = 2
	nfile := 0
	var j int
	var x *Elfaux
	for l := needlib; l != nil; l = l.next {
		nfile++

		// header
		Adduint16(ctxt, s, 1) // table version
		j = 0
		for x = l.aux; x != nil; x = x.next {
			j++
		}
		Adduint16(ctxt, s, uint16(j))                         // aux count
		Adduint32(ctxt, s, uint32(Addstring(dynstr, l.file))) // file string offset
		Adduint32(ctxt, s, 16)                                // offset from header to first aux
		if l.next != nil {
			Adduint32(ctxt, s, 16+uint32(j)*16) // offset from this header to next
		} else {
			Adduint32(ctxt, s, 0)
		}

		for x = l.aux; x != nil; x = x.next {
			x.num = i
			i++

			// aux struct
			Adduint32(ctxt, s, elfhash(x.vers))                   // hash
			Adduint16(ctxt, s, 0)                                 // flags
			Adduint16(ctxt, s, uint16(x.num))                     // other - index we refer to this by
			Adduint32(ctxt, s, uint32(Addstring(dynstr, x.vers))) // version string offset
			if x.next != nil {
				Adduint32(ctxt, s, 16) // offset from this aux to next
			} else {
				Adduint32(ctxt, s, 0)
			}
		}
	}

	// version references
	s = ctxt.Syms.Lookup(".gnu.version", 0)

	for i := 0; i < nsym; i++ {
		if i == 0 {
			Adduint16(ctxt, s, 0) // first entry - no symbol
		} else if need[i] == nil {
			Adduint16(ctxt, s, 1) // global
		} else {
			Adduint16(ctxt, s, uint16(need[i].num))
		}
	}

	s = ctxt.Syms.Lookup(".dynamic", 0)
	elfverneed = nfile
	if elfverneed != 0 {
		elfwritedynentsym(ctxt, s, DT_VERNEED, ctxt.Syms.Lookup(".gnu.version_r", 0))
		Elfwritedynent(ctxt, s, DT_VERNEEDNUM, uint64(nfile))
		elfwritedynentsym(ctxt, s, DT_VERSYM, ctxt.Syms.Lookup(".gnu.version", 0))
	}

	sy := ctxt.Syms.Lookup(elfRelType+".plt", 0)
	if sy.Size > 0 {
		if elfRelType == ".rela" {
			Elfwritedynent(ctxt, s, DT_PLTREL, DT_RELA)
		} else {
			Elfwritedynent(ctxt, s, DT_PLTREL, DT_REL)
		}
		elfwritedynentsymsize(ctxt, s, DT_PLTRELSZ, sy)
		elfwritedynentsym(ctxt, s, DT_JMPREL, sy)
	}

	Elfwritedynent(ctxt, s, DT_NULL, 0)
}

func elfphload(seg *Segment) *ElfPhdr {
	ph := newElfPhdr()
	ph.type_ = PT_LOAD
	if seg.Rwx&4 != 0 {
		ph.flags |= PF_R
	}
	if seg.Rwx&2 != 0 {
		ph.flags |= PF_W
	}
	if seg.Rwx&1 != 0 {
		ph.flags |= 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 *Segment) {
	ph := newElfPhdr()
	ph.type_ = PT_GNU_RELRO
	ph.vaddr = seg.Vaddr
	ph.paddr = seg.Vaddr
	ph.memsz = seg.Length
	ph.off = seg.Fileoff
	ph.filesz = seg.Filelen
	ph.align = uint64(*FlagRound)
}

func elfshname(name string) *ElfShdr {
	var off int
	var sh *ElfShdr

	for i := 0; i < nelfstr; i++ {
		if name == elfstr[i].s {
			off = elfstr[i].off
			for i = 0; i < int(ehdr.shnum); i++ {
				sh = shdr[i]
				if sh.name == uint32(off) {
					return sh
				}
			}

			sh = newElfShdr(int64(off))
			return sh
		}
	}

	Exitf("cannot find elf name %s", name)
	return nil
}

// Create an ElfShdr for the section with name.
// Create a duplicate if one already exists with that name
func elfshnamedup(name string) *ElfShdr {
	var off int
	var sh *ElfShdr

	for i := 0; i < nelfstr; i++ {
		if name == elfstr[i].s {
			off = elfstr[i].off
			sh = newElfShdr(int64(off))
			return sh
		}
	}

	Errorf(nil, "cannot find elf name %s", name)
	errorexit()
	return nil
}

func elfshalloc(sect *Section) *ElfShdr {
	sh := elfshname(sect.Name)
	sect.Elfsect = sh
	return sh
}

func elfshbits(sect *Section) *ElfShdr {
	var sh *ElfShdr

	if sect.Name == ".text" {
		if sect.Elfsect == nil {
			sect.Elfsect = elfshnamedup(sect.Name)
		}
		sh = sect.Elfsect
	} else {
		sh = elfshalloc(sect)
	}

	// If this section has already been set up as a note, we assume type_ and
	// flags are already correct, but the other fields still need filling in.
	if sh.type_ == SHT_NOTE {
		if Linkmode != LinkExternal {
			// TODO(mwhudson): the approach here will work OK when
			// linking internally for notes that we want to be included
			// in a loadable segment (e.g. the abihash note) but not for
			// notes that we do not want to be mapped (e.g. the package
			// list note). The real fix is probably to define new values
			// for Symbol.Type corresponding to mapped and unmapped notes
			// and handle them in dodata().
			Errorf(nil, "sh.type_ == SHT_NOTE in elfshbits when linking internally")
		}
		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 {
		sh.type_ = SHT_PROGBITS
	} else {
		sh.type_ = SHT_NOBITS
	}
	sh.flags = SHF_ALLOC
	if sect.Rwx&1 != 0 {
		sh.flags |= SHF_EXECINSTR
	}
	if sect.Rwx&2 != 0 {
		sh.flags |= SHF_WRITE
	}
	if sect.Name == ".tbss" {
		sh.flags |= SHF_TLS
		sh.type_ = SHT_NOBITS
	}
	if strings.HasPrefix(sect.Name, ".debug") {
		sh.flags = 0
	}

	if Linkmode != LinkExternal {
		sh.addr = sect.Vaddr
	}
	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(sect *Section) *ElfShdr {
	// If main section is SHT_NOBITS, nothing to relocate.
	// Also nothing to relocate in .shstrtab or notes.
	if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
		return nil
	}
	if sect.Name == ".shstrtab" || sect.Name == ".tbss" {
		return nil
	}
	if sect.Elfsect.type_ == SHT_NOTE {
		return nil
	}

	var typ int
	if elfRelType == ".rela" {
		typ = SHT_RELA
	} else {
		typ = SHT_REL
	}

	sh := elfshname(elfRelType + sect.Name)
	// There could be multiple text sections but each needs
	// its own .rela.text.

	if sect.Name == ".text" {
		if sh.info != 0 && sh.info != uint32(sect.Elfsect.shnum) {
			sh = elfshnamedup(elfRelType + sect.Name)
		}
	}

	sh.type_ = uint32(typ)
	sh.entsize = uint64(SysArch.RegSize) * 2
	if typ == SHT_RELA {
		sh.entsize += uint64(SysArch.RegSize)
	}
	sh.link = uint32(elfshname(".symtab").shnum)
	sh.info = uint32(sect.Elfsect.shnum)
	sh.off = sect.Reloff
	sh.size = sect.Rellen
	sh.addralign = uint64(SysArch.RegSize)
	return sh
}

func elfrelocsect(ctxt *Link, sect *Section, syms []*Symbol) {
	// If main section is SHT_NOBITS, nothing to relocate.
	// Also nothing to relocate in .shstrtab.
	if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
		return
	}
	if sect.Name == ".shstrtab" {
		return
	}

	sect.Reloff = uint64(coutbuf.Offset())
	for i, s := range syms {
		if !s.Attr.Reachable() {
			continue
		}
		if uint64(s.Value) >= sect.Vaddr {
			syms = syms[i:]
			break
		}
	}

	eaddr := int32(sect.Vaddr + sect.Length)
	for _, sym := range syms {
		if !sym.Attr.Reachable() {
			continue
		}
		if sym.Value >= int64(eaddr) {
			break
		}
		for ri := 0; ri < len(sym.R); ri++ {
			r := &sym.R[ri]
			if r.Done != 0 {
				continue
			}
			if r.Xsym == nil {
				Errorf(sym, "missing xsym in relocation")
				continue
			}
			if r.Xsym.ElfsymForReloc() == 0 {
				Errorf(sym, "reloc %d to non-elf symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type)
			}
			if !r.Xsym.Attr.Reachable() {
				Errorf(sym, "unreachable reloc %v target %v", r.Type, r.Xsym.Name)
			}
			if Thearch.Elfreloc1(ctxt, r, int64(uint64(sym.Value+int64(r.Off))-sect.Vaddr)) < 0 {
				Errorf(sym, "unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
			}
		}
	}

	sect.Rellen = uint64(coutbuf.Offset()) - sect.Reloff
}

func Elfemitreloc(ctxt *Link) {
	for coutbuf.Offset()&7 != 0 {
		Cput(0)
	}

	for sect := Segtext.Sect; sect != nil; sect = sect.Next {
		if sect.Name == ".text" {
			elfrelocsect(ctxt, sect, ctxt.Textp)
		} else {
			elfrelocsect(ctxt, sect, datap)
		}
	}

	for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
		elfrelocsect(ctxt, sect, datap)
	}
	for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
		elfrelocsect(ctxt, sect, datap)
	}
	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
		elfrelocsect(ctxt, sect, datap)
	}
	for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
		elfrelocsect(ctxt, sect, dwarfp)
	}
}

func addgonote(ctxt *Link, sectionName string, tag uint32, desc []byte) {
	s := ctxt.Syms.Lookup(sectionName, 0)
	s.Attr |= AttrReachable
	s.Type = obj.SELFROSECT
	// namesz
	Adduint32(ctxt, s, uint32(len(ELF_NOTE_GO_NAME)))
	// descsz
	Adduint32(ctxt, s, uint32(len(desc)))
	// tag
	Adduint32(ctxt, s, tag)
	// name + padding
	s.P = append(s.P, ELF_NOTE_GO_NAME...)
	for len(s.P)%4 != 0 {
		s.P = append(s.P, 0)
	}
	// desc + padding
	s.P = append(s.P, desc...)
	for len(s.P)%4 != 0 {
		s.P = append(s.P, 0)
	}
	s.Size = int64(len(s.P))
}

func (ctxt *Link) doelf() {
	if !Iself {
		return
	}

	/* predefine strings we need for section headers */
	shstrtab := ctxt.Syms.Lookup(".shstrtab", 0)

	shstrtab.Type = obj.SELFROSECT
	shstrtab.Attr |= AttrReachable

	Addstring(shstrtab, "")
	Addstring(shstrtab, ".text")
	Addstring(shstrtab, ".noptrdata")
	Addstring(shstrtab, ".data")
	Addstring(shstrtab, ".bss")
	Addstring(shstrtab, ".noptrbss")

	// generate .tbss section (except for OpenBSD where it's not supported)
	// for dynamic internal linker or external linking, so that various
	// binutils could correctly calculate PT_TLS size.
	// see https://golang.org/issue/5200.
	if Headtype != obj.Hopenbsd {
		if !*FlagD || Linkmode == LinkExternal {
			Addstring(shstrtab, ".tbss")
		}
	}
	if Headtype == obj.Hnetbsd {
		Addstring(shstrtab, ".note.netbsd.ident")
	}
	if Headtype == obj.Hopenbsd {
		Addstring(shstrtab, ".note.openbsd.ident")
	}
	if len(buildinfo) > 0 {
		Addstring(shstrtab, ".note.gnu.build-id")
	}
	if *flagBuildid != "" {
		Addstring(shstrtab, ".note.go.buildid")
	}
	Addstring(shstrtab, ".elfdata")
	Addstring(shstrtab, ".rodata")
	// See the comment about data.rel.ro.FOO section names in data.go.
	relro_prefix := ""
	if UseRelro() {
		Addstring(shstrtab, ".data.rel.ro")
		relro_prefix = ".data.rel.ro"
	}
	Addstring(shstrtab, relro_prefix+".typelink")
	Addstring(shstrtab, relro_prefix+".itablink")
	Addstring(shstrtab, relro_prefix+".gosymtab")
	Addstring(shstrtab, relro_prefix+".gopclntab")

	if Linkmode == LinkExternal {
		*FlagD = true

		Addstring(shstrtab, elfRelType+".text")
		Addstring(shstrtab, elfRelType+".rodata")
		Addstring(shstrtab, elfRelType+relro_prefix+".typelink")
		Addstring(shstrtab, elfRelType+relro_prefix+".itablink")
		Addstring(shstrtab, elfRelType+relro_prefix+".gosymtab")
		Addstring(shstrtab, elfRelType+relro_prefix+".gopclntab")
		Addstring(shstrtab, elfRelType+".noptrdata")
		Addstring(shstrtab, elfRelType+".data")
		if UseRelro() {
			Addstring(shstrtab, elfRelType+".data.rel.ro")
		}

		// add a .note.GNU-stack section to mark the stack as non-executable
		Addstring(shstrtab, ".note.GNU-stack")

		if Buildmode == BuildmodeShared {
			Addstring(shstrtab, ".note.go.abihash")
			Addstring(shstrtab, ".note.go.pkg-list")
			Addstring(shstrtab, ".note.go.deps")
		}
	}

	hasinitarr := *FlagLinkshared

	/* shared library initializer */
	switch Buildmode {
	case BuildmodeCArchive, BuildmodeCShared, BuildmodeShared, BuildmodePlugin:
		hasinitarr = true
	}

	if hasinitarr {
		Addstring(shstrtab, ".init_array")
		Addstring(shstrtab, elfRelType+".init_array")
	}

	if !*FlagS {
		Addstring(shstrtab, ".symtab")
		Addstring(shstrtab, ".strtab")
		dwarfaddshstrings(ctxt, shstrtab)
	}

	Addstring(shstrtab, ".shstrtab")

	if !*FlagD { /* -d suppresses dynamic loader format */
		Addstring(shstrtab, ".interp")
		Addstring(shstrtab, ".hash")
		Addstring(shstrtab, ".got")
		if SysArch.Family == sys.PPC64 {
			Addstring(shstrtab, ".glink")
		}
		Addstring(shstrtab, ".got.plt")
		Addstring(shstrtab, ".dynamic")
		Addstring(shstrtab, ".dynsym")
		Addstring(shstrtab, ".dynstr")
		Addstring(shstrtab, elfRelType)
		Addstring(shstrtab, elfRelType+".plt")

		Addstring(shstrtab, ".plt")
		Addstring(shstrtab, ".gnu.version")
		Addstring(shstrtab, ".gnu.version_r")

		/* dynamic symbol table - first entry all zeros */
		s := ctxt.Syms.Lookup(".dynsym", 0)

		s.Type = obj.SELFROSECT
		s.Attr |= AttrReachable
		if elf64 {
			s.Size += ELF64SYMSIZE
		} else {
			s.Size += ELF32SYMSIZE
		}

		/* dynamic string table */
		s = ctxt.Syms.Lookup(".dynstr", 0)

		s.Type = obj.SELFROSECT
		s.Attr |= AttrReachable
		if s.Size == 0 {
			Addstring(s, "")
		}
		dynstr := s

		/* relocation table */
		s = ctxt.Syms.Lookup(elfRelType, 0)
		s.Attr |= AttrReachable
		s.Type = obj.SELFROSECT

		/* global offset table */
		s = ctxt.Syms.Lookup(".got", 0)

		s.Attr |= AttrReachable
		s.Type = obj.SELFGOT // writable

		/* ppc64 glink resolver */
		if SysArch.Family == sys.PPC64 {
			s := ctxt.Syms.Lookup(".glink", 0)
			s.Attr |= AttrReachable
			s.Type = obj.SELFRXSECT
		}

		/* hash */
		s = ctxt.Syms.Lookup(".hash", 0)

		s.Attr |= AttrReachable
		s.Type = obj.SELFROSECT

		s = ctxt.Syms.Lookup(".got.plt", 0)
		s.Attr |= AttrReachable
		s.Type = obj.SELFSECT // writable

		s = ctxt.Syms.Lookup(".plt", 0)

		s.Attr |= AttrReachable
		if SysArch.Family == sys.PPC64 {
			// In the ppc64 ABI, .plt is a data section
			// written by the dynamic linker.
			s.Type = obj.SELFSECT
		} else {
			s.Type = obj.SELFRXSECT
		}

		Thearch.Elfsetupplt(ctxt)

		s = ctxt.Syms.Lookup(elfRelType+".plt", 0)
		s.Attr |= AttrReachable
		s.Type = obj.SELFROSECT

		s = ctxt.Syms.Lookup(".gnu.version", 0)
		s.Attr |= AttrReachable
		s.Type = obj.SELFROSECT

		s = ctxt.Syms.Lookup(".gnu.version_r", 0)
		s.Attr |= AttrReachable
		s.Type = obj.SELFROSECT

		/* define dynamic elf table */
		s = ctxt.Syms.Lookup(".dynamic", 0)

		s.Attr |= AttrReachable
		s.Type = obj.SELFSECT // writable

		/*
		 * .dynamic table
		 */
		elfwritedynentsym(ctxt, s, DT_HASH, ctxt.Syms.Lookup(".hash", 0))

		elfwritedynentsym(ctxt, s, DT_SYMTAB, ctxt.Syms.Lookup(".dynsym", 0))
		if elf64 {
			Elfwritedynent(ctxt, s, DT_SYMENT, ELF64SYMSIZE)
		} else {
			Elfwritedynent(ctxt, s, DT_SYMENT, ELF32SYMSIZE)
		}
		elfwritedynentsym(ctxt, s, DT_STRTAB, ctxt.Syms.Lookup(".dynstr", 0))
		elfwritedynentsymsize(ctxt, s, DT_STRSZ, ctxt.Syms.Lookup(".dynstr", 0))
		if elfRelType == ".rela" {
			elfwritedynentsym(ctxt, s, DT_RELA, ctxt.Syms.Lookup(".rela", 0))
			elfwritedynentsymsize(ctxt, s, DT_RELASZ, ctxt.Syms.Lookup(".rela", 0))
			Elfwritedynent(ctxt, s, DT_RELAENT, ELF64RELASIZE)
		} else {
			elfwritedynentsym(ctxt, s, DT_REL, ctxt.Syms.Lookup(".rel", 0))
			elfwritedynentsymsize(ctxt, s, DT_RELSZ, ctxt.Syms.Lookup(".rel", 0))
			Elfwritedynent(ctxt, s, DT_RELENT, ELF32RELSIZE)
		}

		if rpath.val != "" {
			Elfwritedynent(ctxt, s, DT_RUNPATH, uint64(Addstring(dynstr, rpath.val)))
		}

		if SysArch.Family == sys.PPC64 {
			elfwritedynentsym(ctxt, s, DT_PLTGOT, ctxt.Syms.Lookup(".plt", 0))
		} else if SysArch.Family == sys.S390X {
			elfwritedynentsym(ctxt, s, DT_PLTGOT, ctxt.Syms.Lookup(".got", 0))
		} else {
			elfwritedynentsym(ctxt, s, DT_PLTGOT, ctxt.Syms.Lookup(".got.plt", 0))
		}

		if SysArch.Family == sys.PPC64 {
			Elfwritedynent(ctxt, s, DT_PPC64_OPT, 0)
		}

		// Solaris dynamic linker can't handle an empty .rela.plt if
		// DT_JMPREL is emitted so we have to defer generation of DT_PLTREL,
		// DT_PLTRELSZ, and DT_JMPREL dynamic entries until after we know the
		// size of .rel(a).plt section.
		Elfwritedynent(ctxt, s, DT_DEBUG, 0)
	}

	if Buildmode == BuildmodeShared {
		// The go.link.abihashbytes symbol will be pointed at the appropriate
		// part of the .note.go.abihash section in data.go:func address().
		s := ctxt.Syms.Lookup("go.link.abihashbytes", 0)
		s.Attr |= AttrLocal
		s.Type = obj.SRODATA
		s.Attr |= AttrSpecial
		s.Attr |= AttrReachable
		s.Size = int64(sha1.Size)

		sort.Sort(byPkg(ctxt.Library))
		h := sha1.New()
		for _, l := range ctxt.Library {
			io.WriteString(h, l.hash)
		}
		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 Linkmode == LinkExternal && *flagBuildid != "" {
		addgonote(ctxt, ".note.go.buildid", ELF_NOTE_GOBUILDID_TAG, []byte(*flagBuildid))
	}
}

// Do not write DT_NULL.  elfdynhash will finish it.
func shsym(sh *ElfShdr, s *Symbol) {
	addr := Symaddr(s)
	if sh.flags&SHF_ALLOC != 0 {
		sh.addr = uint64(addr)
	}
	sh.off = uint64(datoff(s, addr))
	sh.size = uint64(s.Size)
}

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() {
	/* This null SHdr must appear before all others */
	elfshname("")

	for sect := Segtext.Sect; sect != nil; sect = sect.Next {
		// There could be multiple .text sections. Instead check the Elfsect
		// field to determine if already has an ElfShdr and if not, create one.
		if sect.Name == ".text" {
			if sect.Elfsect == nil {
				sect.Elfsect = elfshnamedup(sect.Name)
			}
		} else {
			elfshalloc(sect)
		}
	}
	for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
		elfshalloc(sect)
	}
	for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
		elfshalloc(sect)
	}
	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
		elfshalloc(sect)
	}
	for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
		elfshalloc(sect)
	}
}

func Asmbelf(ctxt *Link, symo int64) {
	eh := getElfEhdr()
	switch SysArch.Family {
	default:
		Exitf("unknown architecture in asmbelf: %v", SysArch.Family)
	case sys.MIPS, sys.MIPS64:
		eh.machine = EM_MIPS
	case sys.ARM:
		eh.machine = EM_ARM
	case sys.AMD64:
		eh.machine = EM_X86_64
	case sys.ARM64:
		eh.machine = EM_AARCH64
	case sys.I386:
		eh.machine = EM_386
	case sys.PPC64:
		eh.machine = EM_PPC64
	case sys.S390X:
		eh.machine = EM_S390
	}

	elfreserve := int64(ELFRESERVE)

	numtext := int64(0)
	for sect := Segtext.Sect; sect != nil; sect = sect.Next {
		if sect.Name == ".text" {
			numtext++
		}
	}

	// If there are multiple text sections, extra space is needed
	// in the elfreserve for the additional .text and .rela.text
	// section headers.  It can handle 4 extra now. Headers are
	// 64 bytes.

	if numtext > 4 {
		elfreserve += elfreserve + numtext*64*2
	}

	startva := *FlagTextAddr - int64(HEADR)
	resoff := elfreserve

	var pph *ElfPhdr
	var pnote *ElfPhdr
	if Linkmode == LinkExternal {
		/* skip program headers */
		eh.phoff = 0

		eh.phentsize = 0

		if Buildmode == BuildmodeShared {
			sh := elfshname(".note.go.pkg-list")
			sh.type_ = SHT_NOTE
			sh = elfshname(".note.go.abihash")
			sh.type_ = SHT_NOTE
			sh.flags = SHF_ALLOC
			sh = elfshname(".note.go.deps")
			sh.type_ = SHT_NOTE
		}

		if *flagBuildid != "" {
			sh := elfshname(".note.go.buildid")
			sh.type_ = SHT_NOTE
			sh.flags = SHF_ALLOC
		}

		goto elfobj
	}

	/* program header info */
	pph = newElfPhdr()

	pph.type_ = PT_PHDR
	pph.flags = PF_R
	pph.off = uint64(eh.ehsize)
	pph.vaddr = uint64(*FlagTextAddr) - uint64(HEADR) + pph.off
	pph.paddr = uint64(*FlagTextAddr) - uint64(HEADR) + pph.off
	pph.align = uint64(*FlagRound)

	/*
	 * PHDR must be in a loaded segment. Adjust the text
	 * segment boundaries downwards to include it.
	 * Except on NaCl where it must not be loaded.
	 */
	if Headtype != obj.Hnacl {
		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 { /* -d suppresses dynamic loader format */
		/* interpreter */
		sh := elfshname(".interp")

		sh.type_ = SHT_PROGBITS
		sh.flags = SHF_ALLOC
		sh.addralign = 1
		if interpreter == "" {
			switch Headtype {
			case obj.Hlinux:
				interpreter = Thearch.Linuxdynld

			case obj.Hfreebsd:
				interpreter = Thearch.Freebsddynld

			case obj.Hnetbsd:
				interpreter = Thearch.Netbsddynld

			case obj.Hopenbsd:
				interpreter = Thearch.Openbsddynld

			case obj.Hdragonfly:
				interpreter = Thearch.Dragonflydynld

			case obj.Hsolaris:
				interpreter = Thearch.Solarisdynld
			}
		}

		resoff -= int64(elfinterp(sh, uint64(startva), uint64(resoff), interpreter))

		ph := newElfPhdr()
		ph.type_ = PT_INTERP
		ph.flags = PF_R
		phsh(ph, sh)
	}

	pnote = nil
	if Headtype == obj.Hnetbsd || Headtype == obj.Hopenbsd {
		var sh *ElfShdr
		switch Headtype {
		case obj.Hnetbsd:
			sh = elfshname(".note.netbsd.ident")
			resoff -= int64(elfnetbsdsig(sh, uint64(startva), uint64(resoff)))

		case obj.Hopenbsd:
			sh = elfshname(".note.openbsd.ident")
			resoff -= int64(elfopenbsdsig(sh, uint64(startva), uint64(resoff)))
		}

		pnote = newElfPhdr()
		pnote.type_ = PT_NOTE
		pnote.flags = PF_R
		phsh(pnote, sh)
	}

	if len(buildinfo) > 0 {
		sh := elfshname(".note.gnu.build-id")
		resoff -= int64(elfbuildinfo(sh, uint64(startva), uint64(resoff)))

		if pnote == nil {
			pnote = newElfPhdr()
			pnote.type_ = PT_NOTE
			pnote.flags = PF_R
		}

		phsh(pnote, sh)
	}

	if *flagBuildid != "" {
		sh := elfshname(".note.go.buildid")
		resoff -= int64(elfgobuildid(sh, uint64(startva), uint64(resoff)))

		pnote := newElfPhdr()
		pnote.type_ = PT_NOTE
		pnote.flags = PF_R
		phsh(pnote, sh)
	}

	// Additions to the reserved area must be above this line.

	elfphload(&Segtext)
	if Segrodata.Sect != nil {
		elfphload(&Segrodata)
	}
	if Segrelrodata.Sect != nil {
		elfphload(&Segrelrodata)
		elfphrelro(&Segrelrodata)
	}
	elfphload(&Segdata)

	/* Dynamic linking sections */
	if !*FlagD {
		sh := elfshname(".dynsym")
		sh.type_ = SHT_DYNSYM
		sh.flags = SHF_ALLOC
		if elf64 {
			sh.entsize = ELF64SYMSIZE
		} else {
			sh.entsize = ELF32SYMSIZE
		}
		sh.addralign = uint64(SysArch.RegSize)
		sh.link = uint32(elfshname(".dynstr").shnum)

		// sh->info = index of first non-local symbol (number of local symbols)
		shsym(sh, ctxt.Syms.Lookup(".dynsym", 0))

		sh = elfshname(".dynstr")
		sh.type_ = SHT_STRTAB
		sh.flags = SHF_ALLOC
		sh.addralign = 1
		shsym(sh, ctxt.Syms.Lookup(".dynstr", 0))

		if elfverneed != 0 {
			sh := elfshname(".gnu.version")
			sh.type_ = SHT_GNU_VERSYM
			sh.flags = SHF_ALLOC
			sh.addralign = 2
			sh.link = uint32(elfshname(".dynsym").shnum)
			sh.entsize = 2
			shsym(sh, ctxt.Syms.Lookup(".gnu.version", 0))

			sh = elfshname(".gnu.version_r")
			sh.type_ = SHT_GNU_VERNEED
			sh.flags = SHF_ALLOC
			sh.addralign = uint64(SysArch.RegSize)
			sh.info = uint32(elfverneed)
			sh.link = uint32(elfshname(".dynstr").shnum)
			shsym(sh, ctxt.Syms.Lookup(".gnu.version_r", 0))
		}

		if elfRelType == ".rela" {
			sh := elfshname(".rela.plt")
			sh.type_ = SHT_RELA
			sh.flags = SHF_ALLOC
			sh.entsize = ELF64RELASIZE
			sh.addralign = uint64(SysArch.RegSize)
			sh.link = uint32(elfshname(".dynsym").shnum)
			sh.info = uint32(elfshname(".plt").shnum)
			shsym(sh, ctxt.Syms.Lookup(".rela.plt", 0))

			sh = elfshname(".rela")
			sh.type_ = SHT_RELA
			sh.flags = SHF_ALLOC
			sh.entsize = ELF64RELASIZE
			sh.addralign = 8
			sh.link = uint32(elfshname(".dynsym").shnum)
			shsym(sh, ctxt.Syms.Lookup(".rela", 0))
		} else {
			sh := elfshname(".rel.plt")
			sh.type_ = SHT_REL
			sh.flags = SHF_ALLOC
			sh.entsize = ELF32RELSIZE
			sh.addralign = 4
			sh.link = uint32(elfshname(".dynsym").shnum)
			shsym(sh, ctxt.Syms.Lookup(".rel.plt", 0))

			sh = elfshname(".rel")
			sh.type_ = SHT_REL
			sh.flags = SHF_ALLOC
			sh.entsize = ELF32RELSIZE
			sh.addralign = 4
			sh.link = uint32(elfshname(".dynsym").shnum)
			shsym(sh, ctxt.Syms.Lookup(".rel", 0))
		}

		if eh.machine == EM_PPC64 {
			sh := elfshname(".glink")
			sh.type_ = SHT_PROGBITS
			sh.flags = SHF_ALLOC + SHF_EXECINSTR
			sh.addralign = 4
			shsym(sh, ctxt.Syms.Lookup(".glink", 0))
		}

		sh = elfshname(".plt")
		sh.type_ = SHT_PROGBITS
		sh.flags = SHF_ALLOC + SHF_EXECINSTR
		if eh.machine == EM_X86_64 {
			sh.entsize = 16
		} else if eh.machine == EM_S390 {
			sh.entsize = 32
		} else if eh.machine == EM_PPC64 {
			// On ppc64, this is just a table of addresses
			// filled by the dynamic linker
			sh.type_ = SHT_NOBITS

			sh.flags = SHF_ALLOC + SHF_WRITE
			sh.entsize = 8
		} else {
			sh.entsize = 4
		}
		sh.addralign = sh.entsize
		shsym(sh, ctxt.Syms.Lookup(".plt", 0))

		// On ppc64, .got comes from the input files, so don't
		// create it here, and .got.plt is not used.
		if eh.machine != EM_PPC64 {
			sh := elfshname(".got")
			sh.type_ = SHT_PROGBITS
			sh.flags = SHF_ALLOC + SHF_WRITE
			sh.entsize = uint64(SysArch.RegSize)
			sh.addralign = uint64(SysArch.RegSize)
			shsym(sh, ctxt.Syms.Lookup(".got", 0))

			sh = elfshname(".got.plt")
			sh.type_ = SHT_PROGBITS
			sh.flags = SHF_ALLOC + SHF_WRITE
			sh.entsize = uint64(SysArch.RegSize)
			sh.addralign = uint64(SysArch.RegSize)
			shsym(sh, ctxt.Syms.Lookup(".got.plt", 0))
		}

		sh = elfshname(".hash")
		sh.type_ = SHT_HASH
		sh.flags = SHF_ALLOC
		sh.entsize = 4
		sh.addralign = uint64(SysArch.RegSize)
		sh.link = uint32(elfshname(".dynsym").shnum)
		shsym(sh, ctxt.Syms.Lookup(".hash", 0))

		/* sh and PT_DYNAMIC for .dynamic section */
		sh = elfshname(".dynamic")

		sh.type_ = SHT_DYNAMIC
		sh.flags = SHF_ALLOC + SHF_WRITE
		sh.entsize = 2 * uint64(SysArch.RegSize)
		sh.addralign = uint64(SysArch.RegSize)
		sh.link = uint32(elfshname(".dynstr").shnum)
		shsym(sh, ctxt.Syms.Lookup(".dynamic", 0))
		ph := newElfPhdr()
		ph.type_ = PT_DYNAMIC
		ph.flags = PF_R + PF_W
		phsh(ph, sh)

		/*
		 * Thread-local storage segment (really just size).
		 */
		// Do not emit PT_TLS for OpenBSD since ld.so(1) does
		// not currently support it. This is handled
		// appropriately in runtime/cgo.
		if Headtype != obj.Hopenbsd {
			tlssize := uint64(0)
			for sect := Segdata.Sect; sect != nil; sect = sect.Next {
				if sect.Name == ".tbss" {
					tlssize = sect.Length
				}
			}
			if tlssize != 0 {
				ph := newElfPhdr()
				ph.type_ = PT_TLS
				ph.flags = PF_R
				ph.memsz = tlssize
				ph.align = uint64(SysArch.RegSize)
			}
		}
	}

	if Headtype == obj.Hlinux {
		ph := newElfPhdr()
		ph.type_ = PT_GNU_STACK
		ph.flags = PF_W + PF_R
		ph.align = uint64(SysArch.RegSize)

		ph = newElfPhdr()
		ph.type_ = PT_PAX_FLAGS
		ph.flags = 0x2a00 // mprotect, randexec, emutramp disabled
		ph.align = uint64(SysArch.RegSize)
	} else if Headtype == obj.Hsolaris {
		ph := newElfPhdr()
		ph.type_ = PT_SUNWSTACK
		ph.flags = PF_W + PF_R
	}

elfobj:
	sh := elfshname(".shstrtab")
	sh.type_ = SHT_STRTAB
	sh.addralign = 1
	shsym(sh, ctxt.Syms.Lookup(".shstrtab", 0))
	eh.shstrndx = uint16(sh.shnum)

	// put these sections early in the list
	if !*FlagS {
		elfshname(".symtab")
		elfshname(".strtab")
	}

	for sect := Segtext.Sect; sect != nil; sect = sect.Next {
		elfshbits(sect)
	}
	for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
		elfshbits(sect)
	}
	for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
		elfshbits(sect)
	}
	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
		elfshbits(sect)
	}
	for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
		elfshbits(sect)
	}

	if Linkmode == LinkExternal {
		for sect := Segtext.Sect; sect != nil; sect = sect.Next {
			elfshreloc(sect)
		}
		for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
			elfshreloc(sect)
		}
		for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
			elfshreloc(sect)
		}
		for sect := Segdata.Sect; sect != nil; sect = sect.Next {
			elfshreloc(sect)
		}
		for _, s := range dwarfp {
			if len(s.R) > 0 || s.Type == obj.SDWARFINFO {
				elfshreloc(s.Sect)
			}
			if s.Type == obj.SDWARFINFO {
				break
			}
		}
		// add a .note.GNU-stack section to mark the stack as non-executable
		sh := elfshname(".note.GNU-stack")

		sh.type_ = SHT_PROGBITS
		sh.addralign = 1
		sh.flags = 0
	}

	if !*FlagS {
		sh := elfshname(".symtab")
		sh.type_ = SHT_SYMTAB
		sh.off = uint64(symo)
		sh.size = uint64(Symsize)
		sh.addralign = uint64(SysArch.RegSize)
		sh.entsize = 8 + 2*uint64(SysArch.RegSize)
		sh.link = uint32(elfshname(".strtab").shnum)
		sh.info = uint32(elfglobalsymndx)

		sh = elfshname(".strtab")
		sh.type_ = SHT_STRTAB
		sh.off = uint64(symo) + uint64(Symsize)
		sh.size = uint64(len(Elfstrdat))
		sh.addralign = 1
	}

	/* Main header */
	eh.ident[EI_MAG0] = '\177'

	eh.ident[EI_MAG1] = 'E'
	eh.ident[EI_MAG2] = 'L'
	eh.ident[EI_MAG3] = 'F'
	if Headtype == obj.Hfreebsd {
		eh.ident[EI_OSABI] = ELFOSABI_FREEBSD
	} else if Headtype == obj.Hnetbsd {
		eh.ident[EI_OSABI] = ELFOSABI_NETBSD
	} else if Headtype == obj.Hopenbsd {
		eh.ident[EI_OSABI] = ELFOSABI_OPENBSD
	} else if Headtype == obj.Hdragonfly {
		eh.ident[EI_OSABI] = ELFOSABI_NONE
	}
	if elf64 {
		eh.ident[EI_CLASS] = ELFCLASS64
	} else {
		eh.ident[EI_CLASS] = ELFCLASS32
	}
	if ctxt.Arch.ByteOrder == binary.BigEndian {
		eh.ident[EI_DATA] = ELFDATA2MSB
	} else {
		eh.ident[EI_DATA] = ELFDATA2LSB
	}
	eh.ident[EI_VERSION] = EV_CURRENT

	if Linkmode == LinkExternal {
		eh.type_ = ET_REL
	} else if Buildmode == BuildmodePIE {
		eh.type_ = ET_DYN
	} else {
		eh.type_ = ET_EXEC
	}

	if Linkmode != LinkExternal {
		eh.entry = uint64(Entryvalue(ctxt))
	}

	eh.version = EV_CURRENT

	if pph != nil {
		pph.filesz = uint64(eh.phnum) * uint64(eh.phentsize)
		pph.memsz = pph.filesz
	}

	Cseek(0)
	a := int64(0)
	a += int64(elfwritehdr())
	a += int64(elfwritephdrs())
	a += int64(elfwriteshdrs())
	if !*FlagD {
		a += int64(elfwriteinterp())
	}
	if Linkmode != LinkExternal {
		if Headtype == obj.Hnetbsd {
			a += int64(elfwritenetbsdsig())
		}
		if Headtype == obj.Hopenbsd {
			a += int64(elfwriteopenbsdsig())
		}
		if len(buildinfo) > 0 {
			a += int64(elfwritebuildinfo())
		}
		if *flagBuildid != "" {
			a += int64(elfwritegobuildid())
		}
	}

	if a > elfreserve {
		Errorf(nil, "ELFRESERVE too small: %d > %d with %d text sections", a, elfreserve, numtext)
	}
}

func Elfadddynsym(ctxt *Link, s *Symbol) {
	if elf64 {
		s.Dynid = int32(Nelfsym)
		Nelfsym++

		d := ctxt.Syms.Lookup(".dynsym", 0)

		name := s.Extname
		Adduint32(ctxt, d, uint32(Addstring(ctxt.Syms.Lookup(".dynstr", 0), name)))

		/* type */
		t := STB_GLOBAL << 4

		if s.Attr.CgoExport() && s.Type&obj.SMASK == obj.STEXT {
			t |= STT_FUNC
		} else {
			t |= STT_OBJECT
		}
		Adduint8(ctxt, d, uint8(t))

		/* reserved */
		Adduint8(ctxt, d, 0)

		/* section where symbol is defined */
		if s.Type == obj.SDYNIMPORT {
			Adduint16(ctxt, d, SHN_UNDEF)
		} else {
			Adduint16(ctxt, d, 1)
		}

		/* value */
		if s.Type == obj.SDYNIMPORT {
			Adduint64(ctxt, d, 0)
		} else {
			Addaddr(ctxt, d, s)
		}

		/* size of object */
		Adduint64(ctxt, d, uint64(s.Size))

		if SysArch.Family == sys.AMD64 && !s.Attr.CgoExportDynamic() && s.Dynimplib != "" && !seenlib[s.Dynimplib] {
			Elfwritedynent(ctxt, ctxt.Syms.Lookup(".dynamic", 0), DT_NEEDED, uint64(Addstring(ctxt.Syms.Lookup(".dynstr", 0), s.Dynimplib)))
		}
	} else {
		s.Dynid = int32(Nelfsym)
		Nelfsym++

		d := ctxt.Syms.Lookup(".dynsym", 0)

		/* name */
		name := s.Extname

		Adduint32(ctxt, d, uint32(Addstring(ctxt.Syms.Lookup(".dynstr", 0), name)))

		/* value */
		if s.Type == obj.SDYNIMPORT {
			Adduint32(ctxt, d, 0)
		} else {
			Addaddr(ctxt, d, s)
		}

		/* size of object */
		Adduint32(ctxt, d, uint32(s.Size))

		/* type */
		t := STB_GLOBAL << 4

		// TODO(mwhudson): presumably the behavior should actually be the same on both arm and 386.
		if SysArch.Family == sys.I386 && s.Attr.CgoExport() && s.Type&obj.SMASK == obj.STEXT {
			t |= STT_FUNC
		} else if SysArch.Family == sys.ARM && s.Attr.CgoExportDynamic() && s.Type&obj.SMASK == obj.STEXT {
			t |= STT_FUNC
		} else {
			t |= STT_OBJECT
		}
		Adduint8(ctxt, d, uint8(t))
		Adduint8(ctxt, d, 0)

		/* shndx */
		if s.Type == obj.SDYNIMPORT {
			Adduint16(ctxt, d, SHN_UNDEF)
		} else {
			Adduint16(ctxt, d, 1)
		}
	}
}

func ELF32_R_SYM(info uint32) uint32 {
	return info >> 8
}

func ELF32_R_TYPE(info uint32) uint32 {
	return uint32(uint8(info))
}

func ELF32_R_INFO(sym uint32, type_ uint32) uint32 {
	return sym<<8 | type_
}

func ELF32_ST_BIND(info uint8) uint8 {
	return info >> 4
}

func ELF32_ST_TYPE(info uint8) uint8 {
	return info & 0xf
}

func ELF32_ST_INFO(bind uint8, type_ uint8) uint8 {
	return bind<<4 | type_&0xf
}

func ELF32_ST_VISIBILITY(oth uint8) uint8 {
	return oth & 3
}

func ELF64_R_SYM(info uint64) uint32 {
	return uint32(info >> 32)
}

func ELF64_R_TYPE(info uint64) uint32 {
	return uint32(info)
}

func ELF64_R_INFO(sym uint32, type_ uint32) uint64 {
	return uint64(sym)<<32 | uint64(type_)
}

func ELF64_ST_BIND(info uint8) uint8 {
	return info >> 4
}

func ELF64_ST_TYPE(info uint8) uint8 {
	return info & 0xf
}

func ELF64_ST_INFO(bind uint8, type_ uint8) uint8 {
	return bind<<4 | type_&0xf
}

func ELF64_ST_VISIBILITY(oth uint8) uint8 {
	return oth & 3
}
