diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2015-08-30 05:03:16 -0700 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2015-09-02 05:14:26 -0700 |
commit | 9c8f5f4baf659f60a3604fd0bacc08b2f6fd1d3b (patch) | |
tree | 9acd5d859362cee649580e08629a51ef2f5d1db5 | |
parent | c74be520ba8ed2d013d43916b923b837294343cc (diff) | |
download | fsf-binutils-gdb-9c8f5f4baf659f60a3604fd0bacc08b2f6fd1d3b.zip fsf-binutils-gdb-9c8f5f4baf659f60a3604fd0bacc08b2f6fd1d3b.tar.gz fsf-binutils-gdb-9c8f5f4baf659f60a3604fd0bacc08b2f6fd1d3b.tar.bz2 |
Add R_X86_64_INDBR_GOTPCREL
Change relocation in "call/jmp *foo@GOTPCREL(%rip)" from R_X86_64_GOTPCREL
to R_X86_64_INDBR_GOTPCREL.
-rw-r--r-- | bfd/bfd-in2.h | 1 | ||||
-rw-r--r-- | bfd/elf64-x86-64.c | 126 | ||||
-rw-r--r-- | bfd/libbfd.h | 1 | ||||
-rw-r--r-- | bfd/reloc.c | 2 | ||||
-rw-r--r-- | gas/config/tc-i386.c | 20 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/i386.exp | 2 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/ilp32/x86-64-gotpcrel.d | 27 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/x86-64-gotpcrel.d | 25 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/x86-64-gotpcrel.s | 23 | ||||
-rw-r--r-- | include/elf/x86-64.h | 2 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/gotpcrel1.dd | 17 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/gotpcrel1.out | 8 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/gotpcrel1a.S | 18 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/gotpcrel1b.c | 7 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/gotpcrel1c.c | 7 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/gotpcrel1d.S | 26 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/x86-64.exp | 24 |
17 files changed, 308 insertions, 28 deletions
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 51fa54f..93948c4 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -3206,6 +3206,7 @@ instruction. */ BFD_RELOC_X86_64_IRELATIVE, BFD_RELOC_X86_64_PC32_BND, BFD_RELOC_X86_64_PLT32_BND, + BFD_RELOC_X86_64_INDBR_GOTPCREL, /* ns32k relocations */ BFD_RELOC_NS32K_IMM_8, diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index f753c7a..a492f71 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -31,6 +31,7 @@ #include "dwarf2.h" #include "libiberty.h" +#include "opcode/i386.h" #include "elf/x86-64.h" #ifdef CORE_HEADER @@ -176,12 +177,15 @@ static reloc_howto_type x86_64_elf_howto_table[] = HOWTO(R_X86_64_PLT32_BND, 0, 2, 32, TRUE, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_X86_64_PLT32_BND", FALSE, 0xffffffff, 0xffffffff, TRUE), + HOWTO(R_X86_64_INDBR_GOTPCREL, 0, 2, 32, TRUE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_INDBR_GOTPCREL", FALSE, 0xffffffff, + 0xffffffff, TRUE), /* We have a gap in the reloc numbers here. R_X86_64_standard counts the number up to this point, and R_X86_64_vt_offset is the value to subtract from a reloc type of R_X86_64_GNU_VT* to form an index into this table. */ -#define R_X86_64_standard (R_X86_64_PLT32_BND + 1) +#define R_X86_64_standard (R_X86_64_INDBR_GOTPCREL + 1) #define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard) /* GNU extension to record C++ vtable hierarchy. */ @@ -253,8 +257,9 @@ static const struct elf_reloc_map x86_64_reloc_map[] = { BFD_RELOC_X86_64_TLSDESC_CALL, R_X86_64_TLSDESC_CALL, }, { BFD_RELOC_X86_64_TLSDESC, R_X86_64_TLSDESC, }, { BFD_RELOC_X86_64_IRELATIVE, R_X86_64_IRELATIVE, }, - { BFD_RELOC_X86_64_PC32_BND, R_X86_64_PC32_BND,}, - { BFD_RELOC_X86_64_PLT32_BND, R_X86_64_PLT32_BND,}, + { BFD_RELOC_X86_64_PC32_BND, R_X86_64_PC32_BND, }, + { BFD_RELOC_X86_64_PLT32_BND, R_X86_64_PLT32_BND, }, + { BFD_RELOC_X86_64_INDBR_GOTPCREL, R_X86_64_INDBR_GOTPCREL, }, { BFD_RELOC_VTABLE_INHERIT, R_X86_64_GNU_VTINHERIT, }, { BFD_RELOC_VTABLE_ENTRY, R_X86_64_GNU_VTENTRY, }, }; @@ -1545,7 +1550,7 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd, /* Rename some of the generic section flags to better document how they are used here. */ -#define need_convert_mov_to_lea sec_flg0 +#define need_convert_mov_and_branch sec_flg0 /* Look through the relocs for a section during the first phase, and calculate needed space in the global offset table, procedure @@ -1726,6 +1731,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_X86_64_32S: case R_X86_64_PC64: case R_X86_64_GOTPCREL: + case R_X86_64_INDBR_GOTPCREL: case R_X86_64_GOTPCREL64: if (htab->elf.dynobj == NULL) htab->elf.dynobj = abfd; @@ -1779,6 +1785,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_X86_64_GOT32: case R_X86_64_GOTPCREL: + case R_X86_64_INDBR_GOTPCREL: case R_X86_64_TLSGD: case R_X86_64_GOT64: case R_X86_64_GOTPCREL64: @@ -2144,9 +2151,10 @@ do_size: return FALSE; } - if (r_type == R_X86_64_GOTPCREL + if ((r_type == R_X86_64_GOTPCREL + || r_type == R_X86_64_INDBR_GOTPCREL) && (h == NULL || h->type != STT_GNU_IFUNC)) - sec->need_convert_mov_to_lea = 1; + sec->need_convert_mov_and_branch = 1; } return TRUE; @@ -2950,11 +2958,15 @@ elf_x86_64_readonly_dynrelocs (struct elf_link_hash_entry *h, mov foo@GOTPCREL(%rip), %reg to lea foo(%rip), %reg - with the local symbol, foo. */ + with the local symbol, foo, and convert + call/jmp *foo@GOTPCREL(%rip) + to + nop call foo/jmp foo nop + with the locally defined function, foo. */ static bfd_boolean -elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec, - struct bfd_link_info *link_info) +elf_x86_64_convert_mov_and_branch (bfd *abfd, asection *sec, + struct bfd_link_info *link_info) { Elf_Internal_Shdr *symtab_hdr; Elf_Internal_Rela *internal_relocs; @@ -2972,7 +2984,7 @@ elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec, /* Nothing to do if there is no need or no output. */ if ((sec->flags & (SEC_CODE | SEC_RELOC)) != (SEC_CODE | SEC_RELOC) - || sec->need_convert_mov_to_lea == 0 + || sec->need_convert_mov_and_branch == 0 || bfd_is_abs_section (sec->output_section)) return TRUE; @@ -3011,11 +3023,13 @@ elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec, char symtype; bfd_vma toff, roff; enum { - none, local, global - } convert_mov_to_lea; + none, mov_local, mov_global, relax + } convert_kind; unsigned int opcode; - if (r_type != R_X86_64_GOTPCREL) + if (r_type != R_X86_64_GOTPCREL + && (r_symndx < symtab_hdr->sh_info + || r_type != R_X86_64_INDBR_GOTPCREL)) continue; roff = irel->r_offset; @@ -3026,18 +3040,23 @@ elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec, opcode = bfd_get_8 (abfd, contents + roff - 2); /* PR ld/18591: Don't convert R_X86_64_GOTPCREL relocation if it - isn't for mov instruction. */ - if (opcode != 0x8b) + isn't for mov instruction. Also support call/jmp instruction + with R_X86_64_INDBR_GOTPCREL relocation. */ + if (!(opcode == 0x8b && r_type == R_X86_64_GOTPCREL) + && !(opcode == 0xff && r_type == R_X86_64_INDBR_GOTPCREL)) continue; tsec = NULL; - convert_mov_to_lea = none; + convert_kind = none; /* Get the symbol referred to by the reloc. */ if (r_symndx < symtab_hdr->sh_info) { Elf_Internal_Sym *isym; + if (r_type != R_X86_64_GOTPCREL) + abort (); + /* Silence older GCC warning. */ h = NULL; @@ -3060,7 +3079,7 @@ elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec, tsec = bfd_section_from_elf_index (abfd, isym->st_shndx); toff = isym->st_value; - convert_mov_to_lea = local; + convert_kind = mov_local; } } else @@ -3073,22 +3092,24 @@ elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec, || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; - /* STT_GNU_IFUNC must keep R_X86_64_GOTPCREL relocation. We also - avoid optimizing _DYNAMIC since ld.so may use its link-time - address. */ + /* STT_GNU_IFUNC must keep GOTPCREL relocations. We also + avoid optimizing R_X86_64_GOTPCREL relocation againt + _DYNAMIC since ld.so may use its link-time address. */ if (h->def_regular && h->type != STT_GNU_IFUNC - && h != htab->elf.hdynamic + && (r_type == R_X86_64_INDBR_GOTPCREL + || h != htab->elf.hdynamic) && SYMBOL_REFERENCES_LOCAL (link_info, h)) { tsec = h->root.u.def.section; toff = h->root.u.def.value; symtype = h->type; - convert_mov_to_lea = global; + convert_kind + = r_type == R_X86_64_GOTPCREL ? mov_global : relax; } } - if (convert_mov_to_lea == none) + if (convert_kind == none) continue; if (tsec->sec_info_type == SEC_INFO_TYPE_MERGE) @@ -3163,12 +3184,59 @@ elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec, continue; } - bfd_put_8 (abfd, 0x8d, contents + roff - 2); + if (convert_kind == relax) + { + /* We have "call/jmp *foo@GOTPCREL(%rip)". */ + unsigned int modrm; + unsigned int nop; + bfd_vma nop_offset; + + /* Convert R_X86_64_INDBR_GOTPCREL to R_X86_64_PC32. */ + modrm = bfd_get_8 (abfd, contents + irel->r_offset - 1); + switch (modrm) + { + default: + /* Skip "lcall/ljmp *foo@GOTPCREL(%rip)". */ + continue; + case 0x15: + modrm = 0xe8; + break; + case 0x25: + modrm = 0xe9; + break; + } + if (modrm == 0xe9) + { + unsigned int disp; + /* Convert to "jmp foo nop". */ + nop = NOP_OPCODE; + nop_offset = irel->r_offset + 3; + disp = bfd_get_32 (abfd, contents + irel->r_offset); + irel->r_offset -= 1; + bfd_put_32 (abfd, disp, contents + irel->r_offset); + } + else + { + /* Convert to "nop call foo". ADDR_PREFIX_OPCODE + is a nop prefix. */ + nop = ADDR_PREFIX_OPCODE; + nop_offset = irel->r_offset - 2; + } + bfd_put_8 (abfd, nop, contents + nop_offset); + bfd_put_8 (abfd, modrm, contents + irel->r_offset - 1); + } + else + { + /* Convert "mov foo@GOTPCREL(%rip), %reg" to + "lea foo(%rip), %reg". */ + bfd_put_8 (abfd, 0x8d, contents + roff - 2); + } + irel->r_info = htab->r_info (r_symndx, R_X86_64_PC32); changed_contents = TRUE; changed_relocs = TRUE; - if (convert_mov_to_lea == local) + if (convert_kind == mov_local) { if (local_got_refcounts != NULL && local_got_refcounts[r_symndx] > 0) @@ -3267,7 +3335,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, { struct elf_dyn_relocs *p; - if (!elf_x86_64_convert_mov_to_lea (ibfd, s, info)) + if (!elf_x86_64_convert_mov_and_branch (ibfd, s, info)) return FALSE; for (p = (struct elf_dyn_relocs *) @@ -3988,6 +4056,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, goto do_relocation; case R_X86_64_GOTPCREL: + case R_X86_64_INDBR_GOTPCREL: case R_X86_64_GOTPCREL64: base_got = htab->elf.sgot; off = h->got.offset; @@ -4056,6 +4125,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, /* Relocation is to the entry for this symbol in the global offset table. */ case R_X86_64_GOTPCREL: + case R_X86_64_INDBR_GOTPCREL: case R_X86_64_GOTPCREL64: /* Use global offset table entry as symbol value. */ case R_X86_64_GOTPLT64: @@ -4161,7 +4231,9 @@ elf_x86_64_relocate_section (bfd *output_bfd, relocation = base_got->output_section->vma + base_got->output_offset + off; - if (r_type != R_X86_64_GOTPCREL && r_type != R_X86_64_GOTPCREL64) + if (r_type != R_X86_64_GOTPCREL + && r_type != R_X86_64_INDBR_GOTPCREL + && r_type != R_X86_64_GOTPCREL64) relocation -= htab->elf.sgotplt->output_section->vma - htab->elf.sgotplt->output_offset; diff --git a/bfd/libbfd.h b/bfd/libbfd.h index fc70e29..ee3b33d 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -1321,6 +1321,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_X86_64_IRELATIVE", "BFD_RELOC_X86_64_PC32_BND", "BFD_RELOC_X86_64_PLT32_BND", + "BFD_RELOC_X86_64_INDBR_GOTPCREL", "BFD_RELOC_NS32K_IMM_8", "BFD_RELOC_NS32K_IMM_16", "BFD_RELOC_NS32K_IMM_32", diff --git a/bfd/reloc.c b/bfd/reloc.c index caa6fb4..93ad3a5 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -2737,6 +2737,8 @@ ENUMX BFD_RELOC_X86_64_PC32_BND ENUMX BFD_RELOC_X86_64_PLT32_BND +ENUMX + BFD_RELOC_X86_64_INDBR_GOTPCREL ENUMDOC x86-64/elf relocations diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 13f1d27..72a4eb3 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -2947,6 +2947,7 @@ tc_i386_fix_adjustable (fixS *fixP ATTRIBUTE_UNUSED) || fixP->fx_r_type == BFD_RELOC_X86_64_PLT32 || fixP->fx_r_type == BFD_RELOC_X86_64_GOT32 || fixP->fx_r_type == BFD_RELOC_X86_64_GOTPCREL + || fixP->fx_r_type == BFD_RELOC_X86_64_INDBR_GOTPCREL || fixP->fx_r_type == BFD_RELOC_X86_64_TLSGD || fixP->fx_r_type == BFD_RELOC_X86_64_TLSLD || fixP->fx_r_type == BFD_RELOC_X86_64_DTPOFF32 @@ -8224,7 +8225,14 @@ i386_finalize_displacement (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp, exp->X_op = O_subtract; exp->X_op_symbol = GOT_symbol; if (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL) - i.reloc[this_operand] = BFD_RELOC_32_PCREL; + { + if (i.operands == 1 + && i.types[this_operand].bitfield.jumpabsolute) + /* Borrow the unused BFD_RELOC_X86_64_PC32_BND. */ + i.reloc[this_operand] = BFD_RELOC_X86_64_PC32_BND; + else + i.reloc[this_operand] = BFD_RELOC_32_PCREL; + } else if (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTOFF64) i.reloc[this_operand] = BFD_RELOC_64; else @@ -10335,6 +10343,14 @@ i386_validate_fix (fixS *fixp) abort (); fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL; } + else if (fixp->fx_r_type == BFD_RELOC_X86_64_PC32_BND) + { + /* Covert the borrowed BFD_RELOC_X86_64_PC32_BND back to + BFD_RELOC_X86_64_INDBR_GOTPCREL. */ + if (!object_64bit) + abort (); + fixp->fx_r_type = BFD_RELOC_X86_64_INDBR_GOTPCREL; + } else { if (!object_64bit) @@ -10377,6 +10393,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) case BFD_RELOC_X86_64_PLT32: case BFD_RELOC_X86_64_GOT32: case BFD_RELOC_X86_64_GOTPCREL: + case BFD_RELOC_X86_64_INDBR_GOTPCREL: case BFD_RELOC_386_PLT32: case BFD_RELOC_386_GOT32: case BFD_RELOC_386_GOTOFF: @@ -10530,6 +10547,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) case BFD_RELOC_X86_64_PLT32: case BFD_RELOC_X86_64_GOT32: case BFD_RELOC_X86_64_GOTPCREL: + case BFD_RELOC_X86_64_INDBR_GOTPCREL: case BFD_RELOC_X86_64_TLSGD: case BFD_RELOC_X86_64_TLSLD: case BFD_RELOC_X86_64_GOTTPOFF: diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp index f59b598..4277b84 100644 --- a/gas/testsuite/gas/i386/i386.exp +++ b/gas/testsuite/gas/i386/i386.exp @@ -778,6 +778,8 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_64_check]] t run_dump_test "x86-64-jump" run_dump_test "x86-64-branch-2" run_list_test "x86-64-branch-3" "-al -mintel64" + + run_dump_test "x86-64-gotpcrel" } set ASFLAGS "$old_ASFLAGS" diff --git a/gas/testsuite/gas/i386/ilp32/x86-64-gotpcrel.d b/gas/testsuite/gas/i386/ilp32/x86-64-gotpcrel.d new file mode 100644 index 0000000..425a60b --- /dev/null +++ b/gas/testsuite/gas/i386/ilp32/x86-64-gotpcrel.d @@ -0,0 +1,27 @@ +#source: ../x86-64-gotpcrel.s +#objdump: -dwr +#name: x86-64 (ILP32) gotpcrel + +.*: +file format .* + + +Disassembly of section .text: + +0+ <_start>: +[ ]*[a-f0-9]+: 48 c7 c0 00 00 00 00 mov \$0x0,%rax 3: R_X86_64_GOTPCREL foo +[ ]*[a-f0-9]+: 48 8b 04 25 00 00 00 00 mov 0x0,%rax b: R_X86_64_GOTPCREL foo +[ ]*[a-f0-9]+: 48 8b 05 00 00 00 00 mov 0x0\(%rip\),%rax # 16 <_start\+0x16> 12: R_X86_64_GOTPCREL foo-0x4 +[ ]*[a-f0-9]+: 48 8b 81 00 00 00 00 mov 0x0\(%rcx\),%rax 19: R_X86_64_GOTPCREL foo +[ ]*[a-f0-9]+: ff 15 00 00 00 00 callq \*0x0\(%rip\) # 23 <_start\+0x23> 1f: R_X86_64_INDBR_GOTPCREL foo-0x4 +[ ]*[a-f0-9]+: ff 90 00 00 00 00 callq \*0x0\(%rax\) 25: R_X86_64_INDBR_GOTPCREL foo +[ ]*[a-f0-9]+: ff 25 00 00 00 00 jmpq \*0x0\(%rip\) # 2f <_start\+0x2f> 2b: R_X86_64_INDBR_GOTPCREL foo-0x4 +[ ]*[a-f0-9]+: ff a1 00 00 00 00 jmpq \*0x0\(%rcx\) 31: R_X86_64_INDBR_GOTPCREL foo +[ ]*[a-f0-9]+: 48 c7 c0 00 00 00 00 mov \$0x0,%rax 38: R_X86_64_GOTPCREL foo +[ ]*[a-f0-9]+: 48 8b 04 25 00 00 00 00 mov 0x0,%rax 40: R_X86_64_GOTPCREL foo +[ ]*[a-f0-9]+: 48 8b 05 00 00 00 00 mov 0x0\(%rip\),%rax # 4b <_start\+0x4b> 47: R_X86_64_GOTPCREL foo-0x4 +[ ]*[a-f0-9]+: 48 8b 81 00 00 00 00 mov 0x0\(%rcx\),%rax 4e: R_X86_64_GOTPCREL foo +[ ]*[a-f0-9]+: ff 15 00 00 00 00 callq \*0x0\(%rip\) # 58 <_start\+0x58> 54: R_X86_64_INDBR_GOTPCREL foo-0x4 +[ ]*[a-f0-9]+: ff 90 00 00 00 00 callq \*0x0\(%rax\) 5a: R_X86_64_INDBR_GOTPCREL foo +[ ]*[a-f0-9]+: ff 25 00 00 00 00 jmpq \*0x0\(%rip\) # 64 <_start\+0x64> 60: R_X86_64_INDBR_GOTPCREL foo-0x4 +[ ]*[a-f0-9]+: ff a1 00 00 00 00 jmpq \*0x0\(%rcx\) 66: R_X86_64_INDBR_GOTPCREL foo +#pass diff --git a/gas/testsuite/gas/i386/x86-64-gotpcrel.d b/gas/testsuite/gas/i386/x86-64-gotpcrel.d new file mode 100644 index 0000000..e6d3072 --- /dev/null +++ b/gas/testsuite/gas/i386/x86-64-gotpcrel.d @@ -0,0 +1,25 @@ +#objdump: -dwr + +.*: +file format .* + + +Disassembly of section .text: + +0+ <_start>: +[ ]*[a-f0-9]+: 48 c7 c0 00 00 00 00 mov \$0x0,%rax 3: R_X86_64_GOTPCREL foo +[ ]*[a-f0-9]+: 48 8b 04 25 00 00 00 00 mov 0x0,%rax b: R_X86_64_GOTPCREL foo +[ ]*[a-f0-9]+: 48 8b 05 00 00 00 00 mov 0x0\(%rip\),%rax # 16 <_start\+0x16> 12: R_X86_64_GOTPCREL foo-0x4 +[ ]*[a-f0-9]+: 48 8b 81 00 00 00 00 mov 0x0\(%rcx\),%rax 19: R_X86_64_GOTPCREL foo +[ ]*[a-f0-9]+: ff 15 00 00 00 00 callq \*0x0\(%rip\) # 23 <_start\+0x23> 1f: R_X86_64_INDBR_GOTPCREL foo-0x4 +[ ]*[a-f0-9]+: ff 90 00 00 00 00 callq \*0x0\(%rax\) 25: R_X86_64_INDBR_GOTPCREL foo +[ ]*[a-f0-9]+: ff 25 00 00 00 00 jmpq \*0x0\(%rip\) # 2f <_start\+0x2f> 2b: R_X86_64_INDBR_GOTPCREL foo-0x4 +[ ]*[a-f0-9]+: ff a1 00 00 00 00 jmpq \*0x0\(%rcx\) 31: R_X86_64_INDBR_GOTPCREL foo +[ ]*[a-f0-9]+: 48 c7 c0 00 00 00 00 mov \$0x0,%rax 38: R_X86_64_GOTPCREL foo +[ ]*[a-f0-9]+: 48 8b 04 25 00 00 00 00 mov 0x0,%rax 40: R_X86_64_GOTPCREL foo +[ ]*[a-f0-9]+: 48 8b 05 00 00 00 00 mov 0x0\(%rip\),%rax # 4b <_start\+0x4b> 47: R_X86_64_GOTPCREL foo-0x4 +[ ]*[a-f0-9]+: 48 8b 81 00 00 00 00 mov 0x0\(%rcx\),%rax 4e: R_X86_64_GOTPCREL foo +[ ]*[a-f0-9]+: ff 15 00 00 00 00 callq \*0x0\(%rip\) # 58 <_start\+0x58> 54: R_X86_64_INDBR_GOTPCREL foo-0x4 +[ ]*[a-f0-9]+: ff 90 00 00 00 00 callq \*0x0\(%rax\) 5a: R_X86_64_INDBR_GOTPCREL foo +[ ]*[a-f0-9]+: ff 25 00 00 00 00 jmpq \*0x0\(%rip\) # 64 <_start\+0x64> 60: R_X86_64_INDBR_GOTPCREL foo-0x4 +[ ]*[a-f0-9]+: ff a1 00 00 00 00 jmpq \*0x0\(%rcx\) 66: R_X86_64_INDBR_GOTPCREL foo +#pass diff --git a/gas/testsuite/gas/i386/x86-64-gotpcrel.s b/gas/testsuite/gas/i386/x86-64-gotpcrel.s new file mode 100644 index 0000000..981b14f --- /dev/null +++ b/gas/testsuite/gas/i386/x86-64-gotpcrel.s @@ -0,0 +1,23 @@ + .text +_start: + movq $foo@GOTPCREL, %rax + movq foo@GOTPCREL, %rax + movq foo@GOTPCREL(%rip), %rax + movq foo@GOTPCREL(%rcx), %rax + + call *foo@GOTPCREL(%rip) + call *foo@GOTPCREL(%rax) + jmp *foo@GOTPCREL(%rip) + jmp *foo@GOTPCREL(%rcx) + + .intel_syntax noprefix + + mov rax, offset foo@gotpcrel + mov rax, QWORD PTR [foo@GOTPCREL] + mov rax, QWORD PTR [rip + foo@GOTPCREL] + mov rax, QWORD PTR [rcx + foo@GOTPCREL] + + call QWORD PTR [rip + foo@GOTPCREL] + call QWORD PTR [rax + foo@GOTPCREL] + jmp QWORD PTR [rip + foo@GOTPCREL] + jmp QWORD PTR [rcx + foo@GOTPCREL] diff --git a/include/elf/x86-64.h b/include/elf/x86-64.h index f18ec66..9246bae 100644 --- a/include/elf/x86-64.h +++ b/include/elf/x86-64.h @@ -76,6 +76,8 @@ START_RELOC_NUMBERS (elf_x86_64_reloc_type) signed with BND prefix */ RELOC_NUMBER (R_X86_64_PLT32_BND, 40) /* 32 bit PLT address with BND prefix */ + /* Indirect branch via 32 bit signed pc relative offset to GOT entry */ + RELOC_NUMBER (R_X86_64_INDBR_GOTPCREL, 41) RELOC_NUMBER (R_X86_64_GNU_VTINHERIT, 250) /* GNU C++ hack */ RELOC_NUMBER (R_X86_64_GNU_VTENTRY, 251) /* GNU C++ hack */ END_RELOC_NUMBERS (R_X86_64_max) diff --git a/ld/testsuite/ld-x86-64/gotpcrel1.dd b/ld/testsuite/ld-x86-64/gotpcrel1.dd new file mode 100644 index 0000000..187a1a5 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gotpcrel1.dd @@ -0,0 +1,17 @@ +#... +[a-f0-9]+ <main>: +[ ]*[a-f0-9]+: 48 83 ec 08 sub \$0x8,%rsp +[ ]*[a-f0-9]+: [ a-f0-9]+ addr32 callq [a-f0-9]+ <foo> +[ ]*[a-f0-9]+: [ a-f0-9]+ callq \*0x[a-f0-9]+\(%rip\) # [a-f0-9]+ <_DYNAMIC\+0x[a-f0-9]+> +[ ]*[a-f0-9]+: [ a-f0-9]+ callq \*0x[a-f0-9]+\(%rip\) # [a-f0-9]+ <_DYNAMIC\+0x[a-f0-9]+> +[ ]*[a-f0-9]+: [ a-f0-9]+ lea 0x[a-f0-9]+\(%rip\),%rax # [a-f0-9]+ <foo> +[ ]*[a-f0-9]+: ff d0 callq \*%rax +[ ]*[a-f0-9]+: [ a-f0-9]+ mov 0x[a-f0-9]+\(%rip\),%rcx # [a-f0-9]+ <_DYNAMIC\+0x[a-f0-9]+> +[ ]*[a-f0-9]+: ff d1 callq \*%rcx +[ ]*[a-f0-9]+: [ a-f0-9]+ mov 0x[a-f0-9]+\(%rip\),%rdx # [a-f0-9]+ <_DYNAMIC\+0x[a-f0-9]+> +[ ]*[a-f0-9]+: ff d2 callq \*%rdx +[ ]*[a-f0-9]+: 31 ff xor %edi,%edi +[ ]*[a-f0-9]+: 48 83 c4 08 add \$0x8,%rsp +[ ]*[a-f0-9]+: [ a-f0-9]+ jmpq [a-f0-9]+ <myexit> +[ ]*[a-f0-9]+: 90 nop +#pass diff --git a/ld/testsuite/ld-x86-64/gotpcrel1.out b/ld/testsuite/ld-x86-64/gotpcrel1.out new file mode 100644 index 0000000..4d35632 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gotpcrel1.out @@ -0,0 +1,8 @@ +foo +bar +plt +plt +foo +bar +plt +plt diff --git a/ld/testsuite/ld-x86-64/gotpcrel1a.S b/ld/testsuite/ld-x86-64/gotpcrel1a.S new file mode 100644 index 0000000..58dfbb1 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gotpcrel1a.S @@ -0,0 +1,18 @@ + .text + .globl main + .type main, @function +main: + subq $8, %rsp + call *foo@GOTPCREL(%rip) + call *bar@GOTPCREL(%rip) + call *plt@GOTPCREL(%rip) + movq foo@GOTPCREL(%rip), %rax + call *%rax + movq bar@GOTPCREL(%rip), %rcx + call *%rcx + movq plt@GOTPCREL(%rip), %rdx + call *%rdx + xorl %edi, %edi + addq $8, %rsp + jmp *myexit@GOTPCREL(%rip) + .size main, .-main diff --git a/ld/testsuite/ld-x86-64/gotpcrel1b.c b/ld/testsuite/ld-x86-64/gotpcrel1b.c new file mode 100644 index 0000000..cf0c78e --- /dev/null +++ b/ld/testsuite/ld-x86-64/gotpcrel1b.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +void +foo (void) +{ + printf ("%s\n", __FUNCTION__); +} diff --git a/ld/testsuite/ld-x86-64/gotpcrel1c.c b/ld/testsuite/ld-x86-64/gotpcrel1c.c new file mode 100644 index 0000000..05f5fc2 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gotpcrel1c.c @@ -0,0 +1,7 @@ +#include <stdlib.h> + +void +myexit (int status) +{ + exit (status); +} diff --git a/ld/testsuite/ld-x86-64/gotpcrel1d.S b/ld/testsuite/ld-x86-64/gotpcrel1d.S new file mode 100644 index 0000000..4b01499 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gotpcrel1d.S @@ -0,0 +1,26 @@ + .text + .globl bar + .type bar, @function +bar: + leaq __FUNCTION__.2215(%rip), %rdi + jmp *puts@GOTPCREL(%rip) + .size bar, .-bar + .globl plt + .type plt, @function +plt: + leaq __FUNCTION__.2219(%rip), %rdi + subq $8, %rsp + call *puts@GOTPCREL(%rip) + leaq __FUNCTION__.2219(%rip), %rdi + addq $8, %rsp + jmp *puts@GOTPCREL(%rip) + .size plt, .-plt + .section .rodata + .type __FUNCTION__.2219, @object + .size __FUNCTION__.2219, 4 +__FUNCTION__.2219: + .string "plt" + .type __FUNCTION__.2215, @object + .size __FUNCTION__.2215, 4 +__FUNCTION__.2215: + .string "bar" diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp index 6320999..d8521d2 100644 --- a/ld/testsuite/ld-x86-64/x86-64.exp +++ b/ld/testsuite/ld-x86-64/x86-64.exp @@ -500,6 +500,22 @@ if { [isnative] && [which $CC] != 0 } { {{readelf {-Wrd} pr18900b.rd}} \ "pr18900b" \ ] \ + [list \ + "Build gotpcrel1d.so" \ + "-shared" \ + "" \ + { gotpcrel1d.S } \ + "" \ + "gotpcrel1d.so" \ + ] \ + [list \ + "Build gotpcrel1" \ + "tmpdir/gotpcrel1d.so" \ + "" \ + { gotpcrel1a.S gotpcrel1b.c gotpcrel1c.c } \ + {{objdump {-dw} gotpcrel1.dd}} \ + "gotpcrel1" \ + ] \ ] run_ld_link_exec_tests [] [list \ @@ -554,6 +570,14 @@ if { [isnative] && [which $CC] != 0 } { "pr18900" \ "pr18900.out" \ ] \ + [list \ + "Run gotpcrel1" \ + "tmpdir/gotpcrel1d.so" \ + "" \ + { gotpcrel1a.S gotpcrel1b.c gotpcrel1c.c } \ + "gotpcrel1" \ + "gotpcrel1.out" \ + ] \ ] if { [istarget "x86_64-*-linux*"] \ |