X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf32-ppc.c;h=e808cb523f53d12eec082d82862b015ebf78d141;hb=46a2d504dd875caf60f9be191a55c9ff676bcd5c;hp=ca6df26e59e4b153446c379f347265d94c86e0a7;hpb=dbaa2011452c7ce7ca612c6298964452dce179eb;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index ca6df26e59..e808cb523f 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -1,7 +1,5 @@ /* PowerPC-specific support for 32-bit ELF - Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 - Free Software Foundation, Inc. + Copyright (C) 1994-2016 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support. This file is part of BFD, the Binary File Descriptor library. @@ -38,6 +36,13 @@ #include "elf-vxworks.h" #include "dwarf2.h" +typedef enum split16_format_type +{ + split16a_type = 0, + split16d_type +} +split16_format_type; + /* RELA relocations are used here. */ static bfd_reloc_status_type ppc_elf_addr16_ha_reloc @@ -141,6 +146,7 @@ static const bfd_vma ppc_elf_vxworks_pic_plt0_entry #define ADD_3_12_2 0x7c6c1214 #define ADD_11_0_11 0x7d605a14 #define B 0x48000000 +#define BA 0x48000002 #define BCL_20_31 0x429f0005 #define BCTR 0x4e800420 #define BEQLR 0x4d820020 @@ -180,11 +186,11 @@ static reloc_howto_type ppc_elf_howto_raw[] = { /* This reloc does nothing. */ HOWTO (R_PPC_NONE, /* type */ 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ + 3, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC_NONE", /* name */ FALSE, /* partial_inplace */ @@ -199,7 +205,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 32, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC_ADDR32", /* name */ FALSE, /* partial_inplace */ @@ -215,7 +221,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 26, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC_ADDR24", /* name */ FALSE, /* partial_inplace */ @@ -292,7 +298,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC_ADDR14", /* name */ FALSE, /* partial_inplace */ @@ -309,7 +315,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC_ADDR14_BRTAKEN",/* name */ FALSE, /* partial_inplace */ @@ -326,7 +332,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC_ADDR14_BRNTAKEN",/* name */ FALSE, /* partial_inplace */ @@ -407,7 +413,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_GOT16", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -423,7 +429,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_GOT16_LO", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -438,8 +444,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_GOT16_HI", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -454,8 +460,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - ppc_elf_addr16_ha_reloc, /* special_function */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_GOT16_HA", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -470,8 +476,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 26, /* bitsize */ TRUE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + complain_overflow_signed, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_PLTREL24", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -489,8 +495,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 32, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_COPY", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -505,8 +511,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 32, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_GLOB_DAT", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -520,8 +526,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 32, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_JMP_SLOT", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -537,7 +543,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 32, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC_RELATIVE", /* name */ FALSE, /* partial_inplace */ @@ -569,7 +575,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 32, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC_UADDR32", /* name */ FALSE, /* partial_inplace */ @@ -599,7 +605,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 32, /* bitsize */ TRUE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC_REL32", /* name */ FALSE, /* partial_inplace */ @@ -615,8 +621,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 32, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_PLT32", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -631,8 +637,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 32, /* bitsize */ TRUE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_PLTREL32", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -648,7 +654,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_PLT16_LO", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -663,8 +669,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_PLT16_HI", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -679,8 +685,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - ppc_elf_addr16_ha_reloc, /* special_function */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_PLT16_HA", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -696,7 +702,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_SDAREL16", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -710,8 +716,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + complain_overflow_signed, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_SECTOFF", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -726,7 +732,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_SECTOFF_LO", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -740,8 +746,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_SECTOFF_HI", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -755,8 +761,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - ppc_elf_addr16_ha_reloc, /* special_function */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_SECTOFF_HA", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -1231,8 +1237,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 32, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_EMB_NADDR32", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -1246,8 +1252,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + complain_overflow_signed, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_EMB_NADDR16", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -1262,7 +1268,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_EMB_ADDR16_LO", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -1277,7 +1283,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_EMB_NADDR16_HI", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -1294,7 +1300,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_addr16_ha_reloc, /* special_function */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_EMB_NADDR16_HA", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -1311,7 +1317,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_EMB_SDAI16", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -1328,7 +1334,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_EMB_SDA2I16", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -1344,7 +1350,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_EMB_SDA2REL", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -1361,7 +1367,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_EMB_SDA21", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ @@ -1385,139 +1391,461 @@ static reloc_howto_type ppc_elf_howto_raw[] = { FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ + ppc_elf_unhandled_reloc, /* special_function */ "R_PPC_EMB_RELSDA", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ 0xffff, /* dst_mask */ FALSE), /* pcrel_offset */ - HOWTO (R_PPC_IRELATIVE, /* type */ + /* A relative 8 bit branch. */ + HOWTO (R_PPC_VLE_REL8, /* type */ + 1, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_VLE_REL8", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* A relative 15 bit branch. */ + HOWTO (R_PPC_VLE_REL15, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 15, /* bitsize */ + TRUE, /* pc_relative */ + 1, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_VLE_REL15", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xfffe, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* A relative 24 bit branch. */ + HOWTO (R_PPC_VLE_REL24, /* type */ + 1, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 24, /* bitsize */ + TRUE, /* pc_relative */ + 1, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_VLE_REL24", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x1fffffe, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* The 16 LSBS in split16a format. */ + HOWTO (R_PPC_VLE_LO16A, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ + 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_IRELATIVE", /* name */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ + "R_PPC_VLE_LO16A", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - 0xffffffff, /* dst_mask */ + 0x1f007ff, /* dst_mask */ FALSE), /* pcrel_offset */ - /* A 16 bit relative relocation. */ - HOWTO (R_PPC_REL16, /* type */ + /* The 16 LSBS in split16d format. */ + HOWTO (R_PPC_VLE_LO16D, /* type */ 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ - TRUE, /* pc_relative */ + FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_REL16", /* name */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ + "R_PPC_VLE_LO16D", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ + 0x1f07ff, /* dst_mask */ + FALSE), /* pcrel_offset */ - /* A 16 bit relative relocation without overflow. */ - HOWTO (R_PPC_REL16_LO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ + /* Bits 16-31 split16a format. */ + HOWTO (R_PPC_VLE_HI16A, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ - TRUE, /* pc_relative */ + FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_REL16_LO", /* name */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ + "R_PPC_VLE_HI16A", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ + 0x1f007ff, /* dst_mask */ + FALSE), /* pcrel_offset */ - /* The high order 16 bits of a relative address. */ - HOWTO (R_PPC_REL16_HI, /* type */ + /* Bits 16-31 split16d format. */ + HOWTO (R_PPC_VLE_HI16D, /* type */ 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ - TRUE, /* pc_relative */ + FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_REL16_HI", /* name */ + ppc_elf_unhandled_reloc, /* special_function */ + "R_PPC_VLE_HI16D", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ + 0x1f07ff, /* dst_mask */ + FALSE), /* pcrel_offset */ - /* The high order 16 bits of a relative address, plus 1 if the contents of - the low 16 bits, treated as a signed number, is negative. */ - HOWTO (R_PPC_REL16_HA, /* type */ + /* Bits 16-31 (High Adjusted) in split16a format. */ + HOWTO (R_PPC_VLE_HA16A, /* type */ 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ - TRUE, /* pc_relative */ + FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_addr16_ha_reloc, /* special_function */ - "R_PPC_REL16_HA", /* name */ + ppc_elf_unhandled_reloc, /* special_function */ + "R_PPC_VLE_HA16A", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x1f007ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Bits 16-31 (High Adjusted) in split16d format. */ + HOWTO (R_PPC_VLE_HA16D, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ + "R_PPC_VLE_HA16D", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x1f07ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* This reloc is like R_PPC_EMB_SDA21 but only applies to e_add16i + instructions. If the register base is 0 then the linker changes + the e_add16i to an e_li instruction. */ + HOWTO (R_PPC_VLE_SDA21, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ + "R_PPC_VLE_SDA21", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ + FALSE), /* pcrel_offset */ - /* GNU extension to record C++ vtable hierarchy. */ - HOWTO (R_PPC_GNU_VTINHERIT, /* type */ + /* Like R_PPC_VLE_SDA21 but ignore overflow. */ + HOWTO (R_PPC_VLE_SDA21_LO, /* type */ 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - NULL, /* special_function */ - "R_PPC_GNU_VTINHERIT", /* name */ + ppc_elf_unhandled_reloc, /* special_function */ + "R_PPC_VLE_SDA21_LO", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - 0, /* dst_mask */ + 0xffff, /* dst_mask */ FALSE), /* pcrel_offset */ - /* GNU extension to record C++ vtable member usage. */ - HOWTO (R_PPC_GNU_VTENTRY, /* type */ + /* The 16 LSBS relative to _SDA_BASE_ in split16a format. */ + HOWTO (R_PPC_VLE_SDAREL_LO16A,/* type */ 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - NULL, /* special_function */ - "R_PPC_GNU_VTENTRY", /* name */ + ppc_elf_unhandled_reloc, /* special_function */ + "R_PPC_VLE_SDAREL_LO16A", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - 0, /* dst_mask */ + 0x1f007ff, /* dst_mask */ FALSE), /* pcrel_offset */ - /* Phony reloc to handle AIX style TOC entries. */ - HOWTO (R_PPC_TOC16, /* type */ + /* The 16 LSBS relative to _SDA_BASE_ in split16d format. */ + HOWTO (R_PPC_VLE_SDAREL_LO16D, /* type */ 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_TOC16", /* name */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ + "R_PPC_VLE_SDAREL_LO16D", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - 0xffff, /* dst_mask */ + 0x1f07ff, /* dst_mask */ FALSE), /* pcrel_offset */ -}; - -/* Initialize the ppc_elf_howto_table, so that linear accesses can be done. */ -static void -ppc_elf_howto_init (void) -{ + /* Bits 16-31 relative to _SDA_BASE_ in split16a format. */ + HOWTO (R_PPC_VLE_SDAREL_HI16A, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ + "R_PPC_VLE_SDAREL_HI16A", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x1f007ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Bits 16-31 relative to _SDA_BASE_ in split16d format. */ + HOWTO (R_PPC_VLE_SDAREL_HI16D, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ + "R_PPC_VLE_SDAREL_HI16D", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x1f07ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Bits 16-31 (HA) relative to _SDA_BASE split16a format. */ + HOWTO (R_PPC_VLE_SDAREL_HA16A, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ + "R_PPC_VLE_SDAREL_HA16A", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x1f007ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Bits 16-31 (HA) relative to _SDA_BASE split16d format. */ + HOWTO (R_PPC_VLE_SDAREL_HA16D, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ + "R_PPC_VLE_SDAREL_HA16D", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x1f07ff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + HOWTO (R_PPC_IRELATIVE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ + "R_PPC_IRELATIVE", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* A 16 bit relative relocation. */ + HOWTO (R_PPC_REL16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_REL16", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* A 16 bit relative relocation without overflow. */ + HOWTO (R_PPC_REL16_LO, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_REL16_LO", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* The high order 16 bits of a relative address. */ + HOWTO (R_PPC_REL16_HI, /* type */ + 16, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_REL16_HI", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* The high order 16 bits of a relative address, plus 1 if the contents of + the low 16 bits, treated as a signed number, is negative. */ + HOWTO (R_PPC_REL16_HA, /* type */ + 16, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_addr16_ha_reloc, /* special_function */ + "R_PPC_REL16_HA", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* Like R_PPC_REL16_HA but for split field in addpcis. */ + HOWTO (R_PPC_REL16DX_HA, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + ppc_elf_addr16_ha_reloc, /* special_function */ + "R_PPC_REL16DX_HA", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x1fffc1, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* GNU extension to record C++ vtable hierarchy. */ + HOWTO (R_PPC_GNU_VTINHERIT, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + NULL, /* special_function */ + "R_PPC_GNU_VTINHERIT", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* GNU extension to record C++ vtable member usage. */ + HOWTO (R_PPC_GNU_VTENTRY, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + NULL, /* special_function */ + "R_PPC_GNU_VTENTRY", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* Phony reloc to handle AIX style TOC entries. */ + HOWTO (R_PPC_TOC16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + ppc_elf_unhandled_reloc, /* special_function */ + "R_PPC_TOC16", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ +}; + +/* External 32-bit PPC structure for PRPSINFO. This structure is + ABI-defined, thus we choose to use char arrays here in order to + avoid dealing with different types in different architectures. + + The PPC 32-bit structure uses int for `pr_uid' and `pr_gid' while + most non-PPC architectures use `short int'. + + This structure will ultimately be written in the corefile's note + section, as the PRPSINFO. */ + +struct elf_external_ppc_linux_prpsinfo32 + { + char pr_state; /* Numeric process state. */ + char pr_sname; /* Char for pr_state. */ + char pr_zomb; /* Zombie. */ + char pr_nice; /* Nice val. */ + char pr_flag[4]; /* Flags. */ + char pr_uid[4]; + char pr_gid[4]; + char pr_pid[4]; + char pr_ppid[4]; + char pr_pgrp[4]; + char pr_sid[4]; + char pr_fname[16]; /* Filename of executable. */ + char pr_psargs[80]; /* Initial part of arg list. */ + }; + +/* Helper function to copy an elf_internal_linux_prpsinfo in host + endian to an elf_external_ppc_linux_prpsinfo32 in target endian. */ + +static inline void +swap_ppc_linux_prpsinfo32_out (bfd *obfd, + const struct elf_internal_linux_prpsinfo *from, + struct elf_external_ppc_linux_prpsinfo32 *to) +{ + bfd_put_8 (obfd, from->pr_state, &to->pr_state); + bfd_put_8 (obfd, from->pr_sname, &to->pr_sname); + bfd_put_8 (obfd, from->pr_zomb, &to->pr_zomb); + bfd_put_8 (obfd, from->pr_nice, &to->pr_nice); + bfd_put_32 (obfd, from->pr_flag, to->pr_flag); + bfd_put_32 (obfd, from->pr_uid, to->pr_uid); + bfd_put_32 (obfd, from->pr_gid, to->pr_gid); + bfd_put_32 (obfd, from->pr_pid, to->pr_pid); + bfd_put_32 (obfd, from->pr_ppid, to->pr_ppid); + bfd_put_32 (obfd, from->pr_pgrp, to->pr_pgrp); + bfd_put_32 (obfd, from->pr_sid, to->pr_sid); + strncpy (to->pr_fname, from->pr_fname, sizeof (to->pr_fname)); + strncpy (to->pr_psargs, from->pr_psargs, sizeof (to->pr_psargs)); +} + +/* Initialize the ppc_elf_howto_table, so that linear accesses can be done. */ + +static void +ppc_elf_howto_init (void) +{ unsigned int i, type; for (i = 0; @@ -1550,7 +1878,9 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, case BFD_RELOC_NONE: r = R_PPC_NONE; break; case BFD_RELOC_32: r = R_PPC_ADDR32; break; case BFD_RELOC_PPC_BA26: r = R_PPC_ADDR24; break; + case BFD_RELOC_PPC64_ADDR16_DS: case BFD_RELOC_16: r = R_PPC_ADDR16; break; + case BFD_RELOC_PPC64_ADDR16_LO_DS: case BFD_RELOC_LO16: r = R_PPC_ADDR16_LO; break; case BFD_RELOC_HI16: r = R_PPC_ADDR16_HI; break; case BFD_RELOC_HI16_S: r = R_PPC_ADDR16_HA; break; @@ -1561,7 +1891,9 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, case BFD_RELOC_PPC_B16: r = R_PPC_REL14; break; case BFD_RELOC_PPC_B16_BRTAKEN: r = R_PPC_REL14_BRTAKEN; break; case BFD_RELOC_PPC_B16_BRNTAKEN: r = R_PPC_REL14_BRNTAKEN; break; + case BFD_RELOC_PPC64_GOT16_DS: case BFD_RELOC_16_GOTOFF: r = R_PPC_GOT16; break; + case BFD_RELOC_PPC64_GOT16_LO_DS: case BFD_RELOC_LO16_GOTOFF: r = R_PPC_GOT16_LO; break; case BFD_RELOC_HI16_GOTOFF: r = R_PPC_GOT16_HI; break; case BFD_RELOC_HI16_S_GOTOFF: r = R_PPC_GOT16_HA; break; @@ -1572,26 +1904,34 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, case BFD_RELOC_32_PCREL: r = R_PPC_REL32; break; case BFD_RELOC_32_PLTOFF: r = R_PPC_PLT32; break; case BFD_RELOC_32_PLT_PCREL: r = R_PPC_PLTREL32; break; + case BFD_RELOC_PPC64_PLT16_LO_DS: case BFD_RELOC_LO16_PLTOFF: r = R_PPC_PLT16_LO; break; case BFD_RELOC_HI16_PLTOFF: r = R_PPC_PLT16_HI; break; case BFD_RELOC_HI16_S_PLTOFF: r = R_PPC_PLT16_HA; break; case BFD_RELOC_GPREL16: r = R_PPC_SDAREL16; break; + case BFD_RELOC_PPC64_SECTOFF_DS: case BFD_RELOC_16_BASEREL: r = R_PPC_SECTOFF; break; + case BFD_RELOC_PPC64_SECTOFF_LO_DS: case BFD_RELOC_LO16_BASEREL: r = R_PPC_SECTOFF_LO; break; case BFD_RELOC_HI16_BASEREL: r = R_PPC_SECTOFF_HI; break; case BFD_RELOC_HI16_S_BASEREL: r = R_PPC_SECTOFF_HA; break; case BFD_RELOC_CTOR: r = R_PPC_ADDR32; break; + case BFD_RELOC_PPC64_TOC16_DS: case BFD_RELOC_PPC_TOC16: r = R_PPC_TOC16; break; case BFD_RELOC_PPC_TLS: r = R_PPC_TLS; break; case BFD_RELOC_PPC_TLSGD: r = R_PPC_TLSGD; break; case BFD_RELOC_PPC_TLSLD: r = R_PPC_TLSLD; break; case BFD_RELOC_PPC_DTPMOD: r = R_PPC_DTPMOD32; break; + case BFD_RELOC_PPC64_TPREL16_DS: case BFD_RELOC_PPC_TPREL16: r = R_PPC_TPREL16; break; + case BFD_RELOC_PPC64_TPREL16_LO_DS: case BFD_RELOC_PPC_TPREL16_LO: r = R_PPC_TPREL16_LO; break; case BFD_RELOC_PPC_TPREL16_HI: r = R_PPC_TPREL16_HI; break; case BFD_RELOC_PPC_TPREL16_HA: r = R_PPC_TPREL16_HA; break; case BFD_RELOC_PPC_TPREL: r = R_PPC_TPREL32; break; + case BFD_RELOC_PPC64_DTPREL16_DS: case BFD_RELOC_PPC_DTPREL16: r = R_PPC_DTPREL16; break; + case BFD_RELOC_PPC64_DTPREL16_LO_DS: case BFD_RELOC_PPC_DTPREL16_LO: r = R_PPC_DTPREL16_LO; break; case BFD_RELOC_PPC_DTPREL16_HI: r = R_PPC_DTPREL16_HI; break; case BFD_RELOC_PPC_DTPREL16_HA: r = R_PPC_DTPREL16_HA; break; @@ -1628,10 +1968,40 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, case BFD_RELOC_PPC_EMB_RELST_HA: r = R_PPC_EMB_RELST_HA; break; case BFD_RELOC_PPC_EMB_BIT_FLD: r = R_PPC_EMB_BIT_FLD; break; case BFD_RELOC_PPC_EMB_RELSDA: r = R_PPC_EMB_RELSDA; break; + case BFD_RELOC_PPC_VLE_REL8: r = R_PPC_VLE_REL8; break; + case BFD_RELOC_PPC_VLE_REL15: r = R_PPC_VLE_REL15; break; + case BFD_RELOC_PPC_VLE_REL24: r = R_PPC_VLE_REL24; break; + case BFD_RELOC_PPC_VLE_LO16A: r = R_PPC_VLE_LO16A; break; + case BFD_RELOC_PPC_VLE_LO16D: r = R_PPC_VLE_LO16D; break; + case BFD_RELOC_PPC_VLE_HI16A: r = R_PPC_VLE_HI16A; break; + case BFD_RELOC_PPC_VLE_HI16D: r = R_PPC_VLE_HI16D; break; + case BFD_RELOC_PPC_VLE_HA16A: r = R_PPC_VLE_HA16A; break; + case BFD_RELOC_PPC_VLE_HA16D: r = R_PPC_VLE_HA16D; break; + case BFD_RELOC_PPC_VLE_SDA21: r = R_PPC_VLE_SDA21; break; + case BFD_RELOC_PPC_VLE_SDA21_LO: r = R_PPC_VLE_SDA21_LO; break; + case BFD_RELOC_PPC_VLE_SDAREL_LO16A: + r = R_PPC_VLE_SDAREL_LO16A; + break; + case BFD_RELOC_PPC_VLE_SDAREL_LO16D: + r = R_PPC_VLE_SDAREL_LO16D; + break; + case BFD_RELOC_PPC_VLE_SDAREL_HI16A: + r = R_PPC_VLE_SDAREL_HI16A; + break; + case BFD_RELOC_PPC_VLE_SDAREL_HI16D: + r = R_PPC_VLE_SDAREL_HI16D; + break; + case BFD_RELOC_PPC_VLE_SDAREL_HA16A: + r = R_PPC_VLE_SDAREL_HA16A; + break; + case BFD_RELOC_PPC_VLE_SDAREL_HA16D: + r = R_PPC_VLE_SDAREL_HA16D; + break; case BFD_RELOC_16_PCREL: r = R_PPC_REL16; break; case BFD_RELOC_LO16_PCREL: r = R_PPC_REL16_LO; break; case BFD_RELOC_HI16_PCREL: r = R_PPC_REL16_HI; break; case BFD_RELOC_HI16_S_PCREL: r = R_PPC_REL16_HA; break; + case BFD_RELOC_PPC_REL16DX_HA: r = R_PPC_REL16DX_HA; break; case BFD_RELOC_VTABLE_INHERIT: r = R_PPC_GNU_VTINHERIT; break; case BFD_RELOC_VTABLE_ENTRY: r = R_PPC_GNU_VTENTRY; break; } @@ -1662,19 +2032,28 @@ ppc_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, Elf_Internal_Rela *dst) { + unsigned int r_type; + /* Initialize howto table if not already done. */ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ppc_elf_howto_init (); - BFD_ASSERT (ELF32_R_TYPE (dst->r_info) < (unsigned int) R_PPC_max); - cache_ptr->howto = ppc_elf_howto_table[ELF32_R_TYPE (dst->r_info)]; + r_type = ELF32_R_TYPE (dst->r_info); + if (r_type >= R_PPC_max) + { + (*_bfd_error_handler) (_("%B: unrecognised PPC reloc number: %d"), + abfd, r_type); + bfd_set_error (bfd_error_bad_value); + r_type = R_PPC_NONE; + } + cache_ptr->howto = ppc_elf_howto_table[r_type]; /* Just because the above assert didn't trigger doesn't mean that ELF32_R_TYPE (dst->r_info) is necessarily a valid relocation. */ if (!cache_ptr->howto) { (*_bfd_error_handler) (_("%B: invalid relocation type %d"), - abfd, ELF32_R_TYPE (dst->r_info)); + abfd, r_type); bfd_set_error (bfd_error_bad_value); cache_ptr->howto = ppc_elf_howto_table[R_PPC_NONE]; @@ -1692,7 +2071,10 @@ ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED, bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) { - bfd_vma relocation; + enum elf_ppc_reloc_type r_type; + long insn; + bfd_size_type octets; + bfd_vma value; if (output_bfd != NULL) { @@ -1700,23 +2082,28 @@ ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED, return bfd_reloc_ok; } - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - relocation += reloc_entry->addend; - if (reloc_entry->howto->pc_relative) - relocation -= reloc_entry->address; - - reloc_entry->addend += (relocation & 0x8000) << 1; - - return bfd_reloc_continue; + reloc_entry->addend += 0x8000; + r_type = reloc_entry->howto->type; + if (r_type != R_PPC_REL16DX_HA) + return bfd_reloc_continue; + + value = 0; + if (!bfd_is_com_section (symbol->section)) + value = symbol->value; + value += (reloc_entry->addend + + symbol->section->output_offset + + symbol->section->output_section->vma); + value -= (reloc_entry->address + + input_section->output_offset + + input_section->output_section->vma); + value >>= 16; + + octets = reloc_entry->address * bfd_octets_per_byte (abfd); + insn = bfd_get_32 (abfd, (bfd_byte *) data + octets); + insn &= ~0x1fffc1; + insn |= (value & 0xffc1) | ((value & 0x3e) << 15); + bfd_put_32 (abfd, insn, (bfd_byte *) data + octets); + return bfd_reloc_ok; } static bfd_reloc_status_type @@ -1809,13 +2196,94 @@ ppc_elf_mkobject (bfd *abfd) PPC32_ELF_DATA); } +/* When defaulting arch/mach, decode apuinfo to find a better match. */ + +bfd_boolean +_bfd_elf_ppc_set_arch (bfd *abfd) +{ + unsigned long mach = 0; + asection *s; + unsigned char *contents; + + if (abfd->arch_info->bits_per_word == 32 + && bfd_big_endian (abfd)) + { + + for (s = abfd->sections; s != NULL; s = s->next) + if ((elf_section_data (s)->this_hdr.sh_flags & SHF_PPC_VLE) != 0) + break; + if (s != NULL) + mach = bfd_mach_ppc_vle; + } + + if (mach == 0) + { + s = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME); + if (s != NULL && bfd_malloc_and_get_section (abfd, s, &contents)) + { + unsigned int apuinfo_size = bfd_get_32 (abfd, contents + 4); + unsigned int i; + + for (i = 20; i < apuinfo_size + 20 && i + 4 <= s->size; i += 4) + { + unsigned int val = bfd_get_32 (abfd, contents + i); + switch (val >> 16) + { + case PPC_APUINFO_PMR: + case PPC_APUINFO_RFMCI: + if (mach == 0) + mach = bfd_mach_ppc_titan; + break; + + case PPC_APUINFO_ISEL: + case PPC_APUINFO_CACHELCK: + if (mach == bfd_mach_ppc_titan) + mach = bfd_mach_ppc_e500mc; + break; + + case PPC_APUINFO_SPE: + case PPC_APUINFO_EFS: + case PPC_APUINFO_BRLOCK: + if (mach != bfd_mach_ppc_vle) + mach = bfd_mach_ppc_e500; + break; + + case PPC_APUINFO_VLE: + mach = bfd_mach_ppc_vle; + break; + + default: + mach = -1ul; + } + } + free (contents); + } + } + + if (mach != 0 && mach != -1ul) + { + const bfd_arch_info_type *arch; + + for (arch = abfd->arch_info->next; arch; arch = arch->next) + if (arch->mach == mach) + { + abfd->arch_info = arch; + break; + } + } + return TRUE; +} + /* Fix bad default arch selected for a 32 bit input bfd when the - default is 64 bit. */ + default is 64 bit. Also select arch based on apuinfo. */ static bfd_boolean ppc_elf_object_p (bfd *abfd) { - if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 64) + if (!abfd->arch_info->the_default) + return TRUE; + + if (abfd->arch_info->bits_per_word == 64) { Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd); @@ -1826,7 +2294,7 @@ ppc_elf_object_p (bfd *abfd) BFD_ASSERT (abfd->arch_info->bits_per_word == 32); } } - return TRUE; + return _bfd_elf_ppc_set_arch (abfd); } /* Function to set whether a module needs the -mrelocatable bit set. */ @@ -1857,10 +2325,10 @@ ppc_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) case 268: /* Linux/PPC. */ /* pr_cursig */ - elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); + elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); /* pr_pid */ - elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 24); + elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24); /* pr_reg */ offset = 72; @@ -1883,11 +2351,11 @@ ppc_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) return FALSE; case 128: /* Linux/PPC elf_prpsinfo. */ - elf_tdata (abfd)->core_pid + elf_tdata (abfd)->core->pid = bfd_get_32 (abfd, note->descdata + 16); - elf_tdata (abfd)->core_program + elf_tdata (abfd)->core->program = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16); - elf_tdata (abfd)->core_command + elf_tdata (abfd)->core->command = _bfd_elfcore_strndup (abfd, note->descdata + 48, 80); } @@ -1896,7 +2364,7 @@ ppc_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) implementations, so strip it off if it exists. */ { - char *command = elf_tdata (abfd)->core_command; + char *command = elf_tdata (abfd)->core->command; int n = strlen (command); if (0 < n && command[n - 1] == ' ') @@ -1906,6 +2374,20 @@ ppc_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) return TRUE; } +char * +elfcore_write_ppc_linux_prpsinfo32 + (bfd *abfd, + char *buf, + int *bufsiz, + const struct elf_internal_linux_prpsinfo *prpsinfo) +{ + struct elf_external_ppc_linux_prpsinfo32 data; + + swap_ppc_linux_prpsinfo32_out (abfd, prpsinfo, &data); + return elfcore_write_note (abfd, buf, bufsiz, + "CORE", NT_PRPSINFO, &data, sizeof (data)); +} + static char * ppc_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, ...) { @@ -1952,6 +2434,16 @@ ppc_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, ...) } } +static flagword +ppc_elf_lookup_section_flags (char *flag_name) +{ + + if (!strcmp (flag_name, "SHF_PPC_VLE")) + return SHF_PPC_VLE; + + return 0; +} + /* Return address for Ith PLT stub in section PLT, for relocation REL or (bfd_vma) -1 if it should not be included. */ @@ -2025,6 +2517,94 @@ ppc_elf_additional_program_headers (bfd *abfd, return ret; } +/* Modify the segment map for VLE executables. */ + +bfd_boolean +ppc_elf_modify_segment_map (bfd *abfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED) +{ + struct elf_segment_map *m; + + /* At this point in the link, output sections have already been sorted by + LMA and assigned to segments. All that is left to do is to ensure + there is no mixing of VLE & non-VLE sections in a text segment. + If we find that case, we split the segment. + We maintain the original output section order. */ + + for (m = elf_seg_map (abfd); m != NULL; m = m->next) + { + struct elf_segment_map *n; + bfd_size_type amt; + unsigned int j, k; + unsigned int p_flags; + + if (m->p_type != PT_LOAD || m->count == 0) + continue; + + for (p_flags = PF_R, j = 0; j != m->count; ++j) + { + if ((m->sections[j]->flags & SEC_READONLY) == 0) + p_flags |= PF_W; + if ((m->sections[j]->flags & SEC_CODE) != 0) + { + p_flags |= PF_X; + if ((elf_section_flags (m->sections[j]) & SHF_PPC_VLE) != 0) + p_flags |= PF_PPC_VLE; + break; + } + } + if (j != m->count) + while (++j != m->count) + { + unsigned int p_flags1 = PF_R; + + if ((m->sections[j]->flags & SEC_READONLY) == 0) + p_flags1 |= PF_W; + if ((m->sections[j]->flags & SEC_CODE) != 0) + { + p_flags1 |= PF_X; + if ((elf_section_flags (m->sections[j]) & SHF_PPC_VLE) != 0) + p_flags1 |= PF_PPC_VLE; + if (((p_flags1 ^ p_flags) & PF_PPC_VLE) != 0) + break; + } + p_flags |= p_flags1; + } + /* If we're splitting a segment which originally contained rw + sections then those sections might now only be in one of the + two parts. So always set p_flags if splitting, even if we + are being called for objcopy with p_flags_valid set. */ + if (j != m->count || !m->p_flags_valid) + { + m->p_flags_valid = 1; + m->p_flags = p_flags; + } + if (j == m->count) + continue; + + /* Sections 0..j-1 stay in this (current) segment, + the remainder are put in a new segment. + The scan resumes with the new segment. */ + + amt = sizeof (struct elf_segment_map); + amt += (m->count - j - 1) * sizeof (asection *); + n = (struct elf_segment_map *) bfd_zalloc (abfd, amt); + if (n == NULL) + return FALSE; + + n->p_type = PT_LOAD; + n->count = m->count - j; + for (k = 0; k < n->count; ++k) + n->sections[k] = m->sections[j + k]; + m->count = j; + m->p_size_valid = 0; + n->next = m->next; + m->next = n; + } + + return TRUE; +} + /* Add extra PPC sections -- Note, for now, make .sbss2 and .PPC.EMB.sbss0 a normal section, and not a bss section so that the linker doesn't crater when trying to make more than @@ -2032,16 +2612,16 @@ ppc_elf_additional_program_headers (bfd *abfd, static const struct bfd_elf_special_section ppc_elf_special_sections[] = { - { STRING_COMMA_LEN (".plt"), 0, SHT_NOBITS, SHF_ALLOC + SHF_EXECINSTR }, - { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".sbss2"), -2, SHT_PROGBITS, SHF_ALLOC }, - { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".sdata2"), -2, SHT_PROGBITS, SHF_ALLOC }, - { STRING_COMMA_LEN (".tags"), 0, SHT_ORDERED, SHF_ALLOC }, - { STRING_COMMA_LEN (".PPC.EMB.apuinfo"), 0, SHT_NOTE, 0 }, - { STRING_COMMA_LEN (".PPC.EMB.sbss0"), 0, SHT_PROGBITS, SHF_ALLOC }, - { STRING_COMMA_LEN (".PPC.EMB.sdata0"), 0, SHT_PROGBITS, SHF_ALLOC }, - { NULL, 0, 0, 0, 0 } + { STRING_COMMA_LEN (".plt"), 0, SHT_NOBITS, SHF_ALLOC + SHF_EXECINSTR }, + { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, + { STRING_COMMA_LEN (".sbss2"), -2, SHT_PROGBITS, SHF_ALLOC }, + { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + { STRING_COMMA_LEN (".sdata2"), -2, SHT_PROGBITS, SHF_ALLOC }, + { STRING_COMMA_LEN (".tags"), 0, SHT_ORDERED, SHF_ALLOC }, + { STRING_COMMA_LEN (APUINFO_SECTION_NAME), 0, SHT_NOTE, 0 }, + { STRING_COMMA_LEN (".PPC.EMB.sbss0"), 0, SHT_PROGBITS, SHF_ALLOC }, + { STRING_COMMA_LEN (".PPC.EMB.sdata0"), 0, SHT_PROGBITS, SHF_ALLOC }, + { NULL, 0, 0, 0, 0 } }; /* This is what we want for new plt/got. */ @@ -2150,9 +2730,6 @@ apuinfo_list_finish (void) head = NULL; } -#define APUINFO_SECTION_NAME ".PPC.EMB.apuinfo" -#define APUINFO_LABEL "APUinfo" - /* Scan the input BFDs and create a linked list of the APUinfo values that will need to be emitted. */ @@ -2173,7 +2750,7 @@ ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info) apuinfo_list_init (); /* Read in the input sections contents. */ - for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link_next) + for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link.next) { unsigned long datum; @@ -2463,7 +3040,6 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms, } count = relplt->size / sizeof (Elf32_External_Rela); - stub_vma = glink_vma - (bfd_vma) count * 16; /* If the stubs are those for -shared/-pie then we might have multiple stubs for each plt entry. If that is the case then there is no way to associate stubs with their plt entries short @@ -2494,9 +3070,10 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms, if (s == NULL) return -1; + stub_vma = glink_vma; names = (char *) (s + count + 1 + (resolv_vma != 0)); - p = relplt->relocation; - for (i = 0; i < count; i++, p++) + p = relplt->relocation + count - 1; + for (i = 0; i < count; i++) { size_t len; @@ -2507,6 +3084,9 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms, s->flags |= BSF_GLOBAL; s->flags |= BSF_SYNTHETIC; s->section = glink; + stub_vma -= 16; + if (strcmp ((*p->sym_ptr_ptr)->name, "__tls_get_addr_opt") == 0) + stub_vma -= 32; s->value = stub_vma - glink->vma; s->name = names; s->udata.p = NULL; @@ -2523,7 +3103,7 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms, memcpy (names, "@plt", sizeof ("@plt")); names += sizeof ("@plt"); ++s; - stub_vma += 16; + --p; } /* Add a symbol at the start of the glink branch table. */ @@ -2615,7 +3195,7 @@ must_be_dyn_reloc (struct bfd_link_info *info, case R_PPC_TPREL16_LO: case R_PPC_TPREL16_HI: case R_PPC_TPREL16_HA: - return !info->executable; + return !bfd_link_executable (info); } } @@ -2625,6 +3205,21 @@ must_be_dyn_reloc (struct bfd_link_info *info, shared lib. */ #define ELIMINATE_COPY_RELOCS 1 +/* Used to track dynamic relocations for local symbols. */ +struct ppc_dyn_relocs +{ + struct ppc_dyn_relocs *next; + + /* The input section of the reloc. */ + asection *sec; + + /* Total number of relocs copied for the input section. */ + unsigned int count : 31; + + /* Whether this entry is for STT_GNU_IFUNC symbols. */ + unsigned int ifunc : 1; +}; + /* PPC ELF linker hash entry. */ struct ppc_elf_link_hash_entry @@ -2655,7 +3250,11 @@ struct ppc_elf_link_hash_entry /* Nonzero if we have seen a small data relocation referring to this symbol. */ - unsigned char has_sda_refs; + unsigned char has_sda_refs : 1; + + /* Flag use of given relocations. */ + unsigned char has_addr16_ha : 1; + unsigned char has_addr16_lo : 1; }; #define ppc_elf_hash_entry(ent) ((struct ppc_elf_link_hash_entry *) (ent)) @@ -2666,6 +3265,9 @@ struct ppc_elf_link_hash_table { struct elf_link_hash_table elf; + /* Various options passed from the linker. */ + struct ppc_elf_params *params; + /* Short-cuts to get to dynamic linker sections. */ asection *got; asection *relgot; @@ -2711,12 +3313,6 @@ struct ppc_elf_link_hash_table /* The type of PLT we have chosen to use. */ enum ppc_elf_plt_type plt_type; - /* Set if we should emit symbols for stubs. */ - unsigned int emit_stub_syms:1; - - /* Set if __tls_get_addr optimization should not be done. */ - unsigned int no_tls_get_addr_opt:1; - /* True if the target system is VxWorks. */ unsigned int is_vxworks:1; @@ -2732,7 +3328,7 @@ struct ppc_elf_link_hash_table }; /* Rename some of the generic section flags to better document how they - are used here. */ + are used for ppc32. The flags are only valid for ppc32 elf objects. */ /* Nonzero if this section has TLS related relocations. */ #define has_tls_reloc sec_flg0 @@ -2782,6 +3378,8 @@ static struct bfd_link_hash_table * ppc_elf_link_hash_table_create (bfd *abfd) { struct ppc_elf_link_hash_table *ret; + static struct ppc_elf_params default_params + = { PLT_OLD, 0, 1, 0, 0, 12, 0, 0 }; ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table)); if (ret == NULL) @@ -2801,6 +3399,8 @@ ppc_elf_link_hash_table_create (bfd *abfd) ret->elf.init_plt_offset.offset = 0; ret->elf.init_plt_offset.glist = NULL; + ret->params = &default_params; + ret->sdata[0].name = ".sdata"; ret->sdata[0].sym_name = "_SDA_BASE_"; ret->sdata[0].bss_name = ".sbss"; @@ -2816,6 +3416,18 @@ ppc_elf_link_hash_table_create (bfd *abfd) return &ret->elf.root; } +/* Hook linker params into hash table. */ + +void +ppc_elf_link_params (struct bfd_link_info *info, struct ppc_elf_params *params) +{ + struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); + + if (htab) + htab->params = params; + params->pagesize_p2 = bfd_log2 (params->pagesize); +} + /* Create .got and the related sections. */ static bfd_boolean @@ -2829,13 +3441,13 @@ ppc_elf_create_got (bfd *abfd, struct bfd_link_info *info) return FALSE; htab = ppc_elf_hash_table (info); - htab->got = s = bfd_get_section_by_name (abfd, ".got"); + htab->got = s = bfd_get_linker_section (abfd, ".got"); if (s == NULL) abort (); if (htab->is_vxworks) { - htab->sgotplt = bfd_get_section_by_name (abfd, ".got.plt"); + htab->sgotplt = bfd_get_linker_section (abfd, ".got.plt"); if (!htab->sgotplt) abort (); } @@ -2849,13 +3461,43 @@ ppc_elf_create_got (bfd *abfd, struct bfd_link_info *info) return FALSE; } - htab->relgot = bfd_get_section_by_name (abfd, ".rela.got"); + htab->relgot = bfd_get_linker_section (abfd, ".rela.got"); if (!htab->relgot) abort (); return TRUE; } +/* Create a special linker section, used for R_PPC_EMB_SDAI16 and + R_PPC_EMB_SDA2I16 pointers. These sections become part of .sdata + and .sdata2. Create _SDA_BASE_ and _SDA2_BASE too. */ + +static bfd_boolean +ppc_elf_create_linker_section (bfd *abfd, + struct bfd_link_info *info, + flagword flags, + elf_linker_section_t *lsect) +{ + asection *s; + + flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_LINKER_CREATED); + + s = bfd_make_section_anyway_with_flags (abfd, lsect->name, flags); + if (s == NULL) + return FALSE; + lsect->section = s; + + /* Define the sym on the first section of this name. */ + s = bfd_get_section_by_name (abfd, lsect->name); + + lsect->sym = _bfd_elf_define_linkage_sym (abfd, info, s, lsect->sym_name); + if (lsect->sym == NULL) + return FALSE; + lsect->sym->root.u.def.value = 0x8000; + return TRUE; +} + static bfd_boolean ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info) { @@ -2868,7 +3510,8 @@ ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info) s = bfd_make_section_anyway_with_flags (abfd, ".glink", flags); htab->glink = s; if (s == NULL - || !bfd_set_section_alignment (abfd, s, 4)) + || !bfd_set_section_alignment (abfd, s, + htab->params->ppc476_workaround ? 6 : 4)) return FALSE; if (!info->no_ld_generated_unwind_info) @@ -2896,6 +3539,15 @@ ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info) if (s == NULL || ! bfd_set_section_alignment (abfd, s, 2)) return FALSE; + + if (!ppc_elf_create_linker_section (abfd, info, 0, + &htab->sdata[0])) + return FALSE; + + if (!ppc_elf_create_linker_section (abfd, info, SEC_READONLY, + &htab->sdata[1])) + return FALSE; + return TRUE; } @@ -2923,16 +3575,16 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) && !ppc_elf_create_glink (abfd, info)) return FALSE; - htab->dynbss = bfd_get_section_by_name (abfd, ".dynbss"); + htab->dynbss = bfd_get_linker_section (abfd, ".dynbss"); s = bfd_make_section_anyway_with_flags (abfd, ".dynsbss", SEC_ALLOC | SEC_LINKER_CREATED); htab->dynsbss = s; if (s == NULL) return FALSE; - if (! info->shared) + if (! bfd_link_pic (info)) { - htab->relbss = bfd_get_section_by_name (abfd, ".rela.bss"); + htab->relbss = bfd_get_linker_section (abfd, ".rela.bss"); flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); s = bfd_make_section_anyway_with_flags (abfd, ".rela.sbss", flags); @@ -2946,8 +3598,8 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) && !elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2)) return FALSE; - htab->relplt = bfd_get_section_by_name (abfd, ".rela.plt"); - htab->plt = s = bfd_get_section_by_name (abfd, ".plt"); + htab->relplt = bfd_get_linker_section (abfd, ".rela.plt"); + htab->plt = s = bfd_get_linker_section (abfd, ".plt"); if (s == NULL) abort (); @@ -3021,7 +3673,7 @@ ppc_elf_copy_indirect_symbol (struct bfd_link_info *info, /* If we were called to copy over info for a weak sym, that's all. You might think dyn_relocs need not be copied over; After all, both syms will be dynamic or both non-dynamic so we're just - moving reloc accounting around. However, ELIMINATE_COPY_RELOCS + moving reloc accounting around. However, ELIMINATE_COPY_RELOCS code in ppc_elf_adjust_dynamic_symbol needs to check for dyn_relocs in read-only sections, and it does so on what is the DIR sym here. */ @@ -3087,7 +3739,7 @@ ppc_elf_add_symbol_hook (bfd *abfd, bfd_vma *valp) { if (sym->st_shndx == SHN_COMMON - && !info->relocatable + && !bfd_link_relocatable (info) && is_ppc_elf (info->output_bfd) && sym->st_size <= elf_gp_size (abfd)) { @@ -3096,77 +3748,32 @@ ppc_elf_add_symbol_hook (bfd *abfd, struct ppc_elf_link_hash_table *htab; htab = ppc_elf_hash_table (info); - if (htab->sbss == NULL) - { - flagword flags = SEC_IS_COMMON | SEC_LINKER_CREATED; - - if (!htab->elf.dynobj) - htab->elf.dynobj = abfd; - - htab->sbss = bfd_make_section_anyway_with_flags (htab->elf.dynobj, - ".sbss", - flags); - if (htab->sbss == NULL) - return FALSE; - } - - *secp = htab->sbss; - *valp = sym->st_size; - } - - if ((abfd->flags & DYNAMIC) == 0 - && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC - || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)) - elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE; - - return TRUE; -} - -static bfd_boolean -create_sdata_sym (struct bfd_link_info *info, elf_linker_section_t *lsect) -{ - struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); - - lsect->sym = elf_link_hash_lookup (&htab->elf, lsect->sym_name, - TRUE, FALSE, TRUE); - if (lsect->sym == NULL) - return FALSE; - if (lsect->sym->root.type == bfd_link_hash_new) - lsect->sym->non_elf = 0; - lsect->sym->ref_regular = 1; - _bfd_elf_link_hash_hide_symbol (info, lsect->sym, TRUE); - return TRUE; -} - -/* Create a special linker section. */ - -static bfd_boolean -ppc_elf_create_linker_section (bfd *abfd, - struct bfd_link_info *info, - flagword flags, - elf_linker_section_t *lsect) -{ - struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); - asection *s; + if (htab->sbss == NULL) + { + flagword flags = SEC_IS_COMMON | SEC_LINKER_CREATED; - flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); + if (!htab->elf.dynobj) + htab->elf.dynobj = abfd; - /* Record the first bfd that needs the special sections. */ - if (!htab->elf.dynobj) - htab->elf.dynobj = abfd; + htab->sbss = bfd_make_section_anyway_with_flags (htab->elf.dynobj, + ".sbss", + flags); + if (htab->sbss == NULL) + return FALSE; + } - s = bfd_make_section_anyway_with_flags (htab->elf.dynobj, - lsect->name, - flags); - if (s == NULL - || !bfd_set_section_alignment (htab->elf.dynobj, s, 2)) - return FALSE; - lsect->section = s; + *secp = htab->sbss; + *valp = sym->st_size; + } - return create_sdata_sym (info, lsect); -} + if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC + && (abfd->flags & DYNAMIC) == 0 + && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour) + elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc; + return TRUE; +} + /* Find a linker generated pointer with a given addend and type. */ static elf_linker_section_pointers_t * @@ -3185,10 +3792,10 @@ elf_find_pointer_linker_section /* Allocate a pointer to live in a linker created section. */ static bfd_boolean -elf_create_pointer_linker_section (bfd *abfd, - elf_linker_section_t *lsect, - struct elf_link_hash_entry *h, - const Elf_Internal_Rela *rel) +elf_allocate_pointer_linker_section (bfd *abfd, + elf_linker_section_t *lsect, + struct elf_link_hash_entry *h, + const Elf_Internal_Rela *rel) { elf_linker_section_pointers_t **ptr_linker_section_ptr = NULL; elf_linker_section_pointers_t *linker_section_ptr; @@ -3256,6 +3863,8 @@ elf_create_pointer_linker_section (bfd *abfd, linker_section_ptr->lsect = lsect; *ptr_linker_section_ptr = linker_section_ptr; + if (!bfd_set_section_alignment (lsect->section->owner, lsect->section, 2)) + return FALSE; linker_section_ptr->offset = lsect->section->size; lsect->section->size += 4; @@ -3352,7 +3961,8 @@ is_branch_reloc (enum elf_ppc_reloc_type r_type) || r_type == R_PPC_ADDR24 || r_type == R_PPC_ADDR14 || r_type == R_PPC_ADDR14_BRTAKEN - || r_type == R_PPC_ADDR14_BRNTAKEN); + || r_type == R_PPC_ADDR14_BRNTAKEN + || r_type == R_PPC_VLE_REL24); } static void @@ -3383,7 +3993,7 @@ ppc_elf_check_relocs (bfd *abfd, asection *got2, *sreloc; struct elf_link_hash_entry *tga; - if (info->relocatable) + if (bfd_link_relocatable (info)) return TRUE; /* Don't do anything special with non-loaded, non-alloced sections. @@ -3428,6 +4038,7 @@ ppc_elf_check_relocs (bfd *abfd, enum elf_ppc_reloc_type r_type; struct elf_link_hash_entry *h; int tls_type; + struct plt_entry **ifunc; r_symndx = ELF32_R_SYM (rel->r_info); if (r_symndx < symtab_hdr->sh_info) @@ -3438,6 +4049,10 @@ ppc_elf_check_relocs (bfd *abfd, while (h->root.type == bfd_link_hash_indirect || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; + + /* PR15323, ref flags aren't set for references in the same + object. */ + h->root.non_ir_ref = 1; } /* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got. @@ -3456,6 +4071,7 @@ ppc_elf_check_relocs (bfd *abfd, tls_type = 0; r_type = ELF32_R_TYPE (rel->r_info); + ifunc = NULL; if (h == NULL && !htab->is_vxworks) { Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache, @@ -3463,13 +4079,9 @@ ppc_elf_check_relocs (bfd *abfd, if (isym == NULL) return FALSE; - if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC - && (!info->shared - || is_branch_reloc (r_type))) + if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) { - struct plt_entry **ifunc; - bfd_vma addend; - + /* Set PLT_IFUNC flag for this sym, no GOT entry yet. */ ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx, PLT_IFUNC); if (ifunc == NULL) @@ -3478,15 +4090,19 @@ ppc_elf_check_relocs (bfd *abfd, /* STT_GNU_IFUNC symbols must have a PLT entry; In a non-pie executable even when there are no plt calls. */ - addend = 0; - if (r_type == R_PPC_PLTREL24) + if (!bfd_link_pic (info) + || is_branch_reloc (r_type)) { - ppc_elf_tdata (abfd)->makes_plt_call = 1; - if (info->shared) - addend = rel->r_addend; + bfd_vma addend = 0; + if (r_type == R_PPC_PLTREL24) + { + ppc_elf_tdata (abfd)->makes_plt_call = 1; + if (bfd_link_pic (info)) + addend = rel->r_addend; + } + if (!update_plt_info (abfd, ifunc, got2, addend)) + return FALSE; } - if (!update_plt_info (abfd, ifunc, got2, addend)) - return FALSE; } } @@ -3532,7 +4148,7 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_GOT_TPREL16_LO: case R_PPC_GOT_TPREL16_HI: case R_PPC_GOT_TPREL16_HA: - if (!info->executable) + if (bfd_link_pic (info)) info->flags |= DF_STATIC_TLS; tls_type = TLS_TLS | TLS_TPREL; goto dogottls; @@ -3571,7 +4187,7 @@ ppc_elf_check_relocs (bfd *abfd, /* We may also need a plt entry if the symbol turns out to be an ifunc. */ - if (h != NULL && !info->shared) + if (h != NULL && !bfd_link_pic (info)) { if (!update_plt_info (abfd, &h->plt.plist, NULL, 0)) return FALSE; @@ -3580,17 +4196,14 @@ ppc_elf_check_relocs (bfd *abfd, /* Indirect .sdata relocation. */ case R_PPC_EMB_SDAI16: - if (info->shared) + if (bfd_link_pic (info)) { bad_shared_reloc (abfd, r_type); return FALSE; } - if (htab->sdata[0].section == NULL - && !ppc_elf_create_linker_section (abfd, info, 0, - &htab->sdata[0])) - return FALSE; - if (!elf_create_pointer_linker_section (abfd, &htab->sdata[0], - h, rel)) + htab->sdata[0].sym->ref_regular = 1; + if (!elf_allocate_pointer_linker_section (abfd, &htab->sdata[0], + h, rel)) return FALSE; if (h != NULL) { @@ -3601,17 +4214,14 @@ ppc_elf_check_relocs (bfd *abfd, /* Indirect .sdata2 relocation. */ case R_PPC_EMB_SDA2I16: - if (info->shared) + if (bfd_link_pic (info)) { bad_shared_reloc (abfd, r_type); return FALSE; } - if (htab->sdata[1].section == NULL - && !ppc_elf_create_linker_section (abfd, info, SEC_READONLY, - &htab->sdata[1])) - return FALSE; - if (!elf_create_pointer_linker_section (abfd, &htab->sdata[1], - h, rel)) + htab->sdata[1].sym->ref_regular = 1; + if (!elf_allocate_pointer_linker_section (abfd, &htab->sdata[1], + h, rel)) return FALSE; if (h != NULL) { @@ -3621,9 +4231,15 @@ ppc_elf_check_relocs (bfd *abfd, break; case R_PPC_SDAREL16: - if (htab->sdata[0].sym == NULL - && !create_sdata_sym (info, &htab->sdata[0])) - return FALSE; + htab->sdata[0].sym->ref_regular = 1; + /* Fall thru */ + + case R_PPC_VLE_SDAREL_LO16A: + case R_PPC_VLE_SDAREL_LO16D: + case R_PPC_VLE_SDAREL_HI16A: + case R_PPC_VLE_SDAREL_HI16D: + case R_PPC_VLE_SDAREL_HA16A: + case R_PPC_VLE_SDAREL_HA16D: if (h != NULL) { ppc_elf_hash_entry (h)->has_sda_refs = TRUE; @@ -3631,15 +4247,24 @@ ppc_elf_check_relocs (bfd *abfd, } break; + case R_PPC_VLE_REL8: + case R_PPC_VLE_REL15: + case R_PPC_VLE_REL24: + case R_PPC_VLE_LO16A: + case R_PPC_VLE_LO16D: + case R_PPC_VLE_HI16A: + case R_PPC_VLE_HI16D: + case R_PPC_VLE_HA16A: + case R_PPC_VLE_HA16D: + break; + case R_PPC_EMB_SDA2REL: - if (info->shared) + if (bfd_link_pic (info)) { bad_shared_reloc (abfd, r_type); return FALSE; } - if (htab->sdata[1].sym == NULL - && !create_sdata_sym (info, &htab->sdata[1])) - return FALSE; + htab->sdata[1].sym->ref_regular = 1; if (h != NULL) { ppc_elf_hash_entry (h)->has_sda_refs = TRUE; @@ -3647,19 +4272,15 @@ ppc_elf_check_relocs (bfd *abfd, } break; + case R_PPC_VLE_SDA21_LO: + case R_PPC_VLE_SDA21: case R_PPC_EMB_SDA21: case R_PPC_EMB_RELSDA: - if (info->shared) + if (bfd_link_pic (info)) { bad_shared_reloc (abfd, r_type); return FALSE; } - if (htab->sdata[0].sym == NULL - && !create_sdata_sym (info, &htab->sdata[0])) - return FALSE; - if (htab->sdata[1].sym == NULL - && !create_sdata_sym (info, &htab->sdata[1])) - return FALSE; if (h != NULL) { ppc_elf_hash_entry (h)->has_sda_refs = TRUE; @@ -3672,7 +4293,7 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_EMB_NADDR16_LO: case R_PPC_EMB_NADDR16_HI: case R_PPC_EMB_NADDR16_HA: - if (info->shared) + if (bfd_link_pic (info)) { bad_shared_reloc (abfd, r_type); return FALSE; @@ -3693,21 +4314,20 @@ ppc_elf_check_relocs (bfd *abfd, #ifdef DEBUG fprintf (stderr, "Reloc requires a PLT entry\n"); #endif - /* This symbol requires a procedure linkage table entry. We - actually build the entry in finish_dynamic_symbol, - because this might be a case of linking PIC code without - linking in any dynamic objects, in which case we don't - need to generate a procedure linkage table after all. */ - + /* This symbol requires a procedure linkage table entry. */ if (h == NULL) { - /* It does not make sense to have a procedure linkage - table entry for a local symbol. */ - info->callbacks->einfo (_("%P: %H: %s reloc against local symbol\n"), - abfd, sec, rel->r_offset, - ppc_elf_howto_table[r_type]->name); - bfd_set_error (bfd_error_bad_value); - return FALSE; + if (ifunc == NULL) + { + /* It does not make sense to have a procedure linkage + table entry for a non-ifunc local symbol. */ + info->callbacks->einfo + (_("%P: %H: %s reloc against local symbol\n"), + abfd, sec, rel->r_offset, + ppc_elf_howto_table[r_type]->name); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } } else { @@ -3716,7 +4336,7 @@ ppc_elf_check_relocs (bfd *abfd, if (r_type == R_PPC_PLTREL24) { ppc_elf_tdata (abfd)->makes_plt_call = 1; - if (info->shared) + if (bfd_link_pic (info)) addend = rel->r_addend; } h->needs_plt = 1; @@ -3743,6 +4363,7 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_REL16_LO: case R_PPC_REL16_HI: case R_PPC_REL16_HA: + case R_PPC_REL16DX_HA: ppc_elf_tdata (abfd)->has_rel16 = 1; break; @@ -3780,6 +4401,12 @@ ppc_elf_check_relocs (bfd *abfd, htab->plt_type = PLT_OLD; htab->old_bfd = abfd; } + if (h != NULL && h->type == STT_GNU_IFUNC) + { + h->needs_plt = 1; + if (!update_plt_info (abfd, &h->plt.plist, NULL, 0)) + return FALSE; + } break; /* This relocation describes the C++ object vtable hierarchy. @@ -3804,7 +4431,7 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_TPREL16_LO: case R_PPC_TPREL16_HI: case R_PPC_TPREL16_HA: - if (!info->executable) + if (bfd_link_pic (info)) info->flags |= DF_STATIC_TLS; goto dodyn; @@ -3817,7 +4444,7 @@ ppc_elf_check_relocs (bfd *abfd, if (h == NULL && got2 != NULL && (sec->flags & SEC_CODE) != 0 - && info->shared + && bfd_link_pic (info) && htab->plt_type == PLT_UNSET) { /* Old -fPIC gcc code has .long LCTOC1-LCFx just before @@ -3852,7 +4479,7 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_ADDR16_HA: case R_PPC_UADDR32: case R_PPC_UADDR16: - if (h != NULL && !info->shared) + if (h != NULL && !bfd_link_pic (info)) { /* We may need a plt entry if the symbol turns out to be a function defined in a dynamic object. */ @@ -3862,6 +4489,10 @@ ppc_elf_check_relocs (bfd *abfd, /* We may need a copy reloc too. */ h->non_got_ref = 1; h->pointer_equality_needed = 1; + if (r_type == R_PPC_ADDR16_HA) + ppc_elf_hash_entry (h)->has_addr16_ha = 1; + if (r_type == R_PPC_ADDR16_LO) + ppc_elf_hash_entry (h)->has_addr16_lo = 1; } goto dodyn; @@ -3886,7 +4517,7 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_ADDR14: case R_PPC_ADDR14_BRTAKEN: case R_PPC_ADDR14_BRNTAKEN: - if (h != NULL && !info->shared) + if (h != NULL && !bfd_link_pic (info)) { /* We may need a plt entry if the symbol turns out to be a function defined in a dynamic object. */ @@ -3918,21 +4549,18 @@ ppc_elf_check_relocs (bfd *abfd, may need to keep relocations for symbols satisfied by a dynamic library if we manage to avoid copy relocs for the symbol. */ - if ((info->shared + if ((bfd_link_pic (info) && (must_be_dyn_reloc (info, r_type) || (h != NULL - && (! info->symbolic + && (!SYMBOLIC_BIND (info, h) || h->root.type == bfd_link_hash_defweak || !h->def_regular)))) || (ELIMINATE_COPY_RELOCS - && !info->shared + && !bfd_link_pic (info) && h != NULL && (h->root.type == bfd_link_hash_defweak || !h->def_regular))) { - struct elf_dyn_relocs *p; - struct elf_dyn_relocs **rel_head; - #ifdef DEBUG fprintf (stderr, "ppc_elf_check_relocs needs to " @@ -3956,13 +4584,34 @@ ppc_elf_check_relocs (bfd *abfd, relocations we need for this symbol. */ if (h != NULL) { + struct elf_dyn_relocs *p; + struct elf_dyn_relocs **rel_head; + rel_head = &ppc_elf_hash_entry (h)->dyn_relocs; + p = *rel_head; + if (p == NULL || p->sec != sec) + { + p = bfd_alloc (htab->elf.dynobj, sizeof *p); + if (p == NULL) + return FALSE; + p->next = *rel_head; + *rel_head = p; + p->sec = sec; + p->count = 0; + p->pc_count = 0; + } + p->count += 1; + if (!must_be_dyn_reloc (info, r_type)) + p->pc_count += 1; } else { /* Track dynamic relocs needed for local syms too. We really need local syms available to do this easily. Oh well. */ + struct ppc_dyn_relocs *p; + struct ppc_dyn_relocs **rel_head; + bfd_boolean is_ifunc; asection *s; void *vpp; Elf_Internal_Sym *isym; @@ -3977,25 +4626,24 @@ ppc_elf_check_relocs (bfd *abfd, s = sec; vpp = &elf_section_data (s)->local_dynrel; - rel_head = (struct elf_dyn_relocs **) vpp; - } - - p = *rel_head; - if (p == NULL || p->sec != sec) - { - p = bfd_alloc (htab->elf.dynobj, sizeof *p); - if (p == NULL) - return FALSE; - p->next = *rel_head; - *rel_head = p; - p->sec = sec; - p->count = 0; - p->pc_count = 0; + rel_head = (struct ppc_dyn_relocs **) vpp; + is_ifunc = ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC; + p = *rel_head; + if (p != NULL && p->sec == sec && p->ifunc != is_ifunc) + p = p->next; + if (p == NULL || p->sec != sec || p->ifunc != is_ifunc) + { + p = bfd_alloc (htab->elf.dynobj, sizeof *p); + if (p == NULL) + return FALSE; + p->next = *rel_head; + *rel_head = p; + p->sec = sec; + p->ifunc = is_ifunc; + p->count = 0; + } + p->count += 1; } - - p->count += 1; - if (!must_be_dyn_reloc (info, r_type)) - p->pc_count += 1; } break; @@ -4244,29 +4892,43 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) return TRUE; } + +static void +ppc_elf_vle_split16 (bfd *output_bfd, bfd_byte *loc, + bfd_vma value, + split16_format_type split16_format) + +{ + unsigned int insn, top5; + + insn = bfd_get_32 (output_bfd, loc); + top5 = value & 0xf800; + top5 = top5 << (split16_format == split16a_type ? 9 : 5); + insn &= (split16_format == split16a_type ? ~0x1f007ff : ~0x1f07ff); + insn |= top5; + insn |= value & 0x7ff; + bfd_put_32 (output_bfd, insn, loc); +} + /* Choose which PLT scheme to use, and set .plt flags appropriately. Returns -1 on error, 0 for old PLT, 1 for new PLT. */ int ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, - enum ppc_elf_plt_type plt_style, - int emit_stub_syms) + struct bfd_link_info *info) { struct ppc_elf_link_hash_table *htab; flagword flags; htab = ppc_elf_hash_table (info); - htab->emit_stub_syms = emit_stub_syms; - if (htab->plt_type == PLT_UNSET) { struct elf_link_hash_entry *h; - if (plt_style == PLT_OLD) + if (htab->params->plt_style == PLT_OLD) htab->plt_type = PLT_OLD; - else if (info->shared + else if (bfd_link_pic (info) && htab->elf.dynamic_sections_created && (h = elf_link_hash_lookup (&htab->elf, "_mcount", FALSE, FALSE, TRUE)) != NULL @@ -4286,7 +4948,7 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED, else { bfd *ibfd; - enum ppc_elf_plt_type plt_type = plt_style; + enum ppc_elf_plt_type plt_type = htab->params->plt_style; /* Look through the reloc flags left by ppc_elf_check_relocs. Use the old style bss plt if a file makes plt calls @@ -4294,7 +4956,7 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED, --secure-plt and we never see REL16 relocs. */ if (plt_type == PLT_UNSET) plt_type = PLT_OLD; - for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next) if (is_ppc_elf (ibfd)) { if (ppc_elf_tdata (ibfd)->has_rel16) @@ -4309,7 +4971,7 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED, htab->plt_type = plt_type; } } - if (htab->plt_type == PLT_OLD && plt_style == PLT_NEW) + if (htab->plt_type == PLT_OLD && htab->params->plt_style == PLT_NEW) { if (htab->old_bfd != NULL) info->callbacks->einfo (_("%P: bss-plt forced due to %B\n"), @@ -4382,7 +5044,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd, const Elf_Internal_Rela *rel, *relend; asection *got2; - if (info->relocatable) + if (bfd_link_relocatable (info)) return TRUE; if ((sec->flags & SEC_ALLOC) == 0) @@ -4428,7 +5090,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd, if (!htab->is_vxworks && h == NULL && local_got_refcounts != NULL - && (!info->shared + && (!bfd_link_pic (info) || is_branch_reloc (r_type))) { struct plt_entry **local_plt = (struct plt_entry **) @@ -4441,7 +5103,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd, bfd_vma addend = 0; struct plt_entry *ent; - if (r_type == R_PPC_PLTREL24 && info->shared) + if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info)) addend = rel->r_addend; ent = find_plt_ent (ifunc, got2, addend); if (ent->plt.refcount > 0) @@ -4476,7 +5138,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd, { if (h->got.refcount > 0) h->got.refcount--; - if (!info->shared) + if (!bfd_link_pic (info)) { struct plt_entry *ent; @@ -4512,7 +5174,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd, case R_PPC_ADDR14_BRNTAKEN: case R_PPC_UADDR32: case R_PPC_UADDR16: - if (info->shared) + if (bfd_link_pic (info)) break; case R_PPC_PLT32: @@ -4526,7 +5188,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd, bfd_vma addend = 0; struct plt_entry *ent; - if (r_type == R_PPC_PLTREL24 && info->shared) + if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info)) addend = rel->r_addend; ent = find_plt_ent (&h->plt.plist, got2, addend); if (ent != NULL && ent->plt.refcount > 0) @@ -4545,16 +5207,17 @@ ppc_elf_gc_sweep_hook (bfd *abfd, generic ELF tls_setup function. */ asection * -ppc_elf_tls_setup (bfd *obfd, - struct bfd_link_info *info, - int no_tls_get_addr_opt) +ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info) { struct ppc_elf_link_hash_table *htab; htab = ppc_elf_hash_table (info); htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr", FALSE, FALSE, TRUE); - if (!no_tls_get_addr_opt) + if (htab->plt_type != PLT_NEW) + htab->params->no_tls_get_addr_opt = TRUE; + + if (!htab->params->no_tls_get_addr_opt) { struct elf_link_hash_entry *opt, *tga; opt = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_opt", @@ -4585,6 +5248,7 @@ ppc_elf_tls_setup (bfd *obfd, tga->root.type = bfd_link_hash_indirect; tga->root.u.i.link = &opt->root; ppc_elf_copy_indirect_symbol (info, opt, tga); + opt->forced_local = 0; if (opt->dynindx != -1) { /* Use __tls_get_addr_opt in dynamic relocations. */ @@ -4599,9 +5263,8 @@ ppc_elf_tls_setup (bfd *obfd, } } else - no_tls_get_addr_opt = TRUE; + htab->params->no_tls_get_addr_opt = TRUE; } - htab->no_tls_get_addr_opt = no_tls_get_addr_opt; if (htab->plt_type == PLT_NEW && htab->plt != NULL && htab->plt->output_section != NULL) @@ -4652,7 +5315,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct ppc_elf_link_hash_table *htab; int pass; - if (info->relocatable || !info->executable) + if (!bfd_link_executable (info)) return TRUE; htab = ppc_elf_hash_table (info); @@ -4666,7 +5329,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, notify relocate_section that optimization can be done, and adjust got and plt refcounts. */ for (pass = 0; pass < 2; ++pass) - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { Elf_Internal_Sym *locsyms = NULL; Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd); @@ -4825,7 +5488,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct plt_entry *ent; bfd_vma addend = 0; - if (info->shared + if (bfd_link_pic (info) && ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24) addend = rel[1].r_addend; ent = find_plt_ent (&htab->tls_get_addr->plt.plist, @@ -4975,9 +5638,24 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, will go to this object, or will remain undefined. */ h->plt.plist = NULL; h->needs_plt = 0; + h->pointer_equality_needed = 0; } else { + /* Taking a function's address in a read/write section + doesn't require us to define the function symbol in the + executable on a plt call stub. A dynamic reloc can + be used instead. */ + if (h->pointer_equality_needed + && h->type != STT_GNU_IFUNC + && !htab->is_vxworks + && !ppc_elf_hash_entry (h)->has_sda_refs + && !readonly_dynrelocs (h)) + { + h->pointer_equality_needed = 0; + h->non_got_ref = 0; + } + /* After adjust_dynamic_symbol, non_got_ref set in the non-shared case means that we have allocated space in .dynbss for the symbol and thus dyn_relocs for this @@ -4987,14 +5665,15 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, relocations against this symbol to the PLT entry. Allow dynamic relocs if the reference is weak, and the dynamic relocs will not cause text relocation. */ - if (!h->ref_regular_nonweak - && h->non_got_ref - && h->type != STT_GNU_IFUNC - && !htab->is_vxworks - && !ppc_elf_hash_entry (h)->has_sda_refs - && !readonly_dynrelocs (h)) + else if (!h->ref_regular_nonweak + && h->non_got_ref + && h->type != STT_GNU_IFUNC + && !htab->is_vxworks + && !ppc_elf_hash_entry (h)->has_sda_refs + && !readonly_dynrelocs (h)) h->non_got_ref = 0; } + h->protected_def = 0; return TRUE; } else @@ -5021,13 +5700,42 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, only references to the symbol are via the global offset table. For such cases we need not do anything here; the relocations will be handled correctly by relocate_section. */ - if (info->shared) - return TRUE; + if (bfd_link_pic (info)) + { + h->protected_def = 0; + return TRUE; + } /* If there are no references to this symbol that do not use the GOT, we don't need to generate a copy reloc. */ if (!h->non_got_ref) - return TRUE; + { + h->protected_def = 0; + return TRUE; + } + + /* Protected variables do not work with .dynbss. The copy in + .dynbss won't be used by the shared library with the protected + definition for the variable. Editing to PIC, or text relocations + are preferable to an incorrect program. */ + if (h->protected_def) + { + if (ELIMINATE_COPY_RELOCS + && ppc_elf_hash_entry (h)->has_addr16_ha + && ppc_elf_hash_entry (h)->has_addr16_lo + && htab->params->pic_fixup == 0 + && info->disable_target_specific_optimizations <= 1) + htab->params->pic_fixup = 1; + h->non_got_ref = 0; + return TRUE; + } + + /* If -z nocopyreloc was given, we won't generate them either. */ + if (info->nocopyreloc) + { + h->non_got_ref = 0; + return TRUE; + } /* If we didn't find any dynamic relocs in read-only sections, then we'll be keeping the dynamic relocs and avoiding the copy reloc. @@ -5081,7 +5789,7 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, h->needs_copy = 1; } - return _bfd_elf_adjust_dynamic_copy (h, s); + return _bfd_elf_adjust_dynamic_copy (info, h, s); } /* Generate a symbol to mark plt call stubs. For non-PIC code the sym is @@ -5101,7 +5809,7 @@ add_stub_sym (struct plt_entry *ent, const char *stub; struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); - if (info->shared) + if (bfd_link_pic (info)) stub = ".plt_pic32."; else stub = ".plt_call32."; @@ -5132,6 +5840,7 @@ add_stub_sym (struct plt_entry *ent, sh->ref_regular_nonweak = 1; sh->forced_local = 1; sh->non_elf = 0; + sh->root.linker_def = 1; } return TRUE; } @@ -5209,7 +5918,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) } dyn = htab->elf.dynamic_sections_created; - if (info->shared + if (bfd_link_pic (info) || h->type == STT_GNU_IFUNC || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)) { @@ -5227,16 +5936,16 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) ent->plt.offset = plt_offset; s = htab->glink; - if (!doneone || info->shared) + if (!doneone || bfd_link_pic (info)) { glink_offset = s->size; s->size += GLINK_ENTRY_SIZE; if (h == htab->tls_get_addr - && !htab->no_tls_get_addr_opt) + && !htab->params->no_tls_get_addr_opt) s->size += TLS_GET_ADDR_GLINK_SIZE - GLINK_ENTRY_SIZE; } if (!doneone - && !info->shared + && !bfd_link_pic (info) && h->def_dynamic && !h->def_regular) { @@ -5245,7 +5954,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) } ent->glink_offset = glink_offset; - if (htab->emit_stub_syms + if (htab->params->emit_stub_syms && !add_stub_sym (ent, h, info)) return FALSE; } @@ -5275,7 +5984,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) relocations, and is required to make function pointers compare as equal between the normal executable and the shared library. */ - if (! info->shared + if (! bfd_link_pic (info) && h->def_dynamic && !h->def_regular) { @@ -5309,7 +6018,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (htab->plt_type == PLT_VXWORKS) { /* Allocate space for the unloaded relocations. */ - if (!info->shared + if (!bfd_link_pic (info) && htab->elf.dynamic_sections_created) { if (ent->plt.offset @@ -5352,7 +6061,13 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) } eh = (struct ppc_elf_link_hash_entry *) h; - if (eh->elf.got.refcount > 0) + if (eh->elf.got.refcount > 0 + || (ELIMINATE_COPY_RELOCS + && !eh->elf.def_regular + && eh->elf.protected_def + && eh->has_addr16_ha + && eh->has_addr16_lo + && htab->params->pic_fixup > 0)) { bfd_boolean dyn; unsigned int need; @@ -5395,12 +6110,15 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) { eh->elf.got.offset = allocate_got (htab, need); dyn = htab->elf.dynamic_sections_created; - if ((info->shared + if ((bfd_link_pic (info) || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, &eh->elf)) && (ELF_ST_VISIBILITY (eh->elf.other) == STV_DEFAULT || eh->elf.root.type != bfd_link_hash_undefweak)) { asection *rsec = htab->relgot; + + if (eh->elf.type == STT_GNU_IFUNC) + rsec = htab->reliplt; /* All the entries we allocated need relocs. Except LD only needs one. */ if ((eh->tls_mask & TLS_LD) != 0 @@ -5423,7 +6141,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) space for relocs that have become local due to symbol visibility changes. */ - if (info->shared) + if (bfd_link_pic (info)) { /* Relocs that use pc_count are those that appear on a call insn, or certain REL relocs (see must_be_dyn_reloc) that can be @@ -5492,7 +6210,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) dynamic. */ if (!h->non_got_ref - && !h->def_regular) + && !h->def_regular + && !(h->protected_def + && eh->has_addr16_ha + && eh->has_addr16_lo + && htab->params->pic_fixup > 0)) { /* Make sure this symbol is output as a dynamic symbol. Undefined weak syms won't yet be marked as dynamic. */ @@ -5518,7 +6240,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) for (p = eh->dyn_relocs; p != NULL; p = p->next) { asection *sreloc = elf_section_data (p->sec)->sreloc; - if (!htab->elf.dynamic_sections_created) + if (eh->elf.type == STT_GNU_IFUNC) sreloc = htab->reliplt; sreloc->size += p->count * sizeof (Elf32_External_Rela); } @@ -5562,7 +6284,7 @@ static const unsigned char glink_eh_frame_cie[] = /* Set the sizes of the dynamic sections. */ static bfd_boolean -ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, +ppc_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) { struct ppc_elf_link_hash_table *htab; @@ -5580,9 +6302,9 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, if (elf_hash_table (info)->dynamic_sections_created) { /* Set the contents of the .interp section to the interpreter. */ - if (info->executable) + if (bfd_link_executable (info) && !info->nointerp) { - s = bfd_get_section_by_name (htab->elf.dynobj, ".interp"); + s = bfd_get_linker_section (htab->elf.dynobj, ".interp"); BFD_ASSERT (s != NULL); s->size = sizeof ELF_DYNAMIC_INTERPRETER; s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; @@ -5596,7 +6318,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, /* Set up .got offsets for local syms, and space for local dynamic relocs. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { bfd_signed_vma *local_got; bfd_signed_vma *end_local_got; @@ -5611,9 +6333,9 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, for (s = ibfd->sections; s != NULL; s = s->next) { - struct elf_dyn_relocs *p; + struct ppc_dyn_relocs *p; - for (p = ((struct elf_dyn_relocs *) + for (p = ((struct ppc_dyn_relocs *) elf_section_data (s)->local_dynrel); p != NULL; p = p->next) @@ -5636,7 +6358,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, else if (p->count != 0) { asection *sreloc = elf_section_data (p->sec)->sreloc; - if (!htab->elf.dynamic_sections_created) + if (p->ifunc) sreloc = htab->reliplt; sreloc->size += p->count * sizeof (Elf32_External_Rela); if ((p->sec->output_section->flags @@ -5680,9 +6402,13 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, else { *local_got = allocate_got (htab, need); - if (info->shared) - htab->relgot->size += (need - * (sizeof (Elf32_External_Rela) / 4)); + if (bfd_link_pic (info)) + { + asection *srel = htab->relgot; + if ((*lgot_masks & PLT_IFUNC) != 0) + srel = htab->reliplt; + srel->size += need * (sizeof (Elf32_External_Rela) / 4); + } } } else @@ -5711,7 +6437,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, ent->plt.offset = plt_offset; s = htab->glink; - if (!doneone || info->shared) + if (!doneone || bfd_link_pic (info)) { glink_offset = s->size; s->size += GLINK_ENTRY_SIZE; @@ -5735,7 +6461,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, if (htab->tlsld_got.refcount > 0) { htab->tlsld_got.offset = allocate_got (htab, 8); - if (info->shared) + if (bfd_link_pic (info)) htab->relgot->size += sizeof (Elf32_External_Rela); } else @@ -5759,17 +6485,22 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, htab->elf.hgot->root.u.def.value = g_o_t; } - if (info->shared) + if (bfd_link_pic (info)) { struct elf_link_hash_entry *sda = htab->sdata[0].sym; - if (sda != NULL - && !(sda->root.type == bfd_link_hash_defined - || sda->root.type == bfd_link_hash_defweak)) - { - sda->root.type = bfd_link_hash_defined; - sda->root.u.def.section = htab->elf.hgot->root.u.def.section; - sda->root.u.def.value = htab->elf.hgot->root.u.def.value; - } + + sda->root.u.def.section = htab->elf.hgot->root.u.def.section; + sda->root.u.def.value = htab->elf.hgot->root.u.def.value; + } + if (info->emitrelocations) + { + struct elf_link_hash_entry *sda = htab->sdata[0].sym; + + if (sda != NULL && sda->ref_regular) + sda->root.u.def.section->flags |= SEC_KEEP; + sda = htab->sdata[1].sym; + if (sda != NULL && sda->ref_regular) + sda->root.u.def.section->flags |= SEC_KEEP; } if (htab->glink != NULL @@ -5777,13 +6508,16 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, && htab->elf.dynamic_sections_created) { htab->glink_pltresolve = htab->glink->size; - /* Space for the branch table. */ + /* Space for the branch table. ??? We don't need entries for + non-dynamic symbols in this table. This case can arise with + static ifuncs or forced local ifuncs. */ htab->glink->size += htab->glink->size / (GLINK_ENTRY_SIZE / 4) - 4; /* Pad out to align the start of PLTresolve. */ - htab->glink->size += -htab->glink->size & 15; + htab->glink->size += -htab->glink->size & (htab->params->ppc476_workaround + ? 63 : 15); htab->glink->size += GLINK_PLTRESOLVE; - if (htab->emit_stub_syms) + if (htab->params->emit_stub_syms) { struct elf_link_hash_entry *sh; sh = elf_link_hash_lookup (&htab->elf, "__glink", @@ -5800,6 +6534,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, sh->ref_regular_nonweak = 1; sh->forced_local = 1; sh->non_elf = 0; + sh->root.linker_def = 1; } sh = elf_link_hash_lookup (&htab->elf, "__glink_PLTresolve", TRUE, FALSE, FALSE); @@ -5815,6 +6550,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, sh->ref_regular_nonweak = 1; sh->forced_local = 1; sh->non_elf = 0; + sh->root.linker_def = 1; } } } @@ -5822,11 +6558,12 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, if (htab->glink != NULL && htab->glink->size != 0 && htab->glink_eh_frame != NULL - && !bfd_is_abs_section (htab->glink_eh_frame->output_section)) + && !bfd_is_abs_section (htab->glink_eh_frame->output_section) + && _bfd_elf_eh_frame_present (info)) { s = htab->glink_eh_frame; s->size = sizeof (glink_eh_frame_cie) + 20; - if (info->shared) + if (bfd_link_pic (info)) { s->size += 4; if (htab->glink->size - GLINK_PLTRESOLVE + 8 >= 256) @@ -5861,13 +6598,17 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, || s == htab->sgotplt || s == htab->sbss || s == htab->dynbss - || s == htab->dynsbss - || s == htab->sdata[0].section - || s == htab->sdata[1].section) + || s == htab->dynsbss) { /* Strip these too. */ } - else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela")) + else if (s == htab->sdata[0].section + || s == htab->sdata[1].section) + { + strip_section = (s->flags & SEC_KEEP) == 0; + } + else if (CONST_STRNEQ (bfd_get_section_name (htab->elf.dynobj, s), + ".rela")) { if (s->size != 0) { @@ -5919,7 +6660,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, #define add_dynamic_entry(TAG, VAL) \ _bfd_elf_add_dynamic_entry (info, TAG, VAL) - if (info->executable) + if (bfd_link_executable (info)) { if (!add_dynamic_entry (DT_DEBUG, 0)) return FALSE; @@ -5934,14 +6675,16 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, return FALSE; } - if (htab->glink != NULL && htab->glink->size != 0) + if (htab->plt_type == PLT_NEW + && htab->glink != NULL + && htab->glink->size != 0) { if (!add_dynamic_entry (DT_PPC_GOT, 0)) return FALSE; - if (!htab->no_tls_get_addr_opt + if (!htab->params->no_tls_get_addr_opt && htab->tls_get_addr != NULL && htab->tls_get_addr->plt.plist != NULL - && !add_dynamic_entry (DT_PPC_TLSOPT, 0)) + && !add_dynamic_entry (DT_PPC_OPT, PPC_OPT_TLS)) return FALSE; } @@ -5970,9 +6713,109 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, } #undef add_dynamic_entry + if (htab->glink_eh_frame != NULL + && htab->glink_eh_frame->contents != NULL) + { + unsigned char *p = htab->glink_eh_frame->contents; + bfd_vma val; + + memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie)); + /* CIE length (rewrite in case little-endian). */ + bfd_put_32 (htab->elf.dynobj, sizeof (glink_eh_frame_cie) - 4, p); + p += sizeof (glink_eh_frame_cie); + /* FDE length. */ + val = htab->glink_eh_frame->size - 4 - sizeof (glink_eh_frame_cie); + bfd_put_32 (htab->elf.dynobj, val, p); + p += 4; + /* CIE pointer. */ + val = p - htab->glink_eh_frame->contents; + bfd_put_32 (htab->elf.dynobj, val, p); + p += 4; + /* Offset to .glink. Set later. */ + p += 4; + /* .glink size. */ + bfd_put_32 (htab->elf.dynobj, htab->glink->size, p); + p += 4; + /* Augmentation. */ + p += 1; + + if (bfd_link_pic (info) + && htab->elf.dynamic_sections_created) + { + bfd_vma adv = (htab->glink->size - GLINK_PLTRESOLVE + 8) >> 2; + if (adv < 64) + *p++ = DW_CFA_advance_loc + adv; + else if (adv < 256) + { + *p++ = DW_CFA_advance_loc1; + *p++ = adv; + } + else if (adv < 65536) + { + *p++ = DW_CFA_advance_loc2; + bfd_put_16 (htab->elf.dynobj, adv, p); + p += 2; + } + else + { + *p++ = DW_CFA_advance_loc4; + bfd_put_32 (htab->elf.dynobj, adv, p); + p += 4; + } + *p++ = DW_CFA_register; + *p++ = 65; + p++; + *p++ = DW_CFA_advance_loc + 4; + *p++ = DW_CFA_restore_extended; + *p++ = 65; + } + BFD_ASSERT ((bfd_vma) ((p + 3 - htab->glink_eh_frame->contents) & -4) + == htab->glink_eh_frame->size); + } + return TRUE; } +/* Arrange to have _SDA_BASE_ or _SDA2_BASE_ stripped from the output + if it looks like nothing is using them. */ + +static void +maybe_strip_sdasym (bfd *output_bfd, elf_linker_section_t *lsect) +{ + struct elf_link_hash_entry *sda = lsect->sym; + + if (sda != NULL && !sda->ref_regular && sda->dynindx == -1) + { + asection *s; + + s = bfd_get_section_by_name (output_bfd, lsect->name); + if (s == NULL || bfd_section_removed_from_list (output_bfd, s)) + { + s = bfd_get_section_by_name (output_bfd, lsect->bss_name); + if (s == NULL || bfd_section_removed_from_list (output_bfd, s)) + { + sda->def_regular = 0; + /* This is somewhat magic. See elf_link_output_extsym. */ + sda->ref_dynamic = 1; + sda->forced_local = 0; + } + } + } +} + +void +ppc_elf_maybe_strip_sdata_syms (struct bfd_link_info *info) +{ + struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); + + if (htab != NULL) + { + maybe_strip_sdasym (info->output_bfd, &htab->sdata[0]); + maybe_strip_sdasym (info->output_bfd, &htab->sdata[1]); + } +} + + /* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ static bfd_boolean @@ -5997,7 +6840,7 @@ static const int shared_stub_entry[] = 0x429f0005, /* bcl 20, 31, .Lxxx */ 0x7d8802a6, /* mflr 12 */ 0x3d8c0000, /* addis 12, 12, (xxx-.Lxxx)@ha */ - 0x398c0008, /* addi 12, 12, (xxx-.Lxxx)@l */ + 0x398c0000, /* addi 12, 12, (xxx-.Lxxx)@l */ 0x7c0803a6, /* mtlr 0 */ 0x7d8903a6, /* mtctr 12 */ 0x4e800420, /* bctr */ @@ -6011,15 +6854,26 @@ static const int stub_entry[] = 0x4e800420, /* bctr */ }; +struct ppc_elf_relax_info +{ + unsigned int workaround_size; + unsigned int picfixup_size; +}; + +/* This function implements long branch trampolines, and the ppc476 + icache bug workaround. Any section needing trampolines or patch + space for the workaround has its size extended so that we can + add trampolines at the end of the section. */ + static bfd_boolean ppc_elf_relax_section (bfd *abfd, asection *isec, struct bfd_link_info *link_info, bfd_boolean *again) { - struct one_fixup + struct one_branch_fixup { - struct one_fixup *next; + struct one_branch_fixup *next; asection *tsec; /* Final link, can use the symbol offset. For a relocatable link we use the symbol's index. */ @@ -6031,408 +6885,513 @@ ppc_elf_relax_section (bfd *abfd, bfd_byte *contents = NULL; Elf_Internal_Sym *isymbuf = NULL; Elf_Internal_Rela *internal_relocs = NULL; - Elf_Internal_Rela *irel, *irelend; - struct one_fixup *fixups = NULL; + Elf_Internal_Rela *irel, *irelend = NULL; + struct one_branch_fixup *branch_fixups = NULL; + struct ppc_elf_relax_info *relax_info = NULL; unsigned changes = 0; + bfd_boolean workaround_change; struct ppc_elf_link_hash_table *htab; - bfd_size_type trampoff; + bfd_size_type trampbase, trampoff, newsize, picfixup_size; asection *got2; bfd_boolean maybe_pasted; *again = FALSE; - /* Nothing to do if there are no relocations, and no need to do - anything with non-alloc or non-code sections. */ + /* No need to do anything with non-alloc or non-code sections. */ if ((isec->flags & SEC_ALLOC) == 0 || (isec->flags & SEC_CODE) == 0 - || (isec->flags & SEC_RELOC) == 0 - || isec->reloc_count == 0) + || (isec->flags & SEC_LINKER_CREATED) != 0 + || isec->size < 4) return TRUE; /* We cannot represent the required PIC relocs in the output, so don't do anything. The linker doesn't support mixing -shared and -r anyway. */ - if (link_info->relocatable && link_info->shared) - return TRUE; + if (bfd_link_relocatable (link_info) && bfd_link_pic (link_info)) + return TRUE; + + htab = ppc_elf_hash_table (link_info); + if (htab == NULL) + return TRUE; + + isec->size = (isec->size + 3) & -4; + if (isec->rawsize == 0) + isec->rawsize = isec->size; + trampbase = isec->size; + + BFD_ASSERT (isec->sec_info_type == SEC_INFO_TYPE_NONE + || isec->sec_info_type == SEC_INFO_TYPE_TARGET); + isec->sec_info_type = SEC_INFO_TYPE_TARGET; + + if (htab->params->ppc476_workaround + || htab->params->pic_fixup > 0) + { + if (elf_section_data (isec)->sec_info == NULL) + { + elf_section_data (isec)->sec_info + = bfd_zalloc (abfd, sizeof (struct ppc_elf_relax_info)); + if (elf_section_data (isec)->sec_info == NULL) + return FALSE; + } + relax_info = elf_section_data (isec)->sec_info; + trampbase -= relax_info->workaround_size; + } - trampoff = (isec->size + 3) & (bfd_vma) -4; maybe_pasted = (strcmp (isec->output_section->name, ".init") == 0 || strcmp (isec->output_section->name, ".fini") == 0); /* Space for a branch around any trampolines. */ - if (maybe_pasted) + trampoff = trampbase; + if (maybe_pasted && trampbase == isec->rawsize) trampoff += 4; symtab_hdr = &elf_symtab_hdr (abfd); - - /* Get a copy of the native relocations. */ - internal_relocs = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, - link_info->keep_memory); - if (internal_relocs == NULL) - goto error_return; - - htab = ppc_elf_hash_table (link_info); - got2 = bfd_get_section_by_name (abfd, ".got2"); - - irelend = internal_relocs + isec->reloc_count; - for (irel = internal_relocs; irel < irelend; irel++) + picfixup_size = 0; + if (htab->params->branch_trampolines + || htab->params->pic_fixup > 0) { - unsigned long r_type = ELF32_R_TYPE (irel->r_info); - bfd_vma toff, roff; - asection *tsec; - struct one_fixup *f; - size_t insn_offset = 0; - bfd_vma max_branch_offset, val; - bfd_byte *hit_addr; - unsigned long t0; - struct elf_link_hash_entry *h; - struct plt_entry **plist; - unsigned char sym_type; - - switch (r_type) + /* Get a copy of the native relocations. */ + if (isec->reloc_count != 0) { - case R_PPC_REL24: - case R_PPC_LOCAL24PC: - case R_PPC_PLTREL24: - max_branch_offset = 1 << 25; - break; - - case R_PPC_REL14: - case R_PPC_REL14_BRTAKEN: - case R_PPC_REL14_BRNTAKEN: - max_branch_offset = 1 << 15; - break; - - default: - continue; + internal_relocs = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, + link_info->keep_memory); + if (internal_relocs == NULL) + goto error_return; } - /* Get the value of the symbol referred to by the reloc. */ - h = NULL; - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - - /* Read this BFD's local symbols. */ - if (isymbuf == NULL) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == 0) - goto error_return; - } - isym = isymbuf + ELF32_R_SYM (irel->r_info); - if (isym->st_shndx == SHN_UNDEF) - tsec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - tsec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - tsec = bfd_com_section_ptr; - else - tsec = bfd_section_from_elf_index (abfd, isym->st_shndx); + got2 = bfd_get_section_by_name (abfd, ".got2"); - toff = isym->st_value; - sym_type = ELF_ST_TYPE (isym->st_info); - } - else + irelend = internal_relocs + isec->reloc_count; + for (irel = internal_relocs; irel < irelend; irel++) { - /* Global symbol handling. */ - unsigned long indx; + unsigned long r_type = ELF32_R_TYPE (irel->r_info); + bfd_vma toff, roff; + asection *tsec; + struct one_branch_fixup *f; + size_t insn_offset = 0; + bfd_vma max_branch_offset = 0, val; + bfd_byte *hit_addr; + unsigned long t0; + struct elf_link_hash_entry *h; + struct plt_entry **plist; + unsigned char sym_type; + + switch (r_type) + { + case R_PPC_REL24: + case R_PPC_LOCAL24PC: + case R_PPC_PLTREL24: + max_branch_offset = 1 << 25; + break; - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; + case R_PPC_REL14: + case R_PPC_REL14_BRTAKEN: + case R_PPC_REL14_BRNTAKEN: + max_branch_offset = 1 << 15; + break; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; + case R_PPC_ADDR16_HA: + if (htab->params->pic_fixup > 0) + break; + continue; - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - tsec = h->root.u.def.section; - toff = h->root.u.def.value; + default: + continue; } - else if (h->root.type == bfd_link_hash_undefined - || h->root.type == bfd_link_hash_undefweak) + + /* Get the value of the symbol referred to by the reloc. */ + h = NULL; + if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) { - tsec = bfd_und_section_ptr; - toff = link_info->relocatable ? indx : 0; + /* A local symbol. */ + Elf_Internal_Sym *isym; + + /* Read this BFD's local symbols. */ + if (isymbuf == NULL) + { + isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; + if (isymbuf == NULL) + isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, + symtab_hdr->sh_info, 0, + NULL, NULL, NULL); + if (isymbuf == 0) + goto error_return; + } + isym = isymbuf + ELF32_R_SYM (irel->r_info); + if (isym->st_shndx == SHN_UNDEF) + tsec = bfd_und_section_ptr; + else if (isym->st_shndx == SHN_ABS) + tsec = bfd_abs_section_ptr; + else if (isym->st_shndx == SHN_COMMON) + tsec = bfd_com_section_ptr; + else + tsec = bfd_section_from_elf_index (abfd, isym->st_shndx); + + toff = isym->st_value; + sym_type = ELF_ST_TYPE (isym->st_info); } else - continue; + { + /* Global symbol handling. */ + unsigned long indx; - sym_type = h->type; - } + indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; + h = elf_sym_hashes (abfd)[indx]; - /* The condition here under which we call find_plt_ent must - match that in relocate_section. If we call find_plt_ent here - but not in relocate_section, or vice versa, then the branch - destination used here may be incorrect. */ - plist = NULL; - if (h != NULL) - { - /* We know is_branch_reloc (r_type) is true. */ - if (h->type == STT_GNU_IFUNC - || r_type == R_PPC_PLTREL24) - plist = &h->plt.plist; - } - else if (sym_type == STT_GNU_IFUNC - && elf_local_got_offsets (abfd) != NULL) - { - bfd_vma *local_got_offsets = elf_local_got_offsets (abfd); - struct plt_entry **local_plt = (struct plt_entry **) - (local_got_offsets + symtab_hdr->sh_info); - plist = local_plt + ELF32_R_SYM (irel->r_info); - } - if (plist != NULL) - { - bfd_vma addend = 0; - struct plt_entry *ent; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; - if (r_type == R_PPC_PLTREL24 && link_info->shared) - addend = irel->r_addend; - ent = find_plt_ent (plist, got2, addend); - if (ent != NULL) - { - if (htab->plt_type == PLT_NEW - || h == NULL - || !htab->elf.dynamic_sections_created - || h->dynindx == -1) + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) { - tsec = htab->glink; - toff = ent->glink_offset; + tsec = h->root.u.def.section; + toff = h->root.u.def.value; } - else + else if (h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak) { - tsec = htab->plt; - toff = ent->plt.offset; + tsec = bfd_und_section_ptr; + toff = bfd_link_relocatable (link_info) ? indx : 0; } - } - } - - /* If the branch and target are in the same section, you have - no hope of adding stubs. We'll error out later should the - branch overflow. */ - if (tsec == isec) - continue; + else + continue; - /* There probably isn't any reason to handle symbols in - SEC_MERGE sections; SEC_MERGE doesn't seem a likely - attribute for a code section, and we are only looking at - branches. However, implement it correctly here as a - reference for other target relax_section functions. */ - if (0 && tsec->sec_info_type == SEC_INFO_TYPE_MERGE) - { - /* At this stage in linking, no SEC_MERGE symbol has been - adjusted, so all references to such symbols need to be - passed through _bfd_merged_section_offset. (Later, in - relocate_section, all SEC_MERGE symbols *except* for - section symbols have been adjusted.) - - gas may reduce relocations against symbols in SEC_MERGE - sections to a relocation against the section symbol when - the original addend was zero. When the reloc is against - a section symbol we should include the addend in the - offset passed to _bfd_merged_section_offset, since the - location of interest is the original symbol. On the - other hand, an access to "sym+addend" where "sym" is not - a section symbol should not include the addend; Such an - access is presumed to be an offset from "sym"; The - location of interest is just "sym". */ - if (sym_type == STT_SECTION) - toff += irel->r_addend; + /* If this branch is to __tls_get_addr then we may later + optimise away the call. We won't be needing a long- + branch stub in that case. */ + if (bfd_link_executable (link_info) + && h == htab->tls_get_addr + && irel != internal_relocs) + { + unsigned long t_symndx = ELF32_R_SYM (irel[-1].r_info); + unsigned long t_rtype = ELF32_R_TYPE (irel[-1].r_info); + unsigned int tls_mask = 0; + + /* The previous reloc should be one of R_PPC_TLSGD or + R_PPC_TLSLD, or for older object files, a reloc + on the __tls_get_addr arg setup insn. Get tls + mask bits from the symbol on that reloc. */ + if (t_symndx < symtab_hdr->sh_info) + { + bfd_vma *local_got_offsets = elf_local_got_offsets (abfd); - toff = _bfd_merged_section_offset (abfd, &tsec, - elf_section_data (tsec)->sec_info, - toff); + if (local_got_offsets != NULL) + { + struct plt_entry **local_plt = (struct plt_entry **) + (local_got_offsets + symtab_hdr->sh_info); + char *lgot_masks = (char *) + (local_plt + symtab_hdr->sh_info); + tls_mask = lgot_masks[t_symndx]; + } + } + else + { + struct elf_link_hash_entry *th + = elf_sym_hashes (abfd)[t_symndx - symtab_hdr->sh_info]; - if (sym_type != STT_SECTION) - toff += irel->r_addend; - } - /* PLTREL24 addends are special. */ - else if (r_type != R_PPC_PLTREL24) - toff += irel->r_addend; + while (th->root.type == bfd_link_hash_indirect + || th->root.type == bfd_link_hash_warning) + th = (struct elf_link_hash_entry *) th->root.u.i.link; - /* Attempted -shared link of non-pic code loses. */ - if (tsec->output_section == NULL) - continue; + tls_mask + = ((struct ppc_elf_link_hash_entry *) th)->tls_mask; + } - roff = irel->r_offset; + /* The mask bits tell us if the call will be + optimised away. */ + if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0 + && (t_rtype == R_PPC_TLSGD + || t_rtype == R_PPC_GOT_TLSGD16 + || t_rtype == R_PPC_GOT_TLSGD16_LO)) + continue; + if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0 + && (t_rtype == R_PPC_TLSLD + || t_rtype == R_PPC_GOT_TLSLD16 + || t_rtype == R_PPC_GOT_TLSLD16_LO)) + continue; + } - /* If the branch is in range, no need to do anything. */ - if (tsec != bfd_und_section_ptr - && (!link_info->relocatable - /* A relocatable link may have sections moved during - final link, so do not presume they remain in range. */ - || tsec->output_section == isec->output_section)) - { - bfd_vma symaddr, reladdr; + sym_type = h->type; + } - symaddr = tsec->output_section->vma + tsec->output_offset + toff; - reladdr = isec->output_section->vma + isec->output_offset + roff; - if (symaddr - reladdr + max_branch_offset < 2 * max_branch_offset) - continue; - } + if (r_type == R_PPC_ADDR16_HA) + { + if (h != NULL + && !h->def_regular + && h->protected_def + && ppc_elf_hash_entry (h)->has_addr16_ha + && ppc_elf_hash_entry (h)->has_addr16_lo) + picfixup_size += 12; + continue; + } - /* Look for an existing fixup to this address. */ - for (f = fixups; f ; f = f->next) - if (f->tsec == tsec && f->toff == toff) - break; + /* The condition here under which we call find_plt_ent must + match that in relocate_section. If we call find_plt_ent here + but not in relocate_section, or vice versa, then the branch + destination used here may be incorrect. */ + plist = NULL; + if (h != NULL) + { + /* We know is_branch_reloc (r_type) is true. */ + if (h->type == STT_GNU_IFUNC + || r_type == R_PPC_PLTREL24) + plist = &h->plt.plist; + } + else if (sym_type == STT_GNU_IFUNC + && elf_local_got_offsets (abfd) != NULL) + { + bfd_vma *local_got_offsets = elf_local_got_offsets (abfd); + struct plt_entry **local_plt = (struct plt_entry **) + (local_got_offsets + symtab_hdr->sh_info); + plist = local_plt + ELF32_R_SYM (irel->r_info); + } + if (plist != NULL) + { + bfd_vma addend = 0; + struct plt_entry *ent; - if (f == NULL) - { - size_t size; - unsigned long stub_rtype; + if (r_type == R_PPC_PLTREL24 && bfd_link_pic (link_info)) + addend = irel->r_addend; + ent = find_plt_ent (plist, got2, addend); + if (ent != NULL) + { + if (htab->plt_type == PLT_NEW + || h == NULL + || !htab->elf.dynamic_sections_created + || h->dynindx == -1) + { + tsec = htab->glink; + toff = ent->glink_offset; + } + else + { + tsec = htab->plt; + toff = ent->plt.offset; + } + } + } - val = trampoff - roff; - if (val >= max_branch_offset) - /* Oh dear, we can't reach a trampoline. Don't try to add - one. We'll report an error later. */ + /* If the branch and target are in the same section, you have + no hope of adding stubs. We'll error out later should the + branch overflow. */ + if (tsec == isec) continue; - if (link_info->shared) + /* There probably isn't any reason to handle symbols in + SEC_MERGE sections; SEC_MERGE doesn't seem a likely + attribute for a code section, and we are only looking at + branches. However, implement it correctly here as a + reference for other target relax_section functions. */ + if (0 && tsec->sec_info_type == SEC_INFO_TYPE_MERGE) { - size = 4 * ARRAY_SIZE (shared_stub_entry); - insn_offset = 12; + /* At this stage in linking, no SEC_MERGE symbol has been + adjusted, so all references to such symbols need to be + passed through _bfd_merged_section_offset. (Later, in + relocate_section, all SEC_MERGE symbols *except* for + section symbols have been adjusted.) + + gas may reduce relocations against symbols in SEC_MERGE + sections to a relocation against the section symbol when + the original addend was zero. When the reloc is against + a section symbol we should include the addend in the + offset passed to _bfd_merged_section_offset, since the + location of interest is the original symbol. On the + other hand, an access to "sym+addend" where "sym" is not + a section symbol should not include the addend; Such an + access is presumed to be an offset from "sym"; The + location of interest is just "sym". */ + if (sym_type == STT_SECTION) + toff += irel->r_addend; + + toff + = _bfd_merged_section_offset (abfd, &tsec, + elf_section_data (tsec)->sec_info, + toff); + + if (sym_type != STT_SECTION) + toff += irel->r_addend; } - else + /* PLTREL24 addends are special. */ + else if (r_type != R_PPC_PLTREL24) + toff += irel->r_addend; + + /* Attempted -shared link of non-pic code loses. */ + if ((!bfd_link_relocatable (link_info) + && tsec == bfd_und_section_ptr) + || tsec->output_section == NULL + || (tsec->owner != NULL + && (tsec->owner->flags & BFD_PLUGIN) != 0)) + continue; + + roff = irel->r_offset; + + /* If the branch is in range, no need to do anything. */ + if (tsec != bfd_und_section_ptr + && (!bfd_link_relocatable (link_info) + /* A relocatable link may have sections moved during + final link, so do not presume they remain in range. */ + || tsec->output_section == isec->output_section)) { - size = 4 * ARRAY_SIZE (stub_entry); - insn_offset = 0; + bfd_vma symaddr, reladdr; + + symaddr = tsec->output_section->vma + tsec->output_offset + toff; + reladdr = isec->output_section->vma + isec->output_offset + roff; + if (symaddr - reladdr + max_branch_offset + < 2 * max_branch_offset) + continue; } - stub_rtype = R_PPC_RELAX; - if (tsec == htab->plt - || tsec == htab->glink) + + /* Look for an existing fixup to this address. */ + for (f = branch_fixups; f ; f = f->next) + if (f->tsec == tsec && f->toff == toff) + break; + + if (f == NULL) { - stub_rtype = R_PPC_RELAX_PLT; - if (r_type == R_PPC_PLTREL24) - stub_rtype = R_PPC_RELAX_PLTREL24; - } + size_t size; + unsigned long stub_rtype; - /* Hijack the old relocation. Since we need two - relocations for this use a "composite" reloc. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - stub_rtype); - irel->r_offset = trampoff + insn_offset; - if (r_type == R_PPC_PLTREL24 - && stub_rtype != R_PPC_RELAX_PLTREL24) - irel->r_addend = 0; - - /* Record the fixup so we don't do it again this section. */ - f = bfd_malloc (sizeof (*f)); - f->next = fixups; - f->tsec = tsec; - f->toff = toff; - f->trampoff = trampoff; - fixups = f; - - trampoff += size; - changes++; - } - else - { - val = f->trampoff - roff; - if (val >= max_branch_offset) - continue; + val = trampoff - roff; + if (val >= max_branch_offset) + /* Oh dear, we can't reach a trampoline. Don't try to add + one. We'll report an error later. */ + continue; - /* Nop out the reloc, since we're finalizing things here. */ - irel->r_info = ELF32_R_INFO (0, R_PPC_NONE); - } + if (bfd_link_pic (link_info)) + { + size = 4 * ARRAY_SIZE (shared_stub_entry); + insn_offset = 12; + } + else + { + size = 4 * ARRAY_SIZE (stub_entry); + insn_offset = 0; + } + stub_rtype = R_PPC_RELAX; + if (tsec == htab->plt + || tsec == htab->glink) + { + stub_rtype = R_PPC_RELAX_PLT; + if (r_type == R_PPC_PLTREL24) + stub_rtype = R_PPC_RELAX_PLTREL24; + } - /* Get the section contents. */ - if (contents == NULL) - { - /* Get cached copy if it exists. */ - if (elf_section_data (isec)->this_hdr.contents != NULL) - contents = elf_section_data (isec)->this_hdr.contents; + /* Hijack the old relocation. Since we need two + relocations for this use a "composite" reloc. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), + stub_rtype); + irel->r_offset = trampoff + insn_offset; + if (r_type == R_PPC_PLTREL24 + && stub_rtype != R_PPC_RELAX_PLTREL24) + irel->r_addend = 0; + + /* Record the fixup so we don't do it again this section. */ + f = bfd_malloc (sizeof (*f)); + f->next = branch_fixups; + f->tsec = tsec; + f->toff = toff; + f->trampoff = trampoff; + branch_fixups = f; + + trampoff += size; + changes++; + } else { + val = f->trampoff - roff; + if (val >= max_branch_offset) + continue; + + /* Nop out the reloc, since we're finalizing things here. */ + irel->r_info = ELF32_R_INFO (0, R_PPC_NONE); + } + + /* Get the section contents. */ + if (contents == NULL) + { + /* Get cached copy if it exists. */ + if (elf_section_data (isec)->this_hdr.contents != NULL) + contents = elf_section_data (isec)->this_hdr.contents; /* Go get them off disk. */ - if (!bfd_malloc_and_get_section (abfd, isec, &contents)) + else if (!bfd_malloc_and_get_section (abfd, isec, &contents)) goto error_return; } - } - /* Fix up the existing branch to hit the trampoline. */ - hit_addr = contents + roff; - switch (r_type) - { - case R_PPC_REL24: - case R_PPC_LOCAL24PC: - case R_PPC_PLTREL24: - t0 = bfd_get_32 (abfd, hit_addr); - t0 &= ~0x3fffffc; - t0 |= val & 0x3fffffc; - bfd_put_32 (abfd, t0, hit_addr); - break; + /* Fix up the existing branch to hit the trampoline. */ + hit_addr = contents + roff; + switch (r_type) + { + case R_PPC_REL24: + case R_PPC_LOCAL24PC: + case R_PPC_PLTREL24: + t0 = bfd_get_32 (abfd, hit_addr); + t0 &= ~0x3fffffc; + t0 |= val & 0x3fffffc; + bfd_put_32 (abfd, t0, hit_addr); + break; - case R_PPC_REL14: - case R_PPC_REL14_BRTAKEN: - case R_PPC_REL14_BRNTAKEN: - t0 = bfd_get_32 (abfd, hit_addr); - t0 &= ~0xfffc; - t0 |= val & 0xfffc; - bfd_put_32 (abfd, t0, hit_addr); - break; + case R_PPC_REL14: + case R_PPC_REL14_BRTAKEN: + case R_PPC_REL14_BRNTAKEN: + t0 = bfd_get_32 (abfd, hit_addr); + t0 &= ~0xfffc; + t0 |= val & 0xfffc; + bfd_put_32 (abfd, t0, hit_addr); + break; + } } - } - - /* Write out the trampolines. */ - if (fixups != NULL) - { - const int *stub; - bfd_byte *dest; - int i, size; - do + while (branch_fixups != NULL) { - struct one_fixup *f = fixups; - fixups = fixups->next; + struct one_branch_fixup *f = branch_fixups; + branch_fixups = branch_fixups->next; free (f); } - while (fixups); - - contents = bfd_realloc_or_free (contents, trampoff); - if (contents == NULL) - goto error_return; - - isec->size = (isec->size + 3) & (bfd_vma) -4; - dest = contents + isec->size; - /* Branch around the trampolines. */ - if (maybe_pasted) - { - bfd_vma val = B + trampoff - isec->size; - bfd_put_32 (abfd, val, dest); - dest += 4; - } - isec->size = trampoff; + } - if (link_info->shared) - { - stub = shared_stub_entry; - size = ARRAY_SIZE (shared_stub_entry); - } - else + workaround_change = FALSE; + newsize = trampoff; + if (htab->params->ppc476_workaround + && (!bfd_link_relocatable (link_info) + || isec->output_section->alignment_power >= htab->params->pagesize_p2)) + { + bfd_vma addr, end_addr; + unsigned int crossings; + bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2; + + addr = isec->output_section->vma + isec->output_offset; + end_addr = addr + trampoff; + addr &= -pagesize; + crossings = ((end_addr & -pagesize) - addr) >> htab->params->pagesize_p2; + if (crossings != 0) { - stub = stub_entry; - size = ARRAY_SIZE (stub_entry); + /* Keep space aligned, to ensure the patch code itself does + not cross a page. Don't decrease size calculated on a + previous pass as otherwise we might never settle on a layout. */ + newsize = 15 - ((end_addr - 1) & 15); + newsize += crossings * 16; + if (relax_info->workaround_size < newsize) + { + relax_info->workaround_size = newsize; + workaround_change = TRUE; + } + /* Ensure relocate_section is called. */ + isec->flags |= SEC_RELOC; } + newsize = trampoff + relax_info->workaround_size; + } - i = 0; - while (dest < contents + trampoff) - { - bfd_put_32 (abfd, stub[i], dest); - i++; - if (i == size) - i = 0; - dest += 4; - } - BFD_ASSERT (i == 0); + if (htab->params->pic_fixup > 0) + { + picfixup_size -= relax_info->picfixup_size; + if (picfixup_size != 0) + relax_info->picfixup_size += picfixup_size; + newsize += relax_info->picfixup_size; } + if (changes != 0 || picfixup_size != 0 || workaround_change) + isec->size = newsize; + if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) { @@ -6457,6 +7416,7 @@ ppc_elf_relax_section (bfd *abfd, } } + changes += picfixup_size; if (changes != 0) { /* Append sufficient NOP relocs so we can write out relocation @@ -6483,34 +7443,20 @@ ppc_elf_relax_section (bfd *abfd, rel_hdr = _bfd_elf_single_rel_hdr (isec); rel_hdr->sh_size += changes * rel_hdr->sh_entsize; } - else if (elf_section_data (isec)->relocs != internal_relocs) + else if (internal_relocs != NULL + && elf_section_data (isec)->relocs != internal_relocs) free (internal_relocs); - *again = changes != 0; - if (!*again && link_info->relocatable) - { - /* Convert the internal relax relocs to external form. */ - for (irel = internal_relocs; irel < irelend; irel++) - if (ELF32_R_TYPE (irel->r_info) == R_PPC_RELAX) - { - unsigned long r_symndx = ELF32_R_SYM (irel->r_info); - - /* Rewrite the reloc and convert one of the trailing nop - relocs to describe this relocation. */ - BFD_ASSERT (ELF32_R_TYPE (irelend[-1].r_info) == R_PPC_NONE); - /* The relocs are at the bottom 2 bytes */ - irel[0].r_offset += 2; - memmove (irel + 1, irel, (irelend - irel - 1) * sizeof (*irel)); - irel[0].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA); - irel[1].r_offset += 4; - irel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO); - irel++; - } - } - + *again = changes != 0 || workaround_change; return TRUE; error_return: + while (branch_fixups != NULL) + { + struct one_branch_fixup *f = branch_fixups; + branch_fixups = branch_fixups->next; + free (f); + } if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents) free (isymbuf); if (contents != NULL @@ -6614,7 +7560,7 @@ write_glink_stub (struct plt_entry *ent, asection *plt_sec, unsigned char *p, + plt_sec->output_section->vma + plt_sec->output_offset); - if (info->shared) + if (bfd_link_pic (info)) { bfd_vma got = 0; @@ -6635,7 +7581,7 @@ write_glink_stub (struct plt_entry *ent, asection *plt_sec, unsigned char *p, p += 4; bfd_put_32 (output_bfd, BCTR, p); p += 4; - bfd_put_32 (output_bfd, NOP, p); + bfd_put_32 (output_bfd, htab->params->ppc476_workaround ? BA : NOP, p); p += 4; } else @@ -6759,6 +7705,23 @@ _bfd_elf_ppc_at_tprel_transform (unsigned int insn, unsigned int reg) return insn; } +static bfd_boolean +is_insn_ds_form (unsigned int insn) +{ + return ((insn & (0x3f << 26)) == 58u << 26 /* ld,ldu,lwa */ + || (insn & (0x3f << 26)) == 62u << 26 /* std,stdu,stq */ + || (insn & (0x3f << 26)) == 57u << 26 /* lfdp */ + || (insn & (0x3f << 26)) == 61u << 26 /* stfdp */); +} + +static bfd_boolean +is_insn_dq_form (unsigned int insn) +{ + return ((insn & (0x3f << 26)) == 56u << 26 /* lq */ + || ((insn & (0x3f << 26)) == (61u << 26) /* lxv, stxv */ + && (insn & 3) == 1)); +} + /* The RELOCATE_SECTION function is called by the ELF backend linker to handle the relocations for a section. @@ -6802,20 +7765,23 @@ ppc_elf_relocate_section (bfd *output_bfd, struct elf_link_hash_entry **sym_hashes; struct ppc_elf_link_hash_table *htab; Elf_Internal_Rela *rel; + Elf_Internal_Rela *wrel; Elf_Internal_Rela *relend; Elf_Internal_Rela outrel; - asection *got2, *sreloc = NULL; + asection *got2; bfd_vma *local_got_offsets; bfd_boolean ret = TRUE; bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0); bfd_boolean is_vxworks_tls; + unsigned int picfixup_size = 0; + struct ppc_elf_relax_info *relax_info = NULL; #ifdef DEBUG _bfd_error_handler ("ppc_elf_relocate_section called for %B section %A, " "%ld relocations%s", input_bfd, input_section, (long) input_section->reloc_count, - (info->relocatable) ? " (relocatable)" : ""); + (bfd_link_relocatable (info)) ? " (relocatable)" : ""); #endif got2 = bfd_get_section_by_name (input_bfd, ".got2"); @@ -6830,12 +7796,14 @@ ppc_elf_relocate_section (bfd *output_bfd, sym_hashes = elf_sym_hashes (input_bfd); /* We have to handle relocations in vxworks .tls_vars sections specially, because the dynamic loader is 'weird'. */ - is_vxworks_tls = (htab->is_vxworks && info->shared + is_vxworks_tls = (htab->is_vxworks && bfd_link_pic (info) && !strcmp (input_section->output_section->name, ".tls_vars")); - rel = relocs; + if (input_section->sec_info_type == SEC_INFO_TYPE_TARGET) + relax_info = elf_section_data (input_section)->sec_info; + rel = wrel = relocs; relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) + for (; rel < relend; wrel++, rel++) { enum elf_ppc_reloc_type r_type; bfd_vma addend; @@ -6852,7 +7820,9 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_boolean warned; unsigned int tls_type, tls_mask, tls_gd; struct plt_entry **ifunc; + struct reloc_howto_struct alt_howto; + again: r_type = ELF32_R_TYPE (rel->r_info); sym = NULL; sec = NULL; @@ -6871,10 +7841,12 @@ ppc_elf_relocate_section (bfd *output_bfd, } else { + bfd_boolean ignored; + RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, r_symndx, symtab_hdr, sym_hashes, h, sec, relocation, - unresolved_reloc, warned); + unresolved_reloc, warned, ignored); sym_name = h->root.root.string; } @@ -6887,21 +7859,38 @@ ppc_elf_relocate_section (bfd *output_bfd, howto = NULL; if (r_type < R_PPC_max) howto = ppc_elf_howto_table[r_type]; - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, relend, howto, contents); + + _bfd_clear_contents (howto, input_bfd, input_section, + contents + rel->r_offset); + wrel->r_offset = rel->r_offset; + wrel->r_info = 0; + wrel->r_addend = 0; + + /* For ld -r, remove relocations in debug sections against + sections defined in discarded sections. Not done for + non-debug to preserve relocs in .eh_frame which the + eh_frame editing code expects to be present. */ + if (bfd_link_relocatable (info) + && (input_section->flags & SEC_DEBUGGING)) + wrel--; + + continue; } - if (info->relocatable) + if (bfd_link_relocatable (info)) { if (got2 != NULL && r_type == R_PPC_PLTREL24 - && rel->r_addend >= 32768) + && rel->r_addend != 0) { /* R_PPC_PLTREL24 is rather special. If non-zero, the addend specifies the GOT pointer offset within .got2. */ rel->r_addend += got2->output_offset; } - continue; + if (r_type != R_PPC_RELAX_PLT + && r_type != R_PPC_RELAX_PLTREL24 + && r_type != R_PPC_RELAX) + goto copy_reloc; } /* TLS optimizations. Replace instruction sequences and relocs @@ -6944,10 +7933,12 @@ ppc_elf_relocate_section (bfd *output_bfd, { bfd_vma insn; - insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset); + insn = bfd_get_32 (output_bfd, + contents + rel->r_offset - d_offset); insn &= 31 << 21; insn |= 0x3c020000; /* addis 0,2,0 */ - bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset); + bfd_put_32 (output_bfd, insn, + contents + rel->r_offset - d_offset); r_type = R_PPC_TPREL16_HA; rel->r_info = ELF32_R_INFO (r_symndx, r_type); } @@ -6990,8 +7981,8 @@ ppc_elf_relocate_section (bfd *output_bfd, + R_PPC_GOT_TPREL16); else { - bfd_put_32 (output_bfd, NOP, contents + rel->r_offset); rel->r_offset -= d_offset; + bfd_put_32 (output_bfd, NOP, contents + rel->r_offset); r_type = R_PPC_NONE; } rel->r_info = ELF32_R_INFO (r_symndx, r_type); @@ -7024,12 +8015,16 @@ ppc_elf_relocate_section (bfd *output_bfd, && branch_reloc_hash_match (input_bfd, rel + 1, htab->tls_get_addr)) offset = rel[1].r_offset; + /* We read the low GOT_TLS insn because we need to keep + the destination reg. It may be something other than + the usual r3, and moved to r3 before the call by + intervening code. */ + insn1 = bfd_get_32 (output_bfd, + contents + rel->r_offset - d_offset); if ((tls_mask & tls_gd) != 0) { /* IE */ - insn1 = bfd_get_32 (output_bfd, - contents + rel->r_offset - d_offset); - insn1 &= (1 << 26) - 1; + insn1 &= (0x1f << 21) | (0x1f << 16); insn1 |= 32 << 26; /* lwz */ if (offset != (bfd_vma) -1) { @@ -7044,7 +8039,8 @@ ppc_elf_relocate_section (bfd *output_bfd, else { /* LE */ - insn1 = 0x3c620000; /* addis 3,2,0 */ + insn1 &= 0x1f << 21; + insn1 |= 0x3c020000; /* addis r,2,0 */ if (tls_gd == 0) { /* Was an LD reloc. */ @@ -7078,8 +8074,7 @@ ppc_elf_relocate_section (bfd *output_bfd, { /* We changed the symbol on an LD reloc. Start over in order to get h, sym, sec etc. right. */ - rel--; - continue; + goto again; } } break; @@ -7137,8 +8132,7 @@ ppc_elf_relocate_section (bfd *output_bfd, /* Zap the reloc on the _tls_get_addr call too. */ BFD_ASSERT (rel->r_offset - d_offset == rel[1].r_offset); rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE); - rel--; - continue; + goto again; } break; } @@ -7179,6 +8173,115 @@ ppc_elf_relocate_section (bfd *output_bfd, } } + if (ELIMINATE_COPY_RELOCS + && h != NULL + && !h->def_regular + && h->protected_def + && ppc_elf_hash_entry (h)->has_addr16_ha + && ppc_elf_hash_entry (h)->has_addr16_lo + && htab->params->pic_fixup > 0) + { + /* Convert lis;addi or lis;load/store accessing a protected + variable defined in a shared library to PIC. */ + unsigned int insn; + + if (r_type == R_PPC_ADDR16_HA) + { + insn = bfd_get_32 (output_bfd, + contents + rel->r_offset - d_offset); + if ((insn & (0x3f << 26)) == (15u << 26) + && (insn & (0x1f << 16)) == 0 /* lis */) + { + bfd_byte *p; + bfd_vma off; + bfd_vma got_addr; + + p = (contents + input_section->size + - relax_info->workaround_size + - relax_info->picfixup_size + + picfixup_size); + off = (p - contents) - (rel->r_offset - d_offset); + if (off > 0x1fffffc || (off & 3) != 0) + info->callbacks->einfo + (_("%P: %H: fixup branch overflow\n"), + input_bfd, input_section, rel->r_offset); + + bfd_put_32 (output_bfd, B | off, + contents + rel->r_offset - d_offset); + got_addr = (htab->got->output_section->vma + + htab->got->output_offset + + (h->got.offset & ~1)); + wrel->r_offset = (p - contents) + d_offset; + wrel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_HA); + wrel->r_addend = got_addr; + insn &= ~0xffff; + insn |= ((unsigned int )(got_addr + 0x8000) >> 16) & 0xffff; + bfd_put_32 (output_bfd, insn, p); + + /* Convert lis to lwz, loading address from GOT. */ + insn &= ~0xffff; + insn ^= (32u ^ 15u) << 26; + insn |= (insn & (0x1f << 21)) >> 5; + insn |= got_addr & 0xffff; + bfd_put_32 (output_bfd, insn, p + 4); + + bfd_put_32 (output_bfd, B | ((-4 - off) & 0x3ffffff), p + 8); + picfixup_size += 12; + + /* Use one of the spare relocs, so --emit-relocs + output is reasonable. */ + memmove (rel + 1, rel, (relend - rel - 1) * sizeof (*rel)); + wrel++, rel++; + rel->r_offset = wrel[-1].r_offset + 4; + rel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_LO); + rel->r_addend = wrel[-1].r_addend; + + /* Continue on as if we had a got reloc, to output + dynamic reloc. */ + r_type = R_PPC_GOT16_LO; + } + else + info->callbacks->einfo + (_("%P: %H: error: %s with unexpected instruction %x\n"), + input_bfd, input_section, rel->r_offset, + "R_PPC_ADDR16_HA", insn); + } + else if (r_type == R_PPC_ADDR16_LO) + { + insn = bfd_get_32 (output_bfd, + contents + rel->r_offset - d_offset); + if ((insn & (0x3f << 26)) == 14u << 26 /* addi */ + || (insn & (0x3f << 26)) == 32u << 26 /* lwz */ + || (insn & (0x3f << 26)) == 34u << 26 /* lbz */ + || (insn & (0x3f << 26)) == 36u << 26 /* stw */ + || (insn & (0x3f << 26)) == 38u << 26 /* stb */ + || (insn & (0x3f << 26)) == 40u << 26 /* lhz */ + || (insn & (0x3f << 26)) == 42u << 26 /* lha */ + || (insn & (0x3f << 26)) == 44u << 26 /* sth */ + || (insn & (0x3f << 26)) == 46u << 26 /* lmw */ + || (insn & (0x3f << 26)) == 47u << 26 /* stmw */ + || (insn & (0x3f << 26)) == 48u << 26 /* lfs */ + || (insn & (0x3f << 26)) == 50u << 26 /* lfd */ + || (insn & (0x3f << 26)) == 52u << 26 /* stfs */ + || (insn & (0x3f << 26)) == 54u << 26 /* stfd */ + || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */ + && (insn & 3) != 1) + || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */ + && ((insn & 3) == 0 || (insn & 3) == 3))) + { + /* Arrange to apply the reloc addend, if any. */ + relocation = 0; + unresolved_reloc = FALSE; + rel->r_info = ELF32_R_INFO (0, r_type); + } + else + info->callbacks->einfo + (_("%P: %H: error: %s with unexpected instruction %x\n"), + input_bfd, input_section, rel->r_offset, + "R_PPC_ADDR16_LO", insn); + } + } + ifunc = NULL; if (!htab->is_vxworks) { @@ -7201,16 +8304,36 @@ ppc_elf_relocate_section (bfd *output_bfd, ent = NULL; if (ifunc != NULL - && (!info->shared + && (!bfd_link_pic (info) || is_branch_reloc (r_type))) { addend = 0; - if (r_type == R_PPC_PLTREL24 && info->shared) + if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info)) addend = rel->r_addend; ent = find_plt_ent (ifunc, got2, addend); } if (ent != NULL) { + if (bfd_link_pic (info) + && ent->sec != got2 + && htab->plt_type != PLT_NEW + && (!htab->elf.dynamic_sections_created + || h == NULL + || h->dynindx == -1)) + { + /* Uh oh, we are going to create a pic glink stub + for an ifunc (here for h == NULL and later in + finish_dynamic_symbol for h != NULL), and + apparently are using code compiled with + -mbss-plt. The difficulty is that -mbss-plt code + gives no indication via a magic PLTREL24 addend + whether r30 is equal to _GLOBAL_OFFSET_TABLE_ or + is pointing into a .got2 section (and how far + into .got2). */ + info->callbacks->einfo + (_("%X%P: %H: unsupported bss-plt -fPIC ifunc %s\n"), + input_bfd, input_section, rel->r_offset, sym_name); + } if (h == NULL && (ent->plt.offset & 1) == 0) { Elf_Internal_Rela rela; @@ -7239,7 +8362,8 @@ ppc_elf_relocate_section (bfd *output_bfd, unresolved_reloc = FALSE; if (htab->plt_type == PLT_NEW || !htab->elf.dynamic_sections_created - || h == NULL) + || h == NULL + || h->dynindx == -1) relocation = (htab->glink->output_section->vma + htab->glink->output_offset + (ent->glink_offset & ~1)); @@ -7264,7 +8388,7 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_bad_value); ret = FALSE; - continue; + goto copy_reloc; case R_PPC_NONE: case R_PPC_TLS: @@ -7273,7 +8397,7 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_EMB_MRKREF: case R_PPC_GNU_VTINHERIT: case R_PPC_GNU_VTENTRY: - continue; + goto copy_reloc; /* GOT16 relocations. Like an ADDR16 using the symbol's address in the GOT as relocation value instead of the @@ -7332,8 +8456,8 @@ ppc_elf_relocate_section (bfd *output_bfd, { bfd_boolean dyn; dyn = htab->elf.dynamic_sections_created; - if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) - || (info->shared + if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h) + || (bfd_link_pic (info) && SYMBOL_REFERENCES_LOCAL (info, h))) /* This is actually a static link, or it is a -Bsymbolic link and the symbol is defined @@ -7342,6 +8466,7 @@ ppc_elf_relocate_section (bfd *output_bfd, ; else { + BFD_ASSERT (h->dynindx != -1); indx = h->dynindx; unresolved_reloc = FALSE; } @@ -7400,7 +8525,7 @@ ppc_elf_relocate_section (bfd *output_bfd, } /* Generate relocs for the dynamic linker. */ - if ((info->shared || indx != 0) + if ((bfd_link_pic (info) || indx != 0) && (offp == &htab->tlsld_got.offset || h == NULL || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT @@ -7409,6 +8534,8 @@ ppc_elf_relocate_section (bfd *output_bfd, asection *rsec = htab->relgot; bfd_byte * loc; + if (ifunc != NULL) + rsec = htab->reliplt; outrel.r_offset = (htab->got->output_section->vma + htab->got->output_offset + off); @@ -7442,7 +8569,12 @@ ppc_elf_relocate_section (bfd *output_bfd, { outrel.r_addend += relocation; if (tls_ty & (TLS_GD | TLS_DTPREL | TLS_TPREL)) - outrel.r_addend -= htab->elf.tls_sec->vma; + { + if (htab->elf.tls_sec == NULL) + outrel.r_addend = 0; + else + outrel.r_addend -= htab->elf.tls_sec->vma; + } } loc = rsec->contents; loc += (rsec->reloc_count++ @@ -7460,9 +8592,14 @@ ppc_elf_relocate_section (bfd *output_bfd, value = 1; else if (tls_ty != 0) { - value -= htab->elf.tls_sec->vma + DTP_OFFSET; - if (tls_ty == (TLS_TLS | TLS_TPREL)) - value += DTP_OFFSET - TP_OFFSET; + if (htab->elf.tls_sec == NULL) + value = 0; + else + { + value -= htab->elf.tls_sec->vma + DTP_OFFSET; + if (tls_ty == (TLS_TLS | TLS_TPREL)) + value += DTP_OFFSET - TP_OFFSET; + } if (tls_ty == (TLS_TLS | TLS_GD)) { @@ -7509,6 +8646,10 @@ ppc_elf_relocate_section (bfd *output_bfd, } } + /* If here for a picfixup, we're done. */ + if (r_type != ELF32_R_TYPE (rel->r_info)) + goto copy_reloc; + relocation = (htab->got->output_section->vma + htab->got->output_offset + off @@ -7525,22 +8666,35 @@ ppc_elf_relocate_section (bfd *output_bfd, howto->name, sym_name); } - break; + break; - /* Relocations that need no special processing. */ + /* Relocations that need no special processing. */ case R_PPC_LOCAL24PC: /* It makes no sense to point a local relocation at a symbol not in this object. */ if (unresolved_reloc) { - if (! (*info->callbacks->undefined_symbol) (info, - h->root.root.string, - input_bfd, - input_section, - rel->r_offset, - TRUE)) - return FALSE; - continue; + (*info->callbacks->undefined_symbol) (info, + h->root.root.string, + input_bfd, + input_section, + rel->r_offset, + TRUE); + goto copy_reloc; + } + if (h != NULL && h->type == STT_GNU_IFUNC && bfd_link_pic (info)) + { + /* @local on an ifunc does not really make sense since + the ifunc resolver can take you anywhere. More + seriously, calls to ifuncs must go through a plt call + stub, and for pic the plt call stubs uses r30 to + access the PLT. The problem is that a call that is + local won't have the +32k reloc addend trick marking + -fPIC code, so the linker won't know whether r30 is + _GLOBAL_OFFSET_TABLE_ or pointing into a .got2 section. */ + info->callbacks->einfo (_("%X%P: %H: @local call to ifunc %s\n"), + input_bfd, input_section, rel->r_offset, + h->root.root.string); } break; @@ -7548,7 +8702,8 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_DTPREL16_LO: case R_PPC_DTPREL16_HI: case R_PPC_DTPREL16_HA: - addend -= htab->elf.tls_sec->vma + DTP_OFFSET; + if (htab->elf.tls_sec != NULL) + addend -= htab->elf.tls_sec->vma + DTP_OFFSET; break; /* Relocations that may need to be propagated if this is a shared @@ -7572,18 +8727,21 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_put_32 (output_bfd, insn, p); break; } - addend -= htab->elf.tls_sec->vma + TP_OFFSET; + if (htab->elf.tls_sec != NULL) + addend -= htab->elf.tls_sec->vma + TP_OFFSET; /* The TPREL16 relocs shouldn't really be used in shared libs as they will result in DT_TEXTREL being set, but support them anyway. */ goto dodyn; case R_PPC_TPREL32: - addend -= htab->elf.tls_sec->vma + TP_OFFSET; + if (htab->elf.tls_sec != NULL) + addend -= htab->elf.tls_sec->vma + TP_OFFSET; goto dodyn; case R_PPC_DTPREL32: - addend -= htab->elf.tls_sec->vma + DTP_OFFSET; + if (htab->elf.tls_sec != NULL) + addend -= htab->elf.tls_sec->vma + DTP_OFFSET; goto dodyn; case R_PPC_DTPMOD32: @@ -7595,6 +8753,7 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_REL16_LO: case R_PPC_REL16_HI: case R_PPC_REL16_HA: + case R_PPC_REL16DX_HA: break; case R_PPC_REL32: @@ -7611,6 +8770,9 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_UADDR16: goto dodyn; + case R_PPC_VLE_REL8: + case R_PPC_VLE_REL15: + case R_PPC_VLE_REL24: case R_PPC_REL24: case R_PPC_REL14: case R_PPC_REL14_BRTAKEN: @@ -7626,7 +8788,7 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_ADDR14: case R_PPC_ADDR14_BRTAKEN: case R_PPC_ADDR14_BRNTAKEN: - if (h != NULL && !info->shared) + if (h != NULL && !bfd_link_pic (info)) break; /* fall through */ @@ -7635,7 +8797,7 @@ ppc_elf_relocate_section (bfd *output_bfd, || is_vxworks_tls) break; - if ((info->shared + if ((bfd_link_pic (info) && !(h != NULL && ((h->root.type == bfd_link_hash_undefined && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN @@ -7645,14 +8807,19 @@ ppc_elf_relocate_section (bfd *output_bfd, && (must_be_dyn_reloc (info, r_type) || !SYMBOL_CALLS_LOCAL (info, h))) || (ELIMINATE_COPY_RELOCS - && !info->shared + && !bfd_link_pic (info) && h != NULL && h->dynindx != -1 && !h->non_got_ref - && !h->def_regular)) + && !h->def_regular + && !(h->protected_def + && ppc_elf_hash_entry (h)->has_addr16_ha + && ppc_elf_hash_entry (h)->has_addr16_lo + && htab->params->pic_fixup > 0))) { int skip; - bfd_byte * loc; + bfd_byte *loc; + asection *sreloc; #ifdef DEBUG fprintf (stderr, "ppc_elf_relocate_section needs to " "create relocation for %s\n", @@ -7663,14 +8830,11 @@ ppc_elf_relocate_section (bfd *output_bfd, /* When generating a shared object, these relocations are copied into the output file to be resolved at run time. */ + sreloc = elf_section_data (input_section)->sreloc; + if (ifunc) + sreloc = htab->reliplt; if (sreloc == NULL) - { - sreloc = elf_section_data (input_section)->sreloc; - if (!htab->elf.dynamic_sections_created) - sreloc = htab->reliplt; - if (sreloc == NULL) - return FALSE; - } + return FALSE; skip = 0; outrel.r_offset = _bfd_elf_section_offset (output_bfd, info, @@ -7689,6 +8853,7 @@ ppc_elf_relocate_section (bfd *output_bfd, || h->root.type == bfd_link_hash_undefweak)) || !SYMBOL_REFERENCES_LOCAL (info, h)) { + BFD_ASSERT (h->dynindx != -1); unresolved_reloc = FALSE; outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); outrel.r_addend = rel->r_addend; @@ -7769,7 +8934,7 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); if (skip == -1) - continue; + goto copy_reloc; /* This reloc will be computed at runtime. We clear the memory so that it contains predictable value. */ @@ -7793,7 +8958,7 @@ ppc_elf_relocate_section (bfd *output_bfd, if (r_type == R_PPC_RELAX_PLTREL24) { - if (info->shared) + if (bfd_link_pic (info)) got2_addend = addend; addend = 0; } @@ -7810,41 +8975,65 @@ ppc_elf_relocate_section (bfd *output_bfd, /* Fall thru */ case R_PPC_RELAX: - if (info->shared) - relocation -= (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset - 4); - { - unsigned long t0; - unsigned long t1; - - t0 = bfd_get_32 (output_bfd, contents + rel->r_offset); - t1 = bfd_get_32 (output_bfd, contents + rel->r_offset + 4); + const int *stub; + size_t size; + size_t insn_offset = rel->r_offset; + unsigned int insn; - /* We're clearing the bits for R_PPC_ADDR16_HA - and R_PPC_ADDR16_LO here. */ - t0 &= ~0xffff; - t1 &= ~0xffff; + if (bfd_link_pic (info)) + { + relocation -= (input_section->output_section->vma + + input_section->output_offset + + rel->r_offset - 4); + stub = shared_stub_entry; + bfd_put_32 (output_bfd, stub[0], contents + insn_offset - 12); + bfd_put_32 (output_bfd, stub[1], contents + insn_offset - 8); + bfd_put_32 (output_bfd, stub[2], contents + insn_offset - 4); + stub += 3; + size = ARRAY_SIZE (shared_stub_entry) - 3; + } + else + { + stub = stub_entry; + size = ARRAY_SIZE (stub_entry); + } - /* t0 is HA, t1 is LO */ relocation += addend; - t0 |= ((relocation + 0x8000) >> 16) & 0xffff; - t1 |= relocation & 0xffff; - - bfd_put_32 (output_bfd, t0, contents + rel->r_offset); - bfd_put_32 (output_bfd, t1, contents + rel->r_offset + 4); + if (bfd_link_relocatable (info)) + relocation = 0; + + /* First insn is HA, second is LO. */ + insn = *stub++; + insn |= ((relocation + 0x8000) >> 16) & 0xffff; + bfd_put_32 (output_bfd, insn, contents + insn_offset); + insn_offset += 4; + + insn = *stub++; + insn |= relocation & 0xffff; + bfd_put_32 (output_bfd, insn, contents + insn_offset); + insn_offset += 4; + size -= 2; + + while (size != 0) + { + insn = *stub++; + --size; + bfd_put_32 (output_bfd, insn, contents + insn_offset); + insn_offset += 4; + } /* Rewrite the reloc and convert one of the trailing nop relocs to describe this relocation. */ BFD_ASSERT (ELF32_R_TYPE (relend[-1].r_info) == R_PPC_NONE); /* The relocs are at the bottom 2 bytes */ - rel[0].r_offset += 2; - memmove (rel + 1, rel, (relend - rel - 1) * sizeof (*rel)); - rel[0].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA); - rel[1].r_offset += 4; - rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO); - rel++; + wrel->r_offset = rel->r_offset + d_offset; + wrel->r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA); + wrel->r_addend = rel->r_addend; + memmove (wrel + 1, wrel, (relend - wrel - 1) * sizeof (*wrel)); + wrel++, rel++; + wrel->r_offset += 4; + wrel->r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO); } continue; @@ -7886,40 +9075,48 @@ ppc_elf_relocate_section (bfd *output_bfd, unresolved_reloc = TRUE; break; } - BFD_ASSERT (strcmp (bfd_get_section_name (abfd, sec), ".got") == 0 - || strcmp (bfd_get_section_name (abfd, sec), ".cgot") == 0); + BFD_ASSERT (strcmp (bfd_get_section_name (sec->owner, sec), + ".got") == 0 + || strcmp (bfd_get_section_name (sec->owner, sec), + ".cgot") == 0); addend -= sec->output_section->vma + sec->output_offset + 0x8000; break; case R_PPC_PLTREL24: - if (h == NULL || ifunc != NULL) - break; - /* Relocation is to the entry for this symbol in the - procedure linkage table. */ - { - struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2, - info->shared ? addend : 0); - addend = 0; - if (ent == NULL - || htab->plt == NULL) - { - /* We didn't make a PLT entry for this symbol. This - happens when statically linking PIC code, or when - using -Bsymbolic. */ - break; - } + if (h != NULL && ifunc == NULL) + { + struct plt_entry *ent; - unresolved_reloc = FALSE; - if (htab->plt_type == PLT_NEW) - relocation = (htab->glink->output_section->vma - + htab->glink->output_offset - + ent->glink_offset); - else - relocation = (htab->plt->output_section->vma - + htab->plt->output_offset - + ent->plt.offset); - } + ent = find_plt_ent (&h->plt.plist, got2, + bfd_link_pic (info) ? addend : 0); + if (ent == NULL + || htab->plt == NULL) + { + /* We didn't make a PLT entry for this symbol. This + happens when statically linking PIC code, or when + using -Bsymbolic. */ + } + else + { + /* Relocation is to the entry for this symbol in the + procedure linkage table. */ + unresolved_reloc = FALSE; + if (htab->plt_type == PLT_NEW) + relocation = (htab->glink->output_section->vma + + htab->glink->output_offset + + ent->glink_offset); + else + relocation = (htab->plt->output_section->vma + + htab->plt->output_offset + + ent->plt.offset); + } + } + + /* R_PPC_PLTREL24 is rather special. If non-zero, the + addend specifies the GOT pointer offset within .got2. + Don't apply it to the relocation field. */ + addend = 0; break; /* Relocate against _SDA_BASE_. */ @@ -7937,11 +9134,9 @@ ppc_elf_relocate_section (bfd *output_bfd, } addend -= SYM_VAL (sda); - name = bfd_get_section_name (abfd, sec->output_section); - if (! ((CONST_STRNEQ (name, ".sdata") - && (name[6] == 0 || name[6] == '.')) - || (CONST_STRNEQ (name, ".sbss") - && (name[5] == 0 || name[5] == '.')))) + name = bfd_get_section_name (output_bfd, sec->output_section); + if (!(strcmp (name, ".sdata") == 0 + || strcmp (name, ".sbss") == 0)) { info->callbacks->einfo (_("%P: %B: the target (%s) of a %s relocation is " @@ -7969,9 +9164,9 @@ ppc_elf_relocate_section (bfd *output_bfd, } addend -= SYM_VAL (sda); - name = bfd_get_section_name (abfd, sec->output_section); - if (! (CONST_STRNEQ (name, ".sdata2") - || CONST_STRNEQ (name, ".sbss2"))) + name = bfd_get_section_name (output_bfd, sec->output_section); + if (!(strcmp (name, ".sdata2") == 0 + || strcmp (name, ".sbss2") == 0)) { info->callbacks->einfo (_("%P: %B: the target (%s) of a %s relocation is " @@ -7984,12 +9179,51 @@ ppc_elf_relocate_section (bfd *output_bfd, } break; + case R_PPC_VLE_LO16A: + relocation = relocation + addend; + ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, + relocation, split16a_type); + goto copy_reloc; + + case R_PPC_VLE_LO16D: + relocation = relocation + addend; + ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, + relocation, split16d_type); + goto copy_reloc; + + case R_PPC_VLE_HI16A: + relocation = (relocation + addend) >> 16; + ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, + relocation, split16a_type); + goto copy_reloc; + + case R_PPC_VLE_HI16D: + relocation = (relocation + addend) >> 16; + ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, + relocation, split16d_type); + goto copy_reloc; + + case R_PPC_VLE_HA16A: + relocation = (relocation + addend + 0x8000) >> 16; + ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, + relocation, split16a_type); + goto copy_reloc; + + case R_PPC_VLE_HA16D: + relocation = (relocation + addend + 0x8000) >> 16; + ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, + relocation, split16d_type); + goto copy_reloc; + /* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0. */ case R_PPC_EMB_SDA21: + case R_PPC_VLE_SDA21: case R_PPC_EMB_RELSDA: + case R_PPC_VLE_SDA21_LO: { const char *name; int reg; + unsigned int insn; struct elf_link_hash_entry *sda = NULL; if (sec == NULL || sec->output_section == NULL) @@ -7998,17 +9232,15 @@ ppc_elf_relocate_section (bfd *output_bfd, break; } - name = bfd_get_section_name (abfd, sec->output_section); - if (((CONST_STRNEQ (name, ".sdata") - && (name[6] == 0 || name[6] == '.')) - || (CONST_STRNEQ (name, ".sbss") - && (name[5] == 0 || name[5] == '.')))) + name = bfd_get_section_name (output_bfd, sec->output_section); + if (strcmp (name, ".sdata") == 0 + || strcmp (name, ".sbss") == 0) { reg = 13; sda = htab->sdata[0].sym; } - else if (CONST_STRNEQ (name, ".sdata2") - || CONST_STRNEQ (name, ".sbss2")) + else if (strcmp (name, ".sdata2") == 0 + || strcmp (name, ".sbss2") == 0) { reg = 2; sda = htab->sdata[1].sym; @@ -8030,7 +9262,7 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_bad_value); ret = FALSE; - continue; + goto copy_reloc; } if (sda != NULL) @@ -8043,17 +9275,136 @@ ppc_elf_relocate_section (bfd *output_bfd, addend -= SYM_VAL (sda); } - if (r_type == R_PPC_EMB_SDA21) + insn = bfd_get_32 (output_bfd, contents + rel->r_offset); + if (reg == 0 + && (r_type == R_PPC_VLE_SDA21 + || r_type == R_PPC_VLE_SDA21_LO)) { - bfd_vma insn; /* Fill in register field. */ + relocation = relocation + addend; + addend = 0; + + /* Force e_li insn, keeping RT from original insn. */ + insn &= 0x1f << 21; + insn |= 28u << 26; + + /* We have an li20 field, bits 17..20, 11..15, 21..31. */ + /* Top 4 bits of value to 17..20. */ + insn |= (relocation & 0xf0000) >> 5; + /* Next 5 bits of the value to 11..15. */ + insn |= (relocation & 0xf800) << 5; + /* And the final 11 bits of the value to bits 21 to 31. */ + insn |= relocation & 0x7ff; - insn = bfd_get_32 (output_bfd, contents + rel->r_offset); - insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT); bfd_put_32 (output_bfd, insn, contents + rel->r_offset); + + if (r_type == R_PPC_VLE_SDA21 + && ((relocation + 0x80000) & 0xffffffff) > 0x100000) + goto overflow; + goto copy_reloc; + } + else if (r_type == R_PPC_EMB_SDA21 + || r_type == R_PPC_VLE_SDA21 + || r_type == R_PPC_VLE_SDA21_LO) + { + /* Fill in register field. */ + insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT); } + bfd_put_32 (output_bfd, insn, contents + rel->r_offset); } break; + case R_PPC_VLE_SDAREL_LO16A: + case R_PPC_VLE_SDAREL_LO16D: + case R_PPC_VLE_SDAREL_HI16A: + case R_PPC_VLE_SDAREL_HI16D: + case R_PPC_VLE_SDAREL_HA16A: + case R_PPC_VLE_SDAREL_HA16D: + { + bfd_vma value; + const char *name; + //int reg; + struct elf_link_hash_entry *sda = NULL; + + if (sec == NULL || sec->output_section == NULL) + { + unresolved_reloc = TRUE; + break; + } + + name = bfd_get_section_name (output_bfd, sec->output_section); + if (strcmp (name, ".sdata") == 0 + || strcmp (name, ".sbss") == 0) + { + //reg = 13; + sda = htab->sdata[0].sym; + } + else if (strcmp (name, ".sdata2") == 0 + || strcmp (name, ".sbss2") == 0) + { + //reg = 2; + sda = htab->sdata[1].sym; + } + else + { + (*_bfd_error_handler) + (_("%B: the target (%s) of a %s relocation is " + "in the wrong output section (%s)"), + input_bfd, + sym_name, + howto->name, + name); + + bfd_set_error (bfd_error_bad_value); + ret = FALSE; + goto copy_reloc; + } + + if (sda != NULL) + { + if (!is_static_defined (sda)) + { + unresolved_reloc = TRUE; + break; + } + } + + value = (sda->root.u.def.section->output_section->vma + + sda->root.u.def.section->output_offset + + addend); + + if (r_type == R_PPC_VLE_SDAREL_LO16A) + ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, + value, split16a_type); + else if (r_type == R_PPC_VLE_SDAREL_LO16D) + ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, + value, split16d_type); + else if (r_type == R_PPC_VLE_SDAREL_HI16A) + { + value = value >> 16; + ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, + value, split16a_type); + } + else if (r_type == R_PPC_VLE_SDAREL_HI16D) + { + value = value >> 16; + ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, + value, split16d_type); + } + else if (r_type == R_PPC_VLE_SDAREL_HA16A) + { + value = (value + 0x8000) >> 16; + ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, + value, split16a_type); + } + else if (r_type == R_PPC_VLE_SDAREL_HA16D) + { + value = (value + 0x8000) >> 16; + ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, + value, split16d_type); + } + } + goto copy_reloc; + /* Relocate against the beginning of the section. */ case R_PPC_SECTOFF: case R_PPC_SECTOFF_LO: @@ -8100,7 +9451,7 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_invalid_operation); ret = FALSE; - continue; + goto copy_reloc; } /* Do any further special processing. */ @@ -8111,6 +9462,7 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_ADDR16_HA: case R_PPC_REL16_HA: + case R_PPC_REL16DX_HA: case R_PPC_SECTOFF_HA: case R_PPC_TPREL16_HA: case R_PPC_DTPREL16_HA: @@ -8134,6 +9486,56 @@ ppc_elf_relocate_section (bfd *output_bfd, Bits 0:15 are not used. */ addend += 0x8000; break; + + case R_PPC_ADDR16: + case R_PPC_ADDR16_LO: + case R_PPC_GOT16: + case R_PPC_GOT16_LO: + case R_PPC_SDAREL16: + case R_PPC_SECTOFF: + case R_PPC_SECTOFF_LO: + case R_PPC_DTPREL16: + case R_PPC_DTPREL16_LO: + case R_PPC_TPREL16: + case R_PPC_TPREL16_LO: + case R_PPC_GOT_TLSGD16: + case R_PPC_GOT_TLSGD16_LO: + case R_PPC_GOT_TLSLD16: + case R_PPC_GOT_TLSLD16_LO: + case R_PPC_GOT_DTPREL16: + case R_PPC_GOT_DTPREL16_LO: + case R_PPC_GOT_TPREL16: + case R_PPC_GOT_TPREL16_LO: + { + /* The 32-bit ABI lacks proper relocations to deal with + certain 64-bit instructions. Prevent damage to bits + that make up part of the insn opcode. */ + unsigned int insn, mask, lobit; + + insn = bfd_get_32 (output_bfd, + contents + rel->r_offset - d_offset); + mask = 0; + if (is_insn_ds_form (insn)) + mask = 3; + else if (is_insn_dq_form (insn)) + mask = 15; + else + break; + relocation += addend; + addend = insn & mask; + lobit = mask & relocation; + if (lobit != 0) + { + relocation ^= lobit; + info->callbacks->einfo + (_("%P: %H: error: %s against `%s' not a multiple of %u\n"), + input_bfd, input_section, rel->r_offset, + howto->name, sym_name, mask + 1); + bfd_set_error (bfd_error_bad_value); + ret = FALSE; + } + } + break; } #ifdef DEBUG @@ -8161,42 +9563,75 @@ ppc_elf_relocate_section (bfd *output_bfd, ret = FALSE; } - r = _bfd_final_link_relocate (howto, - input_bfd, - input_section, - contents, - rel->r_offset, - relocation, - addend); + /* 16-bit fields in insns mostly have signed values, but a + few insns have 16-bit unsigned values. Really, we should + have different reloc types. */ + if (howto->complain_on_overflow != complain_overflow_dont + && howto->dst_mask == 0xffff + && (input_section->flags & SEC_CODE) != 0) + { + enum complain_overflow complain = complain_overflow_signed; + + if ((elf_section_flags (input_section) & SHF_PPC_VLE) == 0) + { + unsigned int insn; + + insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3)); + if ((insn & (0x3f << 26)) == 10u << 26 /* cmpli */) + complain = complain_overflow_bitfield; + else if ((insn & (0x3f << 26)) == 28u << 26 /* andi */ + || (insn & (0x3f << 26)) == 24u << 26 /* ori */ + || (insn & (0x3f << 26)) == 26u << 26 /* xori */) + complain = complain_overflow_unsigned; + } + if (howto->complain_on_overflow != complain) + { + alt_howto = *howto; + alt_howto.complain_on_overflow = complain; + howto = &alt_howto; + } + } + + if (r_type == R_PPC_REL16DX_HA) + { + /* Split field reloc isn't handled by _bfd_final_link_relocate. */ + if (rel->r_offset + 4 > input_section->size) + r = bfd_reloc_outofrange; + else + { + unsigned int insn; + + relocation += addend; + relocation -= (rel->r_offset + + input_section->output_offset + + input_section->output_section->vma); + relocation >>= 16; + insn = bfd_get_32 (input_bfd, contents + rel->r_offset); + insn &= ~0x1fffc1; + insn |= (relocation & 0xffc1) | ((relocation & 0x3e) << 15); + bfd_put_32 (input_bfd, insn, contents + rel->r_offset); + r = bfd_reloc_ok; + } + } + else + r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, + rel->r_offset, relocation, addend); if (r != bfd_reloc_ok) { if (r == bfd_reloc_overflow) { - if (warned) - continue; - if (h != NULL - && h->root.type == bfd_link_hash_undefweak - && howto->pc_relative) - { - /* Assume this is a call protected by other code that - detect the symbol is undefined. If this is the case, - we can safely ignore the overflow. If not, the - program is hosed anyway, and a little warning isn't - going to help. */ - - continue; - } - - if (! (*info->callbacks->reloc_overflow) (info, - (h ? &h->root : NULL), - sym_name, - howto->name, - rel->r_addend, - input_bfd, - input_section, - rel->r_offset)) - return FALSE; + overflow: + /* On code like "if (foo) foo();" don't report overflow + on a branch to zero when foo is undefined. */ + if (!warned + && !(h != NULL + && (h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_undefined) + && is_branch_reloc (r_type))) + info->callbacks->reloc_overflow + (info, (h ? &h->root : NULL), sym_name, howto->name, + rel->r_addend, input_bfd, input_section, rel->r_offset); } else { @@ -8207,12 +9642,329 @@ ppc_elf_relocate_section (bfd *output_bfd, ret = FALSE; } } + copy_reloc: + if (wrel != rel) + *wrel = *rel; + } + + if (wrel != rel) + { + Elf_Internal_Shdr *rel_hdr; + size_t deleted = rel - wrel; + + rel_hdr = _bfd_elf_single_rel_hdr (input_section->output_section); + rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted; + if (rel_hdr->sh_size == 0) + { + /* It is too late to remove an empty reloc section. Leave + one NONE reloc. + ??? What is wrong with an empty section??? */ + rel_hdr->sh_size = rel_hdr->sh_entsize; + deleted -= 1; + wrel++; + } + relend = wrel; + rel_hdr = _bfd_elf_single_rel_hdr (input_section); + rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted; + input_section->reloc_count -= deleted; } #ifdef DEBUG fprintf (stderr, "\n"); #endif + if (input_section->sec_info_type == SEC_INFO_TYPE_TARGET + && input_section->size != input_section->rawsize + && (strcmp (input_section->output_section->name, ".init") == 0 + || strcmp (input_section->output_section->name, ".fini") == 0)) + { + /* Branch around the trampolines. */ + unsigned int insn = B + input_section->size - input_section->rawsize; + bfd_put_32 (input_bfd, insn, contents + input_section->rawsize); + } + + if (htab->params->ppc476_workaround + && input_section->sec_info_type == SEC_INFO_TYPE_TARGET + && (!bfd_link_relocatable (info) + || (input_section->output_section->alignment_power + >= htab->params->pagesize_p2))) + { + bfd_vma start_addr, end_addr, addr; + bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2; + + if (relax_info->workaround_size != 0) + { + bfd_byte *p; + unsigned int n; + bfd_byte fill[4]; + + bfd_put_32 (input_bfd, BA, fill); + p = contents + input_section->size - relax_info->workaround_size; + n = relax_info->workaround_size >> 2; + while (n--) + { + memcpy (p, fill, 4); + p += 4; + } + } + + /* The idea is: Replace the last instruction on a page with a + branch to a patch area. Put the insn there followed by a + branch back to the next page. Complicated a little by + needing to handle moved conditional branches, and by not + wanting to touch data-in-text. */ + + start_addr = (input_section->output_section->vma + + input_section->output_offset); + end_addr = (start_addr + input_section->size + - relax_info->workaround_size); + for (addr = ((start_addr & -pagesize) + pagesize - 4); + addr < end_addr; + addr += pagesize) + { + bfd_vma offset = addr - start_addr; + Elf_Internal_Rela *lo, *hi; + bfd_boolean is_data; + bfd_vma patch_off, patch_addr; + unsigned int insn; + + /* Do we have a data reloc at this offset? If so, leave + the word alone. */ + is_data = FALSE; + lo = relocs; + hi = relend; + rel = NULL; + while (lo < hi) + { + rel = lo + (hi - lo) / 2; + if (rel->r_offset < offset) + lo = rel + 1; + else if (rel->r_offset > offset + 3) + hi = rel; + else + { + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_PPC_ADDR32: + case R_PPC_UADDR32: + case R_PPC_REL32: + case R_PPC_ADDR30: + is_data = TRUE; + break; + default: + break; + } + break; + } + } + if (is_data) + continue; + + /* Some instructions can be left alone too. Unconditional + branches, except for bcctr with BO=0x14 (bctr, bctrl), + avoid the icache failure. + + The problem occurs due to prefetch across a page boundary + where stale instructions can be fetched from the next + page, and the mechanism for flushing these bad + instructions fails under certain circumstances. The + unconditional branches: + 1) Branch: b, bl, ba, bla, + 2) Branch Conditional: bc, bca, bcl, bcla, + 3) Branch Conditional to Link Register: bclr, bclrl, + where (2) and (3) have BO=0x14 making them unconditional, + prevent the bad prefetch because the prefetch itself is + affected by these instructions. This happens even if the + instruction is not executed. + + A bctr example: + . + . lis 9,new_page@ha + . addi 9,9,new_page@l + . mtctr 9 + . bctr + . nop + . nop + . new_page: + . + The bctr is not predicted taken due to ctr not being + ready, so prefetch continues on past the bctr into the + new page which might have stale instructions. If they + fail to be flushed, then they will be executed after the + bctr executes. Either of the following modifications + prevent the bad prefetch from happening in the first + place: + . + . lis 9,new_page@ha lis 9,new_page@ha + . addi 9,9,new_page@l addi 9,9,new_page@l + . mtctr 9 mtctr 9 + . bctr bctr + . nop b somewhere_else + . b somewhere_else nop + . new_page: new_page: + . */ + insn = bfd_get_32 (input_bfd, contents + offset); + if ((insn & (0x3f << 26)) == (18u << 26) /* b,bl,ba,bla */ + || ((insn & (0x3f << 26)) == (16u << 26) /* bc,bcl,bca,bcla*/ + && (insn & (0x14 << 21)) == (0x14 << 21)) /* with BO=0x14 */ + || ((insn & (0x3f << 26)) == (19u << 26) + && (insn & (0x3ff << 1)) == (16u << 1) /* bclr,bclrl */ + && (insn & (0x14 << 21)) == (0x14 << 21)))/* with BO=0x14 */ + continue; + + patch_addr = (start_addr + input_section->size + - relax_info->workaround_size); + patch_addr = (patch_addr + 15) & -16; + patch_off = patch_addr - start_addr; + bfd_put_32 (input_bfd, B + patch_off - offset, contents + offset); + + if (rel != NULL + && rel->r_offset >= offset + && rel->r_offset < offset + 4) + { + asection *sreloc; + + /* If the insn we are patching had a reloc, adjust the + reloc r_offset so that the reloc applies to the moved + location. This matters for -r and --emit-relocs. */ + if (rel + 1 != relend) + { + Elf_Internal_Rela tmp = *rel; + + /* Keep the relocs sorted by r_offset. */ + memmove (rel, rel + 1, (relend - (rel + 1)) * sizeof (*rel)); + relend[-1] = tmp; + } + relend[-1].r_offset += patch_off - offset; + + /* Adjust REL16 addends too. */ + switch (ELF32_R_TYPE (relend[-1].r_info)) + { + case R_PPC_REL16: + case R_PPC_REL16_LO: + case R_PPC_REL16_HI: + case R_PPC_REL16_HA: + relend[-1].r_addend += patch_off - offset; + break; + default: + break; + } + + /* If we are building a PIE or shared library with + non-PIC objects, perhaps we had a dynamic reloc too? + If so, the dynamic reloc must move with the insn. */ + sreloc = elf_section_data (input_section)->sreloc; + if (sreloc != NULL) + { + Elf32_External_Rela *slo, *shi, *srelend; + bfd_vma soffset; + + slo = (Elf32_External_Rela *) sreloc->contents; + shi = srelend = slo + sreloc->reloc_count; + soffset = (offset + input_section->output_section->vma + + input_section->output_offset); + while (slo < shi) + { + Elf32_External_Rela *srel = slo + (shi - slo) / 2; + bfd_elf32_swap_reloca_in (output_bfd, (bfd_byte *) srel, + &outrel); + if (outrel.r_offset < soffset) + slo = srel + 1; + else if (outrel.r_offset > soffset + 3) + shi = srel; + else + { + if (srel + 1 != srelend) + { + memmove (srel, srel + 1, + (srelend - (srel + 1)) * sizeof (*srel)); + srel = srelend - 1; + } + outrel.r_offset += patch_off - offset; + bfd_elf32_swap_reloca_out (output_bfd, &outrel, + (bfd_byte *) srel); + break; + } + } + } + } + else + rel = NULL; + + if ((insn & (0x3f << 26)) == (16u << 26) /* bc */ + && (insn & 2) == 0 /* relative */) + { + bfd_vma delta = ((insn & 0xfffc) ^ 0x8000) - 0x8000; + + delta += offset - patch_off; + if (bfd_link_relocatable (info) && rel != NULL) + delta = 0; + if (!bfd_link_relocatable (info) && rel != NULL) + { + enum elf_ppc_reloc_type r_type; + + r_type = ELF32_R_TYPE (relend[-1].r_info); + if (r_type == R_PPC_REL14_BRTAKEN) + insn |= BRANCH_PREDICT_BIT; + else if (r_type == R_PPC_REL14_BRNTAKEN) + insn &= ~BRANCH_PREDICT_BIT; + else + BFD_ASSERT (r_type == R_PPC_REL14); + + if ((r_type == R_PPC_REL14_BRTAKEN + || r_type == R_PPC_REL14_BRNTAKEN) + && delta + 0x8000 < 0x10000 + && (bfd_signed_vma) delta < 0) + insn ^= BRANCH_PREDICT_BIT; + } + if (delta + 0x8000 < 0x10000) + { + bfd_put_32 (input_bfd, + (insn & ~0xfffc) | (delta & 0xfffc), + contents + patch_off); + patch_off += 4; + bfd_put_32 (input_bfd, + B | ((offset + 4 - patch_off) & 0x3fffffc), + contents + patch_off); + patch_off += 4; + } + else + { + if (rel != NULL) + { + unsigned int r_sym = ELF32_R_SYM (relend[-1].r_info); + + relend[-1].r_offset += 8; + relend[-1].r_info = ELF32_R_INFO (r_sym, R_PPC_REL24); + } + bfd_put_32 (input_bfd, + (insn & ~0xfffc) | 8, + contents + patch_off); + patch_off += 4; + bfd_put_32 (input_bfd, + B | ((offset + 4 - patch_off) & 0x3fffffc), + contents + patch_off); + patch_off += 4; + bfd_put_32 (input_bfd, + B | ((delta - 8) & 0x3fffffc), + contents + patch_off); + patch_off += 4; + } + } + else + { + bfd_put_32 (input_bfd, insn, contents + patch_off); + patch_off += 4; + bfd_put_32 (input_bfd, + B | ((offset + 4 - patch_off) & 0x3fffffc), + contents + patch_off); + patch_off += 4; + } + BFD_ASSERT (patch_off <= input_section->size); + relax_info->workaround_size = input_section->size - patch_off; + } + } + return ret; } @@ -8273,11 +10025,11 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, got_offset = (reloc_index + 3) * 4; /* Use the right PLT. */ - plt_entry = info->shared ? ppc_elf_vxworks_pic_plt_entry + plt_entry = bfd_link_pic (info) ? ppc_elf_vxworks_pic_plt_entry : ppc_elf_vxworks_plt_entry; /* Fill in the .plt on VxWorks. */ - if (info->shared) + if (bfd_link_pic (info)) { bfd_put_32 (output_bfd, plt_entry[0] | PPC_HA (got_offset), @@ -8328,14 +10080,14 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, htab->plt->contents + ent->plt.offset + 28); /* Fill in the GOT entry corresponding to this PLT slot with - the address immediately after the the "bctr" instruction + the address immediately after the "bctr" instruction in this PLT entry. */ bfd_put_32 (output_bfd, (htab->plt->output_section->vma + htab->plt->output_offset + ent->plt.offset + 16), htab->sgotplt->contents + got_offset); - if (!info->shared) + if (!bfd_link_pic (info)) { /* Fill in a couple of entries in .rela.plt.unloaded. */ loc = htab->srelplt2->contents @@ -8457,7 +10209,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, } } else if (h->type == STT_GNU_IFUNC - && !info->shared) + && !bfd_link_pic (info)) { /* Set the value of ifunc symbols in a non-pie executable to the glink entry. This is to avoid @@ -8487,7 +10239,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, p = (unsigned char *) htab->glink->contents + ent->glink_offset; - if (h == htab->tls_get_addr && !htab->no_tls_get_addr_opt) + if (h == htab->tls_get_addr && !htab->params->no_tls_get_addr_opt) { bfd_put_32 (output_bfd, LWZ_11_3, p); p += 4; @@ -8509,7 +10261,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, write_glink_stub (ent, splt, p, info); - if (!info->shared) + if (!bfd_link_pic (info)) /* We only need one non-PIC glink stub. */ break; } @@ -8548,26 +10300,23 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, fprintf (stderr, "\n"); #endif - /* Mark some specially defined symbols as absolute. */ - if (strcmp (h->root.root.string, "_DYNAMIC") == 0 - || (!htab->is_vxworks - && (h == htab->elf.hgot - || strcmp (h->root.root.string, - "_PROCEDURE_LINKAGE_TABLE_") == 0))) - sym->st_shndx = SHN_ABS; - return TRUE; } static enum elf_reloc_type_class -ppc_elf_reloc_type_class (const Elf_Internal_Rela *rela) +ppc_elf_reloc_type_class (const struct bfd_link_info *info, + const asection *rel_sec, + const Elf_Internal_Rela *rela) { + struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); + + if (rel_sec == htab->reliplt) + return reloc_class_ifunc; + switch (ELF32_R_TYPE (rela->r_info)) { case R_PPC_RELATIVE: return reloc_class_relative; - case R_PPC_REL24: - case R_PPC_ADDR24: case R_PPC_JMP_SLOT: return reloc_class_plt; case R_PPC_COPY: @@ -8596,9 +10345,9 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, htab = ppc_elf_hash_table (info); dynobj = elf_hash_table (info)->dynobj; - sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + sdyn = bfd_get_linker_section (dynobj, ".dynamic"); if (htab->is_vxworks) - splt = bfd_get_section_by_name (dynobj, ".plt"); + splt = bfd_get_linker_section (dynobj, ".plt"); else splt = NULL; @@ -8707,11 +10456,11 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, if (splt && splt->size > 0) { /* Use the right PLT. */ - const bfd_vma *plt_entry = (info->shared + const bfd_vma *plt_entry = (bfd_link_pic (info) ? ppc_elf_vxworks_pic_plt0_entry : ppc_elf_vxworks_plt0_entry); - if (!info->shared) + if (!bfd_link_pic (info)) { bfd_vma got_value = SYM_VAL (htab->elf.hgot); @@ -8732,7 +10481,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, bfd_put_32 (output_bfd, plt_entry[6], splt->contents + 24); bfd_put_32 (output_bfd, plt_entry[7], splt->contents + 28); - if (! info->shared) + if (! bfd_link_pic (info)) { Elf_Internal_Rela rela; bfd_byte *loc; @@ -8900,7 +10649,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, p += htab->glink_pltresolve; endp = htab->glink->contents; endp += htab->glink->size - GLINK_PLTRESOLVE; - while (p < endp - 8 * 4) + while (p < endp - (htab->params->ppc476_workaround ? 0 : 8 * 4)) { bfd_put_32 (output_bfd, B + endp - p, p); p += 4; @@ -8915,14 +10664,51 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, + htab->glink->output_section->vma + htab->glink->output_offset); + if (htab->params->ppc476_workaround) + { + /* Ensure that a call stub at the end of a page doesn't + result in prefetch over the end of the page into the + glink branch table. */ + bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2; + bfd_vma page_addr; + bfd_vma glink_start = (htab->glink->output_section->vma + + htab->glink->output_offset); + + for (page_addr = res0 & -pagesize; + page_addr > glink_start; + page_addr -= pagesize) + { + /* We have a plt call stub that may need fixing. */ + bfd_byte *loc; + unsigned int insn; + + loc = htab->glink->contents + page_addr - 4 - glink_start; + insn = bfd_get_32 (output_bfd, loc); + if (insn == BCTR) + { + /* By alignment, we know that there must be at least + one other call stub before this one. */ + insn = bfd_get_32 (output_bfd, loc - 16); + if (insn == BCTR) + bfd_put_32 (output_bfd, B | (-16 & 0x3fffffc), loc); + else + bfd_put_32 (output_bfd, B | (-20 & 0x3fffffc), loc); + } + } + } + /* Last comes the PLTresolve stub. */ - if (info->shared) + if (bfd_link_pic (info)) { bfd_vma bcl; for (i = 0; i < ARRAY_SIZE (pic_plt_resolve); i++) { - bfd_put_32 (output_bfd, pic_plt_resolve[i], p); + unsigned int insn = pic_plt_resolve[i]; + + if (htab->params->ppc476_workaround && insn == NOP) + insn = BA + 0; + bfd_put_32 (output_bfd, insn, p); p += 4; } p -= 4 * ARRAY_SIZE (pic_plt_resolve); @@ -8956,7 +10742,11 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, { for (i = 0; i < ARRAY_SIZE (plt_resolve); i++) { - bfd_put_32 (output_bfd, plt_resolve[i], p); + unsigned int insn = plt_resolve[i]; + + if (htab->params->ppc476_workaround && insn == NOP) + insn = BA + 0; + bfd_put_32 (output_bfd, insn, p); p += 4; } p -= 4 * ARRAY_SIZE (plt_resolve); @@ -8990,17 +10780,10 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, unsigned char *p = htab->glink_eh_frame->contents; bfd_vma val; - memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie)); - /* CIE length (rewrite in case little-endian). */ - bfd_put_32 (htab->elf.dynobj, sizeof (glink_eh_frame_cie) - 4, p); p += sizeof (glink_eh_frame_cie); /* FDE length. */ - val = htab->glink_eh_frame->size - 4 - sizeof (glink_eh_frame_cie); - bfd_put_32 (htab->elf.dynobj, val, p); p += 4; /* CIE pointer. */ - val = p - htab->glink_eh_frame->contents; - bfd_put_32 (htab->elf.dynobj, val, p); p += 4; /* Offset to .glink. */ val = (htab->glink->output_section->vma @@ -9009,45 +10792,6 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, + htab->glink_eh_frame->output_offset); val -= p - htab->glink_eh_frame->contents; bfd_put_32 (htab->elf.dynobj, val, p); - p += 4; - /* .glink size. */ - bfd_put_32 (htab->elf.dynobj, htab->glink->size, p); - p += 4; - /* Augmentation. */ - p += 1; - - if (info->shared - && htab->elf.dynamic_sections_created) - { - bfd_vma adv = (htab->glink->size - GLINK_PLTRESOLVE + 8) >> 2; - if (adv < 64) - *p++ = DW_CFA_advance_loc + adv; - else if (adv < 256) - { - *p++ = DW_CFA_advance_loc1; - *p++ = adv; - } - else if (adv < 65536) - { - *p++ = DW_CFA_advance_loc2; - bfd_put_16 (htab->elf.dynobj, adv, p); - p += 2; - } - else - { - *p++ = DW_CFA_advance_loc4; - bfd_put_32 (htab->elf.dynobj, adv, p); - p += 4; - } - *p++ = DW_CFA_register; - *p++ = 65; - p++; - *p++ = DW_CFA_advance_loc + 4; - *p++ = DW_CFA_restore_extended; - *p++ = 65; - } - BFD_ASSERT ((bfd_vma) ((p + 3 - htab->glink_eh_frame->contents) & -4) - == htab->glink_eh_frame->size); if (htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME && !_bfd_elf_write_section_eh_frame (output_bfd, info, @@ -9059,20 +10803,21 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, return ret; } -#define TARGET_LITTLE_SYM bfd_elf32_powerpcle_vec +#define TARGET_LITTLE_SYM powerpc_elf32_le_vec #define TARGET_LITTLE_NAME "elf32-powerpcle" -#define TARGET_BIG_SYM bfd_elf32_powerpc_vec +#define TARGET_BIG_SYM powerpc_elf32_vec #define TARGET_BIG_NAME "elf32-powerpc" #define ELF_ARCH bfd_arch_powerpc #define ELF_TARGET_ID PPC32_ELF_DATA #define ELF_MACHINE_CODE EM_PPC #ifdef __QNXTARGET__ #define ELF_MAXPAGESIZE 0x1000 +#define ELF_COMMONPAGESIZE 0x1000 #else #define ELF_MAXPAGESIZE 0x10000 +#define ELF_COMMONPAGESIZE 0x10000 #endif #define ELF_MINPAGESIZE 0x1000 -#define ELF_COMMONPAGESIZE 0x1000 #define elf_info_to_howto ppc_elf_info_to_howto #ifdef EM_CYGNUS_POWERPC @@ -9087,12 +10832,13 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, #define elf_backend_can_gc_sections 1 #define elf_backend_can_refcount 1 #define elf_backend_rela_normal 1 +#define elf_backend_caches_rawsize 1 #define bfd_elf32_mkobject ppc_elf_mkobject #define bfd_elf32_bfd_merge_private_bfd_data ppc_elf_merge_private_bfd_data #define bfd_elf32_bfd_relax_section ppc_elf_relax_section #define bfd_elf32_bfd_reloc_type_lookup ppc_elf_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup ppc_elf_reloc_name_lookup +#define bfd_elf32_bfd_reloc_name_lookup ppc_elf_reloc_name_lookup #define bfd_elf32_bfd_set_private_flags ppc_elf_set_private_flags #define bfd_elf32_bfd_link_hash_table_create ppc_elf_link_hash_table_create #define bfd_elf32_get_synthetic_symtab ppc_elf_get_synthetic_symtab @@ -9113,6 +10859,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, #define elf_backend_finish_dynamic_sections ppc_elf_finish_dynamic_sections #define elf_backend_fake_sections ppc_elf_fake_sections #define elf_backend_additional_program_headers ppc_elf_additional_program_headers +#define elf_backend_modify_segment_map ppc_elf_modify_segment_map #define elf_backend_grok_prstatus ppc_elf_grok_prstatus #define elf_backend_grok_psinfo ppc_elf_grok_psinfo #define elf_backend_write_core_note ppc_elf_write_core_note @@ -9124,7 +10871,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, #define elf_backend_plt_sym_val ppc_elf_plt_sym_val #define elf_backend_action_discarded ppc_elf_action_discarded #define elf_backend_init_index_section _bfd_elf_init_1_index_section -#define elf_backend_post_process_headers _bfd_elf_set_osabi +#define elf_backend_lookup_section_flags_hook ppc_elf_lookup_section_flags #include "elf32-target.h" @@ -9134,7 +10881,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, #undef TARGET_LITTLE_NAME #undef TARGET_BIG_SYM -#define TARGET_BIG_SYM bfd_elf32_powerpc_freebsd_vec +#define TARGET_BIG_SYM powerpc_elf32_fbsd_vec #undef TARGET_BIG_NAME #define TARGET_BIG_NAME "elf32-powerpc-freebsd" @@ -9152,7 +10899,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, #undef TARGET_LITTLE_NAME #undef TARGET_BIG_SYM -#define TARGET_BIG_SYM bfd_elf32_powerpc_vxworks_vec +#define TARGET_BIG_SYM powerpc_elf32_vxworks_vec #undef TARGET_BIG_NAME #define TARGET_BIG_NAME "elf32-powerpc-vxworks"