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]

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


Hi all,

Currently BFD linker generates 3-word wide .plt entries for ARM targets:

0000825c <.plt>:
...
8270: e28fc600 add ip, pc, #0, 12
8274: e28cca08 add ip, ip, #8, 20 ; 0x8000
8278: e5bcf3e8 ldr pc, [ip, #1000]! ; 0x3e8
827c: e28fc600 add ip, pc, #0, 12
8280: e28cca08 add ip, ip, #8, 20 ; 0x8000
8284: e5bcf3e0 ldr pc, [ip, #992]! ; 0x3e0

These entries are only able to initialize first 28 bits of .plt/.got
displacement. If .text and .rodata are bigger than 2 ^ 28 bytes (i.e. 256M) this may cause linker errors due to assert in elf32_arm_populate_plt_entry (in bfd/elf32-arm.c):
BFD_ASSERT ((got_displacement & 0xf0000000) == 0);

I suggest to add an option --long-plt to allow generation of 4-word wide
.plt entries capable of handling arbitrary .plt/.got displacements:

0000825c <.plt>:
...
8270: e28fc200 add ip, pc, #0, 4
8274: e28cc600 add ip, ip, #0, 12
8278: e28cca08 add ip, ip, #8, 20 ; 0x8000
827c: e5bcf3f4 ldr pc, [ip, #1012]! ; 0x3f4
8280: e28fc200 add ip, pc, #0, 4
8284: e28cc600 add ip, ip, #0, 12
8288: e28cca08 add ip, ip, #8, 20 ; 0x8000
828c: e5bcf3e8 ldr pc, [ip, #1000]! ; 0x3e8

Users will than be able to avoid afore-mentioned link error by compiling
with -Wl,--long-plt.

I'm attaching a draft patch to illustrate my proposal. Does it make sense?

Best regards,
Yury
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..bbf394e 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -2142,13 +2142,24 @@ static const bfd_vma elf32_arm_plt0_entry [] =
 
 /* Subsequent entries in a procedure linkage table look like
    this.  */
-static const bfd_vma elf32_arm_plt_entry [] =
+static const bfd_vma elf32_arm_plt_entry_short [] =
 {
   0xe28fc600,		/* add   ip, pc, #0xNN00000 */
   0xe28cca00,		/* add	 ip, ip, #0xNN000   */
   0xe5bcf000,		/* ldr	 pc, [ip, #0xNNN]!  */
 };
 
+/* Or this */
+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 size_t elf32_arm_use_long_plt_entry = 0;
+
 #endif
 
 /* The format of the first entry in the procedure linkage table
@@ -3464,7 +3475,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 +6038,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 = 1;
+}
+
 /* Add the glue sections to ABFD.  This function is called from the
    linker scripts in ld/emultempl/{armelf}.em.  */
 
@@ -7705,8 +7725,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 +7733,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/elfcpp/arm.h b/elfcpp/arm.h
index ab0618a..5c383c4 100644
--- a/elfcpp/arm.h
+++ b/elfcpp/arm.h
@@ -214,6 +214,8 @@ enum
   EF_ARM_EABI_VER3 = 0x03000000,
   EF_ARM_EABI_VER4 = 0x04000000,
   EF_ARM_EABI_VER5 = 0x05000000,
+
+  EF_ARM_HASENTRY = 0x00000002,
 };
 
 // Extract EABI version from flags.
diff --git a/gold/arm.cc b/gold/arm.cc
index 560f380..b3dd039 100644
--- a/gold/arm.cc
+++ b/gold/arm.cc
@@ -8693,6 +8693,9 @@ Target_arm<big_endian>::do_finalize_sections(
       merged_any_attributes = true;
     }
 
+  if (parameters->entry())
+    this->set_processor_specific_flags(this->processor_specific_flags() | elfcpp::EF_ARM_HASENTRY);
+
   // Create an empty uninitialized attribute section if we still don't have it
   // at this moment.  This happens if there is no attributes sections in all
   // inputs.
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

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