diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2018-02-13 07:34:22 -0800 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2018-02-13 07:34:36 -0800 |
commit | bd7ab16b4537788ad53521c45469a1bdae84ad4a (patch) | |
tree | 375430fcb7deb06890838718c27b204f405c5fae /gas/config | |
parent | 80c96350467f23a54546580b3e2b67a65ec65b66 (diff) | |
download | gdb-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.c | 49 |
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; |