X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf32-ppc.c;h=8415f1ece2b8a6f72299e7e219372c8ca2b0caae;hb=0e1862bb401f47716446aef143b2bf7a4563f541;hp=d13d31b4ece23ad701e32b41dca4d329f54d8b0a;hpb=5446cbdf82892a800ed7eef563a795e75223ec52;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index d13d31b4ec..8415f1ece2 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-2015 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support. This file is part of BFD, the Binary File Descriptor library. @@ -52,8 +50,6 @@ static bfd_reloc_status_type ppc_elf_addr16_ha_reloc (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); static bfd_reloc_status_type ppc_elf_unhandled_reloc (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static void ppc_elf_vle_split16 - (bfd *, bfd_byte *, bfd_vma, bfd_vma, split16_format_type); /* Branch prediction bit for branch taken relocs. */ #define BRANCH_PREDICT_BIT 0x200000 @@ -151,6 +147,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 @@ -190,11 +187,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 */ @@ -209,7 +206,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 */ @@ -225,7 +222,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 */ @@ -302,7 +299,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 */ @@ -319,7 +316,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 */ @@ -336,7 +333,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 */ @@ -448,7 +445,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 16, /* 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_GOT16_HI", /* name */ FALSE, /* partial_inplace */ @@ -464,7 +461,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_dont, /* complain_on_overflow */ ppc_elf_addr16_ha_reloc, /* special_function */ "R_PPC_GOT16_HA", /* name */ FALSE, /* partial_inplace */ @@ -499,7 +496,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_COPY", /* name */ FALSE, /* partial_inplace */ @@ -515,7 +512,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_GLOB_DAT", /* name */ FALSE, /* partial_inplace */ @@ -530,7 +527,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_JMP_SLOT", /* name */ FALSE, /* partial_inplace */ @@ -547,7 +544,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 */ @@ -579,7 +576,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 */ @@ -609,7 +606,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 */ @@ -625,7 +622,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_PLT32", /* name */ FALSE, /* partial_inplace */ @@ -641,7 +638,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_PLTREL32", /* name */ FALSE, /* partial_inplace */ @@ -673,7 +670,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 16, /* 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_PLT16_HI", /* name */ FALSE, /* partial_inplace */ @@ -689,7 +686,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_dont, /* complain_on_overflow */ ppc_elf_addr16_ha_reloc, /* special_function */ "R_PPC_PLT16_HA", /* name */ FALSE, /* partial_inplace */ @@ -720,7 +717,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_SECTOFF", /* name */ FALSE, /* partial_inplace */ @@ -750,7 +747,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 16, /* 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_SECTOFF_HI", /* name */ FALSE, /* partial_inplace */ @@ -765,7 +762,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_dont, /* complain_on_overflow */ ppc_elf_addr16_ha_reloc, /* special_function */ "R_PPC_SECTOFF_HA", /* name */ FALSE, /* partial_inplace */ @@ -1241,7 +1238,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_EMB_NADDR32", /* name */ FALSE, /* partial_inplace */ @@ -1256,7 +1253,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_EMB_NADDR16", /* name */ FALSE, /* partial_inplace */ @@ -1451,10 +1448,10 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 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 */ + complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC_VLE_LO16A", /* name */ FALSE, /* partial_inplace */ @@ -1466,10 +1463,10 @@ static reloc_howto_type ppc_elf_howto_raw[] = { HOWTO (R_PPC_VLE_LO16D, /* 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 */ + complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC_VLE_LO16D", /* name */ FALSE, /* partial_inplace */ @@ -1479,12 +1476,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = { /* Bits 16-31 split16a format. */ HOWTO (R_PPC_VLE_HI16A, /* type */ - 0, /* rightshift */ + 16, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ + 16, /* 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_VLE_HI16A", /* name */ FALSE, /* partial_inplace */ @@ -1494,12 +1491,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = { /* Bits 16-31 split16d format. */ HOWTO (R_PPC_VLE_HI16D, /* type */ - 0, /* rightshift */ + 16, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ + 16, /* 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_VLE_HI16D", /* name */ FALSE, /* partial_inplace */ @@ -1509,12 +1506,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = { /* Bits 16-31 (High Adjusted) in split16a format. */ HOWTO (R_PPC_VLE_HA16A, /* type */ - 0, /* rightshift */ + 16, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ + 16, /* 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_VLE_HA16A", /* name */ FALSE, /* partial_inplace */ @@ -1524,12 +1521,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = { /* Bits 16-31 (High Adjusted) in split16d format. */ HOWTO (R_PPC_VLE_HA16D, /* type */ - 0, /* rightshift */ + 16, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ + 16, /* 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_VLE_HA16D", /* name */ FALSE, /* partial_inplace */ @@ -1537,14 +1534,16 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 0x1f07ff, /* dst_mask */ FALSE), /* pcrel_offset */ - /* This reloc does nothing. */ - HOWTO (R_PPC_VLE_SDA21, /* type */ + /* 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) */ - 32, /* bitsize */ + 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_VLE_SDA21", /* name */ FALSE, /* partial_inplace */ @@ -1552,29 +1551,29 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 0xffff, /* dst_mask */ FALSE), /* pcrel_offset */ - /* This reloc does nothing. */ + /* Like R_PPC_VLE_SDA21 but ignore overflow. */ HOWTO (R_PPC_VLE_SDA21_LO, /* 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 */ + complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC_VLE_SDA21_LO", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ - 0, /* dst_mask */ + 0xffff, /* dst_mask */ FALSE), /* pcrel_offset */ /* The 16 LSBS relative to _SDA_BASE_ in split16a format. */ HOWTO (R_PPC_VLE_SDAREL_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 */ + complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC_VLE_SDAREL_LO16A", /* name */ FALSE, /* partial_inplace */ @@ -1583,14 +1582,13 @@ static reloc_howto_type ppc_elf_howto_raw[] = { FALSE), /* pcrel_offset */ /* The 16 LSBS relative to _SDA_BASE_ in split16d format. */ - /* This reloc does nothing. */ HOWTO (R_PPC_VLE_SDAREL_LO16D, /* 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 */ + complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC_VLE_SDAREL_LO16D", /* name */ FALSE, /* partial_inplace */ @@ -1600,12 +1598,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = { /* Bits 16-31 relative to _SDA_BASE_ in split16a format. */ HOWTO (R_PPC_VLE_SDAREL_HI16A, /* type */ - 0, /* rightshift */ + 16, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ + 16, /* 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_VLE_SDAREL_HI16A", /* name */ FALSE, /* partial_inplace */ @@ -1615,12 +1613,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = { /* Bits 16-31 relative to _SDA_BASE_ in split16d format. */ HOWTO (R_PPC_VLE_SDAREL_HI16D, /* type */ - 0, /* rightshift */ + 16, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ + 16, /* 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_VLE_SDAREL_HI16D", /* name */ FALSE, /* partial_inplace */ @@ -1630,12 +1628,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = { /* Bits 16-31 (HA) relative to _SDA_BASE split16a format. */ HOWTO (R_PPC_VLE_SDAREL_HA16A, /* type */ - 0, /* rightshift */ + 16, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ + 16, /* 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_VLE_SDAREL_HA16A", /* name */ FALSE, /* partial_inplace */ @@ -1645,12 +1643,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = { /* Bits 16-31 (HA) relative to _SDA_BASE split16d format. */ HOWTO (R_PPC_VLE_SDAREL_HA16D, /* type */ - 0, /* rightshift */ + 16, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ + 16, /* 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_VLE_SDAREL_HA16D", /* name */ FALSE, /* partial_inplace */ @@ -1664,7 +1662,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_IRELATIVE", /* name */ FALSE, /* partial_inplace */ @@ -1679,7 +1677,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 16, /* bitsize */ TRUE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC_REL16", /* name */ FALSE, /* partial_inplace */ @@ -2021,19 +2019,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]; @@ -2059,9 +2066,6 @@ 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 @@ -2631,7 +2635,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; @@ -2921,7 +2925,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 @@ -2952,9 +2955,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; @@ -2965,6 +2969,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; @@ -2981,7 +2988,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. */ @@ -3073,7 +3080,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); } } @@ -3128,7 +3135,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)) @@ -3252,6 +3263,7 @@ 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 }; ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table)); if (ret == NULL) @@ -3271,6 +3283,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"; @@ -3337,6 +3351,36 @@ ppc_elf_create_got (bfd *abfd, struct bfd_link_info *info) 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) { @@ -3378,6 +3422,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; } @@ -3412,7 +3465,7 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) if (s == NULL) return FALSE; - if (! info->shared) + if (! bfd_link_pic (info)) { htab->relbss = bfd_get_linker_section (abfd, ".rela.bss"); flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS @@ -3569,7 +3622,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)) { @@ -3596,59 +3649,15 @@ ppc_elf_add_symbol_hook (bfd *abfd, *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; + if ((ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC + || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE) + && (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_any; 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; - - flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - - /* Record the first bfd that needs the special sections. */ - if (!htab->elf.dynobj) - htab->elf.dynobj = abfd; - - 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; - - return create_sdata_sym (info, lsect); -} - /* Find a linker generated pointer with a given addend and type. */ static elf_linker_section_pointers_t * @@ -3667,10 +3676,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; @@ -3738,6 +3747,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; @@ -3865,7 +3876,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. @@ -3962,14 +3973,14 @@ 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. */ - if (!info->shared + if (!bfd_link_pic (info) || is_branch_reloc (r_type)) { bfd_vma addend = 0; 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; } if (!update_plt_info (abfd, ifunc, got2, addend)) @@ -4020,7 +4031,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; @@ -4059,7 +4070,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; @@ -4068,17 +4079,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) { @@ -4089,17 +4097,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) { @@ -4108,21 +4113,16 @@ ppc_elf_check_relocs (bfd *abfd, } break; + case R_PPC_SDAREL16: + 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: - case R_PPC_SDAREL16: - 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; @@ -4142,14 +4142,12 @@ ppc_elf_check_relocs (bfd *abfd, 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; @@ -4161,17 +4159,11 @@ ppc_elf_check_relocs (bfd *abfd, 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; @@ -4184,7 +4176,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; @@ -4228,7 +4220,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; @@ -4294,7 +4286,7 @@ ppc_elf_check_relocs (bfd *abfd, } if (h != NULL && h->type == STT_GNU_IFUNC) { - if (info->shared) + if (bfd_link_pic (info)) { info->callbacks->einfo (_("%P: %H: @local call to ifunc %s\n"), abfd, sec, rel->r_offset, @@ -4330,7 +4322,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; @@ -4343,7 +4335,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 @@ -4378,7 +4370,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. */ @@ -4388,6 +4380,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; @@ -4412,7 +4408,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. */ @@ -4444,14 +4440,14 @@ 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 && (!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))) @@ -4789,20 +4785,19 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) } static void -ppc_elf_vle_split16 (bfd *output_bfd, bfd_byte *contents, - bfd_vma offset, bfd_vma relocation, - split16_format_type split16_format) +ppc_elf_vle_split16 (bfd *output_bfd, bfd_byte *loc, + bfd_vma value, + split16_format_type split16_format) { - bfd_vma insn, top5, bottom11; + unsigned int insn, top5; - insn = bfd_get_32 (output_bfd, contents + offset); - top5 = relocation >> 11; - top5 = top5 << (split16_format == split16a_type ? 20 : 16); - bottom11 = relocation & 0x7ff; + insn = bfd_get_32 (output_bfd, loc); + top5 = value & 0xf800; + top5 = top5 << (split16_format == split16a_type ? 9 : 5); insn |= top5; - insn |= bottom11; - bfd_put_32 (output_bfd, insn, contents + offset); + insn |= value & 0x7ff; + bfd_put_32 (output_bfd, insn, loc); } @@ -4823,7 +4818,7 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED, 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 @@ -4851,7 +4846,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) @@ -4939,7 +4934,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) @@ -4985,7 +4980,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 **) @@ -4998,7 +4993,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) @@ -5033,7 +5028,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; @@ -5069,7 +5064,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: @@ -5083,7 +5078,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) @@ -5109,6 +5104,9 @@ ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info) htab = ppc_elf_hash_table (info); htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr", FALSE, FALSE, TRUE); + 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; @@ -5206,7 +5204,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_relocatable (info) || !bfd_link_executable (info)) return TRUE; htab = ppc_elf_hash_table (info); @@ -5220,7 +5218,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); @@ -5379,7 +5377,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, @@ -5529,9 +5527,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 @@ -5541,14 +5554,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 @@ -5575,13 +5589,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. @@ -5635,7 +5678,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 @@ -5655,7 +5698,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."; @@ -5686,6 +5729,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; } @@ -5763,7 +5807,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)) { @@ -5781,7 +5825,7 @@ 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; @@ -5790,7 +5834,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) s->size += TLS_GET_ADDR_GLINK_SIZE - GLINK_ENTRY_SIZE; } if (!doneone - && !info->shared + && !bfd_link_pic (info) && h->def_dynamic && !h->def_regular) { @@ -5829,7 +5873,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) { @@ -5863,7 +5907,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 @@ -5906,7 +5950,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; @@ -5949,7 +5999,7 @@ 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)) @@ -5980,7 +6030,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 @@ -6049,7 +6099,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. */ @@ -6119,7 +6173,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; @@ -6137,7 +6191,7 @@ 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)) { s = bfd_get_linker_section (htab->elf.dynobj, ".interp"); BFD_ASSERT (s != NULL); @@ -6153,7 +6207,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; @@ -6237,7 +6291,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, else { *local_got = allocate_got (htab, need); - if (info->shared) + if (bfd_link_pic (info)) { asection *srel = htab->relgot; if ((*lgot_masks & PLT_IFUNC) != 0) @@ -6272,7 +6326,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; @@ -6296,7 +6350,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 @@ -6320,17 +6374,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 @@ -6362,6 +6421,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); @@ -6377,6 +6437,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; } } } @@ -6389,7 +6450,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, { 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) @@ -6424,12 +6485,15 @@ 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 (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")) { @@ -6483,7 +6547,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; @@ -6562,7 +6626,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, /* Augmentation. */ p += 1; - if (info->shared + if (bfd_link_pic (info) && htab->elf.dynamic_sections_created) { bfd_vma adv = (htab->glink->size - GLINK_PLTRESOLVE + 8) >> 2; @@ -6599,6 +6663,46 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, 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 @@ -6623,7 +6727,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 */ @@ -6640,15 +6744,13 @@ static const int stub_entry[] = 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. FIXME: We write out - trampoline templates here and later modify them in - relocate_section. We'd save a realloc if we left writing the - templates to relocate_section. */ + add trampolines at the end of the section. */ static bfd_boolean ppc_elf_relax_section (bfd *abfd, @@ -6656,9 +6758,9 @@ ppc_elf_relax_section (bfd *abfd, 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. */ @@ -6671,12 +6773,12 @@ ppc_elf_relax_section (bfd *abfd, Elf_Internal_Sym *isymbuf = NULL; Elf_Internal_Rela *internal_relocs = NULL; Elf_Internal_Rela *irel, *irelend = NULL; - struct one_fixup *fixups = 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 trampbase, trampoff, newsize; + bfd_size_type trampbase, trampoff, newsize, picfixup_size; asection *got2; bfd_boolean maybe_pasted; @@ -6692,8 +6794,8 @@ ppc_elf_relax_section (bfd *abfd, /* 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) @@ -6704,12 +6806,15 @@ ppc_elf_relax_section (bfd *abfd, isec->rawsize = isec->size; trampbase = isec->size; - if (htab->params->ppc476_workaround) + 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) { - BFD_ASSERT (isec->sec_info_type == SEC_INFO_TYPE_NONE); - isec->sec_info_type = SEC_INFO_TYPE_TARGET; elf_section_data (isec)->sec_info = bfd_zalloc (abfd, sizeof (struct ppc_elf_relax_info)); if (elf_section_data (isec)->sec_info == NULL) @@ -6727,8 +6832,9 @@ ppc_elf_relax_section (bfd *abfd, trampoff += 4; symtab_hdr = &elf_symtab_hdr (abfd); - - if (htab->params->branch_trampolines) + picfixup_size = 0; + if (htab->params->branch_trampolines + || htab->params->pic_fixup > 0) { /* Get a copy of the native relocations. */ if (isec->reloc_count != 0) @@ -6747,9 +6853,9 @@ ppc_elf_relax_section (bfd *abfd, unsigned long r_type = ELF32_R_TYPE (irel->r_info); bfd_vma toff, roff; asection *tsec; - struct one_fixup *f; + struct one_branch_fixup *f; size_t insn_offset = 0; - bfd_vma max_branch_offset, val; + bfd_vma max_branch_offset = 0, val; bfd_byte *hit_addr; unsigned long t0; struct elf_link_hash_entry *h; @@ -6770,6 +6876,11 @@ ppc_elf_relax_section (bfd *abfd, max_branch_offset = 1 << 15; break; + case R_PPC_ADDR16_HA: + if (htab->params->pic_fixup > 0) + break; + continue; + default: continue; } @@ -6827,14 +6938,81 @@ ppc_elf_relax_section (bfd *abfd, || h->root.type == bfd_link_hash_undefweak) { tsec = bfd_und_section_ptr; - toff = link_info->relocatable ? indx : 0; + toff = bfd_link_relocatable (link_info) ? indx : 0; } else continue; + /* 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) + && !bfd_link_relocatable (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); + + 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]; + + 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; + + tls_mask + = ((struct ppc_elf_link_hash_entry *) th)->tls_mask; + } + + /* 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; + } + sym_type = h->type; } + 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; + } + /* 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 @@ -6860,7 +7038,7 @@ ppc_elf_relax_section (bfd *abfd, bfd_vma addend = 0; struct plt_entry *ent; - if (r_type == R_PPC_PLTREL24 && link_info->shared) + 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) @@ -6926,7 +7104,7 @@ ppc_elf_relax_section (bfd *abfd, toff += irel->r_addend; /* Attempted -shared link of non-pic code loses. */ - if ((!link_info->relocatable + if ((!bfd_link_relocatable (link_info) && tsec == bfd_und_section_ptr) || tsec->output_section == NULL || (tsec->owner != NULL @@ -6937,7 +7115,7 @@ ppc_elf_relax_section (bfd *abfd, /* If the branch is in range, no need to do anything. */ if (tsec != bfd_und_section_ptr - && (!link_info->relocatable + && (!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)) @@ -6952,7 +7130,7 @@ ppc_elf_relax_section (bfd *abfd, } /* Look for an existing fixup to this address. */ - for (f = fixups; f ; f = f->next) + for (f = branch_fixups; f ; f = f->next) if (f->tsec == tsec && f->toff == toff) break; @@ -6967,7 +7145,7 @@ ppc_elf_relax_section (bfd *abfd, one. We'll report an error later. */ continue; - if (link_info->shared) + if (bfd_link_pic (link_info)) { size = 4 * ARRAY_SIZE (shared_stub_entry); insn_offset = 12; @@ -6997,11 +7175,11 @@ ppc_elf_relax_section (bfd *abfd, /* Record the fixup so we don't do it again this section. */ f = bfd_malloc (sizeof (*f)); - f->next = fixups; + f->next = branch_fixups; f->tsec = tsec; f->toff = toff; f->trampoff = trampoff; - fixups = f; + branch_fixups = f; trampoff += size; changes++; @@ -7051,44 +7229,39 @@ ppc_elf_relax_section (bfd *abfd, } } - while (fixups != NULL) + 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); } } workaround_change = FALSE; newsize = trampoff; - if (htab->params->ppc476_workaround) + 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; - unsigned int pagesize = htab->params->pagesize; + bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2; addr = isec->output_section->vma + isec->output_offset; - end_addr = addr + trampoff - 1; + end_addr = addr + trampoff; addr &= -pagesize; - crossings = ((end_addr & -pagesize) - addr) / pagesize; + crossings = ((end_addr & -pagesize) - addr) >> htab->params->pagesize_p2; if (crossings != 0) { /* 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 & 15); + newsize = 15 - ((end_addr - 1) & 15); newsize += crossings * 16; if (relax_info->workaround_size < newsize) { relax_info->workaround_size = newsize; workaround_change = TRUE; - if (contents == NULL) - { - if (elf_section_data (isec)->this_hdr.contents != NULL) - contents = elf_section_data (isec)->this_hdr.contents; - else if (!bfd_malloc_and_get_section (abfd, isec, &contents)) - goto error_return; - } } /* Ensure relocate_section is called. */ isec->flags |= SEC_RELOC; @@ -7096,55 +7269,15 @@ ppc_elf_relax_section (bfd *abfd, newsize = trampoff + relax_info->workaround_size; } - if (changes || workaround_change) + if (htab->params->pic_fixup > 0) { - contents = bfd_realloc_or_free (contents, newsize); - if (contents == NULL) - goto error_return; - - /* Branch around the trampolines. */ - if (maybe_pasted) - { - bfd_vma val = B + newsize - isec->rawsize; - bfd_put_32 (abfd, val, contents + isec->rawsize); - } + picfixup_size -= relax_info->picfixup_size; + if (picfixup_size != 0) + relax_info->picfixup_size += picfixup_size; + newsize += relax_info->picfixup_size; } - /* Write out the trampolines. */ - if (changes) - { - const int *stub; - bfd_byte *dest; - int i, size; - - dest = contents + trampbase; - if (maybe_pasted && trampbase == isec->rawsize) - dest += 4; - - if (link_info->shared) - { - stub = shared_stub_entry; - size = ARRAY_SIZE (shared_stub_entry); - } - else - { - stub = stub_entry; - size = ARRAY_SIZE (stub_entry); - } - - 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 (changes || workaround_change) + if (changes != 0 || picfixup_size != 0 || workaround_change) isec->size = newsize; if (isymbuf != NULL @@ -7162,7 +7295,7 @@ ppc_elf_relax_section (bfd *abfd, if (contents != NULL && elf_section_data (isec)->this_hdr.contents != contents) { - if (!changes && !workaround_change && !link_info->keep_memory) + if (!changes && !link_info->keep_memory) free (contents); else { @@ -7171,6 +7304,7 @@ ppc_elf_relax_section (bfd *abfd, } } + changes += picfixup_size; if (changes != 0) { /* Append sufficient NOP relocs so we can write out relocation @@ -7202,34 +7336,13 @@ ppc_elf_relax_section (bfd *abfd, free (internal_relocs); *again = changes != 0 || workaround_change; - if (!*again && link_info->relocatable && htab->params->branch_trampolines) - { - /* 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++; - } - } - return TRUE; error_return: - while (fixups != NULL) + 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); } if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents) @@ -7335,7 +7448,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; @@ -7356,7 +7469,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 @@ -7545,13 +7658,15 @@ ppc_elf_relocate_section (bfd *output_bfd, 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"); @@ -7566,9 +7681,11 @@ 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")); + if (input_section->sec_info_type == SEC_INFO_TYPE_TARGET) + relax_info = elf_section_data (input_section)->sec_info; rel = relocs; relend = relocs + input_section->reloc_count; for (; rel < relend; rel++) @@ -7588,6 +7705,7 @@ 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; r_type = ELF32_R_TYPE (rel->r_info); sym = NULL; @@ -7629,7 +7747,7 @@ ppc_elf_relocate_section (bfd *output_bfd, rel, 1, relend, howto, 0, contents); } - if (info->relocatable) + if (bfd_link_relocatable (info)) { if (got2 != NULL && r_type == R_PPC_PLTREL24 @@ -7639,7 +7757,10 @@ ppc_elf_relocate_section (bfd *output_bfd, 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) + continue; } /* TLS optimizations. Replace instruction sequences and relocs @@ -7728,8 +7849,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); @@ -7762,12 +7883,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) { @@ -7782,7 +7907,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. */ @@ -7917,6 +8043,114 @@ 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)); + rel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_HA); + rel->r_addend = got_addr; + rel->r_offset = (p - contents) + d_offset; + 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)); + rel++; + rel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_LO); + rel->r_offset += 4; + + /* 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) { @@ -7939,11 +8173,11 @@ 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); } @@ -8071,8 +8305,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 @@ -8140,7 +8374,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 @@ -8184,7 +8418,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++ @@ -8202,9 +8441,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)) { @@ -8251,6 +8495,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)) + continue; + relocation = (htab->got->output_section->vma + htab->got->output_offset + off @@ -8267,9 +8515,9 @@ 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. */ @@ -8290,7 +8538,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 @@ -8314,18 +8563,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: @@ -8371,7 +8623,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 */ @@ -8380,7 +8632,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 @@ -8390,11 +8642,15 @@ 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; @@ -8537,7 +8793,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; } @@ -8554,36 +8810,59 @@ 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; + const int *stub; + size_t size; + size_t insn_offset = rel->r_offset; + unsigned int insn; - t0 = bfd_get_32 (output_bfd, contents + rel->r_offset); - t1 = bfd_get_32 (output_bfd, contents + rel->r_offset + 4); - - /* 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; + rel[0].r_offset += d_offset; 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; @@ -8642,7 +8921,7 @@ ppc_elf_relocate_section (bfd *output_bfd, if (h != NULL && ifunc == NULL) { struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2, - info->shared ? addend : 0); + bfd_link_pic (info) ? addend : 0); if (ent == NULL || htab->plt == NULL) { @@ -8688,10 +8967,8 @@ ppc_elf_relocate_section (bfd *output_bfd, addend -= SYM_VAL (sda); name = bfd_get_section_name (output_bfd, sec->output_section); - if (! ((CONST_STRNEQ (name, ".sdata") - && (name[6] == 0 || name[6] == '.')) - || (CONST_STRNEQ (name, ".sbss") - && (name[5] == 0 || name[5] == '.')))) + if (!(strcmp (name, ".sdata") == 0 + || strcmp (name, ".sbss") == 0)) { info->callbacks->einfo (_("%P: %B: the target (%s) of a %s relocation is " @@ -8720,8 +8997,8 @@ ppc_elf_relocate_section (bfd *output_bfd, addend -= SYM_VAL (sda); name = bfd_get_section_name (output_bfd, sec->output_section); - if (! (CONST_STRNEQ (name, ".sdata2") - || CONST_STRNEQ (name, ".sbss2"))) + if (!(strcmp (name, ".sdata2") == 0 + || strcmp (name, ".sbss2") == 0)) { info->callbacks->einfo (_("%P: %B: the target (%s) of a %s relocation is " @@ -8735,45 +9012,39 @@ ppc_elf_relocate_section (bfd *output_bfd, break; case R_PPC_VLE_LO16A: - relocation = (relocation + addend) & 0xffff; - ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, - relocation, split16a_type); + relocation = relocation + addend; + ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, + relocation, split16a_type); continue; case R_PPC_VLE_LO16D: - relocation = (relocation + addend) & 0xffff; - ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, - relocation, split16d_type); + relocation = relocation + addend; + ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, + relocation, split16d_type); continue; case R_PPC_VLE_HI16A: - relocation = ((relocation + addend) >> 16) & 0xffff; - ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, - relocation, split16a_type); + relocation = (relocation + addend) >> 16; + ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, + relocation, split16a_type); continue; case R_PPC_VLE_HI16D: - relocation = ((relocation + addend) >> 16) & 0xffff; - ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, - relocation, split16d_type); + relocation = (relocation + addend) >> 16; + ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, + relocation, split16d_type); continue; case R_PPC_VLE_HA16A: - { - bfd_vma value = relocation + addend; - value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff); - ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, - value, split16a_type); - } + relocation = (relocation + addend + 0x8000) >> 16; + ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, + relocation, split16a_type); continue; case R_PPC_VLE_HA16D: - { - bfd_vma value = relocation + addend; - value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff); - ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, - value, split16d_type); - } + relocation = (relocation + addend + 0x8000) >> 16; + ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, + relocation, split16d_type); continue; /* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0. */ @@ -8784,6 +9055,7 @@ ppc_elf_relocate_section (bfd *output_bfd, { const char *name; int reg; + unsigned int insn; struct elf_link_hash_entry *sda = NULL; if (sec == NULL || sec->output_section == NULL) @@ -8793,16 +9065,14 @@ ppc_elf_relocate_section (bfd *output_bfd, } name = bfd_get_section_name (output_bfd, sec->output_section); - if (((CONST_STRNEQ (name, ".sdata") - && (name[6] == 0 || name[6] == '.')) - || (CONST_STRNEQ (name, ".sbss") - && (name[5] == 0 || name[5] == '.')))) + 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; @@ -8837,32 +9107,41 @@ ppc_elf_relocate_section (bfd *output_bfd, addend -= SYM_VAL (sda); } + 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)) { - /* Use the split20 format. */ - bfd_vma insn, bits12to15, bits21to31; - bfd_vma value = (relocation + rel->r_offset) & 0xffff; - /* Propagate sign bit, if necessary. */ - insn = (value & 0x8000) ? 0x70107800 : 0x70000000; - bits12to15 = value & 0x700; - bits21to31 = value & 0x7ff; - insn |= bits12to15; - insn |= bits21to31; - bfd_put_32 (output_bfd, insn, contents + rel->r_offset); + 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; + + bfd_put_32 (output_bfd, insn, contents + rel->r_offset); + + if (r_type == R_PPC_VLE_SDA21 + && ((relocation + 0x80000) & 0xffffffff) > 0x100000) + goto overflow; continue; } else if (r_type == R_PPC_EMB_SDA21 || r_type == R_PPC_VLE_SDA21 || r_type == R_PPC_VLE_SDA21_LO) { - bfd_vma insn; /* Fill in register field. */ - - insn = bfd_get_32 (output_bfd, contents + rel->r_offset); + /* Fill in register field. */ insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT); - bfd_put_32 (output_bfd, insn, contents + rel->r_offset); } + bfd_put_32 (output_bfd, insn, contents + rel->r_offset); } break; @@ -8885,16 +9164,14 @@ ppc_elf_relocate_section (bfd *output_bfd, } name = bfd_get_section_name (output_bfd, sec->output_section); - if (((CONST_STRNEQ (name, ".sdata") - && (name[6] == 0 || name[6] == '.')) - || (CONST_STRNEQ (name, ".sbss") - && (name[5] == 0 || name[5] == '.')))) + 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; @@ -8923,46 +9200,39 @@ ppc_elf_relocate_section (bfd *output_bfd, } } - value = sda->root.u.def.section->output_section->vma - + sda->root.u.def.section->output_offset; - - if (r_type == R_PPC_VLE_SDAREL_LO16A) - { - value = (value + addend) & 0xffff; - ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, - value, split16a_type); - } - else if (r_type == R_PPC_VLE_SDAREL_LO16D) - { - value = (value + addend) & 0xffff; - ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, - value, split16d_type); - } - else if (r_type == R_PPC_VLE_SDAREL_HI16A) + 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 + addend) >> 16) & 0xffff; - ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, - value, split16a_type); + 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) + else if (r_type == R_PPC_VLE_SDAREL_HI16D) { - value = ((value + addend) >> 16) & 0xffff; - ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, - value, split16d_type); + 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) + else if (r_type == R_PPC_VLE_SDAREL_HA16A) { - value += addend; - value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff); - ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, - value, split16a_type); + 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) + else if (r_type == R_PPC_VLE_SDAREL_HA16D) { - value += addend; - value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff); - ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, - value, split16d_type); + value = (value + 0x8000) >> 16; + ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, + value, split16d_type); } } continue; @@ -9122,42 +9392,57 @@ 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; + } + } + + 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) + 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))) { - /* 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; } - - 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; } else { @@ -9174,17 +9459,40 @@ ppc_elf_relocate_section (bfd *output_bfd, 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) + && input_section->sec_info_type == SEC_INFO_TYPE_TARGET + && (!bfd_link_relocatable (info) + || (input_section->output_section->alignment_power + >= htab->params->pagesize_p2))) { - struct ppc_elf_relax_info *relax_info; bfd_vma start_addr, end_addr, addr; - unsigned int pagesize = htab->params->pagesize; + bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2; - relax_info = elf_section_data (input_section)->sec_info; if (relax_info->workaround_size != 0) - memset (contents + input_section->size - relax_info->workaround_size, - 0, relax_info->workaround_size); + { + 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 @@ -9210,13 +9518,14 @@ ppc_elf_relocate_section (bfd *output_bfd, the word alone. */ is_data = FALSE; lo = relocs; - hi = lo + input_section->reloc_count; + 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) + else if (rel->r_offset > offset + 3) hi = rel; else { @@ -9237,27 +9546,56 @@ ppc_elf_relocate_section (bfd *output_bfd, if (is_data) continue; - /* Some instructions can be left alone too. In this - category are most insns that unconditionally change - control flow, and isync. Of these, some *must* be left - alone, for example, the "bcl 20, 31, label" used in pic - sequences to give the address of the next insn. twui - and twu apparently are not safe. */ + /* 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 == 0 - || (insn & (0x3f << 26)) == (18u << 26) /* b */ - || ((insn & (0x3f << 26)) == (16u << 26) /* bc always */ - && (insn & (0x14 << 21)) == (0x14 << 21)) - || ((insn & (0x3f << 26)) == (19u << 26) /* blr, bctr */ - && (insn & (0x14 << 21)) == (0x14 << 21) - && (insn & (0x1ff << 1)) == (16u << 1)) - || (insn & (0x3f << 26)) == (17u << 26) /* sc */ + 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)) == (38u << 1) /* rfmci */ - || (insn & (0x3ff << 1)) == (50u << 1) /* rfi */ - || (insn & (0x3ff << 1)) == (51u << 1) /* rfci */ - || (insn & (0x3ff << 1)) == (82u << 1) /* rfsvc */ - || (insn & (0x3ff << 1)) == (150u << 1))) /* isync */) + && (insn & (0x3ff << 1)) == (16u << 1) /* bclr,bclrl */ + && (insn & (0x14 << 21)) == (0x14 << 21)))/* with BO=0x14 */ continue; patch_addr = (start_addr + input_section->size @@ -9265,12 +9603,106 @@ ppc_elf_relocate_section (bfd *output_bfd, 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, @@ -9284,6 +9716,13 @@ ppc_elf_relocate_section (bfd *output_bfd, } 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); @@ -9372,11 +9811,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), @@ -9434,7 +9873,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, + 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 @@ -9556,7 +9995,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 @@ -9608,7 +10047,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; } @@ -9803,11 +10242,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); @@ -9828,7 +10267,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; @@ -9996,7 +10435,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; @@ -10011,14 +10450,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); @@ -10052,7 +10528,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); @@ -10109,20 +10589,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 @@ -10137,6 +10618,7 @@ 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 @@ -10186,7 +10668,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" @@ -10204,7 +10686,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"