This is the mail archive of the binutils@sourceware.org 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]

Re: [RFC][PATCH] Handle arbitrary .plt/.got displacements in ld on ARM


Nick wrote:
Fair enough - in which case the patch is approved - please apply.

Unfortunately I don't have write access. Could someone commit it for me?

Re-attaching just in case.

-Y
diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h
index c7c5a7d..52fa19e 100644
--- a/bfd/bfd-in.h
+++ b/bfd/bfd-in.h
@@ -887,6 +887,8 @@ extern bfd_boolean bfd_is_arm_special_symbol_name
 
 extern void bfd_elf32_arm_set_byteswap_code (struct bfd_link_info *, int);
 
+extern void bfd_elf32_arm_use_long_plt (void);
+
 /* ARM Note section processing.  */
 extern bfd_boolean bfd_arm_merge_machines
   (bfd *, bfd *);
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 33792f4..92cd688 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -894,6 +894,8 @@ extern bfd_boolean bfd_is_arm_special_symbol_name
 
 extern void bfd_elf32_arm_set_byteswap_code (struct bfd_link_info *, int);
 
+extern void bfd_elf32_arm_use_long_plt (void);
+
 /* ARM Note section processing.  */
 extern bfd_boolean bfd_arm_merge_machines
   (bfd *, bfd *);
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 7216244..ecc5ee4 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -2140,15 +2140,27 @@ static const bfd_vma elf32_arm_plt0_entry [] =
   0x00000000,		/* &GOT[0] - .          */
 };
 
-/* Subsequent entries in a procedure linkage table look like
-   this.  */
-static const bfd_vma elf32_arm_plt_entry [] =
+/* By default subsequent entries in a procedure linkage table look like
+   this. Offsets that don't fit into 28 bits will cause link error. */
+static const bfd_vma elf32_arm_plt_entry_short [] =
 {
   0xe28fc600,		/* add   ip, pc, #0xNN00000 */
   0xe28cca00,		/* add	 ip, ip, #0xNN000   */
   0xe5bcf000,		/* ldr	 pc, [ip, #0xNNN]!  */
 };
 
+/* When explicitly asked, we'll use this "long" entry format
+   which can cope with arbitrary displacements. */
+static const bfd_vma elf32_arm_plt_entry_long [] =
+  {
+    0xe28fc200,     /* add   ip, pc, #0xN0000000 */
+    0xe28cc600,		/* add   ip, ip, #0xNN00000 */
+    0xe28cca00,		/* add	 ip, ip, #0xNN000   */
+    0xe5bcf000,		/* ldr	 pc, [ip, #0xNNN]!  */
+  };
+
+static bfd_boolean elf32_arm_use_long_plt_entry = FALSE;
+
 #endif
 
 /* The format of the first entry in the procedure linkage table
@@ -3464,7 +3476,7 @@ elf32_arm_link_hash_table_create (bfd *abfd)
   ret->plt_entry_size = 16;
 #else
   ret->plt_header_size = 20;
-  ret->plt_entry_size = 12;
+  ret->plt_entry_size = elf32_arm_use_long_plt_entry ? 16 : 12;
 #endif
   ret->use_rel = 1;
   ret->obfd = abfd;
@@ -6027,6 +6039,15 @@ arm_make_glue_section (bfd * abfd, const char * name)
   return TRUE;
 }
 
+/* Set size of .plt entries.  This function is called from the
+   linker scripts in ld/emultempl/{armelf}.em.  */
+
+void
+bfd_elf32_arm_use_long_plt (void)
+{
+  elf32_arm_use_long_plt_entry = TRUE;
+}
+
 /* Add the glue sections to ABFD.  This function is called from the
    linker scripts in ld/emultempl/{armelf}.em.  */
 
@@ -7705,8 +7726,6 @@ elf32_arm_populate_plt_entry (bfd *output_bfd, struct bfd_link_info *info,
 	     of the PLT stub.  */
 	  got_displacement = got_address - (plt_address + 8);
 
-	  BFD_ASSERT ((got_displacement & 0xf0000000) == 0);
-
 	  if (elf32_arm_plt_needs_thumb_stub_p (info, arm_plt))
 	    {
 	      put_thumb_insn (htab, output_bfd,
@@ -7715,21 +7734,44 @@ elf32_arm_populate_plt_entry (bfd *output_bfd, struct bfd_link_info *info,
 			      elf32_arm_plt_thumb_stub[1], ptr - 2);
 	    }
 
-	  put_arm_insn (htab, output_bfd,
-			elf32_arm_plt_entry[0]
-			| ((got_displacement & 0x0ff00000) >> 20),
-			ptr + 0);
-	  put_arm_insn (htab, output_bfd,
-			elf32_arm_plt_entry[1]
-			| ((got_displacement & 0x000ff000) >> 12),
-			ptr+ 4);
-	  put_arm_insn (htab, output_bfd,
-			elf32_arm_plt_entry[2]
-			| (got_displacement & 0x00000fff),
-			ptr + 8);
+	  if (!elf32_arm_use_long_plt_entry)
+	    {
+	      BFD_ASSERT ((got_displacement & 0xf0000000) == 0);
+	      put_arm_insn (htab, output_bfd,
+			      elf32_arm_plt_entry_short[0]
+			      | ((got_displacement & 0x0ff00000) >> 20),
+			      ptr + 0);
+	      put_arm_insn (htab, output_bfd,
+			      elf32_arm_plt_entry_short[1]
+			      | ((got_displacement & 0x000ff000) >> 12),
+			      ptr+ 4);
+	      put_arm_insn (htab, output_bfd,
+			      elf32_arm_plt_entry_short[2]
+			      | (got_displacement & 0x00000fff),
+			      ptr + 8);
 #ifdef FOUR_WORD_PLT
-	  bfd_put_32 (output_bfd, elf32_arm_plt_entry[3], ptr + 12);
+	      bfd_put_32 (output_bfd, elf32_arm_plt_entry_short[3], ptr + 12);
 #endif
+	    }
+	  else
+	    {
+	      put_arm_insn (htab, output_bfd,
+			      elf32_arm_plt_entry_long[0]
+			      | ((got_displacement & 0xf0000000) >> 28),
+			      ptr + 0);
+	      put_arm_insn (htab, output_bfd,
+			      elf32_arm_plt_entry_long[1]
+			      | ((got_displacement & 0x0ff00000) >> 20),
+			      ptr + 4);
+	      put_arm_insn (htab, output_bfd,
+			      elf32_arm_plt_entry_long[2]
+			      | ((got_displacement & 0x000ff000) >> 12),
+			      ptr+ 8);
+	      put_arm_insn (htab, output_bfd,
+			      elf32_arm_plt_entry_long[3]
+			      | (got_displacement & 0x00000fff),
+			      ptr + 12);
+	    }
 	}
 
       /* Fill in the entry in the .rel(a).(i)plt section.  */
diff --git a/ld/emultempl/armelf.em b/ld/emultempl/armelf.em
index 85e924f..ce3d688 100644
--- a/ld/emultempl/armelf.em
+++ b/ld/emultempl/armelf.em
@@ -531,6 +531,7 @@ PARSE_AND_LIST_PROLOGUE='
 #define OPTION_NO_MERGE_EXIDX_ENTRIES   316
 #define OPTION_FIX_ARM1176		317
 #define OPTION_NO_FIX_ARM1176		318
+#define OPTION_LONG_PLT		319
 '
 
 PARSE_AND_LIST_SHORTOPTS=p
@@ -555,6 +556,7 @@ PARSE_AND_LIST_LONGOPTS='
   { "no-merge-exidx-entries", no_argument, NULL, OPTION_NO_MERGE_EXIDX_ENTRIES },
   { "fix-arm1176", no_argument, NULL, OPTION_FIX_ARM1176 },
   { "no-fix-arm1176", no_argument, NULL, OPTION_NO_FIX_ARM1176 },
+  { "long-plt", no_argument, NULL, OPTION_LONG_PLT },
 '
 
 PARSE_AND_LIST_OPTIONS='
@@ -572,6 +574,8 @@ PARSE_AND_LIST_OPTIONS='
   fprintf (file, _("  --no-wchar-size-warning     Don'\''t warn about objects with incompatible\n"
 		   "                                wchar_t sizes\n"));
   fprintf (file, _("  --pic-veneer                Always generate PIC interworking veneers\n"));
+  fprintf (file, _("  --long-plt                  Generate long .plt entries\n"
+           "                              to handle large .plt/.got displacements\n"));
   fprintf (file, _("\
   --stub-group-size=N         Maximum size of a group of input sections that\n\
                                can be handled by one stub section.  A negative\n\
@@ -675,6 +679,10 @@ PARSE_AND_LIST_ARGS_CASES='
    case OPTION_NO_FIX_ARM1176:
       fix_arm1176 = 0;
       break;
+
+   case OPTION_LONG_PLT:
+      bfd_elf32_arm_use_long_plt ();
+      break;
 '
 
 # We have our own before_allocation etc. functions, but they call
diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
index 4c0f802..cea18fa 100644
--- a/ld/testsuite/ld-arm/arm-elf.exp
+++ b/ld/testsuite/ld-arm/arm-elf.exp
@@ -188,6 +188,10 @@ set armelftests_common {
      "" {exec-got-1b.s}
      {{readelf --relocs exec-got-1.d}}
      "exec-got-1"}
+    {"Long PLT entries in executables" "--long-plt -shared --section-start=.plt=0x200 --section-start=.got=0xf0000300" ""
+     "" {long-plt-format.s}
+     {{objdump "-d -j .plt" long-plt-format.d}}
+     "long-plt-format"}
     {"abs call" "-T arm.ld" "" "" {abs-call-1.s}
      {{objdump -d abs-call-1.d}}
      "abs-call-1"}
diff --git a/ld/testsuite/ld-arm/long-plt-format.d b/ld/testsuite/ld-arm/long-plt-format.d
index e69de29..c08cb71 100644
--- a/ld/testsuite/ld-arm/long-plt-format.d
+++ b/ld/testsuite/ld-arm/long-plt-format.d
@@ -0,0 +1,15 @@
+.*:     file format elf32-.*
+
+
+Disassembly of section .plt:
+
+00000200 <.plt>:
+ 200:	.*
+ 204:	.*
+ 208:	.*
+ 20c:	.*
+ 210:	.* 	.word	.*
+ 214:	.* 	add	ip, pc, #-268435456	; 0xf0000000
+ 218:	.* 	add	ip, ip, #0, 12
+ 21c:	.* 	add	ip, ip, #0, 20
+ 220:	.* 	ldr	pc, [ip, #[0-9]*]!	; 0x.*
diff --git a/ld/testsuite/ld-arm/long-plt-format.s b/ld/testsuite/ld-arm/long-plt-format.s
index e69de29..bb0c3a2 100644
--- a/ld/testsuite/ld-arm/long-plt-format.s
+++ b/ld/testsuite/ld-arm/long-plt-format.s
@@ -0,0 +1,7 @@
+	.globl	_start
+	.type	_start,%function
+	.globl foo
+_start:
+	bl foo(PLT)
+	.size	_start,.-_start
+

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