public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH, arm] Thumb shared library support: Thumb PLT, etc.
@ 2002-07-17 18:14 Adam Nemet
  2002-07-18  4:11 ` Richard Earnshaw
  0 siblings, 1 reply; 11+ messages in thread
From: Adam Nemet @ 2002-07-17 18:14 UTC (permalink / raw)
  To: binutils

Hi,

This is the second piece of a series of patches to make shared
libraries work on Thumb.  The first (yet unreviewed) patch was a GCC
patch: http://gcc.gnu.org/ml/gcc-patches/2002-07/msg00398.html .

This patch among other things adds a new switch --thumb-plt to
generate Thumb PLT on ARM ELF.  My third patch will handle the
interworking aspects of this new flag.

I ran the GCC testsuite with all combinations of -marm/-mthumb and
/-fPIC.  I also did lots of manual testing especially on the lazy
relocation part as our (LynxOS) ld.so does not support that.  A
slightly different form of this patch has been part of our ld (2.10.1)
for sometime now and underwent extensive testing.

Please apply if OK.
Adam

bfd/ChangeLog:
2002-07-17  Adam Nemet  <anemet@lnxw.com>

	* elf32-arm.h (arm_plt): New global.
	(ARM_PLT_ENTRY_SIZE): Rename PLT_ENTRY_SIZE.
	(THUMB_PLT_ENTRY_SIZE): New macro.
	(PLT_ENTRY_SIZE): Return *_PLT_ENTRY_SIZE depending on arm_plt.
	(elf32_arm_plt0_entry): Rename PLT_ENTRY_SIZE to
	ARM_PLT_ENTRY_SIZE.
	(elf32_arm_plt_entry): Likewise.
	(elf_backend_plt_header_size): Likewise.
	(elf32_thumb_plt0_entry): New global.
	(elf32_arm_finish_dynamic_sections): Use it.
	(elf32_thumb_plt_entry): New global.
	(elf32_arm_finish_dynamic_symbol): Use it.  Account for the PLT
	type when setting GOT entries to &PLT[0].
	(elf32_arm_final_link_relocate, R_ARM_THM_PC22 case): Handle
	relocations against the PLT.
	(elf32_arm_check_relocs, case R_ARM_THM_PC22 case): New case.
	Determine if relocation needs a PLT entry.
	(elf32_arm_adjust_dynamic_symbol): Create PLT entries for Thumb
	functions as well.

	* elflink.h (elf_bfd_final_link): Allow numbers in
	link_info.{init,fini}_function.

ld/ChangeLog:
2002-07-17  Adam Nemet  <anemet@lnxw.com>

	* emultempl/armelf.em: Include elf-bfd.h and elf/arm.h.
	(arm_plt): New extern.
	(gld${EMULATION_NAME}_before_parse): Initialize it.
	(arm_elf_finish): Set the last bit of DT_INIT and DT_FINI
	depending on the type of the function.
	(OPTION_THUMB_PLT): New marco.
	(PARSE_AND_LIST_LONGOPTS): Add --thumb-plt.
	(PARSE_AND_LIST_OPTIONS): Likewise.
	(PARSE_AND_LIST_ARGS_CASES): Likewise.

	* ld.texinfo (ARM): Document --thumb-plt.

Index: bfd/elf32-arm.h
===================================================================
RCS file: /cvs/src/src/bfd/elf32-arm.h,v
retrieving revision 1.87
diff -c -p -r1.87 elf32-arm.h
*** bfd/elf32-arm.h	7 Jul 2002 09:10:40 -0000	1.87
--- bfd/elf32-arm.h	17 Jul 2002 22:30:27 -0000
*************** static enum elf_reloc_type_class elf32_a
*** 110,123 ****
     section.  */
  #define ELF_DYNAMIC_INTERPRETER     "/usr/lib/ld.so.1"
  
  /* The size in bytes of an entry in the procedure linkage table.  */
! #define PLT_ENTRY_SIZE 16
  
  /* The first entry in a procedure linkage table looks like
     this.  It is set up so that any shared library function that is
     called before the relocation has been set up calls the dynamic
     linker first.  */
! static const bfd_vma elf32_arm_plt0_entry [PLT_ENTRY_SIZE / 4] =
    {
      0xe52de004,	/* str   lr, [sp, #-4]!     */
      0xe59fe010,	/* ldr   lr, [pc, #16]      */
--- 110,129 ----
     section.  */
  #define ELF_DYNAMIC_INTERPRETER     "/usr/lib/ld.so.1"
  
+ /* Which instruction set should be used when producing the PLT.  Set
+    in ld/emultempl/armelf.em.  */
+ int arm_plt;
+ 
  /* The size in bytes of an entry in the procedure linkage table.  */
! #define ARM_PLT_ENTRY_SIZE 	16
! #define THUMB_PLT_ENTRY_SIZE	20
! #define PLT_ENTRY_SIZE (arm_plt ? ARM_PLT_ENTRY_SIZE : THUMB_PLT_ENTRY_SIZE)
  
  /* The first entry in a procedure linkage table looks like
     this.  It is set up so that any shared library function that is
     called before the relocation has been set up calls the dynamic
     linker first.  */
! static const bfd_vma elf32_arm_plt0_entry [ARM_PLT_ENTRY_SIZE / 4] =
    {
      0xe52de004,	/* str   lr, [sp, #-4]!     */
      0xe59fe010,	/* ldr   lr, [pc, #16]      */
*************** static const bfd_vma elf32_arm_plt0_entr
*** 125,139 ****
      0xe5bef008	/* ldr   pc, [lr, #8]!      */
    };
  
  /* Subsequent entries in a procedure linkage table look like
     this.  */
! static const bfd_vma elf32_arm_plt_entry [PLT_ENTRY_SIZE / 4] =
   {
     0xe59fc004,	/* ldr   ip, [pc, #4]       */
     0xe08fc00c,	/* add   ip, pc, ip         */
     0xe59cf000,	/* ldr   pc, [ip]           */
     0x00000000	/* offset to symbol in got  */
   };
  
  /* The ARM linker needs to keep track of the number of relocs that it
     decides to copy in check_relocs for each symbol.  This is so that
--- 131,178 ----
      0xe5bef008	/* ldr   pc, [lr, #8]!      */
    };
  
+ static const insn16 elf32_thumb_plt0_entry [THUMB_PLT_ENTRY_SIZE / 2] =
+   {
+     0xb500,	/* push    {lr}		    */
+     0xb082,	/* sub     sp, #8	    */
+     0x9000,	/* str     r0, [sp]	    */
+     0x4807,	/* ldr     r0, [pc, #28]    */
+     0x300c,	/* add     r0, #12	    */
+     0x4478,	/* add     r0, pc	    */
+     0x4686,	/* mov     lr, r0	    */
+     0x6800,	/* ldr     r0, [r0]	    */
+     0x9001,	/* str     r0, [sp, #4]	    */
+     0xbd01	/* pop     {r0, pc}	    */
+   };
+ 
  /* Subsequent entries in a procedure linkage table look like
     this.  */
! static const bfd_vma elf32_arm_plt_entry [ARM_PLT_ENTRY_SIZE / 4] =
   {
     0xe59fc004,	/* ldr   ip, [pc, #4]       */
     0xe08fc00c,	/* add   ip, pc, ip         */
     0xe59cf000,	/* ldr   pc, [ip]           */
     0x00000000	/* offset to symbol in got  */
   };
+  
+ /* Note that on ARMv5 and above unlike the ARM PLT entries, the Thumb
+    entry can switch mode depending on the corresponding address in the
+    GOT.  The dynamic linker should set or clear the last bit of the
+    address in the GOT accordingly.  */
+ 
+ static const insn16 elf32_thumb_plt_entry [THUMB_PLT_ENTRY_SIZE / 2] =
+   {
+     0xb082,	/* sub   sp, #8		    */
+     0x9000,	/* str   r0, [sp]	    */
+     0x4802,	/* ldr   r0, [pc, #8]	    */
+     0x4478,	/* add   r0, pc		    */
+     0x4684,	/* mov   ip, r0		    */
+     0x6800,	/* ldr   r0, [r0]	    */
+     0x9001,	/* str   r0, [sp, #4]	    */
+     0xbd01,	/* pop   {r0, pc}	    */
+     0x0000,	/* offset to symbol in got  */
+     0x0000
+   };
  
  /* The ARM linker needs to keep track of the number of relocs that it
     decides to copy in check_relocs for each symbol.  This is so that
*************** elf32_arm_final_link_relocate (howto, in
*** 1407,1412 ****
--- 1446,1459 ----
  	  signed_addend = addend;
  	}
  #endif
+ 
+ 	/* If value is zero then we are linking a shared object and
+ 	   this is a reference to an externally visible symbol.  */
+ 	if (h != NULL && h->plt.offset != (bfd_vma) -1 && value == 0)
+ 	  value = (splt->output_section->vma
+ 		   + splt->output_offset
+ 		   + h->plt.offset);
+ 
  #ifndef OLD_ARM_ABI
  	if (r_type == R_ARM_THM_XPC22)
  	  {
*************** elf32_arm_check_relocs (abfd, info, sec,
*** 2725,2730 ****
--- 2772,2788 ----
  	    h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
  	    break;
  
+ 	  case R_ARM_THM_PC22:
+ 	    /* Since there is no PLT32 for Thumb if we are creating a
+ 	       shared library and this is an externally visible symbol
+ 	       then add it to the PLT.  */
+ 	    if (info->shared && h != NULL && h->dynindx != -1
+ 		&& (! info->symbolic
+ 		    || (h->elf_link_hash_flags
+ 			& ELF_LINK_HASH_DEF_REGULAR) == 0))
+ 	      h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+ 	    break;
+ 
  	  case R_ARM_ABS32:
  	  case R_ARM_REL32:
  	  case R_ARM_PC24:
*************** elf32_arm_adjust_dynamic_symbol (info, h
*** 2955,2961 ****
    /* If this is a function, put it in the procedure linkage table.  We
       will fill in the contents of the procedure linkage table later,
       when we know the address of the .got section.  */
!   if (h->type == STT_FUNC
        || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
      {
        if (! info->shared
--- 3013,3019 ----
    /* If this is a function, put it in the procedure linkage table.  We
       will fill in the contents of the procedure linkage table later,
       when we know the address of the .got section.  */
!   if (h->type == STT_FUNC || h->type == STT_ARM_TFUNC
        || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
      {
        if (! info->shared
*************** elf32_arm_finish_dynamic_symbol (output_
*** 3345,3369 ****
        got_offset = (plt_index + 3) * 4;
  
        /* Fill in the entry in the procedure linkage table.  */
!       bfd_put_32 (output_bfd, elf32_arm_plt_entry[0],
! 		  splt->contents + h->plt.offset + 0);
!       bfd_put_32 (output_bfd, elf32_arm_plt_entry[1],
! 		  splt->contents + h->plt.offset + 4);
!       bfd_put_32 (output_bfd, elf32_arm_plt_entry[2],
! 		  splt->contents + h->plt.offset + 8);
!       bfd_put_32 (output_bfd,
! 		      (sgot->output_section->vma
! 		       + sgot->output_offset
! 		       + got_offset
! 		       - splt->output_section->vma
! 		       - splt->output_offset
! 		       - h->plt.offset - 12),
  		      splt->contents + h->plt.offset + 12);
  
        /* Fill in the entry in the global offset table.  */
        bfd_put_32 (output_bfd,
  		  (splt->output_section->vma
! 		   + splt->output_offset),
  		  sgot->contents + got_offset);
  
        /* Fill in the entry in the .rel.plt section.  */
--- 3403,3450 ----
        got_offset = (plt_index + 3) * 4;
  
        /* Fill in the entry in the procedure linkage table.  */
!       
!       if (arm_plt)
! 	{
! 	  bfd_put_32 (output_bfd, elf32_arm_plt_entry[0],
! 		      splt->contents + h->plt.offset + 0);
! 	  bfd_put_32 (output_bfd, elf32_arm_plt_entry[1],
! 		      splt->contents + h->plt.offset + 4);
! 	  bfd_put_32 (output_bfd, elf32_arm_plt_entry[2],
! 		      splt->contents + h->plt.offset + 8);
! 	}
!       else
! 	{
! 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt_entry[0],
! 		      splt->contents + h->plt.offset + 0);
! 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt_entry[1],
! 		      splt->contents + h->plt.offset + 2);
! 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt_entry[2],
! 		      splt->contents + h->plt.offset + 4);
! 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt_entry[3],
! 		      splt->contents + h->plt.offset + 6);
! 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt_entry[4],
! 		      splt->contents + h->plt.offset + 8);
! 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt_entry[5],
! 		      splt->contents + h->plt.offset + 10);
! 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt_entry[6],
  		      splt->contents + h->plt.offset + 12);
+ 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt_entry[7],
+ 		      splt->contents + h->plt.offset + 14);
+ 	}
+       bfd_put_32 (output_bfd,
+ 		  (sgot->output_section->vma
+ 		   + sgot->output_offset
+ 		   + got_offset
+ 		   - splt->output_section->vma
+ 		   - splt->output_offset
+ 		   - h->plt.offset - (arm_plt ? 12 : 10)),
+ 		  splt->contents + h->plt.offset + (arm_plt ? 12 : 16));
  
        /* Fill in the entry in the global offset table.  */
        bfd_put_32 (output_bfd,
  		  (splt->output_section->vma
! 		   + splt->output_offset | (arm_plt ? 0 : 1)),
  		  sgot->contents + got_offset);
  
        /* Fill in the entry in the .rel.plt section.  */
*************** elf32_arm_finish_dynamic_sections (outpu
*** 3547,3556 ****
        /* Fill in the first entry in the procedure linkage table.  */
        if (splt->_raw_size > 0)
  	{
! 	  bfd_put_32 (output_bfd, elf32_arm_plt0_entry[0], splt->contents +  0);
! 	  bfd_put_32 (output_bfd, elf32_arm_plt0_entry[1], splt->contents +  4);
! 	  bfd_put_32 (output_bfd, elf32_arm_plt0_entry[2], splt->contents +  8);
! 	  bfd_put_32 (output_bfd, elf32_arm_plt0_entry[3], splt->contents + 12);
  	}
  
        /* UnixWare sets the entsize of .plt to 4, although that doesn't
--- 3628,3667 ----
        /* Fill in the first entry in the procedure linkage table.  */
        if (splt->_raw_size > 0)
  	{
! 	  if (arm_plt)
! 	    {
! 	      bfd_put_32 (output_bfd, elf32_arm_plt0_entry[0],
! 			  splt->contents +  0);
! 	      bfd_put_32 (output_bfd, elf32_arm_plt0_entry[1],
! 			  splt->contents +  4);
! 	      bfd_put_32 (output_bfd, elf32_arm_plt0_entry[2],
! 			  splt->contents +  8);
! 	      bfd_put_32 (output_bfd, elf32_arm_plt0_entry[3],
! 			  splt->contents + 12);
! 	    }
! 	  else
! 	    {
! 	      bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt0_entry[0],
! 			  splt->contents + 0);
! 	      bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt0_entry[1],
! 			  splt->contents + 2);
! 	      bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt0_entry[2],
! 			  splt->contents + 4);
! 	      bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt0_entry[3],
! 			  splt->contents + 6);
! 	      bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt0_entry[4],
! 			  splt->contents + 8);
! 	      bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt0_entry[5],
! 			  splt->contents + 10);
! 	      bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt0_entry[6],
! 			  splt->contents + 12);
! 	      bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt0_entry[7],
! 			  splt->contents + 14);
! 	      bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt0_entry[8],
! 			  splt->contents + 16);
! 	      bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt0_entry[9],
! 			  splt->contents + 18);
! 	    }
  	}
  
        /* UnixWare sets the entsize of .plt to 4, although that doesn't
*************** elf32_arm_reloc_type_class (rela)
*** 3641,3646 ****
  #endif
  
  #define elf_backend_got_header_size	12
! #define elf_backend_plt_header_size	PLT_ENTRY_SIZE
  
  #include "elf32-target.h"
--- 3752,3757 ----
  #endif
  
  #define elf_backend_got_header_size	12
! #define elf_backend_plt_header_size	ARM_PLT_ENTRY_SIZE
  
  #include "elf32-target.h"
Index: bfd/elflink.h
===================================================================
RCS file: /cvs/src/src/bfd/elflink.h,v
retrieving revision 1.177
diff -c -p -r1.177 elflink.h
*** bfd/elflink.h	16 Jul 2002 12:31:35 -0000	1.177
--- bfd/elflink.h	17 Jul 2002 22:30:28 -0000
*************** elf_bfd_final_link (abfd, info)
*** 5662,5667 ****
--- 5662,5681 ----
  
  		    elf_swap_dyn_out (dynobj, &dyn, dyncon);
  		  }
+ 		else
+ 		  {
+ 		    bfd_vma val;
+ 		    CONST char *send;
+ 
+ 		    /* We couldn't find the entry symbol.  Try parsing it as a
+ 		       number.  */
+ 		    val = bfd_scan_vma (name, &send, 0);
+ 		    if (*send == '\0')
+ 		      {
+ 			dyn.d_un.d_val = val;
+ 			elf_swap_dyn_out (dynobj, &dyn, dyncon);
+ 		      }
+ 		  }
  	      }
  	      break;
  
Index: ld/emultempl/armelf.em
===================================================================
RCS file: /cvs/src/src/ld/emultempl/armelf.em,v
retrieving revision 1.27
diff -c -p -r1.27 armelf.em
*** ld/emultempl/armelf.em	1 Jul 2002 08:07:31 -0000	1.27
--- ld/emultempl/armelf.em	17 Jul 2002 22:30:28 -0000
***************
*** 24,33 ****
  #
  cat >>e${EMULATION_NAME}.c <<EOF
  
  static int no_pipeline_knowledge = 0;
  static char *thumb_entry_symbol = NULL;
  static bfd *bfd_for_interwork;
! 
  
  static void
  gld${EMULATION_NAME}_before_parse ()
--- 24,36 ----
  #
  cat >>e${EMULATION_NAME}.c <<EOF
  
+ #include "elf-bfd.h"
+ #include "elf/arm.h"
+ 
  static int no_pipeline_knowledge = 0;
  static char *thumb_entry_symbol = NULL;
  static bfd *bfd_for_interwork;
! extern int arm_plt;
  
  static void
  gld${EMULATION_NAME}_before_parse ()
*************** gld${EMULATION_NAME}_before_parse ()
*** 37,42 ****
--- 40,46 ----
  #endif /* not TARGET_ */
    config.dynamic_link = ${DYNAMIC_LINK-true};
    config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo true ; else echo false ; fi`;
+   arm_plt = 1;
  }
  
  static void arm_elf_after_open PARAMS ((void));
*************** static void
*** 138,185 ****
  arm_elf_finish ()
  {
    struct bfd_link_hash_entry * h;
  
    /* Call the elf32.em routine.  */
    gld${EMULATION_NAME}_finish ();
  
!   if (thumb_entry_symbol == NULL)
!     return;
!   
!   h = bfd_link_hash_lookup (link_info.hash, thumb_entry_symbol,
! 			    false, false, true);
  
    if (h != (struct bfd_link_hash_entry *) NULL
        && (h->type == bfd_link_hash_defined
  	  || h->type == bfd_link_hash_defweak)
        && h->u.def.section->output_section != NULL)
      {
        static char buffer[32];
        bfd_vma val;
!       
!       /* Special procesing is required for a Thumb entry symbol.  The
! 	 bottom bit of its address must be set.  */
        val = (h->u.def.value
  	     + bfd_get_section_vma (output_bfd,
  				    h->u.def.section->output_section)
  	     + h->u.def.section->output_offset);
!       
        val |= 1;
  
!       /* Now convert this value into a string and store it in entry_symbol
!          where the lang_finish() function will pick it up.  */
        buffer[0] = '0';
        buffer[1] = 'x';
!       
        sprintf_vma (buffer + 2, val);
  
!       if (entry_symbol.name != NULL && entry_from_cmdline)
! 	einfo (_("%P: warning: '--thumb-entry %s' is overriding '-e %s'\n"),
! 	       thumb_entry_symbol, entry_symbol.name);
!       entry_symbol.name = buffer;
      }
-   else
-     einfo (_("%P: warning: connot find thumb start symbol %s\n"),
- 	   thumb_entry_symbol);
  }
  
  EOF
--- 142,256 ----
  arm_elf_finish ()
  {
    struct bfd_link_hash_entry * h;
+   struct elf_link_hash_entry * eh;
  
    /* Call the elf32.em routine.  */
    gld${EMULATION_NAME}_finish ();
  
!   if (thumb_entry_symbol != NULL)
!     {
!       h = bfd_link_hash_lookup (link_info.hash, thumb_entry_symbol,
! 				false, false, true);
! 
!       if (h != (struct bfd_link_hash_entry *) NULL
! 	  && (h->type == bfd_link_hash_defined
! 	      || h->type == bfd_link_hash_defweak)
! 	  && h->u.def.section->output_section != NULL)
! 	{
! 	  static char buffer[32];
! 	  bfd_vma val;
!       
! 	  /* Special procesing is required for a Thumb entry symbol.  The
! 	     bottom bit of its address must be set.  */
! 	  val = (h->u.def.value
! 		 + bfd_get_section_vma (output_bfd,
! 					h->u.def.section->output_section)
! 		 + h->u.def.section->output_offset);
!       
! 	  val |= 1;
! 
! 	  /* Now convert this value into a string and store it in entry_symbol
! 	     where the lang_finish() function will pick it up.  */
! 	  buffer[0] = '0';
! 	  buffer[1] = 'x';
!       
! 	  sprintf_vma (buffer + 2, val);
! 
! 	  if (entry_symbol.name != NULL && entry_from_cmdline)
! 	    einfo (_("%P: warning: '--thumb-entry %s' is overriding '-e %s'\n"),
! 		   thumb_entry_symbol, entry_symbol.name);
! 	  entry_symbol.name = buffer;
! 	}
!       else
! 	einfo (_("%P: warning: connot find thumb start symbol %s\n"),
! 	       thumb_entry_symbol);
!     }
! 
!   /* If init is a Thumb function set the LSB.  */
!   h = bfd_link_hash_lookup (link_info.hash, link_info.init_function, false,
! 			    false, true);
!   eh = (struct elf_link_hash_entry *)h;
  
    if (h != (struct bfd_link_hash_entry *) NULL
        && (h->type == bfd_link_hash_defined
  	  || h->type == bfd_link_hash_defweak)
+       && ELF_ST_TYPE (eh->type) == STT_ARM_TFUNC
        && h->u.def.section->output_section != NULL)
      {
        static char buffer[32];
        bfd_vma val;
! 
!       /* Special procesing is required for a Thumb symbol.  The bottom
! 	 bit of its address must be set.  */
        val = (h->u.def.value
  	     + bfd_get_section_vma (output_bfd,
  				    h->u.def.section->output_section)
  	     + h->u.def.section->output_offset);
! 
        val |= 1;
  
!       /* Now convert this value into a string and store it in
! 	 init_function where the elf_bfd_final_link() function will
! 	 pick it up.  */
        buffer[0] = '0';
        buffer[1] = 'x';
! 
        sprintf_vma (buffer + 2, val);
+       link_info.init_function = buffer;
+     }
+ 
+   /* If fini is a Thumb function set the LSB.  */
+   h = bfd_link_hash_lookup (link_info.hash, link_info.fini_function, false,
+ 			    false, true);
+   eh = (struct elf_link_hash_entry *)h;
  
!   if (h != (struct bfd_link_hash_entry *) NULL
!       && (h->type == bfd_link_hash_defined
! 	  || h->type == bfd_link_hash_defweak)
!       && ELF_ST_TYPE (eh->type) == STT_ARM_TFUNC
!       && h->u.def.section->output_section != NULL)
!     {
!       static char buffer[32];
!       bfd_vma val;
! 
!       /* Special procesing is required for a Thumb symbol.  The bottom
! 	 bit of its address must be set.  */
!       val = (h->u.def.value
! 	     + bfd_get_section_vma (output_bfd,
! 				    h->u.def.section->output_section)
! 	     + h->u.def.section->output_offset);
! 
!       val |= 1;
! 
!       /* Now convert this value into a string and store it in
! 	 fini_function where the elf_bfd_final_link() function will
! 	 pick it up.  */
!       buffer[0] = '0';
!       buffer[1] = 'x';
! 
!       sprintf_vma (buffer + 2, val);
!       link_info.fini_function = buffer;
      }
  }
  
  EOF
*************** EOF
*** 189,194 ****
--- 260,266 ----
  #
  PARSE_AND_LIST_PROLOGUE='
  #define OPTION_THUMB_ENTRY		301
+ #define OPTION_THUMB_PLT		302
  '
  
  # Note we add 'n' to the short option list in order to prevent
*************** PARSE_AND_LIST_SHORTOPTS=pn
*** 201,211 ****
--- 273,285 ----
  PARSE_AND_LIST_LONGOPTS='
    { "no-pipeline-knowledge", no_argument, NULL, '\'p\''},
    { "thumb-entry", required_argument, NULL, OPTION_THUMB_ENTRY},
+   { "thumb-plt", no_argument, NULL, OPTION_THUMB_PLT},
  '
  
  PARSE_AND_LIST_OPTIONS='
    fprintf (file, _("  -p --no-pipeline-knowledge  Stop the linker knowing about the pipeline length\n"));
    fprintf (file, _("     --thumb-entry=<sym>      Set the entry point to be Thumb symbol <sym>\n"));
+   fprintf (file, _("     --thumb-plt              Generate Thumb PLT section\n"));
  '
  
  PARSE_AND_LIST_ARGS_CASES='
*************** PARSE_AND_LIST_ARGS_CASES='
*** 215,220 ****
--- 289,298 ----
  
      case OPTION_THUMB_ENTRY:
        thumb_entry_symbol = optarg;
+       break;
+ 
+     case OPTION_THUMB_PLT:
+       arm_plt = 0;
        break;
  '
  
Index: ld/ld.texinfo
===================================================================
RCS file: /cvs/src/src/ld/ld.texinfo,v
retrieving revision 1.71
diff -c -p -r1.71 ld.texinfo
*** ld/ld.texinfo	15 Jul 2002 02:23:26 -0000	1.71
--- ld/ld.texinfo	17 Jul 2002 22:30:29 -0000
*************** But it also sets the bottom bit of the a
*** 4494,4499 ****
--- 4494,4506 ----
  branched to using a BX instruction, and the program will start
  executing in Thumb mode straight away.
  
+ @cindex thumb PLT
+ @cindex PLT, thumb
+ @kindex --thumb-plt
+ For ELF, the @samp{--thumb-plt} switch forces @command{ld} to use the
+ Thumb instruction set to generate the PLT.  This allows building pure
+ Thumb shared libraries.
+ 
  @node HPPA ELF32
  @section @command{ld} and HPPA 32-bit ELF support
  @cindex HPPA multiple sub-space stubs

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH, arm] Thumb shared library support: Thumb PLT, etc.
  2002-07-17 18:14 [PATCH, arm] Thumb shared library support: Thumb PLT, etc Adam Nemet
@ 2002-07-18  4:11 ` Richard Earnshaw
  2002-07-18 12:00   ` Adam Nemet
  0 siblings, 1 reply; 11+ messages in thread
From: Richard Earnshaw @ 2002-07-18  4:11 UTC (permalink / raw)
  To: Adam Nemet; +Cc: binutils, Richard.Earnshaw

> Hi,
> 
> This is the second piece of a series of patches to make shared
> libraries work on Thumb.  The first (yet unreviewed) patch was a GCC
> patch: http://gcc.gnu.org/ml/gcc-patches/2002-07/msg00398.html .
> 
> This patch among other things adds a new switch --thumb-plt to
> generate Thumb PLT on ARM ELF.  My third patch will handle the
> interworking aspects of this new flag.
> 
> I ran the GCC testsuite with all combinations of -marm/-mthumb and
> /-fPIC.  I also did lots of manual testing especially on the lazy
> relocation part as our (LynxOS) ld.so does not support that.  A
> slightly different form of this patch has been part of our ld (2.10.1)
> for sometime now and underwent extensive testing.
> 
> Please apply if OK.
> Adam

Hmm, there's some useful stuff in here, but I don't think it's quite right 
yet.

First of all, do you have a copyright assignment in place for binutils 
(and gcc, for your other patch)?  Until that's sorted out we can't use 
your code.

Now for some comments.

1) I don't like the idea of having some special flag (--thumb-plt) that 
indicates that we should build a different type of PLT.  The linker must 
be able to figure this out automatically, or we will end up with major 
problems when it comes to interworking.




>   
> + static const insn16 elf32_thumb_plt0_entry [THUMB_PLT_ENTRY_SIZE / 2] =
> +   {
> +     0xb500,	/* push    {lr}		    */
> +     0xb082,	/* sub     sp, #8	    */
> +     0x9000,	/* str     r0, [sp]	    */
> +     0x4807,	/* ldr     r0, [pc, #28]    */
> +     0x300c,	/* add     r0, #12	    */
> +     0x4478,	/* add     r0, pc	    */
> +     0x4686,	/* mov     lr, r0	    */
> +     0x6800,	/* ldr     r0, [r0]	    */
> +     0x9001,	/* str     r0, [sp, #4]	    */
> +     0xbd01	/* pop     {r0, pc}	    */
> +   };
> + 

Hmm, would you really want the entry point in your dynamic linker to be 
Thumb code?  The first thing it has to do is stack every register, so i'd 
have thought a switch to ARM state in the stub would be in order.  See 
also the comments below re sharing with ARM code.

>   /* Subsequent entries in a procedure linkage table look like
>      this.  */
> ! static const bfd_vma elf32_arm_plt_entry [ARM_PLT_ENTRY_SIZE / 4] =
>    {
>      0xe59fc004,	/* ldr   ip, [pc, #4]       */
>      0xe08fc00c,	/* add   ip, pc, ip         */
>      0xe59cf000,	/* ldr   pc, [ip]           */
>      0x00000000	/* offset to symbol in got  */
>    };
> +  
> + /* Note that on ARMv5 and above unlike the ARM PLT entries, the Thumb
> +    entry can switch mode depending on the corresponding address in the
> +    GOT.  The dynamic linker should set or clear the last bit of the
> +    address in the GOT accordingly.  */
> + 
> + static const insn16 elf32_thumb_plt_entry [THUMB_PLT_ENTRY_SIZE / 2] =
> +   {
> +     0xb082,	/* sub   sp, #8		    */
> +     0x9000,	/* str   r0, [sp]	    */
> +     0x4802,	/* ldr   r0, [pc, #8]	    */
> +     0x4478,	/* add   r0, pc		    */
> +     0x4684,	/* mov   ip, r0		    */
> +     0x6800,	/* ldr   r0, [r0]	    */
> +     0x9001,	/* str   r0, [sp, #4]	    */
> +     0xbd01,	/* pop   {r0, pc}	    */
> +     0x0000,	/* offset to symbol in got  */
> +     0x0000
> +   };
>   

We need more space for the thumb sequence than we do for an ARM one.  That 
suggests that we should probably be looking to switch to ARM code for the 
stub.  For example, we could use

	.code 16
	.align 2
_plt_stub_thumb:
	bx	pc
	nop
	.code 32
_plt_stub_arm:
	ldr	ip, [pc, #8]
	add	ip, pc, ip
	ldr	ip, [ip]
	bx	ip
	.word	offset_to_target

which means we can share the stub with both ARM and Thumb code.  So while 
this is now 6 words long we save on duplication, and we have interworking 
from the start.

Further, if we know we are targeting v5 we can adjust the caller to use 
blx so that it jumps straight to the ARM entry point, and since loading 
the pc from memory will cause an arm<->thumb transition if required then 
we can revert to the more efficient sequence that is the default ARM case.


I think most of the rest of the changes are just a natural consequence of 
how we design the PLT stubs, so I'm not going to concentrate on that until 
we have the above sorted out.

R.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH, arm] Thumb shared library support: Thumb PLT, etc.
  2002-07-18  4:11 ` Richard Earnshaw
@ 2002-07-18 12:00   ` Adam Nemet
  2002-07-19  9:06     ` Richard Earnshaw
  0 siblings, 1 reply; 11+ messages in thread
From: Adam Nemet @ 2002-07-18 12:00 UTC (permalink / raw)
  To: Richard.Earnshaw; +Cc: binutils

Richard,

> First of all, do you have a copyright assignment in place for binutils 
> (and gcc, for your other patch)?  Until that's sorted out we can't use 
> your code.

Yes, I have assingment papers on file for GCC and binutils.

> 1) I don't like the idea of having some special flag (--thumb-plt) that 
> indicates that we should build a different type of PLT.  The linker must 
> be able to figure this out automatically, or we will end up with major 
> problems when it comes to interworking.

First of all these were my design principals while implementing this:

1. Making Thumb shared libraries work should _not_ effect ARM shared
   libraries.  People who want to make their code smaller are more
   likely to have the time to ``manually'' fine-tune their application
   than those who don't care and just want something to work on ARM.

2. Interworking issues should be kept separately.  I'd like to be able
   to build pure ARM and pure Thumb shared libraries without compiling
   them with --mthumb-interwork.

> We need more space for the thumb sequence than we do for an ARM one.  That 
> suggests that we should probably be looking to switch to ARM code for the 
> stub.  For example, we could use
> 
> 	.code 16
> 	.align 2
> _plt_stub_thumb:
> 	bx	pc
> 	nop
> 	.code 32
> _plt_stub_arm:
> 	ldr	ip, [pc, #8]
> 	add	ip, pc, ip
> 	ldr	ip, [ip]
> 	bx	ip
> 	.word	offset_to_target
> 
> which means we can share the stub with both ARM and Thumb code.  So while 
> this is now 6 words long we save on duplication, and we have interworking 
> from the start.

I was playing with the same idea originally but I didn't like it
because:
  Major issues:

  * It does not fit well with principle #1 above.  6 instead of 4
    words in the ARM case and 6 instead of 5 words for Thumb.  ARM PLT
    will be 50% bigger.

  * It won't work.  Upon calling plt[0] with lazy relocation, ip has
    to hold &GOT[n+3] so that ld.so can figure which GOT entry it
    needs to relocate.  See sysdeps/arm/dl-machine.h in glibc for an
    example.

  Minor issues:

  * In addition, what is the cost of switching mode twice for a pure
    thumb shared library call every time we call it?

  * What if a Thumb function in the library wants to return with mov
    pc, lr.  I know that GCC does not generate such a sequence but it
    is still valid and contradicts principal #2.

Bottom line, I don't think we should favor Thumb or interwork over ARM
or some complication in the linker.  Pure ARM should be as fast as
possible.  In fact the reason why we need an explicit switch to
generate a PLT that can handle Thumb is pretty much the same why
--mthumb-interwork is not the default behavior in the GCC backend: it
is not free.

Adam

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH, arm] Thumb shared library support: Thumb PLT, etc.
  2002-07-18 12:00   ` Adam Nemet
@ 2002-07-19  9:06     ` Richard Earnshaw
  2002-07-20 11:36       ` Adam Nemet
  2002-07-23  1:23       ` [PATCH, arm] Support for Thumb PLT entries with interwork Adam Nemet
  0 siblings, 2 replies; 11+ messages in thread
From: Richard Earnshaw @ 2002-07-19  9:06 UTC (permalink / raw)
  To: Adam Nemet; +Cc: Richard.Earnshaw, binutils

> Richard,
> 
> > First of all, do you have a copyright assignment in place for binutils 
> > (and gcc, for your other patch)?  Until that's sorted out we can't use 
> > your code.
> 
> Yes, I have assingment papers on file for GCC and binutils.

OK.

> 
> > 1) I don't like the idea of having some special flag (--thumb-plt) that 
> > indicates that we should build a different type of PLT.  The linker must 
> > be able to figure this out automatically, or we will end up with major 
> > problems when it comes to interworking.
> 
> First of all these were my design principals while implementing this:
> 
> 1. Making Thumb shared libraries work should _not_ effect ARM shared
>    libraries.  People who want to make their code smaller are more
>    likely to have the time to ``manually'' fine-tune their application
>    than those who don't care and just want something to work on ARM.

It's true that a pure ARM-code application is most likely to be aiming for 
performance and that we shouldn't do things that hinder that.  However, 
that's not what I was proposing.

> 
> 2. Interworking issues should be kept separately.  I'd like to be able
>    to build pure ARM and pure Thumb shared libraries without compiling
>    them with --mthumb-interwork.

The issue here is that Thumb is about improving *overall* code density.  
At times best code density is achieved by using ARM code.  For example, if 
you know that you have a floating-point intensive function and that you 
have a VFP co-processor available, best code density will come from 
compiling the function to use the VFP rather than relying on softfp and 
emulation.

> > We need more space for the thumb sequence than we do for an ARM one.  That 
> > suggests that we should probably be looking to switch to ARM code for the 
> > stub.  For example, we could use
> > 
> > 	.code 16
> > 	.align 2
> > _plt_stub_thumb:
> > 	bx	pc
> > 	nop
> > 	.code 32
> > _plt_stub_arm:
> > 	ldr	ip, [pc, #8]
> > 	add	ip, pc, ip
> > 	ldr	ip, [ip]
> > 	bx	ip
> > 	.word	offset_to_target
> > 
> > which means we can share the stub with both ARM and Thumb code.  So while 
> > this is now 6 words long we save on duplication, and we have interworking 
> > from the start.
> 
> I was playing with the same idea originally but I didn't like it
> because:
>   Major issues:
> 
>   * It does not fit well with principle #1 above.  6 instead of 4
>     words in the ARM case and 6 instead of 5 words for Thumb.  ARM PLT
>     will be 50% bigger.

It wouldn't be used for #1, only when interworking was required.  With 
respect to #2 the issue is about best overall code density.

> 
>   * It won't work.  Upon calling plt[0] with lazy relocation, ip has
>     to hold &GOT[n+3] so that ld.so can figure which GOT entry it
>     needs to relocate.  See sysdeps/arm/dl-machine.h in glibc for an
>     example.

That's a much bigger issue (possibly a show-stopper).  I need to think 
about this one some more.  The idea of having the PLT stub branch to 
another stub just to achieve the mode change does not particularly appeal.


> 
>   Minor issues:
> 
>   * In addition, what is the cost of switching mode twice for a pure
>     thumb shared library call every time we call it?

A switch of state requires a pipeline flush, so it's the same as a 
mis-predicted branch (all branches are 'mis-predicted' on earlier ARM 
processors, as are all loads to the PC).  In fact, if we know we are 
generating for ARMv5, then we should always output the traditional ARM PLT 
entry, since it gives us interworking for free and is the shortest 
sequence of them all.

> 
>   * What if a Thumb function in the library wants to return with mov
>     pc, lr.  I know that GCC does not generate such a sequence but it
>     is still valid and contradicts principal #2.

This isn't an issue we need to consider here, the PLT stub is not used on 
the return path, so it is the same as if the caller had called the 
subroutine directly.

> 
> Bottom line, I don't think we should favor Thumb or interwork over ARM
> or some complication in the linker.  Pure ARM should be as fast as
> possible.  In fact the reason why we need an explicit switch to
> generate a PLT that can handle Thumb is pretty much the same why
> --mthumb-interwork is not the default behavior in the GCC backend: it
> is not free.

We still don't need such a switch, after all, a PLT stub is generated in 
response to a relocation directive.  Since we know whether that was an ARM 
or a Thumb type relocation we can generate the correct PLT entry without 
the need to have a command line switch.  All it requires is for the linker 
to track a bit more information when pushing an internal PLT data 
structure onto the list of things to generate.

R.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH, arm] Thumb shared library support: Thumb PLT, etc.
  2002-07-19  9:06     ` Richard Earnshaw
@ 2002-07-20 11:36       ` Adam Nemet
  2002-07-23  1:23       ` [PATCH, arm] Support for Thumb PLT entries with interwork Adam Nemet
  1 sibling, 0 replies; 11+ messages in thread
From: Adam Nemet @ 2002-07-20 11:36 UTC (permalink / raw)
  To: Richard.Earnshaw; +Cc: binutils

> All it requires is for the linker to track a bit more information
> when pushing an internal PLT data structure onto the list of things
> to generate.

As long as we can make sure that neither pure ARM nor pure Thumb get
punished because of this generalization, I am fine with this and I am
ready to change my patch to cover interworking as well.

BTW, what do you think about the fini/init parts.  Are they
acceptable?  And what about the GCC patch?

> Since we know whether that was an ARM or a Thumb type relocation we
> can generate the correct PLT entry without the need to have a
> command line switch.

I think instead of the relocation type, we should rather look at the
the type of the function (STT_FUNC or STT_ARM_TFUNC) we are relocating
against.  I believe the logic is cleaner if we just consider the PLT
as an extension of the shared library and as such it should match the
type of the function it calls into.  (In case of STT_NOTYPE, we should
probably assume that the callee matches the caller.)  Of course on the
caller side between the caller and the PLT entry, we might need to
emit stubs for mode switching the usual way.

In your solution if we were to match the instruction set of the
caller, if the same PLT entry is referred from a Thumb and an ARM
function we have no way to decide which type of PLT entry we need to
generate whereas if it matches the callee it is always obvious.

I would also prefer to have separate plt for the Thumb entries e.g.
.plt.thumb or something like that so that disassembling the plt would
be as simple as:

  objdump -d -j.plt a.out
  objdump -d -j.plt.thumb --disassembler-option=force-thumb a.out

Also note that the Thumb and the ARM PLT entries are of different size
(5 words and 4 words) so finding the offset to one entry is easier if
we keep them separately.

I also plan to issue a warning is someone is trying to mix
instrunction sets between the caller and the callee without having the
interworking flag set in the ELF header.  This is a good indicator
that the user doesn't want the interwork overhead but just accidently
used the wrong version of the library.  This is pretty much a natural
extension of the existing warning message when one wants to intermix
different non-interworking object files.

If we agree on these details I will go and try to extend how PLT is
handled currently so that it can provide the functionality for mixing
the two types of PLT entries.

Adam

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH, arm] Support for Thumb PLT entries with interwork
  2002-07-19  9:06     ` Richard Earnshaw
  2002-07-20 11:36       ` Adam Nemet
@ 2002-07-23  1:23       ` Adam Nemet
  2002-07-31  5:34         ` Nick Clifton
  1 sibling, 1 reply; 11+ messages in thread
From: Adam Nemet @ 2002-07-23  1:23 UTC (permalink / raw)
  To: Richard.Earnshaw; +Cc: binutils

Richard,

I updated the patch based on your comments.  Here is a list of changes
since the last version of this patch.

* I removed the --thumb-plt switch.
* I removed the DT_INIT/FINI part.  I will submit a separate patch for
  those parts later.
* There is a new section called .plt.thumb.  It holds the PLT entries
  that refer to Thumb functions.
* The type of the PLT entry follows the type of the function it refers
  to.  For an undefined function, I generate the same type as the type
  of the code where the function was first referenced.

I gcc-regtested this patch with the combinations of -marm/-mthumb and
-fno-pic/-fPIC on arm-elf.  I ran the ld testsuite.  I also built
binutils with --enable-targets=all.

For interwork, with this patch ld generates the proper .plt(.thumb)
entries.  However, stub generation seems to require more tweaking in
order to work with PLT entries.  In an upcoming patch I will address
those issues too.

Please apply if OK.
Adam

bfd/ChangeLog:
2002-07-23  Adam Nemet  <anemet@lnxw.com>

	* elf32-arm.h (ARM_PLT_ENTRY_SIZE): Rename PLT_ENTRY_SIZE.
	(THUMB_PLT_ENTRY_SIZE): New macro.
	(PLT_ENTRY_SIZE): Return the appropriate *_PLT_ENTRY_SIZE.
	(elf32_arm_plt0_entry): Rename PLT_ENTRY_SIZE to
	ARM_PLT_ENTRY_SIZE.
	(elf32_arm_plt_entry): Likewise.
	(elf_backend_plt_header_size): Likewise.

	(elf32_thumb_plt0_entry): New global.
	(elf32_arm_finish_dynamic_sections): Use it.  Put Thumb entries
	into .plt.thumb.
	(elf32_thumb_plt_entry): New global.
	(elf32_arm_finish_dynamic_symbol): Use it.  Use .thumb.plt for
	Thumb entries.  Set the bottom bit of the corresponding GOT entry
	for a Thumb PLT entry.

	(struct elf32_arm_plt_entry_info): New structure.
	(struct elf32_arm_link_hash_entry, plt_info): New member of this
	type.
	(elf32_arm_link_hash_newfunc): Initialize new member.

	(elf32_arm_final_link_relocate, R_ARM_THM_PC22 case): Handle
	relocations against the PLT.
	(elf32_arm_check_relocs, case R_ARM_PLT32 case): Set
	first_rel_type if this is the first time we encounter the symbol.
	(elf32_arm_check_relocs, case R_ARM_THM_PC22 case): New case.
	Determine if relocation needs a PLT entry.  Set first_rel_type if
	this is the first time we encounter the symbol
	(elf32_arm_adjust_dynamic_symbol): Create PLT entries for Thumb
	functions as well.
	(elf32_arm_size_dynamic_sections): Handle .plt.thumb like .plt.

	(elf32_arm_create_dynamic_sections): New function.  Create the
	.plt.thumb section.
	(elf_backend_create_dynamic_sections): Call it.

ld/ChangeLog:
2002-07-23  Adam Nemet  <anemet@lnxw.com>

	* emulparams/armelf.sh (OTHER_PLT_SECTIONS): New variable.  Set it
	to .plt.thumb.
	* scripttempl/elf.sc: Comment it.  Use the same way as ${PLT} is
	used.

Index: bfd/elf32-arm.h
===================================================================
RCS file: /cvs/src/src/bfd/elf32-arm.h,v
retrieving revision 1.87
diff -c -p -r1.87 elf32-arm.h
*** bfd/elf32-arm.h	7 Jul 2002 09:10:40 -0000	1.87
--- bfd/elf32-arm.h	23 Jul 2002 07:41:40 -0000
*************** static struct bfd_hash_entry * elf32_arm
*** 84,89 ****
--- 84,91 ----
  static void arm_add_to_rel
    PARAMS ((bfd *, bfd_byte *, reloc_howto_type *, bfd_signed_vma));
  #endif
+ static boolean elf32_arm_create_dynamic_sections
+   PARAMS ((bfd *, struct bfd_link_info *));
  
  boolean bfd_elf32_arm_allocate_interworking_sections
    PARAMS ((struct bfd_link_info *));
*************** static enum elf_reloc_type_class elf32_a
*** 111,123 ****
  #define ELF_DYNAMIC_INTERPRETER     "/usr/lib/ld.so.1"
  
  /* The size in bytes of an entry in the procedure linkage table.  */
! #define PLT_ENTRY_SIZE 16
  
  /* The first entry in a procedure linkage table looks like
     this.  It is set up so that any shared library function that is
     called before the relocation has been set up calls the dynamic
     linker first.  */
! static const bfd_vma elf32_arm_plt0_entry [PLT_ENTRY_SIZE / 4] =
    {
      0xe52de004,	/* str   lr, [sp, #-4]!     */
      0xe59fe010,	/* ldr   lr, [pc, #16]      */
--- 113,128 ----
  #define ELF_DYNAMIC_INTERPRETER     "/usr/lib/ld.so.1"
  
  /* The size in bytes of an entry in the procedure linkage table.  */
! #define ARM_PLT_ENTRY_SIZE 	16
! #define THUMB_PLT_ENTRY_SIZE	20
! #define PLT_ENTRY_SIZE(ARM) \
!   ((ARM) ? ARM_PLT_ENTRY_SIZE : THUMB_PLT_ENTRY_SIZE)
  
  /* The first entry in a procedure linkage table looks like
     this.  It is set up so that any shared library function that is
     called before the relocation has been set up calls the dynamic
     linker first.  */
! static const bfd_vma elf32_arm_plt0_entry [ARM_PLT_ENTRY_SIZE / 4] =
    {
      0xe52de004,	/* str   lr, [sp, #-4]!     */
      0xe59fe010,	/* ldr   lr, [pc, #16]      */
*************** static const bfd_vma elf32_arm_plt0_entr
*** 125,139 ****
      0xe5bef008	/* ldr   pc, [lr, #8]!      */
    };
  
  /* Subsequent entries in a procedure linkage table look like
     this.  */
! static const bfd_vma elf32_arm_plt_entry [PLT_ENTRY_SIZE / 4] =
   {
     0xe59fc004,	/* ldr   ip, [pc, #4]       */
     0xe08fc00c,	/* add   ip, pc, ip         */
     0xe59cf000,	/* ldr   pc, [ip]           */
     0x00000000	/* offset to symbol in got  */
   };
  
  /* The ARM linker needs to keep track of the number of relocs that it
     decides to copy in check_relocs for each symbol.  This is so that
--- 130,177 ----
      0xe5bef008	/* ldr   pc, [lr, #8]!      */
    };
  
+ static const insn16 elf32_thumb_plt0_entry [THUMB_PLT_ENTRY_SIZE / 2] =
+   {
+     0xb500,	/* push    {lr}		    */
+     0xb082,	/* sub     sp, #8	    */
+     0x9000,	/* str     r0, [sp]	    */
+     0x4807,	/* ldr     r0, [pc, #28]    */
+     0x300c,	/* add     r0, #12	    */
+     0x4478,	/* add     r0, pc	    */
+     0x4686,	/* mov     lr, r0	    */
+     0x6800,	/* ldr     r0, [r0]	    */
+     0x9001,	/* str     r0, [sp, #4]	    */
+     0xbd01	/* pop     {r0, pc}	    */
+   };
+ 
  /* Subsequent entries in a procedure linkage table look like
     this.  */
! static const bfd_vma elf32_arm_plt_entry [ARM_PLT_ENTRY_SIZE / 4] =
   {
     0xe59fc004,	/* ldr   ip, [pc, #4]       */
     0xe08fc00c,	/* add   ip, pc, ip         */
     0xe59cf000,	/* ldr   pc, [ip]           */
     0x00000000	/* offset to symbol in got  */
   };
+  
+ /* Note that on ARMv5 and above unlike the ARM PLT entries, the Thumb
+    entry can switch mode depending on the corresponding address in the
+    GOT.  The dynamic linker should set or clear the last bit of the
+    address in the GOT accordingly.  */
+ 
+ static const insn16 elf32_thumb_plt_entry [THUMB_PLT_ENTRY_SIZE / 2] =
+   {
+     0xb082,	/* sub   sp, #8		    */
+     0x9000,	/* str   r0, [sp]	    */
+     0x4802,	/* ldr   r0, [pc, #8]	    */
+     0x4478,	/* add   r0, pc		    */
+     0x4684,	/* mov   ip, r0		    */
+     0x6800,	/* ldr   r0, [r0]	    */
+     0x9001,	/* str   r0, [sp, #4]	    */
+     0xbd01,	/* pop   {r0, pc}	    */
+     0x0000,	/* offset to symbol in got  */
+     0x0000
+   };
  
  /* The ARM linker needs to keep track of the number of relocs that it
     decides to copy in check_relocs for each symbol.  This is so that
*************** struct elf32_arm_pcrel_relocs_copied
*** 153,158 ****
--- 191,215 ----
      bfd_size_type count;
    };
  
+ 
+ /* We can generate Thumb or ARM PLT entries.  This structure holds
+    additional information for symbols that have corresponding PLT
+    entries.  */
+ 
+ struct elf32_arm_plt_entry_info
+   {
+     /* The first relocation type referring to this PLT entry.  Used to
+        determine the type of the entry if the symbol is undefined.  */
+     long first_rel_type;
+ 
+     /* True if we decided to emit the ARM version of the PLT entry for
+        this symbol.  Otherwise the entry is Thumb.  */
+     boolean arm_plt;
+ 
+     /* The offset of the corresponding .got.plt entry.  */
+     bfd_vma got_plt_offset;
+   };
+ 
  /* Arm ELF linker hash entry.  */
  struct elf32_arm_link_hash_entry
    {
*************** struct elf32_arm_link_hash_entry
*** 160,165 ****
--- 217,224 ----
  
      /* Number of PC relative relocs copied for this symbol.  */
      struct elf32_arm_pcrel_relocs_copied * pcrel_relocs_copied;
+ 
+     struct elf32_arm_plt_entry_info plt_info;
    };
  
  /* Declare this now that the above structures are defined.  */
*************** elf32_arm_link_hash_newfunc (entry, tabl
*** 222,228 ****
  	 _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret,
  				     table, string));
    if (ret != (struct elf32_arm_link_hash_entry *) NULL)
!     ret->pcrel_relocs_copied = NULL;
  
    return (struct bfd_hash_entry *) ret;
  }
--- 281,290 ----
  	 _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret,
  				     table, string));
    if (ret != (struct elf32_arm_link_hash_entry *) NULL)
!     {
!       ret->pcrel_relocs_copied = NULL;
!       ret->plt_info.first_rel_type = R_ARM_NONE;
!     }
  
    return (struct bfd_hash_entry *) ret;
  }
*************** elf32_arm_final_link_relocate (howto, in
*** 1058,1063 ****
--- 1120,1126 ----
    bfd_vma *                     local_got_offsets;
    asection *                    sgot = NULL;
    asection *                    splt = NULL;
+   asection *                    splt_thumb = NULL;
    asection *                    sreloc = NULL;
    bfd_vma                       addend;
    bfd_signed_vma                signed_addend;
*************** elf32_arm_final_link_relocate (howto, in
*** 1082,1087 ****
--- 1145,1151 ----
      {
        sgot = bfd_get_section_by_name (dynobj, ".got");
        splt = bfd_get_section_by_name (dynobj, ".plt");
+       splt_thumb = bfd_get_section_by_name (dynobj, ".plt.thumb");
      }
    symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
    sym_hashes = elf_sym_hashes (input_bfd);
*************** elf32_arm_final_link_relocate (howto, in
*** 1407,1412 ****
--- 1471,1484 ----
  	  signed_addend = addend;
  	}
  #endif
+ 
+ 	/* If value is zero then we are linking a shared object and
+ 	   this is a reference to an externally visible symbol.  */
+ 	if (h != NULL && h->plt.offset != (bfd_vma) -1 && value == 0)
+ 	  value = (splt_thumb->output_section->vma
+ 		   + splt_thumb->output_offset
+ 		   + h->plt.offset);
+ 
  #ifndef OLD_ARM_ABI
  	if (r_type == R_ARM_THM_XPC22)
  	  {
*************** elf32_arm_check_relocs (abfd, info, sec,
*** 2723,2728 ****
--- 2795,2825 ----
  	      continue;
  
  	    h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+ 	    {
+ 	      struct elf32_arm_link_hash_entry *eh;
+ 
+ 	      eh = (struct elf32_arm_link_hash_entry *) h;
+ 	      if (eh->plt_info.first_rel_type == R_ARM_NONE)
+ 		eh->plt_info.first_rel_type = R_ARM_PLT32;
+ 	    }
+ 	    break;
+ 
+ 	  case R_ARM_THM_PC22:
+ 	    /* Since there is no PLT32 for Thumb if we are creating a
+ 	       shared library and this is an externally visible symbol
+ 	       then add it to the PLT.  */
+ 	    if (info->shared && h != NULL && h->dynindx != -1
+ 		&& (! info->symbolic
+ 		    || (h->elf_link_hash_flags
+ 			& ELF_LINK_HASH_DEF_REGULAR) == 0))
+ 	      {
+ 		struct elf32_arm_link_hash_entry *eh;
+ 
+ 		eh = (struct elf32_arm_link_hash_entry *) h;
+ 		h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+ 		if (eh->plt_info.first_rel_type == R_ARM_NONE)
+ 		  eh->plt_info.first_rel_type = R_ARM_THM_PC22;
+ 	      }
  	    break;
  
  	  case R_ARM_ABS32:
*************** elf32_arm_adjust_dynamic_symbol (info, h
*** 2955,2963 ****
    /* If this is a function, put it in the procedure linkage table.  We
       will fill in the contents of the procedure linkage table later,
       when we know the address of the .got section.  */
!   if (h->type == STT_FUNC
        || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
      {
        if (! info->shared
  	  && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
  	  && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0)
--- 3052,3067 ----
    /* If this is a function, put it in the procedure linkage table.  We
       will fill in the contents of the procedure linkage table later,
       when we know the address of the .got section.  */
!   if (h->type == STT_FUNC || h->type == STT_ARM_TFUNC
        || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
      {
+       struct elf32_arm_plt_entry_info *plt_info;
+ 
+       plt_info = &((struct elf32_arm_link_hash_entry *) h)->plt_info;
+       plt_info->arm_plt = ! (h->type == STT_ARM_TFUNC ||
+ 			     (h->type != STT_ARM_TFUNC && h->type != STT_FUNC
+ 			      && plt_info->first_rel_type == R_ARM_THM_PC22));
+ 
        if (! info->shared
  	  && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
  	  && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0)
*************** elf32_arm_adjust_dynamic_symbol (info, h
*** 2978,2990 ****
  	    return false;
  	}
  
!       s = bfd_get_section_by_name (dynobj, ".plt");
        BFD_ASSERT (s != NULL);
  
!       /* If this is the first .plt entry, make room for the special
  	 first entry.  */
        if (s->_raw_size == 0)
! 	s->_raw_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
--- 3082,3095 ----
  	    return false;
  	}
  
!       s = bfd_get_section_by_name (dynobj,
! 				   plt_info->arm_plt ? ".plt" : ".plt.thumb");
        BFD_ASSERT (s != NULL);
  
!       /* If this is the first PLT entry, make room for the special
  	 first entry.  */
        if (s->_raw_size == 0)
! 	s->_raw_size += PLT_ENTRY_SIZE (plt_info->arm_plt);
  
        /* If this symbol is not defined in a regular file, and we are
  	 not generating a shared library, then set the symbol to this
*************** elf32_arm_adjust_dynamic_symbol (info, h
*** 3001,3012 ****
        h->plt.offset = s->_raw_size;
  
        /* Make room for this entry.  */
!       s->_raw_size += PLT_ENTRY_SIZE;
  
        /* We also need to make an entry in the .got.plt section, which
  	 will be placed in the .got section by the linker script.  */
        s = bfd_get_section_by_name (dynobj, ".got.plt");
        BFD_ASSERT (s != NULL);
        s->_raw_size += 4;
  
        /* We also need to make an entry in the .rel.plt section.  */
--- 3106,3118 ----
        h->plt.offset = s->_raw_size;
  
        /* Make room for this entry.  */
!       s->_raw_size += PLT_ENTRY_SIZE (plt_info->arm_plt);
  
        /* We also need to make an entry in the .got.plt section, which
  	 will be placed in the .got section by the linker script.  */
        s = bfd_get_section_by_name (dynobj, ".got.plt");
        BFD_ASSERT (s != NULL);
+       plt_info->got_plt_offset = s->_raw_size;
        s->_raw_size += 4;
  
        /* We also need to make an entry in the .rel.plt section.  */
*************** elf32_arm_size_dynamic_sections (output_
*** 3157,3163 ****
  
        strip = false;
  
!       if (strcmp (name, ".plt") == 0)
  	{
  	  if (s->_raw_size == 0)
  	    {
--- 3263,3270 ----
  
        strip = false;
  
!       /* Match .plt.thumb as well.  */
!       if (strncmp (name, ".plt", 4) == 0)
  	{
  	  if (s->_raw_size == 0)
  	    {
*************** elf32_arm_finish_dynamic_symbol (output_
*** 3317,3327 ****
    if (h->plt.offset != (bfd_vma) -1)
      {
        asection * splt;
        asection * sgot;
        asection * srel;
!       bfd_vma plt_index;
!       bfd_vma got_offset;
        Elf_Internal_Rel rel;
  
        /* This symbol has an entry in the procedure linkage table.  Set
  	 it up.  */
--- 3424,3435 ----
    if (h->plt.offset != (bfd_vma) -1)
      {
        asection * splt;
+       asection * splt_thumb;
        asection * sgot;
        asection * srel;
!       bfd_vma rel_index;
        Elf_Internal_Rel rel;
+       struct elf32_arm_plt_entry_info *plt_info;
  
        /* This symbol has an entry in the procedure linkage table.  Set
  	 it up.  */
*************** elf32_arm_finish_dynamic_symbol (output_
*** 3329,3379 ****
        BFD_ASSERT (h->dynindx != -1);
  
        splt = bfd_get_section_by_name (dynobj, ".plt");
        sgot = bfd_get_section_by_name (dynobj, ".got.plt");
        srel = bfd_get_section_by_name (dynobj, ".rel.plt");
!       BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL);
  
!       /* Get the index in the procedure linkage table which
! 	 corresponds to this symbol.  This is the index of this symbol
! 	 in all the symbols for which we are making plt entries.  The
! 	 first entry in the procedure linkage table is reserved.  */
!       plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
! 
!       /* Get the offset into the .got table of the entry that
! 	 corresponds to this function.  Each .got entry is 4 bytes.
! 	 The first three are reserved.  */
!       got_offset = (plt_index + 3) * 4;
  
        /* Fill in the entry in the procedure linkage table.  */
!       bfd_put_32 (output_bfd, elf32_arm_plt_entry[0],
! 		  splt->contents + h->plt.offset + 0);
!       bfd_put_32 (output_bfd, elf32_arm_plt_entry[1],
! 		  splt->contents + h->plt.offset + 4);
!       bfd_put_32 (output_bfd, elf32_arm_plt_entry[2],
! 		  splt->contents + h->plt.offset + 8);
!       bfd_put_32 (output_bfd,
  		      (sgot->output_section->vma
  		       + sgot->output_offset
! 		       + got_offset
  		       - splt->output_section->vma
  		       - splt->output_offset
  		       - h->plt.offset - 12),
  		      splt->contents + h->plt.offset + 12);
  
!       /* Fill in the entry in the global offset table.  */
!       bfd_put_32 (output_bfd,
! 		  (splt->output_section->vma
! 		   + splt->output_offset),
! 		  sgot->contents + got_offset);
  
        /* Fill in the entry in the .rel.plt section.  */
        rel.r_offset = (sgot->output_section->vma
  		      + sgot->output_offset
! 		      + got_offset);
        rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_JUMP_SLOT);
        bfd_elf32_swap_reloc_out (output_bfd, &rel,
  				((Elf32_External_Rel *) srel->contents
! 				 + plt_index));
  
        if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
  	{
--- 3437,3524 ----
        BFD_ASSERT (h->dynindx != -1);
  
        splt = bfd_get_section_by_name (dynobj, ".plt");
+       splt_thumb = bfd_get_section_by_name (dynobj, ".plt.thumb");
        sgot = bfd_get_section_by_name (dynobj, ".got.plt");
        srel = bfd_get_section_by_name (dynobj, ".rel.plt");
!       BFD_ASSERT (splt != NULL && splt_thumb != NULL && sgot != NULL
! 		  && srel != NULL);
  
!       plt_info = &((struct elf32_arm_link_hash_entry *) h)->plt_info;
! 
!       /* Get the index in the relocation table that corresponds to the
! 	 entry in the global offset table.  */
!       rel_index = plt_info->got_plt_offset / 4 - 3;
  
        /* Fill in the entry in the procedure linkage table.  */
!       
!       if (plt_info->arm_plt)
! 	{
! 	  bfd_put_32 (output_bfd, elf32_arm_plt_entry[0],
! 		      splt->contents + h->plt.offset + 0);
! 	  bfd_put_32 (output_bfd, elf32_arm_plt_entry[1],
! 		      splt->contents + h->plt.offset + 4);
! 	  bfd_put_32 (output_bfd, elf32_arm_plt_entry[2],
! 		      splt->contents + h->plt.offset + 8);
! 
! 	  bfd_put_32 (output_bfd,
  		      (sgot->output_section->vma
  		       + sgot->output_offset
! 		       + plt_info->got_plt_offset
  		       - splt->output_section->vma
  		       - splt->output_offset
  		       - h->plt.offset - 12),
  		      splt->contents + h->plt.offset + 12);
  
! 	  /* Fill in the entry in the global offset table.  */
! 	  bfd_put_32 (output_bfd,
! 		      (splt->output_section->vma
! 		       + splt->output_offset),
! 		      sgot->contents + plt_info->got_plt_offset);
! 	}
!       else
! 	{
! 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt_entry[0],
! 		      splt_thumb->contents + h->plt.offset + 0);
! 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt_entry[1],
! 		      splt_thumb->contents + h->plt.offset + 2);
! 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt_entry[2],
! 		      splt_thumb->contents + h->plt.offset + 4);
! 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt_entry[3],
! 		      splt_thumb->contents + h->plt.offset + 6);
! 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt_entry[4],
! 		      splt_thumb->contents + h->plt.offset + 8);
! 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt_entry[5],
! 		      splt_thumb->contents + h->plt.offset + 10);
! 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt_entry[6],
! 		      splt_thumb->contents + h->plt.offset + 12);
! 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt_entry[7],
! 		      splt_thumb->contents + h->plt.offset + 14);
! 
! 	  bfd_put_32 (output_bfd,
! 		      (sgot->output_section->vma
! 		       + sgot->output_offset
! 		       + plt_info->got_plt_offset
! 		       - splt_thumb->output_section->vma
! 		       - splt_thumb->output_offset
! 		       - h->plt.offset - 10),
! 		      splt_thumb->contents + h->plt.offset + 16);
! 
! 	  /* Fill in the entry in the global offset table and set
! 	     bottom bit as plt[0] is a Thumb function.  */
! 	  bfd_put_32 (output_bfd,
! 		      (splt_thumb->output_section->vma
! 		       + (splt_thumb->output_offset | 1)),
! 		      sgot->contents + plt_info->got_plt_offset);
! 	}
  
        /* Fill in the entry in the .rel.plt section.  */
        rel.r_offset = (sgot->output_section->vma
  		      + sgot->output_offset
! 		      + plt_info->got_plt_offset);
        rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_JUMP_SLOT);
        bfd_elf32_swap_reloc_out (output_bfd, &rel,
  				((Elf32_External_Rel *) srel->contents
! 				 + rel_index));
  
        if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
  	{
*************** elf32_arm_finish_dynamic_sections (outpu
*** 3478,3487 ****
    if (elf_hash_table (info)->dynamic_sections_created)
      {
        asection *splt;
        Elf32_External_Dyn *dyncon, *dynconend;
  
        splt = bfd_get_section_by_name (dynobj, ".plt");
!       BFD_ASSERT (splt != NULL && sdyn != NULL);
  
        dyncon = (Elf32_External_Dyn *) sdyn->contents;
        dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size);
--- 3623,3634 ----
    if (elf_hash_table (info)->dynamic_sections_created)
      {
        asection *splt;
+       asection *splt_thumb;
        Elf32_External_Dyn *dyncon, *dynconend;
  
        splt = bfd_get_section_by_name (dynobj, ".plt");
!       splt_thumb = bfd_get_section_by_name (dynobj, ".plt.thumb");
!       BFD_ASSERT (splt != NULL && splt_thumb != NULL && sdyn != NULL);
  
        dyncon = (Elf32_External_Dyn *) sdyn->contents;
        dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size);
*************** elf32_arm_finish_dynamic_sections (outpu
*** 3544,3550 ****
  	    }
  	}
  
!       /* Fill in the first entry in the procedure linkage table.  */
        if (splt->_raw_size > 0)
  	{
  	  bfd_put_32 (output_bfd, elf32_arm_plt0_entry[0], splt->contents +  0);
--- 3691,3697 ----
  	    }
  	}
  
!       /* Fill in the first entries in the procedure linkage tables.  */
        if (splt->_raw_size > 0)
  	{
  	  bfd_put_32 (output_bfd, elf32_arm_plt0_entry[0], splt->contents +  0);
*************** elf32_arm_finish_dynamic_sections (outpu
*** 3552,3557 ****
--- 3699,3727 ----
  	  bfd_put_32 (output_bfd, elf32_arm_plt0_entry[2], splt->contents +  8);
  	  bfd_put_32 (output_bfd, elf32_arm_plt0_entry[3], splt->contents + 12);
  	}
+       if (splt_thumb->_raw_size > 0)
+ 	{
+ 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt0_entry[0],
+ 		      splt_thumb->contents + 0);
+ 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt0_entry[1],
+ 		      splt_thumb->contents + 2);
+ 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt0_entry[2],
+ 		      splt_thumb->contents + 4);
+ 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt0_entry[3],
+ 		      splt_thumb->contents + 6);
+ 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt0_entry[4],
+ 		      splt_thumb->contents + 8);
+ 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt0_entry[5],
+ 		      splt_thumb->contents + 10);
+ 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt0_entry[6],
+ 		      splt_thumb->contents + 12);
+ 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt0_entry[7],
+ 		      splt_thumb->contents + 14);
+ 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt0_entry[8],
+ 		      splt_thumb->contents + 16);
+ 	  bfd_put_16 (output_bfd, (bfd_vma) elf32_thumb_plt0_entry[9],
+ 		      splt_thumb->contents + 18);
+ 	}
  
        /* UnixWare sets the entsize of .plt to 4, although that doesn't
  	 really seem like the right value.  */
*************** elf32_arm_reloc_type_class (rela)
*** 3606,3611 ****
--- 3776,3811 ----
      }
  }
  
+ boolean
+ elf32_arm_create_dynamic_sections (abfd, info)
+      bfd *abfd;
+      struct bfd_link_info *info;
+ {
+   boolean ret;
+ 
+   ret = _bfd_elf_create_dynamic_sections (abfd, info);
+   if (ret)
+     {
+       asection *splt;
+       asection *splt_thumb;
+       flagword flags;
+       unsigned int alignent_power;
+ 
+       /* Let's match the attributes of .plt.  */
+       splt = bfd_get_section_by_name (abfd, ".plt");
+       BFD_ASSERT (splt != NULL);
+ 
+       flags = bfd_get_section_flags (abfd, splt);
+       alignent_power = bfd_get_section_alignment (abfd, splt);
+ 
+       splt_thumb = bfd_make_section (abfd, ".plt.thumb");
+       if (splt_thumb == NULL
+ 	  || !bfd_set_section_flags (abfd, splt_thumb, flags)
+ 	  || !bfd_set_section_alignment (abfd, splt_thumb, alignent_power))
+ 	return false;
+     }
+   return ret;
+ }
  
  #define ELF_ARCH			bfd_arch_arm
  #define ELF_MACHINE_CODE		EM_ARM
*************** elf32_arm_reloc_type_class (rela)
*** 3625,3631 ****
  #define elf_backend_check_relocs                elf32_arm_check_relocs
  #define elf_backend_relocate_section		elf32_arm_relocate_section
  #define elf_backend_adjust_dynamic_symbol	elf32_arm_adjust_dynamic_symbol
! #define elf_backend_create_dynamic_sections	_bfd_elf_create_dynamic_sections
  #define elf_backend_finish_dynamic_symbol	elf32_arm_finish_dynamic_symbol
  #define elf_backend_finish_dynamic_sections	elf32_arm_finish_dynamic_sections
  #define elf_backend_size_dynamic_sections	elf32_arm_size_dynamic_sections
--- 3825,3831 ----
  #define elf_backend_check_relocs                elf32_arm_check_relocs
  #define elf_backend_relocate_section		elf32_arm_relocate_section
  #define elf_backend_adjust_dynamic_symbol	elf32_arm_adjust_dynamic_symbol
! #define elf_backend_create_dynamic_sections	elf32_arm_create_dynamic_sections
  #define elf_backend_finish_dynamic_symbol	elf32_arm_finish_dynamic_symbol
  #define elf_backend_finish_dynamic_sections	elf32_arm_finish_dynamic_sections
  #define elf_backend_size_dynamic_sections	elf32_arm_size_dynamic_sections
*************** elf32_arm_reloc_type_class (rela)
*** 3641,3646 ****
  #endif
  
  #define elf_backend_got_header_size	12
! #define elf_backend_plt_header_size	PLT_ENTRY_SIZE
  
  #include "elf32-target.h"
--- 3841,3846 ----
  #endif
  
  #define elf_backend_got_header_size	12
! #define elf_backend_plt_header_size	ARM_PLT_ENTRY_SIZE
  
  #include "elf32-target.h"
Index: ld/emulparams/armelf.sh
===================================================================
RCS file: /cvs/src/src/ld/emulparams/armelf.sh,v
retrieving revision 1.6
diff -c -p -r1.6 armelf.sh
*** ld/emulparams/armelf.sh	22 Nov 2001 09:08:04 -0000	1.6
--- ld/emulparams/armelf.sh	23 Jul 2002 07:42:03 -0000
*************** EXTRA_EM_FILE=armelf
*** 9,14 ****
--- 9,15 ----
  OTHER_TEXT_SECTIONS='*(.glue_7t) *(.glue_7)'
  OTHER_BSS_SYMBOLS='__bss_start__ = .;'
  OTHER_BSS_END_SYMBOLS='_bss_end__ = . ; __bss_end__ = . ; __end__ = . ;'
+ OTHER_PLT_SECTIONS=".plt.thumb    ${RELOCATING-0} : { *(.plt.thumb) }"
  
  DATA_START_SYMBOLS='__data_start = . ;';
  
Index: ld/scripttempl/elf.sc
===================================================================
RCS file: /cvs/src/src/ld/scripttempl/elf.sc,v
retrieving revision 1.32
diff -c -p -r1.32 elf.sc
*** ld/scripttempl/elf.sc	7 Jun 2002 09:59:07 -0000	1.32
--- ld/scripttempl/elf.sc	23 Jul 2002 07:42:03 -0000
***************
*** 11,16 ****
--- 11,17 ----
  #	OTHER_READWRITE_SECTIONS - other than .data .bss .ctors .sdata ...
  #		(e.g., .PARISC.global)
  #	OTHER_BSS_SECTIONS - other than .bss .sbss ...
+ #	OTHER_PLT_SECTIONS - other than .plt ...
  #	OTHER_SECTIONS - at the end
  #	EXECUTABLE_SYMBOLS - symbols that must be defined for an
  #		executable (e.g., _DYNAMIC_LINK)
*************** cat <<EOF
*** 257,262 ****
--- 258,264 ----
    } =${NOP-0}
  
    ${DATA_PLT-${BSS_PLT-${PLT}}}
+   ${DATA_PLT-${BSS_PLT-${OTHER_PLT_SECTIONS}}}
    .text         ${RELOCATING-0} :
    {
      ${RELOCATING+${TEXT_START_SYMBOLS}}
*************** cat <<EOF
*** 321,326 ****
--- 323,329 ----
    ${RELOCATING+${DTOR}}
    .jcr          ${RELOCATING-0} : { KEEP (*(.jcr)) }
    ${DATA_PLT+${PLT}}
+   ${DATA_PLT+${OTHER_PLT_SECTIONS}}
    ${RELOCATING+${OTHER_GOT_SYMBOLS}}
    .got          ${RELOCATING-0} : { *(.got.plt) *(.got) }
    ${OTHER_GOT_SECTIONS}
*************** cat <<EOF
*** 334,339 ****
--- 337,343 ----
    ${RELOCATING+${OTHER_BSS_SYMBOLS}}
    ${SBSS}
    ${BSS_PLT+${PLT}}
+   ${BSS_PLT+${OTHER_PLT_SECTIONS}}
    .bss          ${RELOCATING-0} :
    {
     *(.dynbss)

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH, arm] Support for Thumb PLT entries with interwork
  2002-07-23  1:23       ` [PATCH, arm] Support for Thumb PLT entries with interwork Adam Nemet
@ 2002-07-31  5:34         ` Nick Clifton
  2002-07-31  5:51           ` Richard Earnshaw
  0 siblings, 1 reply; 11+ messages in thread
From: Nick Clifton @ 2002-07-31  5:34 UTC (permalink / raw)
  To: Adam Nemet; +Cc: Richard.Earnshaw, binutils

Hi Adam,

> bfd/ChangeLog:
> 2002-07-23  Adam Nemet  <anemet@lnxw.com>
> 
> 	* elf32-arm.h (ARM_PLT_ENTRY_SIZE): Rename PLT_ENTRY_SIZE.
> 	(THUMB_PLT_ENTRY_SIZE): New macro.
> 	(PLT_ENTRY_SIZE): Return the appropriate *_PLT_ENTRY_SIZE.
> 	(elf32_arm_plt0_entry): Rename PLT_ENTRY_SIZE to
> 	ARM_PLT_ENTRY_SIZE.
> 	(elf32_arm_plt_entry): Likewise.
> 	(elf_backend_plt_header_size): Likewise.
> 
> 	(elf32_thumb_plt0_entry): New global.
> 	(elf32_arm_finish_dynamic_sections): Use it.  Put Thumb entries
> 	into .plt.thumb.
> 	(elf32_thumb_plt_entry): New global.
> 	(elf32_arm_finish_dynamic_symbol): Use it.  Use .thumb.plt for
> 	Thumb entries.  Set the bottom bit of the corresponding GOT entry
> 	for a Thumb PLT entry.
> 
> 	(struct elf32_arm_plt_entry_info): New structure.
> 	(struct elf32_arm_link_hash_entry, plt_info): New member of this
> 	type.
> 	(elf32_arm_link_hash_newfunc): Initialize new member.
> 
> 	(elf32_arm_final_link_relocate, R_ARM_THM_PC22 case): Handle
> 	relocations against the PLT.
> 	(elf32_arm_check_relocs, case R_ARM_PLT32 case): Set
> 	first_rel_type if this is the first time we encounter the symbol.
> 	(elf32_arm_check_relocs, case R_ARM_THM_PC22 case): New case.
> 	Determine if relocation needs a PLT entry.  Set first_rel_type if
> 	this is the first time we encounter the symbol
> 	(elf32_arm_adjust_dynamic_symbol): Create PLT entries for Thumb
> 	functions as well.
> 	(elf32_arm_size_dynamic_sections): Handle .plt.thumb like .plt.
> 
> 	(elf32_arm_create_dynamic_sections): New function.  Create the
> 	.plt.thumb section.
> 	(elf_backend_create_dynamic_sections): Call it.
> 
> ld/ChangeLog:
> 2002-07-23  Adam Nemet  <anemet@lnxw.com>
> 
> 	* emulparams/armelf.sh (OTHER_PLT_SECTIONS): New variable.  Set it
> 	to .plt.thumb.
> 	* scripttempl/elf.sc: Comment it.  Use the same way as ${PLT} is
> 	used.

Approved and applied.

Cheers
        Nick

PS. Sorry about the delay...

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH, arm] Support for Thumb PLT entries with interwork
  2002-07-31  5:34         ` Nick Clifton
@ 2002-07-31  5:51           ` Richard Earnshaw
  2002-07-31  7:24             ` Nick Clifton
  0 siblings, 1 reply; 11+ messages in thread
From: Richard Earnshaw @ 2002-07-31  5:51 UTC (permalink / raw)
  To: Nick Clifton; +Cc: Adam Nemet, Richard.Earnshaw, binutils

Nick,

I don't think this should have gone in yet.

I've been in some discussion (off-line) with Adam concerning it.  I'd like 
whatever we do in this respect to be compatible with the EABI, and it's 
still not clear what we want to do for that here.

*If* we decide that this is how the EABI should do things, then the code 
is probably OK; but I'd rather we made that decision first than had yet 
another potential incompatibility.

R.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH, arm] Support for Thumb PLT entries with interwork
  2002-07-31  5:51           ` Richard Earnshaw
@ 2002-07-31  7:24             ` Nick Clifton
  0 siblings, 0 replies; 11+ messages in thread
From: Nick Clifton @ 2002-07-31  7:24 UTC (permalink / raw)
  To: Richard.Earnshaw; +Cc: Adam Nemet, binutils

Hi Richard,

> I don't think this should have gone in yet.
> 
> I've been in some discussion (off-line) with Adam concerning it.  I'd like 
> whatever we do in this respect to be compatible with the EABI, and it's 
> still not clear what we want to do for that here.

Ahh - sorry I was unaware of this.  I assumed that you were busy and
that the revised patch was OK.

> *If* we decide that this is how the EABI should do things, then the
> code is probably OK; but I'd rather we made that decision first than
> had yet another potential incompatibility.

OK - shall I back the patch put then ?

Cheers
        Nick

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH, arm] Support for Thumb PLT entries with interwork
  2002-08-01  1:55 ` Richard Earnshaw
@ 2002-08-01  7:04   ` Nick Clifton
  0 siblings, 0 replies; 11+ messages in thread
From: Nick Clifton @ 2002-08-01  7:04 UTC (permalink / raw)
  To: Adam Nemet, Richard.Earnshaw; +Cc: binutils

Hi Richard, Hi Adam

> Nick, I think I'd prefer that the patch were removed until we have
> an EABI spec for this area.

OK - I have reverted the patch.

Cheers
        Nick

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH, arm] Support for Thumb PLT entries with interwork
       [not found] <hcvg6v5ald.fsf@anemet1.lynx.com>
@ 2002-08-01  1:55 ` Richard Earnshaw
  2002-08-01  7:04   ` Nick Clifton
  0 siblings, 1 reply; 11+ messages in thread
From: Richard Earnshaw @ 2002-08-01  1:55 UTC (permalink / raw)
  To: Adam Nemet; +Cc: Richard.Earnshaw, Nick Clifton, binutils

> > I've been in some discussion (off-line) with Adam concerning it.  I'd like 
> > whatever we do in this respect to be compatible with the EABI, and it's 
> > still not clear what we want to do for that here.
> 
> Nick, sorry for taking the thread off-line but I wanted to check with
> Richard if he was OK with the updated patch.
> 
> BTW, there is a related GCC patch
> (http://gcc.gnu.org/ml/gcc-patches/2002-07/msg00398.html) that I don't
> think has any ABI implications.  Can you please take a look at it.
> 
> > *If* we decide that this is how the EABI should do things, then the code 
> > is probably OK; but I'd rather we made that decision first than had yet 
> > another potential incompatibility.
> 
> Richard, how far do you think the EABI should go in specifying the PLT
> (for Thumb, ARM and interwork).  I think the rule of thumb :) is that
> an application/shared library built by one tool chain should be able
> to work (link and dynamically link) with another shared library built
> by another tool chain.

As far as it is necessary to go for a linker and a dynamic loader to be 
written, from the EABI specs, by independent people and for the results to 
work together.  These are independent tools that share an interface.

Nick, I think I'd prefer that the patch were removed until we have an EABI 
spec for this area.

R.

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2002-08-01 14:04 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-07-17 18:14 [PATCH, arm] Thumb shared library support: Thumb PLT, etc Adam Nemet
2002-07-18  4:11 ` Richard Earnshaw
2002-07-18 12:00   ` Adam Nemet
2002-07-19  9:06     ` Richard Earnshaw
2002-07-20 11:36       ` Adam Nemet
2002-07-23  1:23       ` [PATCH, arm] Support for Thumb PLT entries with interwork Adam Nemet
2002-07-31  5:34         ` Nick Clifton
2002-07-31  5:51           ` Richard Earnshaw
2002-07-31  7:24             ` Nick Clifton
     [not found] <hcvg6v5ald.fsf@anemet1.lynx.com>
2002-08-01  1:55 ` Richard Earnshaw
2002-08-01  7:04   ` Nick Clifton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).