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]

[PATCH/ARM][PING] Handle arbitrary .plt/.got displacements in ld on ARM


Link to original discussion: https://sourceware.org/ml/binutils/2014-02/msg00053.html

Will Newton wrote:
I suggest to add an option --long-plt to allow generation of 4-word wide
.plt entries capable of handling arbitrary .plt/.got displacements:
>
> This sounds ok in principle to me (note I am not the ARM or a global
> maintainer).

I think elf32_arm_use_long_plt_entry should probably be
a boolean rather than size_t.

Done, thanks

The comments on the PLT entries could be more verbose (i.e. point out
that one PLT can address 28 bits and the other 32).

Ok, I tried my best.

I wonder whether the FOUR_WORD_PLT #define is now rather ambiguous,
maybe it should be removed?

That was my impression as well. At least there are no options in
configure scripts to define.

The gold parts of this patch look like they are not related?

Sorry, unrelated indeed.

And obviously there would need to be ld testcases.

Added ld/testsuite/ld-arm/long-plt-format.{s,d}. BTW are there any
guidelines for writing tests? I was unable to find any...

-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]