diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2017-08-03 09:43:28 -0700 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2017-08-04 10:21:07 -0700 |
commit | dc044a14027136c864d69c83598f3ba37c44fc9c (patch) | |
tree | f09cf65dd04daaf5a59c8056e09b48cb61698e1e | |
parent | f02fd7745d003d65fd3b981618e07b874b721d79 (diff) | |
download | binutils-gdb-users/hjl/gprel/master.tar.gz |
Add R_X86_64_GPRELusers/hjl/gprel/master
"%seg:foo@GPREL" is used to address symbol, foo, relative to __gp. foo is
addressed by %seg + offset of foo relative to __gp. Linker sets __gp to
the middle of GP section which contains definitions of symbols with GPREL
relocations. Run-time should load address of __gp into segment register,
%seg before accessing foo via "%seg:foo@GPREL".
-rw-r--r-- | bfd/elf64-x86-64.c | 224 | ||||
-rw-r--r-- | gas/config/tc-i386.c | 42 | ||||
-rw-r--r-- | gas/config/tc-i386.h | 6 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/i386.exp | 3 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/x86-64-gprel.d | 10 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/x86-64-gprel.s | 3 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/x86-64-inval-gprel.l | 34 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/x86-64-inval-gprel.s | 8 | ||||
-rw-r--r-- | include/elf/x86-64.h | 2 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/gprel-1a.S | 15 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/gprel-1b.c | 32 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/gprel-2a.S | 14 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/gprel-2b.c | 30 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/gprel-3.d | 3 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/gprel-3.s | 4 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/gprel-4.d | 3 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/gprel-4.s | 17 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/gprel-5.d | 3 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/gprel-5.s | 19 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/x86-64.exp | 48 |
20 files changed, 509 insertions, 11 deletions
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index 448599eb9b3..320c6983220 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -183,12 +183,15 @@ static reloc_howto_type x86_64_elf_howto_table[] = HOWTO(R_X86_64_REX_GOTPCRELX, 0, 2, 32, TRUE, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_X86_64_REX_GOTPCRELX", FALSE, 0xffffffff, 0xffffffff, TRUE), + HOWTO(R_X86_64_GPREL, 0, 2, 32, FALSE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_GPREL", + FALSE, MINUS_ONE, MINUS_ONE, FALSE), /* 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_REX_GOTPCRELX + 1) +#define R_X86_64_standard (R_X86_64_GPREL + 1) #define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard) /* GNU extension to record C++ vtable hierarchy. */ @@ -264,6 +267,7 @@ static const struct elf_reloc_map x86_64_reloc_map[] = { BFD_RELOC_X86_64_PLT32_BND, R_X86_64_PLT32_BND, }, { BFD_RELOC_X86_64_GOTPCRELX, R_X86_64_GOTPCRELX, }, { BFD_RELOC_X86_64_REX_GOTPCRELX, R_X86_64_REX_GOTPCRELX, }, + { BFD_RELOC_GPREL32, R_X86_64_GPREL, }, { BFD_RELOC_VTABLE_INHERIT, R_X86_64_GNU_VTINHERIT, }, { BFD_RELOC_VTABLE_ENTRY, R_X86_64_GNU_VTENTRY, }, }; @@ -1092,6 +1096,12 @@ struct elf_x86_64_link_hash_entry real definition and check it when allowing copy reloc in PIE. */ unsigned int needs_copy : 1; + /* TRUE if symbol is __gp. */ + unsigned int is_gp : 1; + + /* TRUE if symbol has GPREL relocations. */ + unsigned int has_gprel_reloc : 1; + /* TRUE if symbol has GOT or PLT relocations. */ unsigned int has_got_reloc : 1; @@ -1171,6 +1181,8 @@ struct elf_x86_64_link_hash_table asection *plt_got; asection *plt_got_eh_frame; + struct elf_link_hash_entry *gp; + /* Parameters describing PLT generation, lazy or non-lazy. */ struct elf_x86_64_plt_layout plt; @@ -1261,6 +1273,8 @@ elf_x86_64_link_hash_newfunc (struct bfd_hash_entry *entry, eh->dyn_relocs = NULL; eh->tls_type = GOT_UNKNOWN; eh->needs_copy = 0; + eh->is_gp = 0; + eh->has_gprel_reloc = 0; eh->has_got_reloc = 0; eh->has_non_got_reloc = 0; eh->no_finish_dynamic_symbol = 0; @@ -1423,6 +1437,7 @@ elf_x86_64_copy_indirect_symbol (struct bfd_link_info *info, edir = (struct elf_x86_64_link_hash_entry *) dir; eind = (struct elf_x86_64_link_hash_entry *) ind; + edir->has_gprel_reloc |= eind->has_gprel_reloc; edir->has_got_reloc |= eind->has_got_reloc; edir->has_non_got_reloc |= eind->has_non_got_reloc; @@ -2098,6 +2113,7 @@ elf_x86_64_convert_load_reloc (bfd *abfd, asection *sec, /* Avoid optimizing GOTPCREL relocations againt _DYNAMIC since ld.so may use its link-time address. */ else if (h->start_stop + || ((struct elf_x86_64_link_hash_entry *) h)->is_gp || ((h->def_regular || h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) @@ -2108,8 +2124,10 @@ elf_x86_64_convert_load_reloc (bfd *abfd, asection *sec, set by an assignment in a linker script in bfd_elf_record_link_assignment. start_stop is set on __start_SECNAME/__stop_SECNAME which mark section - SECNAME. */ + SECNAME. is_gp is set on __gp symbol which will be + resolved to GP section and marked as hidden. */ if (h->start_stop + || ((struct elf_x86_64_link_hash_entry *) h)->is_gp || (h->def_regular && (h->root.type == bfd_link_hash_new || h->root.type == bfd_link_hash_undefined @@ -2453,18 +2471,26 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, if (isym == NULL) goto error_return; - /* Check relocation against local STT_GNU_IFUNC symbol. */ - if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) + /* Check relocation against local STT_GNU_IFUNC symbol and + GPREL relocation. */ + if (r_type == R_X86_64_GPREL + || ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) { h = elf_x86_64_get_local_sym_hash (htab, abfd, rel, TRUE); if (h == NULL) goto error_return; - /* Fake a STT_GNU_IFUNC symbol. */ - h->root.root.string = bfd_elf_sym_name (abfd, symtab_hdr, - isym, NULL); - h->type = STT_GNU_IFUNC; + if (r_type == R_X86_64_GPREL) + /* Prepare for GP section. */ + h->root.u.def.section + = bfd_section_from_elf_index (abfd, isym->st_shndx); + else + /* Fake a STT_GNU_IFUNC symbol. */ + h->root.root.string = bfd_elf_sym_name (abfd, symtab_hdr, + isym, NULL); + + h->type = ELF_ST_TYPE (isym->st_info); h->def_regular = 1; h->ref_regular = 1; h->forced_local = 1; @@ -2891,6 +2917,11 @@ do_size: goto error_return; break; + case R_X86_64_GPREL: + if (eh != NULL) + eh->has_gprel_reloc = 1; + break; + default: break; } @@ -3548,6 +3579,10 @@ elf_x86_64_allocate_local_dynrelocs (void **slot, void *inf) struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) *slot; + /* Skip local symbol with GPREL relocation. */ + if (((struct elf_x86_64_link_hash_entry *) h)->has_gprel_reloc) + return TRUE; + if (h->type != STT_GNU_IFUNC || !h->def_regular || !h->ref_regular @@ -5716,6 +5751,41 @@ direct: relocation -= elf_x86_64_dtpoff_base (info); break; + case R_X86_64_GPREL: + if (h == NULL || h->def_regular) + { + asection *def_sec; + + if (h != NULL) + def_sec = h->root.u.def.section; + else + def_sec = local_sections[r_symndx]; + + if (htab->gp->root.u.def.section + != def_sec->output_section) + { + if (h != NULL && h->root.root.string != NULL) + _bfd_error_handler + /* xgettext:c-format */ + (_("%B: symbol `%s' with GPREL relocation " + "defined in %B(%A) isn't in GP section `%A'"), + input_bfd, h->root.root.string, def_sec->owner, + def_sec, htab->gp->root.u.def.section); + else + _bfd_error_handler + /* xgettext:c-format */ + (_("%B: GPREL relocation at %#Lx in section " + "`%A' must be against symbol defined in GP " + "section `%A'"), + input_bfd, rel->r_offset, input_section, + htab->gp->root.u.def.section); + return FALSE; + } + relocation -= (htab->gp->root.u.def.section->vma + + htab->gp->root.u.def.value); + } + break; + default: break; } @@ -6225,8 +6295,12 @@ elf_x86_64_finish_local_dynamic_symbol (void **slot, void *inf) struct bfd_link_info *info = (struct bfd_link_info *) inf; + /* Skip local symbol with GPREL relocation. */ + if (((struct elf_x86_64_link_hash_entry *) h)->has_gprel_reloc) + return TRUE; + return elf_x86_64_finish_dynamic_symbol (info->output_bfd, - info, h, NULL); + info, h, NULL); } /* Finish up undefined weak symbol handling in PIE. Fill its PLT entry @@ -7332,6 +7406,7 @@ elf_x86_64_link_setup_gnu_properties (struct bfd_link_info *info) bfd_boolean use_ibt_plt; unsigned int plt_alignment, features; struct elf_x86_64_link_hash_table *htab; + struct elf_link_hash_entry *gp; bfd *pbfd; features = 0; @@ -7712,9 +7787,137 @@ error_alignment: goto error_alignment; } + /* Set is_gp for __gp symbol. */ + gp = elf_link_hash_lookup (elf_hash_table (info), "__gp", FALSE, + FALSE, FALSE); + if (gp != NULL) + { + ((struct elf_x86_64_link_hash_entry *) gp)->is_gp = 1; + htab->gp = gp; + } + return pbfd; } +/* Set up GP section from symbols with GPREL relocations. */ + +static bfd_boolean +elf_x86_64_setup_gp (struct elf_link_hash_entry *h, void * inf) +{ + struct bfd_link_info *info; + struct elf_x86_64_link_hash_table *htab; + struct elf_x86_64_link_hash_entry *eh; + struct elf_link_hash_entry *gp; + const struct elf_backend_data *bed; + asection *gpsection; + bfd_size_type gpsection_size; + + eh = (struct elf_x86_64_link_hash_entry *) h; + + /* Skip if there is no GPREL relocation or symbol is undefined. */ + if (!eh->has_gprel_reloc + || (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak)) + return TRUE; + + info = (struct bfd_link_info *) inf; + htab = elf_x86_64_hash_table (info); + if (htab == NULL) + return FALSE; + + gpsection = h->root.u.def.section->output_section; + gpsection_size = bfd_get_section_size (gpsection); + if (gpsection_size > 0xffffffff) + { + info->callbacks->einfo (_("%F%B: GP section `%A' size overflow\n"), + info->output_bfd, gpsection); + return FALSE; + } + + gp = htab->gp; + gp->def_regular = 1; + gp->root.type = bfd_link_hash_defined; + gp->root.u.def.value = gpsection_size / 2; + gp->root.u.def.section = gpsection; + gp->root.linker_def = 1; + gp->other = STV_HIDDEN; + bed = get_elf_backend_data (info->output_bfd); + bed->elf_backend_hide_symbol (info, gp, TRUE); + + return FALSE; +} + +/* Set up GP section from local symbols with GPREL relocations. */ + +static bfd_boolean +elf_x86_64_setup_gp_from_local_symbol (void **slot, void *inf) +{ + struct elf_link_hash_entry *h + = (struct elf_link_hash_entry *) *slot; + struct bfd_link_info *info + = (struct bfd_link_info *) inf; + + return elf_x86_64_setup_gp (h, info); +} + +/* Set up GP section for __gp symbol. */ + +static bfd_boolean +elf_x86_64_final_link (bfd *abfd, struct bfd_link_info *info) +{ + if (!bfd_link_relocatable (info)) + { + struct elf_link_hash_entry *gp; + struct elf_x86_64_link_hash_table *htab; + + htab = elf_x86_64_hash_table (info); + if (htab == NULL) + return FALSE; + + gp = htab->gp; + if (gp != NULL) + { + if (gp->root.type == bfd_link_hash_defined + || gp->root.type == bfd_link_hash_defweak) + { + /* Hide __gp. */ + const struct elf_backend_data *bed + = get_elf_backend_data (abfd); + gp->other = STV_HIDDEN; + bed->elf_backend_hide_symbol (info, gp, TRUE); + } + else + { + /* Set up __gp from a symbol with GPREL relocations. */ + elf_link_hash_traverse (&htab->elf, + elf_x86_64_setup_gp, + info); + + if (gp->root.type != bfd_link_hash_defined + && gp->root.type != bfd_link_hash_defweak) + { + /* Set up __gp from a local symbol with GPREL + relocations. */ + htab_traverse (htab->loc_hash_table, + elf_x86_64_setup_gp_from_local_symbol, + info); + } + + if (gp->root.type != bfd_link_hash_defined + && gp->root.type != bfd_link_hash_defweak) + { + info->callbacks->einfo (_("%F%B: undefined __gp symbol\n"), + info->output_bfd); + return FALSE; + } + } + } + } + + /* Invoke the regular ELF backend linker to do all the work. */ + return bfd_elf_final_link (abfd, info); +} + static const struct bfd_elf_special_section elf_x86_64_special_sections[]= { @@ -7779,6 +7982,7 @@ elf_x86_64_special_sections[]= #define elf_backend_object_p elf64_x86_64_elf_object_p #define bfd_elf64_mkobject elf_x86_64_mkobject #define bfd_elf64_get_synthetic_symtab elf_x86_64_get_synthetic_symtab +#define bfd_elf64_bfd_final_link elf_x86_64_final_link #define elf_backend_section_from_shdr \ elf_x86_64_section_from_shdr @@ -8078,6 +8282,8 @@ elf32_x86_64_nacl_elf_object_p (bfd *abfd) elf_x86_64_mkobject #define bfd_elf32_get_synthetic_symtab \ elf_x86_64_get_synthetic_symtab +#define bfd_elf32_bfd_final_link \ + elf_x86_64_final_link #undef elf_backend_object_p #define elf_backend_object_p \ diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 456be9e07cf..c15742b1c12 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -672,6 +672,9 @@ static enum rc_type evexrcig = rne; /* Pre-defined "_GLOBAL_OFFSET_TABLE_". */ static symbolS *GOT_symbol; +/* Pre-defined "__gp". */ +static symbolS *GP_symbol; + /* The dwarf2 return column, adjusted for 32 or 64 bit. */ unsigned int x86_dwarf2_return_column; @@ -7776,6 +7779,9 @@ lex_got (enum bfd_reloc_code_real *rel, { STRING_COMMA_LEN ("GOTPCREL"), { _dummy_first_bfd_reloc_code_real, BFD_RELOC_X86_64_GOTPCREL }, OPERAND_TYPE_IMM32_32S_DISP32 }, + { STRING_COMMA_LEN ("GPREL"), { _dummy_first_bfd_reloc_code_real, + BFD_RELOC_GPREL32 }, + OPERAND_TYPE_IMM32_32S_DISP32 }, { STRING_COMMA_LEN ("TLSGD"), { BFD_RELOC_386_TLS_GD, BFD_RELOC_X86_64_TLSGD }, OPERAND_TYPE_IMM32_32S_DISP32 }, @@ -7848,8 +7854,19 @@ lex_got (enum bfd_reloc_code_real *rel, *types = gotrel[j].types64; } - if (j != 0 && GOT_symbol == NULL) - GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME); + if (j != 0) + { + if (gotrel[j].rel[1] == BFD_RELOC_GPREL32) + { + if (GP_symbol == NULL) + GP_symbol = symbol_find_or_make (GLOBAL_POINTER_NAME); + } + else + { + if (GOT_symbol == NULL) + GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME); + } + } /* The length of the first part of our input line. */ first = cp - input_line_pointer; @@ -8506,6 +8523,11 @@ i386_displacement (char *disp_start, char *disp_end) if (gotfree_input_line) input_line_pointer = gotfree_input_line; + if (i.reloc[this_operand] == BFD_RELOC_GPREL32 + && (i.seg[0] == NULL + || i.types[this_operand].bitfield.baseindex)) + as_bad (_("invalid GP relocation")); + exp_seg = expression (exp); SKIP_WHITESPACE (); @@ -10740,6 +10762,21 @@ md_undefined_symbol (char *name) }; return GOT_symbol; } + else if (name[0] == GLOBAL_POINTER_NAME[0] + && name[1] == GLOBAL_POINTER_NAME[1] + && name[2] == GLOBAL_POINTER_NAME[2] + && name[3] == GLOBAL_POINTER_NAME[3] + && strcmp (name, GLOBAL_POINTER_NAME) == 0) + { + if (!GP_symbol) + { + if (symbol_find (name)) + as_bad (_("GP already in symbol table")); + GP_symbol = symbol_new (name, undefined_section, + (valueT) 0, &zero_address_frag); + }; + return GP_symbol; + } return 0; } @@ -10899,6 +10936,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) case BFD_RELOC_X86_64_PLTOFF64: case BFD_RELOC_X86_64_GOTPC32_TLSDESC: case BFD_RELOC_X86_64_TLSDESC_CALL: + case BFD_RELOC_GPREL32: case BFD_RELOC_RVA: case BFD_RELOC_VTABLE_ENTRY: case BFD_RELOC_VTABLE_INHERIT: diff --git a/gas/config/tc-i386.h b/gas/config/tc-i386.h index f54924c4382..beaa4614ddc 100644 --- a/gas/config/tc-i386.h +++ b/gas/config/tc-i386.h @@ -128,6 +128,12 @@ extern const char *i386_comment_chars; #define GLOBAL_OFFSET_TABLE_NAME "_GLOBAL_OFFSET_TABLE_" #endif +/* The name of the global pointer. Allow this to be overridden if need + be. */ +#ifndef GLOBAL_POINTER_NAME +#define GLOBAL_POINTER_NAME "__gp" +#endif + #if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) && !defined (LEX_AT) #define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) x86_cons (EXP, NBYTES) #endif diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp index 67a7a13b259..427a758b35a 100644 --- a/gas/testsuite/gas/i386/i386.exp +++ b/gas/testsuite/gas/i386/i386.exp @@ -868,6 +868,9 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_64_check]] t run_dump_test "x86-64-gotpcrel-no-relax" run_dump_test "x86-64-addend" + + run_dump_test "x86-64-gprel" + run_list_test "x86-64-inval-gprel" "-al" } set ASFLAGS "$old_ASFLAGS" diff --git a/gas/testsuite/gas/i386/x86-64-gprel.d b/gas/testsuite/gas/i386/x86-64-gprel.d new file mode 100644 index 00000000000..f70624ab42e --- /dev/null +++ b/gas/testsuite/gas/i386/x86-64-gprel.d @@ -0,0 +1,10 @@ +#objdump: -drw +#name: x86-64 gprel + +.*: +file format .* + +Disassembly of section .text: + +0+ <_start>: + +[a-f0-9]+: 65 8b 04 25 00 00 00 00 mov %gs:0x0,%eax 4: R_X86_64_GPREL foo +#pass diff --git a/gas/testsuite/gas/i386/x86-64-gprel.s b/gas/testsuite/gas/i386/x86-64-gprel.s new file mode 100644 index 00000000000..96b3ce90444 --- /dev/null +++ b/gas/testsuite/gas/i386/x86-64-gprel.s @@ -0,0 +1,3 @@ + .text +_start: + movl %gs:foo@GPREL, %eax diff --git a/gas/testsuite/gas/i386/x86-64-inval-gprel.l b/gas/testsuite/gas/i386/x86-64-inval-gprel.l new file mode 100644 index 00000000000..b6683b036d1 --- /dev/null +++ b/gas/testsuite/gas/i386/x86-64-inval-gprel.l @@ -0,0 +1,34 @@ +.*: Assembler messages: +.*:3: Error: invalid GP relocation +.*:3: Error: non-pc-relative relocation for pc-relative field +.*:4: Error: invalid GP relocation +.*:5: Error: invalid GP relocation +.*:6: Error: invalid GP relocation +.*:6: Error: non-pc-relative relocation for pc-relative field +.*:7: Error: invalid GP relocation +.*:8: Error: invalid GP relocation +GAS LISTING .* + + +[ ]*1[ ]+\.text +[ ]*2[ ]+_start: +[ ]*3[ ]+\?\?\?\? 648B0500 movl %fs:foo@GPREL\(%rip\), %eax +\*\*\*\* Error: invalid GP relocation +\*\*\*\* Error: non-pc-relative relocation for pc-relative field +[ ]*3[ ]+000000 +[ ]*4[ ]+\?\?\?\? 648B8000 movl %fs:foo@GPREL\(%rax\), %eax +\*\*\*\* Error: invalid GP relocation +[ ]*4[ ]+000000 +[ ]*5[ ]+\?\?\?\? 8B844800 movl %ds:foo@GPREL\(%rax, %rcx, 2\), %eax +\*\*\*\* Error: invalid GP relocation +[ ]*5[ ]+000000 +[ ]*6[ ]+\?\?\?\? 8B050000 movl foo@GPREL\(%rip\), %eax +\*\*\*\* Error: invalid GP relocation +\*\*\*\* Error: non-pc-relative relocation for pc-relative field +[ ]*6[ ]+0000 +[ ]*7[ ]+\?\?\?\? 8B800000 movl foo@GPREL\(%rax\), %eax +\*\*\*\* Error: invalid GP relocation +[ ]*7[ ]+0000 +[ ]*8[ ]+\?\?\?\? 8B042500 movl foo@GPREL, %eax +\*\*\*\* Error: invalid GP relocation +[ ]*8[ ]+000000 diff --git a/gas/testsuite/gas/i386/x86-64-inval-gprel.s b/gas/testsuite/gas/i386/x86-64-inval-gprel.s new file mode 100644 index 00000000000..8507926860d --- /dev/null +++ b/gas/testsuite/gas/i386/x86-64-inval-gprel.s @@ -0,0 +1,8 @@ + .text +_start: + movl %fs:foo@GPREL(%rip), %eax + movl %fs:foo@GPREL(%rax), %eax + movl %ds:foo@GPREL(%rax, %rcx, 2), %eax + movl foo@GPREL(%rip), %eax + movl foo@GPREL(%rax), %eax + movl foo@GPREL, %eax diff --git a/include/elf/x86-64.h b/include/elf/x86-64.h index 976f4fe347b..f9697ebd009 100644 --- a/include/elf/x86-64.h +++ b/include/elf/x86-64.h @@ -82,6 +82,8 @@ START_RELOC_NUMBERS (elf_x86_64_reloc_type) /* Load from 32 bit signed pc relative offset to GOT entry with REX prefix, relaxable. */ RELOC_NUMBER (R_X86_64_REX_GOTPCRELX, 42) + RELOC_NUMBER (R_X86_64_GPREL, 43) /* 32 bit signed pc relative + offset to GP */ 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/gprel-1a.S b/ld/testsuite/ld-x86-64/gprel-1a.S new file mode 100644 index 00000000000..db099abb6a7 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gprel-1a.S @@ -0,0 +1,15 @@ + .text + .globl get_foo +get_foo: + movl %gs:foo@GPREL, %eax + ret + + .data + .globl foo_gprel +foo_gprel: + .long foo@GPREL + + .data + .globl foo +foo: + .long 0x12345678 diff --git a/ld/testsuite/ld-x86-64/gprel-1b.c b/ld/testsuite/ld-x86-64/gprel-1b.c new file mode 100644 index 00000000000..97d3b553b95 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gprel-1b.c @@ -0,0 +1,32 @@ +#include <stdio.h> +#include <syscall.h> +#include <asm/prctl.h> + +extern int foo; +extern int __gp; +extern int foo_gprel; +extern int get_foo (void); + +int +setup_gp (void *p) +{ + int result; + asm volatile ("syscall" + : "=a" (result) + : "0" ((unsigned long int) SYS_arch_prctl), + "D" ((unsigned long int) ARCH_SET_GS), + "S" (p) + : "memory", "cc", "r11", "cx"); + return result; +} + +int +main () +{ + setup_gp (&__gp); + if (foo == 0x12345678 + && *(int *) ((char *) &__gp + foo_gprel) == 0x12345678 + && get_foo () == 0x12345678) + printf ("PASS\n"); + return 0; +} diff --git a/ld/testsuite/ld-x86-64/gprel-2a.S b/ld/testsuite/ld-x86-64/gprel-2a.S new file mode 100644 index 00000000000..99165e5b6a4 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gprel-2a.S @@ -0,0 +1,14 @@ + .text + .globl get_foo +get_foo: + movl %gs:foo@GPREL, %eax + ret + + .data + .globl foo_gprel +foo_gprel: + .long foo@GPREL + + .data +foo: + .long 0x12345678 diff --git a/ld/testsuite/ld-x86-64/gprel-2b.c b/ld/testsuite/ld-x86-64/gprel-2b.c new file mode 100644 index 00000000000..3b53fad432c --- /dev/null +++ b/ld/testsuite/ld-x86-64/gprel-2b.c @@ -0,0 +1,30 @@ +#include <stdio.h> +#include <syscall.h> +#include <asm/prctl.h> + +extern int __gp; +extern int foo_gprel; +extern int get_foo (void); + +int +setup_gp (void *p) +{ + int result; + asm volatile ("syscall" + : "=a" (result) + : "0" ((unsigned long int) SYS_arch_prctl), + "D" ((unsigned long int) ARCH_SET_GS), + "S" (p) + : "memory", "cc", "r11", "cx"); + return result; +} + +int +main () +{ + setup_gp (&__gp); + if (*(int *) ((char *) &__gp + foo_gprel) == 0x12345678 + && get_foo () == 0x12345678) + printf ("PASS\n"); + return 0; +} diff --git a/ld/testsuite/ld-x86-64/gprel-3.d b/ld/testsuite/ld-x86-64/gprel-3.d new file mode 100644 index 00000000000..c870a95ad7f --- /dev/null +++ b/ld/testsuite/ld-x86-64/gprel-3.d @@ -0,0 +1,3 @@ +#as: --64 +#ld: -melf_x86_64 +#error: undefined __gp symbol diff --git a/ld/testsuite/ld-x86-64/gprel-3.s b/ld/testsuite/ld-x86-64/gprel-3.s new file mode 100644 index 00000000000..ba79246fda8 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gprel-3.s @@ -0,0 +1,4 @@ + .text + .globl _start +_start: + movl %gs:foo@GPREL, %eax diff --git a/ld/testsuite/ld-x86-64/gprel-4.d b/ld/testsuite/ld-x86-64/gprel-4.d new file mode 100644 index 00000000000..024e06634e1 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gprel-4.d @@ -0,0 +1,3 @@ +#as: --64 +#ld: -melf_x86_64 +#error: GPREL relocation at 0x4 in section `\.text' must be against symbol defined in GP section `\.rodata' diff --git a/ld/testsuite/ld-x86-64/gprel-4.s b/ld/testsuite/ld-x86-64/gprel-4.s new file mode 100644 index 00000000000..a0a89ba0cd9 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gprel-4.s @@ -0,0 +1,17 @@ + .text + .globl _start +_start: + movl %gs:foo@GPREL, %eax + + .data + .globl bar_gprel +bar_gprel: + .long bar@GPREL + +foo: + .long 0x12345678 + + .section .rodata,"a",@progbits +bar: + .long 0x12345678 + diff --git a/ld/testsuite/ld-x86-64/gprel-5.d b/ld/testsuite/ld-x86-64/gprel-5.d new file mode 100644 index 00000000000..3186c346b4e --- /dev/null +++ b/ld/testsuite/ld-x86-64/gprel-5.d @@ -0,0 +1,3 @@ +#as: --64 +#ld: -melf_x86_64 +#error: symbol `bar' with GPREL relocation defined in .*\.o\(\.rodata\) isn't in GP section `\.data' diff --git a/ld/testsuite/ld-x86-64/gprel-5.s b/ld/testsuite/ld-x86-64/gprel-5.s new file mode 100644 index 00000000000..a49adec8dab --- /dev/null +++ b/ld/testsuite/ld-x86-64/gprel-5.s @@ -0,0 +1,19 @@ + .text + .globl _start +_start: + movl %gs:foo@GPREL, %eax + + .data + .globl bar_gprel +bar_gprel: + .long bar@GPREL + + .globl foo +foo: + .long 0x12345678 + + .section .rodata,"a",@progbits + .globl bar +bar: + .long 0x12345678 + diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp index c5825822978..8f6f0a40384 100644 --- a/ld/testsuite/ld-x86-64/x86-64.exp +++ b/ld/testsuite/ld-x86-64/x86-64.exp @@ -567,6 +567,9 @@ run_dump_test "pr20253-4f" run_dump_test "pr20253-5a" run_dump_test "pr20253-5b" run_dump_test "tlsdesc2" +run_dump_test "gprel-3" +run_dump_test "gprel-4" +run_dump_test "gprel-5" proc undefined_weak {cflags ldflags} { set testname "Undefined weak symbol" @@ -1571,6 +1574,51 @@ run_ld_link_tests [list \ ] \ ] +run_ld_link_exec_tests [list \ + [list \ + "Run GPREL 1" \ + "" \ + "" \ + {gprel-1a.S gprel-1b.c} \ + "gprel-1" "pass.out" \ + ] \ + [list \ + "Run GPREL 1 (PIE)" \ + "-pie" \ + "" \ + {gprel-1a.S gprel-1b.c} \ + "gprel-1-pie" "pass.out" "-fPIE" \ + ] \ + [list \ + "Run GPREL 1 (static)" \ + "-static" \ + "" \ + {gprel-1a.S gprel-1b.c} \ + "gprel-1-static" "pass.out" \ + ] \ + [list \ + "Run GPREL 2" \ + "" \ + "" \ + {gprel-2a.S gprel-2b.c} \ + "gprel-2" "pass.out" \ + ] \ + [list \ + "Run GPREL 2 (PIE)" \ + "-pie" \ + "" \ + {gprel-2a.S gprel-2b.c} \ + "gprel-2-pie" "pass.out" "-fPIE" \ + ] \ + [list \ + "Run GPREL 2 (static)" \ + "-static" \ + "" \ + {gprel-2a.S gprel-2b.c} \ + "gprel-2-static" "pass.out" \ + ] \ +] + # Linux only tests run_dump_test "pr17618" run_dump_test "pltgot-1" |