diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2020-11-29 06:00:37 -0800 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2020-11-29 06:00:50 -0800 |
commit | 568cbddc710f6cb6be752f390a1521cd5556ad9b (patch) | |
tree | 8953d9b7c53cab14e7bc302a3bf66524dcb3686f /gold/x86_64.cc | |
parent | 8ca751ee637ce1b8d1b284a794ffdb327951d0f8 (diff) | |
download | binutils-gdb-568cbddc710f6cb6be752f390a1521cd5556ad9b.tar.gz |
gold: Convert x86-64 GOTPCRELX only if addend == -4
Convert x86-64 GOTPCRELX relocations only if addend == -4.
PR gold/26939
* x86_64.cc (Target_x86_64<size>::Scan::local): Check
get_r_addend() == -4 for GOTPCRELX conversion.
(Target_x86_64<size>::Scan::global): Likewise.
(Target_x86_64<size>::Relocate::relocate): Likewise.
* testsuite/Makefile.am (check_DATA): Add
x86_64_mov_to_lea15.stdout and x86_64_mov_to_lea16.stdout.
(MOSTLYCLEANFILES): Add x86_64_mov_to_lea15 and
x86_64_mov_to_lea16.
(x86_64_mov_to_lea9.o): New target.
(x86_64_mov_to_lea10.o): Likewise.
(x86_64_mov_to_lea15): Likewise.
(x86_64_mov_to_lea16): Likewise.
(x86_64_mov_to_lea15.stdout): Likewise.
(x86_64_mov_to_lea16.stdout): Likewise.
* testsuite/Makefile.in: Regenerated.
* testsuite/x86_64_mov_to_lea.sh: Updated.
* testsuite/x86_64_mov_to_lea5.s: New file.
Diffstat (limited to 'gold/x86_64.cc')
-rw-r--r-- | gold/x86_64.cc | 117 |
1 files changed, 67 insertions, 50 deletions
diff --git a/gold/x86_64.cc b/gold/x86_64.cc index 378bac16f78..ddf4722160b 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -3730,6 +3730,7 @@ Target_x86_64<size>::Scan::local(Symbol_table* symtab, && (r_type == elfcpp::R_X86_64_GOTPCREL || r_type == elfcpp::R_X86_64_GOTPCRELX || r_type == elfcpp::R_X86_64_REX_GOTPCRELX) + && reloc.get_r_addend() == -4 && reloc.get_r_offset() >= 2 && !is_ifunc) { @@ -4200,6 +4201,7 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab, Lazy_view<size> view(object, data_shndx); size_t r_offset = reloc.get_r_offset(); if (!parameters->incremental() + && reloc.get_r_addend() == -4 && r_offset >= 2 && Target_x86_64<size>::can_convert_mov_to_lea(gsym, r_type, r_offset, &view)) @@ -4890,63 +4892,78 @@ Target_x86_64<size>::Relocate::relocate( case elfcpp::R_X86_64_GOTPCRELX: case elfcpp::R_X86_64_REX_GOTPCRELX: { - // Convert - // mov foo@GOTPCREL(%rip), %reg - // to lea foo(%rip), %reg. - // if possible. - if (!parameters->incremental() - && ((gsym == NULL - && rela.get_r_offset() >= 2 - && view[-2] == 0x8b - && !psymval->is_ifunc_symbol()) - || (gsym != NULL - && rela.get_r_offset() >= 2 - && Target_x86_64<size>::can_convert_mov_to_lea(gsym, r_type, - 0, &view)))) - { - view[-2] = 0x8d; - Reloc_funcs::pcrela32(view, object, psymval, addend, address); - } - // Convert - // callq *foo@GOTPCRELX(%rip) to - // addr32 callq foo - // and jmpq *foo@GOTPCRELX(%rip) to - // jmpq foo - // nop - else if (!parameters->incremental() - && gsym != NULL - && rela.get_r_offset() >= 2 - && Target_x86_64<size>::can_convert_callq_to_direct(gsym, - r_type, - 0, &view)) + bool converted_p = false; + + if (rela.get_r_addend() == -4) { - if (view[-1] == 0x15) + // Convert + // mov foo@GOTPCREL(%rip), %reg + // to lea foo(%rip), %reg. + // if possible. + if (!parameters->incremental() + && ((gsym == NULL + && rela.get_r_offset() >= 2 + && view[-2] == 0x8b + && !psymval->is_ifunc_symbol()) + || (gsym != NULL + && rela.get_r_offset() >= 2 + && Target_x86_64<size>::can_convert_mov_to_lea(gsym, + r_type, + 0, + &view)))) { - // Convert callq *foo@GOTPCRELX(%rip) to addr32 callq. - // Opcode of addr32 is 0x67 and opcode of direct callq is 0xe8. - view[-2] = 0x67; - view[-1] = 0xe8; - // Convert GOTPCRELX to 32-bit pc relative reloc. + view[-2] = 0x8d; Reloc_funcs::pcrela32(view, object, psymval, addend, address); + converted_p = true; } - else + // Convert + // callq *foo@GOTPCRELX(%rip) to + // addr32 callq foo + // and jmpq *foo@GOTPCRELX(%rip) to + // jmpq foo + // nop + else if (!parameters->incremental() + && gsym != NULL + && rela.get_r_offset() >= 2 + && Target_x86_64<size>::can_convert_callq_to_direct(gsym, + r_type, + 0, + &view)) { - // Convert jmpq *foo@GOTPCRELX(%rip) to - // jmpq foo - // nop - // The opcode of direct jmpq is 0xe9. - view[-2] = 0xe9; - // The opcode of nop is 0x90. - view[3] = 0x90; - // Convert GOTPCRELX to 32-bit pc relative reloc. jmpq is rip - // relative and since the instruction following the jmpq is now - // the nop, offset the address by 1 byte. The start of the - // relocation also moves ahead by 1 byte. - Reloc_funcs::pcrela32(&view[-1], object, psymval, addend, - address - 1); + if (view[-1] == 0x15) + { + // Convert callq *foo@GOTPCRELX(%rip) to addr32 callq. + // Opcode of addr32 is 0x67 and opcode of direct callq + // is 0xe8. + view[-2] = 0x67; + view[-1] = 0xe8; + // Convert GOTPCRELX to 32-bit pc relative reloc. + Reloc_funcs::pcrela32(view, object, psymval, addend, + address); + converted_p = true; + } + else + { + // Convert jmpq *foo@GOTPCRELX(%rip) to + // jmpq foo + // nop + // The opcode of direct jmpq is 0xe9. + view[-2] = 0xe9; + // The opcode of nop is 0x90. + view[3] = 0x90; + // Convert GOTPCRELX to 32-bit pc relative reloc. jmpq + // is rip relative and since the instruction following + // the jmpq is now the nop, offset the address by 1 + // byte. The start of the relocation also moves ahead + // by 1 byte. + Reloc_funcs::pcrela32(&view[-1], object, psymval, addend, + address - 1); + converted_p = true; + } } } - else + + if (!converted_p) { if (gsym != NULL) { |