This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [RFC][PATCH] Handle arbitrary .plt/.got displacements in ld on ARM
- From: Yury Gribov <y dot gribov at samsung dot com>
- To: nick clifton <nickc at redhat dot com>, Will Newton <will dot newton at linaro dot org>
- Cc: "binutils at sourceware dot org" <binutils at sourceware dot org>, Viacheslav Garbuzov <v dot garbuzov at samsung dot com>, Yuri Gribov <tetra2005 at gmail dot com>
- Date: Thu, 27 Feb 2014 16:53:51 +0400
- Subject: Re: [RFC][PATCH] Handle arbitrary .plt/.got displacements in ld on ARM
- Authentication-results: sourceware.org; auth=none
- References: <52F4B2B3 dot 8060804 at samsung dot com> <CANu=Dmh_amrVpf_hQMt2CsnLdTbxv78muPLBi3U_WGS-XE7kSQ at mail dot gmail dot com> <52F8BD92 dot 5080609 at samsung dot com> <5307609F dot 8070001 at redhat dot com> <530B6043 dot 4070605 at samsung dot com> <530C5B23 dot 2070306 at redhat dot com>
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
+