This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[RFC][PATCH] Handle arbitrary .plt/.got displacements in ld on ARM
- From: Yury Gribov <y dot gribov at samsung dot com>
- To: binutils at sourceware dot org
- Cc: Viacheslav Garbuzov <v dot garbuzov at samsung dot com>, Yuri Gribov <tetra2005 at gmail dot com>
- Date: Fri, 07 Feb 2014 14:17:23 +0400
- Subject: [RFC][PATCH] Handle arbitrary .plt/.got displacements in ld on ARM
- Authentication-results: sourceware.org; auth=none
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