This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

powerpc new PLT and GOT


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 <name> 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 <versyms> vers_defns
 %type <versnode> 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\[\]\-\!\^\\]([
 <EXPRESSION,BOTH,SCRIPT>"OVERLAY"	{ RTOKEN(OVERLAY);}
 <EXPRESSION,BOTH,SCRIPT>"ONLY_IF_RO"	{ RTOKEN(ONLY_IF_RO); }
 <EXPRESSION,BOTH,SCRIPT>"ONLY_IF_RW"	{ RTOKEN(ONLY_IF_RW); }
+<EXPRESSION,BOTH,SCRIPT>"SPECIAL"	{ RTOKEN(SPECIAL); }
 <BOTH,SCRIPT>"o"			{ RTOKEN(ORIGIN);}
 <BOTH,SCRIPT>"org"			{ RTOKEN(ORIGIN);}
 <BOTH,SCRIPT>"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 <<EOF
   ${RELOCATING+${DATARELRO}}
   ${OTHER_RELRO_SECTIONS}
   ${TEXT_DYNAMIC-${DYNAMIC}}
-  ${NO_SMALL_DATA+${RELRO_NOW+${GOT}}}
-  ${NO_SMALL_DATA+${RELRO_NOW-${SEPARATE_GOTPLT+${GOT}}}}
+  ${DATA_GOT+${RELRO_NOW+${GOT}}}
+  ${DATA_GOT+${RELRO_NOW+${GOTPLT}}}
+  ${DATA_GOT+${RELRO_NOW-${SEPARATE_GOTPLT+${GOT}}}}
   ${RELOCATING+${DATA_SEGMENT_RELRO_END}}
-  ${NO_SMALL_DATA+${RELRO_NOW-${SEPARATE_GOTPLT+${GOTPLT}}}}
-  ${NO_SMALL_DATA+${RELRO_NOW-${SEPARATE_GOTPLT-${GOT}}}}
+  ${DATA_GOT+${RELRO_NOW-${SEPARATE_GOTPLT-${GOT}}}}
+  ${DATA_GOT+${RELRO_NOW-${GOTPLT}}}
 
   ${DATA_PLT+${PLT_BEFORE_GOT-${PLT}}}
 
@@ -364,9 +377,9 @@ cat <<EOF
   ${SMALL_DATA_CTOR+${RELOCATING+${CTOR}}}
   ${SMALL_DATA_DTOR+${RELOCATING+${DTOR}}}
   ${DATA_PLT+${PLT_BEFORE_GOT+${PLT}}}
-  ${RELOCATING+${OTHER_GOT_SYMBOLS}}
-  ${NO_SMALL_DATA-${GOT}}
-  ${OTHER_GOT_SECTIONS}
+  ${SDATA_GOT+${RELOCATING+${OTHER_GOT_SYMBOLS}}}
+  ${SDATA_GOT+${GOT}}
+  ${SDATA_GOT+${OTHER_GOT_SECTIONS}}
   ${SDATA}
   ${OTHER_SDATA_SECTIONS}
   ${RELOCATING+${DATA_END_SYMBOLS-_edata = .; PROVIDE (edata = .);}}

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

Attachment: ppc32abi-2
Description: Text document


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]