From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 25987 invoked by alias); 11 May 2005 14:13:51 -0000 Mailing-List: contact binutils-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: binutils-owner@sources.redhat.com Received: (qmail 25603 invoked from network); 11 May 2005 14:12:54 -0000 Received: from unknown (HELO omta03ps.mx.bigpond.com) (144.140.82.155) by sourceware.org with SMTP; 11 May 2005 14:12:54 -0000 Received: from grove.modra.org ([144.136.167.90]) by omta03ps.mx.bigpond.com with ESMTP id <20050511141249.FXIA4956.omta03ps.mx.bigpond.com@grove.modra.org> for ; Wed, 11 May 2005 14:12:49 +0000 Received: by bubble.grove.modra.org (Postfix, from userid 500) id 1B5991AB31F; Wed, 11 May 2005 23:42:50 +0930 (CST) Date: Wed, 11 May 2005 14:22:00 -0000 From: Alan Modra To: binutils@sources.redhat.com Subject: powerpc new PLT and GOT Message-ID: <20050511141249.GA29302@bubble.grove.modra.org> Mail-Followup-To: binutils@sources.redhat.com Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="SUOF0GtieIMvvwua" Content-Disposition: inline User-Agent: Mutt/1.4i X-SW-Source: 2005-05/txt/msg00392.txt.bz2 --SUOF0GtieIMvvwua Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 39671 The current PowerPC ABI requires PLT and GOT to be both writable and executable, which is a security concern. It's worse than that actually, since the entire data segment ends up executable. This patch implements binutils support for a new PLT and GOT on PowerPC, details of which are in the attached ABI proposal. Note that the proposal is by no means final; There's likely to be some change in .glink to do without the lwzu instructions, but I think it's solid enough to throw some code together. Also, the ld support doesn't allow registers other than r30 as a GOT pointer. We'll worry about that if and when gcc generates code using a different register. >From a user perspective, this ld change won't do anything until gcc starts generating code for the new PLT and GOT. ie. ld will continue to link using the old PLT scheme. bfd/ * reloc.c (BFD_RELOC_HI16_PCREL): Define. (BFD_RELOC_HI16_S_PCREL, BFD_RELOC_LO16_PCREL): Define. * elf32-ppc.c (GLINK_PLTRESOLVE, GLINK_ENTRY_SIZE): Define. (CROR_151515, CROR_313131): Delete. (ADDIS_11_11, ADDI_11_11, SUB_11_11_30, ADD_0_11_11, ADD_11_0_11, LWZ_0_4_30, MTCTR_0, LWZ_12_8_30, BCTR, ADDIS_11_30, LWZU_0_X_11): Define. (ppc_elf_howto_raw): Add R_PPC_REL16, R_PPC_REL16_LO, R_PPC_REL16_HI and R_PPC_REL16_HA entries. (ppc_elf_reloc_type_lookup): Convert new bfd reloc types. (ppc_elf_addr16_ha_reloc): Also handle R_PPC_REL16_HA. (struct ppc_elf_link_hash_table): Add glink, glink_pltresolve, new_plt, and old_plt. (ppc_elf_create_dynamic_sections): Create .glink section. (ppc_elf_check_relocs): Set new_plt and old_plt. (ppc_elf_select_plt_layout): New function. (ppc_elf_tls_setup): Set plt output section elf type and flags. (allocate_got): Handle differences between old and new got layout. (allocate_dynrelocs): Likewise for plt. (ppc_elf_size_dynamic_sections): Likewise. Allocate memory for .glink. Don't allocate memory for old bss .plt. Emit DT_PPC_GLINK. (ppc_elf_relax_section): Rename ppc_info to htab. Handle .glink destination of R_PPC_PLTREL24 relocs. (ppc_elf_relocate_section): Handle new relocs and changed destination of R_PPC_PLTREL24. (ppc_elf_finish_dynamic_symbol): Init new style plt and handle differences in layout. (ppc_elf_finish_dynamic_sections): Set DT_PPC_GLINK value. Don't put a blrl in new got. Write glink contents. * elf32-ppc.h (ppc_elf_select_plt_layout): Declare. * libbfd.h: Regenerate. * bfd-in2.h: Regenerate. binutils/ * readelf.c (get_ppc_dynamic_type): New function for DT_PPC_GLINK. (get_dynamic_type): Call the above. gas/ * config/tc-ppc.c (md_apply_fix3): Allow pcrel forms of BFD_RELOC_16, BFD_RELOC_LO16, BFD_RELOC_HI16 and BFD_RELOC_HI16_S. include/elf/ * ppc.h (R_PPC_RELAX32, R_PPC_RELAX32PC, R_PPC_RELAX32_PLT, R_PPC_RELAX32PC_PLT) Adjust. (R_PPC_REL16, R_PPC_REL16_LO, R_PPC_REL16_HI, R_PPC_REL16_HA): Define. (DT_PPC_GLINK): Define. ld/ * ldgram.y: Add SPECIAL token. (sect_constraint): Handle SPECIAL. * ldlang.c (lang_output_section_find_1): Don't match SPECIAL. (map_input_to_output_sections): Likewise. * ldlex.l (SPECIAL): Define. * emulparams/elf32ppc.sh (DATA_GOT, SDATA_GOT, SEPARATE_GOTPLT, GOT, PLT, GOTPLT): Define. * emultempl/ppc32elf.em (old_plt, old_got): New static vars. (ppc_after_open): New function. (PARSE_AND_LIST_PROLOGUE): Define OPTION_OLD_LPT and OPTION_OLD_GOT. (PARSE_AND_LIST_LONGOPTS): Add "bss-plt" and "sdata-got". (PARSE_AND_LIST_OPTIONS): Document them. (PARSE_AND_LIST_ARGS_CASES): Handle them. (LDEMUL_AFTER_OPEN): Define. * scripttempl/elf.sc (PLT): Don't override existing define. (DATA_GOT, SDATA_GOT): Define and use to enable alternate got placement rather than using NO_SMALL_DATA. Emit GOTPLT for RELRO_NOW. Index: bfd/reloc.c =================================================================== RCS file: /cvs/src/src/bfd/reloc.c,v retrieving revision 1.126 diff -u -p -r1.126 reloc.c --- bfd/reloc.c 4 May 2005 15:53:37 -0000 1.126 +++ bfd/reloc.c 11 May 2005 08:57:41 -0000 @@ -2063,6 +2063,19 @@ ENUMDOC Low 16 bits. ENUM + BFD_RELOC_HI16_PCREL +ENUMDOC + High 16 bits of 32-bit pc-relative value +ENUM + BFD_RELOC_HI16_S_PCREL +ENUMDOC + High 16 bits of 32-bit pc-relative value, adjusted +ENUM + BFD_RELOC_LO16_PCREL +ENUMDOC + Low 16 bits of pc-relative value + +ENUM BFD_RELOC_MIPS16_HI16 ENUMDOC MIPS16 high 16 bits of 32-bit value. Index: bfd/elf32-ppc.c =================================================================== RCS file: /cvs/src/src/bfd/elf32-ppc.c,v retrieving revision 1.155 diff -u -p -r1.155 elf32-ppc.c --- bfd/elf32-ppc.c 7 May 2005 13:22:49 -0000 1.155 +++ bfd/elf32-ppc.c 11 May 2005 13:23:05 -0000 @@ -51,6 +51,7 @@ static bfd_reloc_status_type ppc_elf_unh section. */ #define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" +/* For old-style PLT. */ /* The size in bytes of an entry in the procedure linkage table. */ #define PLT_ENTRY_SIZE 12 /* The initial size of the plt reserved for the dynamic linker. */ @@ -60,10 +61,23 @@ static bfd_reloc_status_type ppc_elf_unh /* The number of single-slot PLT entries (the rest use two slots). */ #define PLT_NUM_SINGLE_ENTRIES 8192 -/* Some nop instructions. */ +/* For new-style .glink and .plt. */ +#define GLINK_PLTRESOLVE 12*4 +#define GLINK_ENTRY_SIZE 4*4 + +/* Some instructions. */ #define NOP 0x60000000 -#define CROR_151515 0x4def7b82 -#define CROR_313131 0x4ffffb82 +#define ADDIS_11_11 0x3d6b0000 +#define ADDI_11_11 0x396b0000 +#define SUB_11_11_30 0x7d7e5850 +#define ADD_0_11_11 0x7c0b5a14 +#define ADD_11_0_11 0x7d605a14 +#define LWZ_0_4_30 0x801e0004 +#define MTCTR_0 0x7c0903a6 +#define LWZ_12_8_30 0x819e0008 +#define BCTR 0x4e800420 +#define ADDIS_11_30 0x3d7e0000 +#define LWZU_0_X_11 0x840b0000 /* Offset of tp and dtp pointers from start of TLS block. */ #define TP_OFFSET 0x7000 @@ -1259,6 +1273,67 @@ static reloc_howto_type ppc_elf_howto_ra 0xffff, /* dst_mask */ FALSE), /* pcrel_offset */ + /* A 16 bit relative relocation. */ + HOWTO (R_PPC_REL16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_REL16", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* A 16 bit relative relocation without overflow. */ + HOWTO (R_PPC_REL16_LO, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_REL16_LO", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* The high order 16 bits of a relative address. */ + HOWTO (R_PPC_REL16_HI, /* type */ + 16, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_REL16_HI", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* The high order 16 bits of a relative address, plus 1 if the contents of + the low 16 bits, treated as a signed number, is negative. */ + HOWTO (R_PPC_REL16_HA, /* type */ + 16, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + ppc_elf_addr16_ha_reloc, /* special_function */ + "R_PPC_REL16_HA", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + /* GNU extension to record C++ vtable hierarchy. */ HOWTO (R_PPC_GNU_VTINHERIT, /* type */ 0, /* rightshift */ @@ -1418,6 +1493,10 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATT case BFD_RELOC_PPC_EMB_RELST_HA: r = R_PPC_EMB_RELST_HA; break; case BFD_RELOC_PPC_EMB_BIT_FLD: r = R_PPC_EMB_BIT_FLD; break; case BFD_RELOC_PPC_EMB_RELSDA: r = R_PPC_EMB_RELSDA; break; + case BFD_RELOC_16_PCREL: r = R_PPC_REL16; break; + case BFD_RELOC_LO16_PCREL: r = R_PPC_REL16_LO; break; + case BFD_RELOC_HI16_PCREL: r = R_PPC_REL16_HI; break; + case BFD_RELOC_HI16_S_PCREL: r = R_PPC_REL16_HA; break; case BFD_RELOC_VTABLE_INHERIT: r = R_PPC_GNU_VTINHERIT; break; case BFD_RELOC_VTABLE_ENTRY: r = R_PPC_GNU_VTENTRY; break; } @@ -1440,7 +1519,7 @@ ppc_elf_info_to_howto (bfd *abfd ATTRIBU cache_ptr->howto = ppc_elf_howto_table[ELF32_R_TYPE (dst->r_info)]; } -/* Handle the R_PPC_ADDR16_HA reloc. */ +/* Handle the R_PPC_ADDR16_HA and R_PPC_REL16_HA relocs. */ static bfd_reloc_status_type ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED, @@ -1470,6 +1549,8 @@ ppc_elf_addr16_ha_reloc (bfd *abfd ATTRI relocation += symbol->section->output_section->vma; relocation += symbol->section->output_offset; relocation += reloc_entry->addend; + if (reloc_entry->howto->pc_relative) + relocation -= reloc_entry->address; reloc_entry->addend += (relocation & 0x8000) << 1; @@ -2164,6 +2245,7 @@ struct ppc_elf_link_hash_table /* Short-cuts to get to dynamic linker sections. */ asection *got; asection *relgot; + asection *glink; asection *plt; asection *relplt; asection *dynbss; @@ -2182,11 +2264,18 @@ struct ppc_elf_link_hash_table bfd_vma offset; } tlsld_got; + /* Offset of PltResolve function in glink. */ + bfd_vma glink_pltresolve; + /* Size of reserved GOT entries. */ unsigned int got_header_size; /* Non-zero if allocating the header left a gap. */ unsigned int got_gap; + /* Whether to use new plt/got layout or not. */ + unsigned int new_plt:1; + unsigned int old_plt:1; + /* Small local sym to section mapping cache. */ struct sym_sec_cache sym_sec; }; @@ -2306,8 +2395,14 @@ ppc_elf_create_dynamic_sections (bfd *ab if (!_bfd_elf_create_dynamic_sections (abfd, info)) return FALSE; - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); + flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS + | SEC_IN_MEMORY | SEC_LINKER_CREATED); + + s = bfd_make_section_anyway_with_flags (abfd, ".glink", flags | SEC_CODE); + htab->glink = s; + if (s == NULL + || !bfd_set_section_alignment (abfd, s, 4)) + return FALSE; htab->dynbss = bfd_get_section_by_name (abfd, ".dynbss"); s = bfd_make_section_with_flags (abfd, ".dynsbss", @@ -2319,8 +2414,7 @@ ppc_elf_create_dynamic_sections (bfd *ab if (! info->shared) { htab->relbss = bfd_get_section_by_name (abfd, ".rela.bss"); - s = bfd_make_section_with_flags (abfd, ".rela.sbss", - flags | SEC_READONLY); + s = bfd_make_section_with_flags (abfd, ".rela.sbss", flags); htab->relsbss = s; if (s == NULL || ! bfd_set_section_alignment (abfd, s, 2)) @@ -2845,6 +2939,13 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_TOC16: break; + case R_PPC_REL16: + case R_PPC_REL16_LO: + case R_PPC_REL16_HI: + case R_PPC_REL16_HA: + htab->new_plt = 1; + break; + /* This are just markers. */ case R_PPC_TLS: case R_PPC_EMB_MRKREF: @@ -2870,6 +2971,8 @@ ppc_elf_check_relocs (bfd *abfd, /* This refers only to functions defined in the shared library. */ case R_PPC_LOCAL24PC: + if (h && h == htab->elf.hgot) + htab->old_plt = 1; break; /* This relocation describes the C++ object vtable hierarchy. @@ -2913,8 +3016,13 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_REL14_BRTAKEN: case R_PPC_REL14_BRNTAKEN: case R_PPC_REL32: - if (h == NULL || h == htab->elf.hgot) + if (h == NULL) break; + if (h == htab->elf.hgot) + { + htab->old_plt = 1; + break; + } /* fall through */ case R_PPC_ADDR32: @@ -3157,6 +3265,43 @@ ppc_elf_merge_private_bfd_data (bfd *ibf return TRUE; } +/* Choose which PLT scheme to use, and set .plt flags appropriately. + Returns -1 on error, 0 for old PLT, 1 for new PLT. */ +int +ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info, + int force_old_plt) +{ + struct ppc_elf_link_hash_table *htab; + + htab = ppc_elf_hash_table (info); + if (force_old_plt || !htab->new_plt) + htab->old_plt = 1; + + if (!htab->old_plt) + { + /* The new PLT is a loaded section. Fix its flags. */ + if (htab->plt != NULL) + { + flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS + | SEC_IN_MEMORY | SEC_LINKER_CREATED); + + if (!bfd_set_section_flags (htab->elf.dynobj, htab->plt, flags)) + return -1; + } + } + else + { + /* Stop an unused .glink section from affecting .text alignment. */ + if (htab->glink != NULL) + { + if (!bfd_set_section_alignment (htab->elf.dynobj, htab->glink, 0)) + return -1; + } + } + return !htab->old_plt; +} + /* Return the section that should be marked against GC for a given relocation. */ @@ -3334,9 +3479,16 @@ ppc_elf_tls_setup (bfd *obfd, struct bfd struct ppc_elf_link_hash_table *htab; htab = ppc_elf_hash_table (info); + if (!htab->old_plt + && htab->plt != NULL + && htab->plt->output_section != NULL) + { + elf_section_type (htab->plt->output_section) = SHT_PROGBITS; + elf_section_flags (htab->plt->output_section) = SHF_ALLOC + SHF_WRITE; + } + htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr", FALSE, FALSE, TRUE); - return _bfd_elf_tls_setup (obfd, info); } @@ -3706,7 +3858,10 @@ static bfd_vma allocate_got (struct ppc_elf_link_hash_table *htab, unsigned int need) { bfd_vma where; - unsigned int max_before_header = 32764; + unsigned int max_before_header = 32768; + + if (htab->old_plt) + max_before_header = 32764; if (need <= htab->got_gap) { @@ -3763,37 +3918,54 @@ allocate_dynrelocs (struct elf_link_hash { asection *s = htab->plt; - /* If this is the first .plt entry, make room for the special - first entry. */ - if (s->size == 0) - s->size += PLT_INITIAL_ENTRY_SIZE; - - /* The PowerPC PLT is actually composed of two parts, the - first part is 2 words (for a load and a jump), and then - there is a remaining word available at the end. */ - h->plt.offset = (PLT_INITIAL_ENTRY_SIZE - + (PLT_SLOT_SIZE - * ((s->size - PLT_INITIAL_ENTRY_SIZE) - / PLT_ENTRY_SIZE))); - - /* If this symbol is not defined in a regular file, and we - are not generating a shared library, then set the symbol - to this location in the .plt. This is required to make - function pointers compare as equal between the normal - executable and the shared library. */ - if (! info->shared - && !h->def_regular) + if (!htab->old_plt) { - h->root.u.def.section = s; - h->root.u.def.value = h->plt.offset; + h->plt.offset = s->size; + s->size += 4; + + s = htab->glink; + if (!info->shared + && !h->def_regular) + { + h->root.u.def.section = s; + h->root.u.def.value = s->size; + } + s->size += GLINK_ENTRY_SIZE; } + else + { + /* If this is the first .plt entry, make room for the + special first entry. */ + if (s->size == 0) + s->size += PLT_INITIAL_ENTRY_SIZE; + + /* The PowerPC PLT is actually composed of two parts, the + first part is 2 words (for a load and a jump), and then + there is a remaining word available at the end. */ + h->plt.offset = (PLT_INITIAL_ENTRY_SIZE + + (PLT_SLOT_SIZE + * ((s->size - PLT_INITIAL_ENTRY_SIZE) + / PLT_ENTRY_SIZE))); + + /* If this symbol is not defined in a regular file, and we + are not generating a shared library, then set the symbol + to this location in the .plt. This is required to make + function pointers compare as equal between the normal + executable and the shared library. */ + if (! info->shared + && !h->def_regular) + { + h->root.u.def.section = s; + h->root.u.def.value = h->plt.offset; + } - /* Make room for this entry. After the 8192nd entry, room - for two entries is allocated. */ - s->size += PLT_ENTRY_SIZE; - if ((s->size - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE - > PLT_NUM_SINGLE_ENTRIES) - s->size += PLT_ENTRY_SIZE; + /* Make room for this entry. After the 8192nd entry, room + for two entries is allocated. */ + s->size += PLT_ENTRY_SIZE; + if ((s->size - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE + > PLT_NUM_SINGLE_ENTRIES) + s->size += PLT_ENTRY_SIZE; + } /* We also need to make an entry in the .rela.plt section. */ htab->relplt->size += sizeof (Elf32_External_Rela); @@ -4010,7 +4182,10 @@ ppc_elf_size_dynamic_sections (bfd *outp } } - htab->got_header_size = 16; + if (htab->old_plt) + htab->got_header_size = 16; + else + htab->got_header_size = 12; /* Set up .got offsets for local syms, and space for local dynamic relocs. */ @@ -4118,11 +4293,18 @@ ppc_elf_size_dynamic_sections (bfd *outp g_o_t = htab->got->size; htab->got->size += htab->got_header_size; } - g_o_t += 4; + if (htab->old_plt) + g_o_t += 4; htab->elf.hgot->root.u.def.value = g_o_t; } + if (htab->glink != NULL && htab->glink->size != 0) + { + htab->glink_pltresolve = htab->glink->size; + htab->glink->size += GLINK_PLTRESOLVE; + } + /* We've now determined the sizes of the various dynamic sections. Allocate memory for them. */ relocs = FALSE; @@ -4132,6 +4314,7 @@ ppc_elf_size_dynamic_sections (bfd *outp continue; if (s == htab->plt + || s == htab->glink || s == htab->got || s == htab->sbss) { @@ -4179,7 +4362,7 @@ ppc_elf_size_dynamic_sections (bfd *outp continue; } - if (s == htab->sbss) + if ((s->flags & SEC_HAS_CONTENTS) == 0) continue; /* Allocate memory for the section contents. */ @@ -4213,6 +4396,12 @@ ppc_elf_size_dynamic_sections (bfd *outp return FALSE; } + if (htab->glink != NULL && htab->glink->size != 0) + { + if (!add_dynamic_entry (DT_PPC_GLINK, 0)) + return FALSE; + } + if (relocs) { if (!add_dynamic_entry (DT_RELA, 0) @@ -4281,7 +4470,7 @@ ppc_elf_relax_section (bfd *abfd, Elf_Internal_Rela *irel, *irelend; struct one_fixup *fixups = NULL; bfd_boolean changed; - struct ppc_elf_link_hash_table *ppc_info; + struct ppc_elf_link_hash_table *htab; bfd_size_type trampoff; *again = FALSE; @@ -4305,7 +4494,7 @@ ppc_elf_relax_section (bfd *abfd, if (internal_relocs == NULL) goto error_return; - ppc_info = ppc_elf_hash_table (link_info); + htab = ppc_elf_hash_table (link_info); irelend = internal_relocs + isec->reloc_count; for (irel = internal_relocs; irel < irelend; irel++) @@ -4382,11 +4571,19 @@ ppc_elf_relax_section (bfd *abfd, h = (struct elf_link_hash_entry *) h->root.u.i.link; if (r_type == R_PPC_PLTREL24 - && ppc_info->plt != NULL + && htab->plt != NULL && h->plt.offset != (bfd_vma) -1) { - tsec = ppc_info->plt; - toff = h->plt.offset; + if (!htab->old_plt) + { + tsec = htab->glink; + toff = h->plt.offset * (GLINK_ENTRY_SIZE / 4); + } + else + { + tsec = htab->plt; + toff = h->plt.offset; + } } else if (h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) @@ -4483,7 +4680,8 @@ ppc_elf_relax_section (bfd *abfd, if (R_PPC_RELAX32_PLT - R_PPC_RELAX32 != R_PPC_RELAX32PC_PLT - R_PPC_RELAX32PC) abort (); - if (tsec == ppc_info->plt) + if (tsec == htab->plt + || tsec == htab->glink) stub_rtype += R_PPC_RELAX32_PLT - R_PPC_RELAX32; /* Hijack the old relocation. Since we need two @@ -5426,6 +5624,12 @@ ppc_elf_relocate_section (bfd *output_bf addend = 0; goto dodyn; + case R_PPC_REL16: + case R_PPC_REL16_LO: + case R_PPC_REL16_HI: + case R_PPC_REL16_HA: + break; + case R_PPC_REL24: case R_PPC_REL32: case R_PPC_REL14: @@ -5595,9 +5799,14 @@ ppc_elf_relocate_section (bfd *output_bf && h->plt.offset != (bfd_vma) -1 && htab->plt != NULL); - relocation = (htab->plt->output_section->vma - + htab->plt->output_offset - + h->plt.offset); + if (!htab->old_plt) + relocation = (htab->glink->output_section->vma + + htab->glink->output_offset + + h->plt.offset * (GLINK_ENTRY_SIZE / 4)); + else + relocation = (htab->plt->output_section->vma + + htab->plt->output_offset + + h->plt.offset); if (r_type == R_PPC_RELAX32_PLT) goto relax32; /* Fall thru */ @@ -5676,9 +5885,14 @@ ppc_elf_relocate_section (bfd *output_bf } unresolved_reloc = FALSE; - relocation = (htab->plt->output_section->vma - + htab->plt->output_offset - + h->plt.offset); + if (!htab->old_plt) + relocation = (htab->glink->output_section->vma + + htab->glink->output_offset + + h->plt.offset * (GLINK_ENTRY_SIZE / 4)); + else + relocation = (htab->plt->output_section->vma + + htab->plt->output_offset + + h->plt.offset); break; /* Relocate against _SDA_BASE_. */ @@ -5837,6 +6051,7 @@ ppc_elf_relocate_section (bfd *output_bf break; case R_PPC_ADDR16_HA: + case R_PPC_REL16_HA: case R_PPC_GOT16_HA: case R_PPC_PLT16_HA: case R_PPC_SECTOFF_HA: @@ -5974,8 +6189,18 @@ ppc_elf_finish_dynamic_symbol (bfd *outp BFD_ASSERT (h->dynindx != -1); BFD_ASSERT (htab->plt != NULL && htab->relplt != NULL); - /* We don't need to fill in the .plt. The ppc dynamic linker - will fill it in. */ + if (htab->old_plt) + { + /* We don't need to fill in the .plt. The ppc dynamic linker + will fill it in. */ + } + else + { + bfd_vma val = (htab->glink_pltresolve + + htab->glink->output_section->vma + + htab->glink->output_offset); + bfd_put_32 (output_bfd, val, htab->plt->contents + h->plt.offset); + } /* Fill in the entry in the .rela.plt section. */ rela.r_offset = (htab->plt->output_section->vma @@ -5984,9 +6209,15 @@ ppc_elf_finish_dynamic_symbol (bfd *outp rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT); rela.r_addend = 0; - reloc_index = (h->plt.offset - PLT_INITIAL_ENTRY_SIZE) / PLT_SLOT_SIZE; - if (reloc_index > PLT_NUM_SINGLE_ENTRIES) - reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2; + if (!htab->old_plt) + reloc_index = h->plt.offset / 4; + else + { + reloc_index = ((h->plt.offset - PLT_INITIAL_ENTRY_SIZE) + / PLT_SLOT_SIZE); + if (reloc_index > PLT_NUM_SINGLE_ENTRIES) + reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2; + } loc = (htab->relplt->contents + reloc_index * sizeof (Elf32_External_Rela)); bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); @@ -6112,6 +6343,12 @@ ppc_elf_finish_dynamic_sections (bfd *ou dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; break; + case DT_PPC_GLINK: + s = htab->glink; + dyn.d_un.d_ptr = (htab->glink_pltresolve + + s->output_section->vma + s->output_offset); + break; + default: continue; } @@ -6128,7 +6365,8 @@ ppc_elf_finish_dynamic_sections (bfd *ou bfd_vma val; p += elf_hash_table (info)->hgot->root.u.def.value; - bfd_put_32 (output_bfd, 0x4e800021 /* blrl */, p - 4); + if (htab->old_plt) + bfd_put_32 (output_bfd, 0x4e800021 /* blrl */, p - 4); val = 0; if (sdyn != NULL) @@ -6138,6 +6376,67 @@ ppc_elf_finish_dynamic_sections (bfd *ou elf_section_data (htab->got->output_section)->this_hdr.sh_entsize = 4; } + if (htab->glink != NULL && htab->glink->contents != NULL) + { + unsigned char *p; + unsigned char *endp; + bfd_vma pltgot; + unsigned int i; + static const unsigned int plt_resolve[] = + { + SUB_11_11_30, + ADD_0_11_11, + ADD_11_0_11, + LWZ_0_4_30, + MTCTR_0, + LWZ_12_8_30, + BCTR, + NOP, + NOP, + NOP + }; + +#define PPC_LO(v) ((v) & 0xffff) +#define PPC_HI(v) (((v) >> 16) & 0xffff) +#define PPC_HA(v) PPC_HI ((v) + 0x8000) + + pltgot = (htab->plt->output_section->vma + + htab->plt->output_offset + - htab->elf.hgot->root.u.def.value + - htab->elf.hgot->root.u.def.section->output_section->vma + - htab->elf.hgot->root.u.def.section->output_offset); + + p = htab->glink->contents; + p += htab->glink_pltresolve; + bfd_put_32 (output_bfd, ADDIS_11_11 + PPC_HA (-pltgot), p); + p += 4; + bfd_put_32 (output_bfd, ADDI_11_11 + PPC_LO (-pltgot), p); + p += 4; + + for (i = 0; i < ARRAY_SIZE (plt_resolve); i++) + { + bfd_put_32 (output_bfd, plt_resolve[i], p); + p += 4; + } + if (ARRAY_SIZE (plt_resolve) + 2 != GLINK_PLTRESOLVE / 4) + abort (); + + p = htab->glink->contents; + endp = p + htab->glink_pltresolve; + while (p < endp) + { + bfd_put_32 (output_bfd, ADDIS_11_30 + PPC_HA (pltgot), p); + p += 4; + bfd_put_32 (output_bfd, LWZU_0_X_11 + PPC_LO (pltgot), p); + p += 4; + bfd_put_32 (output_bfd, MTCTR_0, p); + p += 4; + bfd_put_32 (output_bfd, BCTR, p); + p += 4; + pltgot += 4; + } + } + return TRUE; } Index: bfd/elf32-ppc.h =================================================================== RCS file: /cvs/src/src/bfd/elf32-ppc.h,v retrieving revision 1.6 diff -u -p -r1.6 elf32-ppc.h --- bfd/elf32-ppc.h 4 May 2005 15:53:19 -0000 1.6 +++ bfd/elf32-ppc.h 11 May 2005 08:57:36 -0000 @@ -17,6 +17,7 @@ You should have received a copy of the G along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ +int ppc_elf_select_plt_layout (bfd *, struct bfd_link_info *, int); asection *ppc_elf_tls_setup (bfd *, struct bfd_link_info *); bfd_boolean ppc_elf_tls_optimize (bfd *, struct bfd_link_info *); bfd_boolean ppc_elf_set_sdata_syms (bfd *, struct bfd_link_info *); Index: binutils/readelf.c =================================================================== RCS file: /cvs/src/src/binutils/readelf.c,v retrieving revision 1.288 diff -u -p -r1.288 readelf.c --- binutils/readelf.c 8 May 2005 14:17:39 -0000 1.288 +++ binutils/readelf.c 11 May 2005 08:57:48 -0000 @@ -1413,6 +1413,17 @@ get_sparc64_dynamic_type (unsigned long } static const char * +get_ppc_dynamic_type (unsigned long type) +{ + switch (type) + { + case DT_PPC_GLINK: return "PPC_GLINK"; + default: + return NULL; + } +} + +static const char * get_ppc64_dynamic_type (unsigned long type) { switch (type) @@ -1552,6 +1563,9 @@ get_dynamic_type (unsigned long type) case EM_SPARCV9: result = get_sparc64_dynamic_type (type); break; + case EM_PPC: + result = get_ppc_dynamic_type (type); + break; case EM_PPC64: result = get_ppc64_dynamic_type (type); break; Index: gas/config/tc-ppc.c =================================================================== RCS file: /cvs/src/src/gas/config/tc-ppc.c,v retrieving revision 1.96 diff -u -p -r1.96 tc-ppc.c --- gas/config/tc-ppc.c 5 May 2005 09:13:02 -0000 1.96 +++ gas/config/tc-ppc.c 11 May 2005 08:58:14 -0000 @@ -5707,8 +5719,6 @@ md_apply_fix3 (fixP, valP, seg) value, 8); break; - case BFD_RELOC_LO16: - case BFD_RELOC_16: case BFD_RELOC_GPREL16: case BFD_RELOC_16_GOT_PCREL: case BFD_RELOC_16_GOTOFF: @@ -5754,19 +5764,45 @@ md_apply_fix3 (fixP, valP, seg) value, 2); break; + case BFD_RELOC_16: + if (fixP->fx_pcrel) + fixP->fx_r_type = BFD_RELOC_16_PCREL; + /* fall through */ + + case BFD_RELOC_16_PCREL: + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, + value, 2); + break; + + case BFD_RELOC_LO16: + if (fixP->fx_pcrel) + fixP->fx_r_type = BFD_RELOC_LO16_PCREL; + /* fall through */ + + case BFD_RELOC_LO16_PCREL: + md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, + value, 2); + break; + /* This case happens when you write, for example, lis %r3,(L1-L2)@ha where L1 and L2 are defined later. */ case BFD_RELOC_HI16: if (fixP->fx_pcrel) - abort (); + fixP->fx_r_type = BFD_RELOC_HI16_PCREL; + /* fall through */ + + case BFD_RELOC_HI16_PCREL: md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, PPC_HI (value), 2); break; case BFD_RELOC_HI16_S: if (fixP->fx_pcrel) - abort (); + fixP->fx_r_type = BFD_RELOC_HI16_S_PCREL; + /* fall through */ + + case BFD_RELOC_HI16_S_PCREL: md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, PPC_HA (value), 2); break; Index: include/elf/ppc.h =================================================================== RCS file: /cvs/src/src/include/elf/ppc.h,v retrieving revision 1.16 diff -u -p -r1.16 ppc.h --- include/elf/ppc.h 10 May 2005 10:21:10 -0000 1.16 +++ include/elf/ppc.h 11 May 2005 08:58:25 -0000 @@ -120,12 +120,17 @@ START_RELOC_NUMBERS (elf_ppc_reloc_type) RELOC_NUMBER (R_PPC_EMB_BIT_FLD, 115) RELOC_NUMBER (R_PPC_EMB_RELSDA, 116) -/* Fake relocations for branch stubs. This will keep them - together. */ -#define R_PPC_RELAX32 249 -#define R_PPC_RELAX32PC 250 -#define R_PPC_RELAX32_PLT 251 -#define R_PPC_RELAX32PC_PLT 252 +/* Fake relocations for branch stubs, only used internally by ld. */ +#define R_PPC_RELAX32 245 +#define R_PPC_RELAX32PC 246 +#define R_PPC_RELAX32_PLT 247 +#define R_PPC_RELAX32PC_PLT 248 + +/* These are GNU extensions used in PIC code sequences. */ + RELOC_NUMBER (R_PPC_REL16, 249) + RELOC_NUMBER (R_PPC_REL16_LO, 250) + RELOC_NUMBER (R_PPC_REL16_HI, 251) + RELOC_NUMBER (R_PPC_REL16_HA, 252) /* These are GNU extensions to enable C++ vtable garbage collection. */ RELOC_NUMBER (R_PPC_GNU_VTINHERIT, 253) @@ -140,6 +145,9 @@ END_RELOC_NUMBERS (R_PPC_max) #define IS_PPC_TLS_RELOC(R) \ ((R) >= R_PPC_TLS && (R) <= R_PPC_GOT_DTPREL16_HA) +/* Specify the start of the .glink section. */ +#define DT_PPC_GLINK DT_LOPROC + /* Processor specific flags for the ELF header e_flags field. */ #define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag. */ Index: ld/ldgram.y =================================================================== RCS file: /cvs/src/src/ld/ldgram.y,v retrieving revision 1.40 diff -u -p -r1.40 ldgram.y --- ld/ldgram.y 28 Apr 2005 23:54:32 -0000 1.40 +++ ld/ldgram.y 11 May 2005 08:58:27 -0000 @@ -151,7 +151,7 @@ static int error_index; %token INPUT_SCRIPT INPUT_MRI_SCRIPT INPUT_DEFSYM CASE EXTERN START %token VERS_TAG VERS_IDENTIFIER %token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT -%token KEEP ONLY_IF_RO ONLY_IF_RW +%token KEEP ONLY_IF_RO ONLY_IF_RW SPECIAL %token EXCLUDE_FILE %type vers_defns %type vers_tag @@ -899,6 +899,7 @@ opt_subalign: sect_constraint: ONLY_IF_RO { $$ = ONLY_IF_RO; } | ONLY_IF_RW { $$ = ONLY_IF_RW; } + | SPECIAL { $$ = SPECIAL; } | { $$ = 0; } ; Index: ld/ldlang.c =================================================================== RCS file: /cvs/src/src/ld/ldlang.c,v retrieving revision 1.180 diff -u -p -r1.180 ldlang.c --- ld/ldlang.c 4 May 2005 11:00:26 -0000 1.180 +++ ld/ldlang.c 11 May 2005 08:58:30 -0000 @@ -991,7 +991,9 @@ lang_output_section_find_1 (const char * { if (strcmp (name, lookup->name) == 0 && lookup->constraint != -1 - && (constraint == 0 || constraint == lookup->constraint)) + && (constraint == 0 + || (constraint == lookup->constraint + && constraint != SPECIAL))) return lookup; } return NULL; @@ -2951,7 +2953,8 @@ map_input_to_output_sections case lang_output_section_statement_enum: if (s->output_section_statement.constraint) { - if (s->output_section_statement.constraint == -1) + if (s->output_section_statement.constraint != ONLY_IF_RW + && s->output_section_statement.constraint != ONLY_IF_RO) break; s->output_section_statement.all_input_readonly = TRUE; check_input_sections (s->output_section_statement.children.head, Index: ld/ldlex.l =================================================================== RCS file: /cvs/src/src/ld/ldlex.l,v retrieving revision 1.30 diff -u -p -r1.30 ldlex.l --- ld/ldlex.l 15 Feb 2005 14:36:19 -0000 1.30 +++ ld/ldlex.l 11 May 2005 08:58:31 -0000 @@ -303,6 +303,7 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([ "OVERLAY" { RTOKEN(OVERLAY);} "ONLY_IF_RO" { RTOKEN(ONLY_IF_RO); } "ONLY_IF_RW" { RTOKEN(ONLY_IF_RW); } +"SPECIAL" { RTOKEN(SPECIAL); } "o" { RTOKEN(ORIGIN);} "org" { RTOKEN(ORIGIN);} "l" { RTOKEN( LENGTH);} Index: ld/emulparams/elf32ppc.sh =================================================================== RCS file: /cvs/src/src/ld/emulparams/elf32ppc.sh,v retrieving revision 1.14 diff -u -p -r1.14 elf32ppc.sh --- ld/emulparams/elf32ppc.sh 11 May 2004 17:08:33 -0000 1.14 +++ ld/emulparams/elf32ppc.sh 11 May 2005 08:58:31 -0000 @@ -12,7 +12,16 @@ MAXPAGESIZE=0x10000 COMMONPAGESIZE=0x1000 ARCH=powerpc:common MACHINE= +# Yes, we want duplicate .got and .plt sections. The linker chooses the +# appropriate one magically in ppc_after_open +DATA_GOT= +SDATA_GOT= +SEPARATE_GOTPLT=0 BSS_PLT= +GOT=".got ${RELOCATING-0} : SPECIAL { *(.got) }" +PLT=".plt ${RELOCATING-0} : SPECIAL { *(.plt) }" +GOTPLT="${PLT}" +OTHER_TEXT_SECTIONS="*(.glink)" EXECUTABLE_SYMBOLS='PROVIDE (__stack = 0); PROVIDE (___stack = 0);' OTHER_BSS_END_SYMBOLS='__end = .;' OTHER_RELRO_SECTIONS=" Index: ld/emultempl/ppc32elf.em =================================================================== RCS file: /cvs/src/src/ld/emultempl/ppc32elf.em,v retrieving revision 1.4 diff -u -p -r1.4 ppc32elf.em --- ld/emultempl/ppc32elf.em 21 Mar 2005 13:23:15 -0000 1.4 +++ ld/emultempl/ppc32elf.em 11 May 2005 08:58:31 -0000 @@ -32,6 +32,66 @@ extern const bfd_target bfd_elf32_powerp /* Whether to run tls optimization. */ static int notlsopt = 0; +/* Chooses the correct place for .plt and .got. */ +static int old_plt = 0; +static int old_got = 0; + +static void +ppc_after_open (void) +{ + if (link_info.hash->creator == &bfd_elf32_powerpc_vec + || link_info.hash->creator == &bfd_elf32_powerpcle_vec) + { + int new_plt; + int keep_new; + unsigned int num_plt; + unsigned int num_got; + lang_output_section_statement_type *os; + lang_output_section_statement_type *plt_os[2]; + lang_output_section_statement_type *got_os[2]; + + new_plt = ppc_elf_select_plt_layout (output_bfd, &link_info, old_plt); + if (new_plt < 0) + einfo ("%X%P: select_plt_layout problem %E\n"); + + num_got = 0; + num_plt = 0; + for (os = &lang_output_section_statement.head->output_section_statement; + os != NULL; + os = os->next) + { + if (os->constraint == SPECIAL && strcmp (os->name, ".plt") == 0) + { + if (num_plt < 2) + plt_os[num_plt] = os; + ++num_plt; + } + if (os->constraint == SPECIAL && strcmp (os->name, ".got") == 0) + { + if (num_got < 2) + got_os[num_got] = os; + ++num_got; + } + } + + keep_new = new_plt == 1 ? 0 : -1; + if (num_plt == 2) + { + plt_os[0]->constraint = keep_new; + plt_os[1]->constraint = ~keep_new; + } + if (num_got == 2) + { + if (old_got) + keep_new = -1; + got_os[0]->constraint = keep_new; + got_os[1]->constraint = ~keep_new; + } + } + + gld${EMULATION_NAME}_after_open (); +} + static void ppc_before_allocation (void) { @@ -68,15 +128,21 @@ EOF # PARSE_AND_LIST_PROLOGUE=' #define OPTION_NO_TLS_OPT 301 +#define OPTION_OLD_PLT 302 +#define OPTION_OLD_GOT 303 ' PARSE_AND_LIST_LONGOPTS=' { "no-tls-optimize", no_argument, NULL, OPTION_NO_TLS_OPT }, + { "bss-plt", no_argument, NULL, OPTION_OLD_PLT }, + { "sdata-got", no_argument, NULL, OPTION_OLD_GOT }, ' PARSE_AND_LIST_OPTIONS=' fprintf (file, _("\ - --no-tls-optimize Don'\''t try to optimize TLS accesses.\n" + --no-tls-optimize Don'\''t try to optimize TLS accesses.\n\ + --bss-plt Force old-style BSS PLT.\n\ + --sdata-got Force GOT location just before .sdata.\n" )); ' @@ -84,9 +150,18 @@ PARSE_AND_LIST_ARGS_CASES=' case OPTION_NO_TLS_OPT: notlsopt = 1; break; + + case OPTION_OLD_PLT: + old_plt = 1; + break; + + case OPTION_OLD_GOT: + old_got = 1; + break; ' # Put these extra ppc32elf routines in ld_${EMULATION_NAME}_emulation # +LDEMUL_AFTER_OPEN=ppc_after_open LDEMUL_BEFORE_ALLOCATION=ppc_before_allocation LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation Index: ld/scripttempl/elf.sc =================================================================== RCS file: /cvs/src/src/ld/scripttempl/elf.sc,v retrieving revision 1.56 diff -u -p -r1.56 elf.sc --- ld/scripttempl/elf.sc 10 May 2005 02:27:38 -0000 1.56 +++ ld/scripttempl/elf.sc 11 May 2005 08:58:32 -0000 @@ -101,7 +101,9 @@ if test -n "${COMMONPAGESIZE}"; then DATA_SEGMENT_RELRO_END=". = DATA_SEGMENT_RELRO_END (${SEPARATE_GOTPLT-0}, .);" fi INTERP=".interp ${RELOCATING-0} : { *(.interp) }" -PLT=".plt ${RELOCATING-0} : { *(.plt) }" +if test -z "$PLT"; then + PLT=".plt ${RELOCATING-0} : { *(.plt) }" +fi if test -z "$GOT"; then if test -z "$SEPARATE_GOTPLT"; then GOT=".got ${RELOCATING-0} : { *(.got.plt) *(.got) }" @@ -144,6 +146,16 @@ if test -z "${NO_SMALL_DATA}"; then else NO_SMALL_DATA=" " fi +if test -z "${DATA_GOT}"; then + if test -n "${NO_SMALL_DATA}"; then + DATA_GOT=" " + fi +fi +if test -z "${SDATA_GOT}"; then + if test -z "${NO_SMALL_DATA}"; then + SDATA_GOT=" " + fi +fi test -n "$SEPARATE_GOTPLT" && SEPARATE_GOTPLT=" " CTOR=".ctors ${CONSTRUCTING-0} : { @@ -343,11 +355,12 @@ cat <