Re: Avoiding unnecessary jump relocations in gas?
From: H.J. Lu
Date: Thu May 07 2015 - 12:22:00 EST
On Thu, May 7, 2015 at 4:52 AM, Jan Beulich <JBeulich@xxxxxxxx> wrote:
>>>> On 07.05.15 at 08:02, <luto@xxxxxxxxxxxxxx> wrote:
>> AFAICT gas will produce relocations for jumps to global labels in the
>> same file. This doesn't seem directly harmful to me, except that, on
>> x86, it forces five-byte jumps instead of two-byte jumps.
>>
>> This seems especially unfortunate, since even hidden and protected
>> symbols have this problem.
>>
>> Given that many users don't want interposition support (especially the
>> kernel and anyone using .hidden or .protected), it would be nice to
>> have a command-line option to turn this off and probably also to turn
>> it off by default for hidden and protected symbols. Can gas do this?
>
> I've been running with the below changes (taken off of a bigger set
> of changes, so the line numbers may look a little odd) for the last
> couple of years. I never tried to submit this change because so far
> I couldn't find the time to check whether this would have any
> unwanted side effects on cases I don't normally use.
>
This is the patch I checked in.
Thanks.
--
H.J.
---
Branches to global non-weak symbols defined in the same segment with
non-default visibility can be optimized the same way as branches to
local symbols.
gas/
* config/tc-i386.c (elf_symbol_resolved_in_segment_p): New.
(md_estimate_size_before_relax): Use it.
gas/testsuite/
* gas/i386/i386.exp: Run relax-3 and x86-64-relax-2.
* gas/i386/relax-3.d: New file.
* gas/i386/relax-3.s: Likewise.
* gas/i386/x86-64-relax-2.d: Likewise.
From b084df0b8d1262fb1e969c74bcc5c61e262a6199 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@xxxxxxxxx>
Date: Thu, 7 May 2015 09:13:39 -0700
Subject: [PATCH] Optimize branches to non-weak symbols with visibility
Branches to global non-weak symbols defined in the same segment with
non-default visibility can be optimized the same way as branches to
local symbols.
gas/
* config/tc-i386.c (elf_symbol_resolved_in_segment_p): New.
(md_estimate_size_before_relax): Use it.
gas/testsuite/
* gas/i386/i386.exp: Run relax-3 and x86-64-relax-2.
* gas/i386/relax-3.d: New file.
* gas/i386/relax-3.s: Likewise.
* gas/i386/x86-64-relax-2.d: Likewise.
---
gas/ChangeLog | 5 +++++
gas/config/tc-i386.c | 24 ++++++++++++++++----
gas/testsuite/ChangeLog | 7 ++++++
gas/testsuite/gas/i386/i386.exp | 4 ++++
gas/testsuite/gas/i386/relax-3.d | 30 +++++++++++++++++++++++++
gas/testsuite/gas/i386/relax-3.s | 39 +++++++++++++++++++++++++++++++++
gas/testsuite/gas/i386/x86-64-relax-2.d | 32 +++++++++++++++++++++++++++
7 files changed, 137 insertions(+), 4 deletions(-)
create mode 100644 gas/testsuite/gas/i386/relax-3.d
create mode 100644 gas/testsuite/gas/i386/relax-3.s
create mode 100644 gas/testsuite/gas/i386/x86-64-relax-2.d
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 7f42a64..9758e72 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,8 @@
+2015-05-07 H.J. Lu <hongjiu.lu@xxxxxxxxx>
+
+ * config/tc-i386.c (elf_symbol_resolved_in_segment_p): New.
+ (md_estimate_size_before_relax): Use it.
+
2015-05-06 Jose E. Marchesi <jose.marchesi@xxxxxxxxxx>
* config/tc-sparc.c: Typo in comment fixed.
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 50f9cb4..c4ba13d 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -8772,6 +8772,25 @@ i386_frag_max_var (fragS *frag)
return TYPE_FROM_RELAX_STATE (frag->fr_subtype) == UNCOND_JUMP ? 4 : 5;
}
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+static int
+elf_symbol_resolved_in_segment_p (symbolS *fr_symbol)
+{
+ /* STT_GNU_IFUNC symbol must go through PLT. */
+ if ((symbol_get_bfdsym (fr_symbol)->flags
+ & BSF_GNU_INDIRECT_FUNCTION) != 0)
+ return 0;
+
+ if (!S_IS_EXTERNAL (fr_symbol))
+ /* Symbol may be weak or local. */
+ return !S_IS_WEAK (fr_symbol);
+
+ /* Global symbols with default visibility in a shared library may be
+ preempted by another definition. */
+ return ELF_ST_VISIBILITY (S_GET_OTHER (fr_symbol)) != STV_DEFAULT;
+}
+#endif
+
/* md_estimate_size_before_relax()
Called just before relax() for rs_machine_dependent frags. The x86
@@ -8795,10 +8814,7 @@ md_estimate_size_before_relax (fragS *fragP, segT segment)
if (S_GET_SEGMENT (fragP->fr_symbol) != segment
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
|| (IS_ELF
- && (S_IS_EXTERNAL (fragP->fr_symbol)
- || S_IS_WEAK (fragP->fr_symbol)
- || ((symbol_get_bfdsym (fragP->fr_symbol)->flags
- & BSF_GNU_INDIRECT_FUNCTION))))
+ && !elf_symbol_resolved_in_segment_p (fragP->fr_symbol))
#endif
#if defined (OBJ_COFF) && defined (TE_PE)
|| (OUTPUT_FLAVOR == bfd_target_coff_flavour
diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog
index 6339bff..1cfa577 100644
--- a/gas/testsuite/ChangeLog
+++ b/gas/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2015-05-07 H.J. Lu <hongjiu.lu@xxxxxxxxx>
+
+ * gas/i386/i386.exp: Run relax-3 and x86-64-relax-2.
+ * gas/i386/relax-3.d: New file.
+ * gas/i386/relax-3.s: Likewise.
+ * gas/i386/x86-64-relax-2.d: Likewise.
+
2015-05-06 Jose E. Marchesi <jose.marchesi@xxxxxxxxxx>
* gas/sparc/natural-32.d: Test ldn, ldna, stn, stna, slln, srln,
diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp
index e1fdd18..af56c26 100644
--- a/gas/testsuite/gas/i386/i386.exp
+++ b/gas/testsuite/gas/i386/i386.exp
@@ -394,6 +394,8 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_32_check]]
run_dump_test "size-4"
run_dump_test "note"
+
+ run_dump_test "relax-3"
}
# This is a PE specific test.
@@ -748,6 +750,8 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_64_check]] t
run_dump_test "x86-64-size-4"
run_dump_test "x86-64-size-5"
run_list_test "x86-64-size-inval-1" "-al"
+
+ run_dump_test "x86-64-relax-2"
}
set ASFLAGS "$old_ASFLAGS"
diff --git a/gas/testsuite/gas/i386/relax-3.d b/gas/testsuite/gas/i386/relax-3.d
new file mode 100644
index 0000000..8aa94e9
--- /dev/null
+++ b/gas/testsuite/gas/i386/relax-3.d
@@ -0,0 +1,30 @@
+#objdump: -dwr
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+0+ <foo>:
+[ ]*[a-f0-9]+: eb 1f jmp 21 <local>
+[ ]*[a-f0-9]+: eb 19 jmp 1d <hidden_def>
+[ ]*[a-f0-9]+: e9 fc ff ff ff jmp 5 <foo\+0x5> 5: (R_386_PC)?(DISP)?32 global_def
+[ ]*[a-f0-9]+: e9 fc ff ff ff jmp a <foo\+0xa> a: (R_386_PC)?(DISP)?32 weak_def
+[ ]*[a-f0-9]+: e9 fc ff ff ff jmp f <foo\+0xf> f: (R_386_PC)?(DISP)?32 weak_hidden_undef
+[ ]*[a-f0-9]+: e9 fc ff ff ff jmp 14 <foo\+0x14> 14: (R_386_PC)?(DISP)?32 weak_hidden_def
+[ ]*[a-f0-9]+: e9 fc ff ff ff jmp 19 <foo\+0x19> 19: (R_386_PC)?(DISP)?32 hidden_undef
+
+0+1d <hidden_def>:
+[ ]*[a-f0-9]+: c3 ret
+
+0+1e <weak_hidden_def>:
+[ ]*[a-f0-9]+: c3 ret
+
+0+1f <global_def>:
+[ ]*[a-f0-9]+: c3 ret
+
+0+20 <weak_def>:
+[ ]*[a-f0-9]+: c3 ret
+
+0+21 <local>:
+[ ]*[a-f0-9]+: c3 ret
+#pass
diff --git a/gas/testsuite/gas/i386/relax-3.s b/gas/testsuite/gas/i386/relax-3.s
new file mode 100644
index 0000000..ab52185
--- /dev/null
+++ b/gas/testsuite/gas/i386/relax-3.s
@@ -0,0 +1,39 @@
+ .text
+ .global foo
+foo:
+ jmp local
+ jmp hidden_def
+ jmp global_def
+ jmp weak_def
+ jmp weak_hidden_undef
+ jmp weak_hidden_def
+ jmp hidden_undef
+
+ .hidden hidden_undef
+
+ .global hidden_def
+ .hidden hidden_def
+hidden_def:
+ ret
+
+ .global weak_hidden_def
+ .hidden weak_hidden_def
+ .weak weak_hidden_def
+weak_hidden_def:
+ ret
+
+ .global global_def
+global_def:
+ ret
+
+ .global weak_def
+ .weak weak_def
+weak_def:
+ ret
+
+local:
+ ret
+
+ .global weak_hidden_undef
+ .weak weak_hidden_undef
+ .hidden weak_hidden_undef
diff --git a/gas/testsuite/gas/i386/x86-64-relax-2.d b/gas/testsuite/gas/i386/x86-64-relax-2.d
new file mode 100644
index 0000000..7b0bd56
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-relax-2.d
@@ -0,0 +1,32 @@
+#source: relax-3.s
+#objdump: -dwr
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <foo>:
+[ ]*[a-f0-9]+: eb 1f jmp 21 <local>
+[ ]*[a-f0-9]+: eb 19 jmp 1d <hidden_def>
+[ ]*[a-f0-9]+: e9 00 00 00 00 jmpq 9 <foo\+0x9> 5: R_X86_64_PC32 global_def-0x4
+[ ]*[a-f0-9]+: e9 00 00 00 00 jmpq e <foo\+0xe> a: R_X86_64_PC32 weak_def-0x4
+[ ]*[a-f0-9]+: e9 00 00 00 00 jmpq 13 <foo\+0x13> f: R_X86_64_PC32 weak_hidden_undef-0x4
+[ ]*[a-f0-9]+: e9 00 00 00 00 jmpq 18 <foo\+0x18> 14: R_X86_64_PC32 weak_hidden_def-0x4
+[ ]*[a-f0-9]+: e9 00 00 00 00 jmpq 1d <hidden_def> 19: R_X86_64_PC32 hidden_undef-0x4
+
+0+1d <hidden_def>:
+[ ]*[a-f0-9]+: c3 retq
+
+0+1e <weak_hidden_def>:
+[ ]*[a-f0-9]+: c3 retq
+
+0+1f <global_def>:
+[ ]*[a-f0-9]+: c3 retq
+
+0+20 <weak_def>:
+[ ]*[a-f0-9]+: c3 retq
+
+0+21 <local>:
+[ ]*[a-f0-9]+: c3 retq
+#pass
--
1.9.3