aboutsummaryrefslogtreecommitdiff
path: root/gas/config
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2018-02-13 07:34:22 -0800
committerH.J. Lu <hjl.tools@gmail.com>2018-02-13 07:34:36 -0800
commitbd7ab16b4537788ad53521c45469a1bdae84ad4a (patch)
tree375430fcb7deb06890838718c27b204f405c5fae /gas/config
parent80c96350467f23a54546580b3e2b67a65ec65b66 (diff)
downloadgdb-bd7ab16b4537788ad53521c45469a1bdae84ad4a.zip
gdb-bd7ab16b4537788ad53521c45469a1bdae84ad4a.tar.gz
gdb-bd7ab16b4537788ad53521c45469a1bdae84ad4a.tar.bz2
x86-64: Generate branch with PLT32 relocation
Since there is no need to prepare for PLT branch on x86-64, generate R_X86_64_PLT32, instead of R_X86_64_PC32, if possible, which can be used as a marker for 32-bit PC-relative branches. To compile Linux kernel, this patch: From: "H.J. Lu" <hjl.tools@gmail.com> Subject: [PATCH] x86: Treat R_X86_64_PLT32 as R_X86_64_PC32 On i386, there are 2 types of PLTs, PIC and non-PIC. PIE and shared objects must use PIC PLT. To use PIC PLT, you need to load _GLOBAL_OFFSET_TABLE_ into EBX first. There is no need for that on x86-64 since x86-64 uses PC-relative PLT. On x86-64, for 32-bit PC-relative branches, we can generate PLT32 relocation, instead of PC32 relocation, which can also be used as a marker for 32-bit PC-relative branches. Linker can always reduce PLT32 relocation to PC32 if function is defined locally. Local functions should use PC32 relocation. As far as Linux kernel is concerned, R_X86_64_PLT32 can be treated the same as R_X86_64_PC32 since Linux kernel doesn't use PLT. is needed. It is available on hjl/plt32/master branch at https://github.com/hjl-tools/linux bfd/ PR gas/22791 * elf64-x86-64.c (is_32bit_relative_branch): Removed. (elf_x86_64_relocate_section): Check PIC relocations in PIE. Remove is_32bit_relative_branch usage. Disallow PC32 reloc against protected function in shared object. gas/ PR gas/22791 * config/tc-i386.c (need_plt32_p): New function. (output_jump): Generate BFD_RELOC_X86_64_PLT32 if possible. (md_estimate_size_before_relax): Likewise. * testsuite/gas/i386/reloc64.d: Updated. * testsuite/gas/i386/x86-64-jump.d: Likewise. * testsuite/gas/i386/x86-64-mpx-branch-1.d: Likewise. * testsuite/gas/i386/x86-64-mpx-branch-2.d: Likewise. * testsuite/gas/i386/x86-64-relax-2.d: Likewise. * testsuite/gas/i386/x86-64-relax-3.d: Likewise. * testsuite/gas/i386/ilp32/reloc64.d: Likewise. * testsuite/gas/i386/ilp32/x86-64-branch.d: Likewise. ld/ PR gas/22791 * testsuite/ld-x86-64/mpx1c.rd: Updated. * testsuite/ld-x86-64/pr22791-1.err: New file. * testsuite/ld-x86-64/pr22791-1a.c: Likewise. * testsuite/ld-x86-64/pr22791-1b.s: Likewise. * testsuite/ld-x86-64/pr22791-2.rd: Likewise. * testsuite/ld-x86-64/pr22791-2a.s: Likewise. * testsuite/ld-x86-64/pr22791-2b.c: Likewise. * testsuite/ld-x86-64/pr22791-2c.s: Likewise. * testsuite/ld-x86-64/x86-64.exp: Run PR ld/22791 tests.
Diffstat (limited to 'gas/config')
-rw-r--r--gas/config/tc-i386.c49
1 files changed, 48 insertions, 1 deletions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 552c1b8..1a5be1b 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -7023,12 +7023,46 @@ output_branch (void)
frag_var (rs_machine_dependent, 5, i.reloc[0], subtype, sym, off, p);
}
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+/* Return TRUE iff PLT32 relocation should be used for branching to
+ symbol S. */
+
+static bfd_boolean
+need_plt32_p (symbolS *s)
+{
+ /* PLT32 relocation is ELF only. */
+ if (!IS_ELF)
+ return FALSE;
+
+ /* Since there is no need to prepare for PLT branch on x86-64, we
+ can generate R_X86_64_PLT32, instead of R_X86_64_PC32, which can
+ be used as a marker for 32-bit PC-relative branches. */
+ if (!object_64bit)
+ return FALSE;
+
+ /* Weak or undefined symbol need PLT32 relocation. */
+ if (S_IS_WEAK (s) || !S_IS_DEFINED (s))
+ return TRUE;
+
+ /* Non-global symbol doesn't need PLT32 relocation. */
+ if (! S_IS_EXTERNAL (s))
+ return FALSE;
+
+ /* Other global symbols need PLT32 relocation. NB: Symbol with
+ non-default visibilities are treated as normal global symbol
+ so that PLT32 relocation can be used as a marker for 32-bit
+ PC-relative branches. It is useful for linker relaxation. */
+ return TRUE;
+}
+#endif
+
static void
output_jump (void)
{
char *p;
int size;
fixS *fixP;
+ bfd_reloc_code_real_type jump_reloc = i.reloc[0];
if (i.tm.opcode_modifier.jumpbyte)
{
@@ -7096,8 +7130,17 @@ output_jump (void)
abort ();
}
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+ if (size == 4
+ && jump_reloc == NO_RELOC
+ && need_plt32_p (i.op[0].disps->X_add_symbol))
+ jump_reloc = BFD_RELOC_X86_64_PLT32;
+#endif
+
+ jump_reloc = reloc (size, 1, 1, jump_reloc);
+
fixP = fix_new_exp (frag_now, p - frag_now->fr_literal, size,
- i.op[0].disps, 1, reloc (size, 1, 1, i.reloc[0]));
+ i.op[0].disps, 1, jump_reloc);
/* All jumps handled here are signed, but don't use a signed limit
check for 32 and 16 bit jumps as we want to allow wrap around at
@@ -9315,6 +9358,10 @@ md_estimate_size_before_relax (fragS *fragP, segT segment)
reloc_type = (enum bfd_reloc_code_real) fragP->fr_var;
else if (size == 2)
reloc_type = BFD_RELOC_16_PCREL;
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+ else if (need_plt32_p (fragP->fr_symbol))
+ reloc_type = BFD_RELOC_X86_64_PLT32;
+#endif
else
reloc_type = BFD_RELOC_32_PCREL;