// 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 }