This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH/ARM][PING] 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" <binutils at sourceware dot org>
- Date: Mon, 17 Feb 2014 10:39:12 +0400
- Subject: [PATCH/ARM][PING] Handle arbitrary .plt/.got displacements in ld on ARM
- Authentication-results: sourceware.org; auth=none
- References: <52F8BD92 dot 5080609 at samsung dot com>
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
+