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-10-14 11:49:36 -0700 |
commit | c3d646723ce1b7d68270ae2b0f8163a9be434576 (patch) | |
tree | 4fcc568f0d2aeb66d5d1d7faf6d09b850694bebf | |
parent | 851b6fa13707d187e068c8773f21d376391387a9 (diff) | |
download | binutils-gdb-users/hjl/gpoff/master.tar.gz |
x86: Add R_X86_64_GPOFF/R_386_GPOFF relocationusers/hjl/gpoff/master
On x86, a segment register is used as thread pointer to access thread
local storage (TLS) with __thread. TLS is an OS-dependent, user-space
feature.
Here is a proposal to add R_X86_64_GPOFF/R_386_GPOFF relocation to
access symbol with an offset to global pointer, __gp. The assembly
syntax is
1. Load value of foo relative to __gp, pointed by %seg, into %reg:
op %seg:foo@GPOFF, %reg
2. Store value in %reg to foo relative to __gp, pointed by %seg:
op %reg, %seg:foo@GPOFF
3. Compute offset of foo to __gp:
lea foo@GPOFF, %reg
.long foo@GPOFF
Linker sets __gp to the middle of the section which contains definitions
of symbols with GPOFF relocations and the maximum offset is [-2G, 2G).
Run-time must initialize the segment register, %seg, with the address of
global pointer, __gp.
bfd/
* elf32-i386.c (elf_howto_table): Add R_386_GPOFF.
(R_386_ext2): Replace R_386_GOT32X with R_386_GPOFF.
(elf_i386_reloc_type_lookup): Support BFD_RELOC_GPREL32.
(elf_i386_check_relocs): Add a fake local symbol and set
has_gpoff_reloc for GPOFF relocation.
(elf_i386_allocate_local_dynrelocs): Skip local symbol with
GPOFF relocation.
(elf_i386_finish_local_dynamic_symbol): Likewise.
(elf_i386_relocate_section): Process GPOFF relocation.
* elf64-x86-64.c (elf_howto_table): Add R_X86_64_GPOFF.
(R_X86_64_standard): Replace R_X86_64_REX_GOTPCRELX with
R_X86_64_GPOFF.
(x86_64_reloc_map): Add BFD_RELOC_GPREL32.
(elf_x86_64_check_relocs): Add a fake local symbol and set
has_gpoff_reloc for GPOFF relocation.
(elf_x86_64_allocate_local_dynrelocs): Skip local symbol with
GPOFF relocation.
(elf_x86_64_finish_local_dynamic_symbol): Likewise.
(elf_x86_64_relocate_section): Process GPOFF relocation.
* elfxx-x86.c (_bfd_x86_elf_link_check_relocs): Cache and hide
__gp symbol.
(_bfd_x86_elf_copy_indirect_symbol): Also copy has_gpoff_reloc.
(elf_x86_setup_gp): New function.
(elf_x86_setup_gp_from_local_symbol): Likewise.
(_bfd_x86_elf_final_link): Likewise.
* elfxx-x86.h (elf_x86_link_hash_entry): Add has_gpoff_reloc.
(elf_x86_link_hash_table): Add gp.
(_bfd_x86_elf_final_link): New.
(bfd_elf64_bfd_final_link): Likewise.
(bfd_elf32_bfd_final_link): Likewise.
gas/
* config/tc-i386.c (GP_symbol): New.
(gotrel): Add "GPOFF".
(lex_got): Support BFD_RELOC_GPREL32.
(i386_displacement): Disallow BFD_RELOC_GPREL32 relocation
with base or index registers.
(md_undefined_symbol): Create GP_symbol if needed.
(tc_gen_reloc): Handle BFD_RELOC_GPREL32.
* config/tc-i386.h (GLOBAL_POINTER_NAME): New.
* testsuite/gas/i386/gpoff.d: New file.
* testsuite/gas/i386/gpoff.s: Likewise.
* testsuite/gas/i386/inval-gpoff.l: Likewise.
* testsuite/gas/i386/inval-gpoff.s: Likewise.
* testsuite/gas/i386/x86-64-gpoff.d: Likewise.
* testsuite/gas/i386/x86-64-gpoff.s: Likewise.
* testsuite/gas/i386/x86-64-inval-gpoff.l: Likewise.
* testsuite/gas/i386/x86-64-inval-gpoff.s: Likewise.
* testsuite/gas/i386/i386.exp: Run gpoff, inval-gpoff,
x86-64-gpoff and x86-64-inval-gpoff.
include/
* elf/i386.h (R_386_GPOFF): New relocation.
* elf/x86-64.h (R_X86_64_GPOFF): Likewise.
ld/
* testsuite/ld-i386/gpoff-1a.S: New file.
* testsuite/ld-i386/gpoff-1b.c: Likewise.
* testsuite/ld-i386/gpoff-2a.S: Likewise.
* testsuite/ld-i386/gpoff-2b.c: Likewise.
* testsuite/ld-i386/gpoff-3.d: Likewise.
* testsuite/ld-i386/gpoff-3.s: Likewise.
* testsuite/ld-i386/gpoff-4.d: Likewise.
* testsuite/ld-i386/gpoff-4.s: Likewise.
* testsuite/ld-i386/gpoff-5.d: Likewise.
* testsuite/ld-i386/gpoff-5.s: Likewise.
* testsuite/ld-i386/gpoff-6.d: Likewise.
* testsuite/ld-i386/gpoff-6.s: Likewise.
* testsuite/ld-i386/gpoff-7.d: Likewise.
* testsuite/ld-i386/gpoff-7.s: Likewise.
* testsuite/ld-i386/gpoff-8.s: Likewise.
* testsuite/ld-i386/gpoff-8.t: Likewise.
* testsuite/ld-i386/gpoff-8a.d: Likewise.
* testsuite/ld-i386/gpoff-8b.d: Likewise.
* testsuite/ld-i386/gpoff-8c.d: Likewise.
* testsuite/ld-i386/gpoff-8d.d: Likewise.
* testsuite/ld-i386/gpoff-8e.d: Likewise.
* testsuite/ld-i386/gpoff-8f.d: Likewise.
* testsuite/ld-x86-64/gpoff-1a.S: Likewise.
* testsuite/ld-x86-64/gpoff-1b.c: Likewise.
* testsuite/ld-x86-64/gpoff-2a.S: Likewise.
* testsuite/ld-x86-64/gpoff-2b.c: Likewise.
* testsuite/ld-x86-64/gpoff-3.d: Likewise.
* testsuite/ld-x86-64/gpoff-3.s: Likewise.
* testsuite/ld-x86-64/gpoff-4.d: Likewise.
* testsuite/ld-x86-64/gpoff-4.s: Likewise.
* testsuite/ld-x86-64/gpoff-5.d: Likewise.
* testsuite/ld-x86-64/gpoff-5.s: Likewise.
* testsuite/ld-x86-64/gpoff-6.d: Likewise.
* testsuite/ld-x86-64/gpoff-6.s: Likewise.
* testsuite/ld-x86-64/gpoff-7.d: Likewise.
* testsuite/ld-x86-64/gpoff-7.s: Likewise.
* testsuite/ld-x86-64/gpoff-8.s: Likewise.
* testsuite/ld-x86-64/gpoff-8.t: Likewise.
* testsuite/ld-x86-64/gpoff-8a.d: Likewise.
* testsuite/ld-x86-64/gpoff-8b.d: Likewise.
* testsuite/ld-x86-64/gpoff-8c.d: Likewise.
* testsuite/ld-x86-64/gpoff-8d.d: Likewise.
* testsuite/ld-x86-64/gpoff-8e.d: Likewise.
* testsuite/ld-x86-64/gpoff-8f.d: Likewise.
* testsuite/ld-i386/i386.exp: Run R_386_GPOFF tests.
* testsuite/ld-x86-64/x86-64.exp: Run R_X86_64_GPOFF tests.
63 files changed, 1338 insertions, 16 deletions
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 4b57b652ed5..889fa235b48 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -143,9 +143,12 @@ static reloc_howto_type elf_howto_table[]= HOWTO(R_386_GOT32X, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_GOT32X", TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_GPOFF, 0, 2, 32, FALSE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_386_GPOFF", + TRUE, 0xffffffff, 0xffffffff, FALSE), /* Another gap. */ -#define R_386_ext2 (R_386_GOT32X + 1 - R_386_tls_offset) +#define R_386_ext2 (R_386_GPOFF + 1 - R_386_tls_offset) #define R_386_vt_offset (R_386_GNU_VTINHERIT - R_386_ext2) /* GNU extension to record C++ vtable hierarchy. */ @@ -337,6 +340,10 @@ elf_i386_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, TRACE ("BFD_RELOC_386_GOT32X"); return &elf_howto_table[R_386_GOT32X - R_386_tls_offset]; + case BFD_RELOC_GPREL32: + TRACE ("BFD_RELOC_GPREL32"); + return &elf_howto_table[R_386_GPOFF - R_386_tls_offset]; + case BFD_RELOC_VTABLE_INHERIT: TRACE ("BFD_RELOC_VTABLE_INHERIT"); return &elf_howto_table[R_386_GNU_VTINHERIT - R_386_vt_offset]; @@ -1520,17 +1527,26 @@ elf_i386_check_relocs (bfd *abfd, if (isym == NULL) goto error_return; - /* Check relocation against local STT_GNU_IFUNC symbol. */ - if (ELF32_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) + /* Check relocation against local STT_GNU_IFUNC symbol and + GPOFF relocation. */ + if (r_type == R_386_GPOFF + || ELF32_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) { h = _bfd_elf_x86_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_386_GPOFF) + /* 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; @@ -1879,6 +1895,11 @@ do_size: goto error_return; break; + case R_386_GPOFF: + if (eh != NULL) + eh->has_gpoff_reloc = 1; + break; + default: break; } @@ -3411,6 +3432,41 @@ disallow_got32: relocation = -elf_i386_tpoff (info, relocation); break; + case R_386_GPOFF: + 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 GPOFF 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: GPOFF 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; } @@ -3914,6 +3970,10 @@ elf_i386_finish_local_dynamic_symbol (void **slot, void *inf) struct bfd_link_info *info = (struct bfd_link_info *) inf; + /* Skip local symbol with GPOFF relocation. */ + if (((struct elf_x86_link_hash_entry *) h)->has_gpoff_reloc) + return TRUE; + return elf_i386_finish_dynamic_symbol (info->output_bfd, info, h, NULL); } diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index 6a5159d4b0c..30958c85511 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -173,12 +173,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_GPOFF, 0, 2, 32, FALSE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_GPOFF", + 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_GPOFF + 1) #define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard) /* GNU extension to record C++ vtable hierarchy. */ @@ -260,6 +263,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_GPOFF, }, { BFD_RELOC_VTABLE_INHERIT, R_X86_64_GNU_VTINHERIT, }, { BFD_RELOC_VTABLE_ENTRY, R_X86_64_GNU_VTENTRY, }, }; @@ -1833,18 +1837,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 + GPOFF relocation. */ + if (r_type == R_X86_64_GPOFF + || ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) { h = _bfd_elf_x86_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_GPOFF) + /* 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; @@ -2250,6 +2262,11 @@ do_size: goto error_return; break; + case R_X86_64_GPOFF: + if (eh != NULL) + eh->has_gpoff_reloc = 1; + break; + default: break; } @@ -3755,6 +3772,41 @@ direct: relocation -= _bfd_x86_elf_dtpoff_base (info); break; + case R_X86_64_GPOFF: + 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 GPOFF 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: GPOFF 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; } @@ -4263,6 +4315,10 @@ 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 GPOFF relocation. */ + if (((struct elf_x86_link_hash_entry *) h)->has_gpoff_reloc) + return TRUE; + return elf_x86_64_finish_dynamic_symbol (info->output_bfd, info, h, NULL); } diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c index f4466ebd592..f2eb978fa19 100644 --- a/bfd/elfxx-x86.c +++ b/bfd/elfxx-x86.c @@ -579,6 +579,10 @@ elf_x86_allocate_local_dynreloc (void **slot, void *inf) struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) *slot; + /* Skip local symbol with GPOFF relocation. */ + if (((struct elf_x86_link_hash_entry *) h)->has_gpoff_reloc) + return TRUE; + if (h->type != STT_GNU_IFUNC || !h->def_regular || !h->ref_regular @@ -865,6 +869,21 @@ _bfd_x86_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info) elf_x86_hash_entry (h)->local_ref = 2; elf_x86_hash_entry (h)->linker_def = 1; } + + /* Cache and hide __gp symbol. */ + h = elf_link_hash_lookup (elf_hash_table (info), "__gp", FALSE, + FALSE, FALSE); + if (h != NULL) + { + htab->gp = h; + /* It should be defined by elf_x86_64_setup_gp later. */ + if (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak) + h->def_regular = 1; + h->other = STV_HIDDEN; + bed = get_elf_backend_data (info->output_bfd); + bed->elf_backend_hide_symbol (info, h, TRUE); + } } } @@ -1627,6 +1646,7 @@ _bfd_x86_elf_copy_indirect_symbol (struct bfd_link_info *info, edir->gotoff_ref |= eind->gotoff_ref; edir->zero_undefweak |= eind->zero_undefweak; + edir->has_gpoff_reloc |= eind->has_gpoff_reloc; if (ELIMINATE_COPY_RELOCS && ind->root.type != bfd_link_hash_indirect @@ -2750,3 +2770,102 @@ error_alignment: return pbfd; } + +/* Set up GP section from symbols with GPOFF relocations. */ + +static bfd_boolean +elf_x86_setup_gp (struct elf_link_hash_entry *h, void * inf) +{ + struct bfd_link_info *info; + struct elf_x86_link_hash_table *htab; + struct elf_x86_link_hash_entry *eh; + struct elf_link_hash_entry *gp; + asection *gpsection; + bfd_size_type gpsection_size; + const struct elf_backend_data *bed; + + eh = (struct elf_x86_link_hash_entry *) h; + + /* Skip if there is no GPOFF relocation or symbol is undefined. */ + if (!eh->has_gpoff_reloc + || (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak)) + return TRUE; + + info = (struct bfd_link_info *) inf; + bed = get_elf_backend_data (info->output_bfd); + htab = elf_x86_hash_table (info, bed->target_id); + if (htab == NULL) + return FALSE; + + gpsection = h->root.u.def.section->output_section; + gpsection_size = bfd_get_section_size (gpsection); + + if (bed->target_id == X86_64_ELF_DATA && gpsection_size > 0xffffffff) + { + info->callbacks->einfo (_("%F%B: GP section `%A' size overflow\n"), + info->output_bfd, gpsection); + return FALSE; + } + + gp = htab->gp; + 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; + + /* Found GP section. No need to continue. */ + return FALSE; +} + +/* Set up GP section from local symbols with GPOFF relocations. */ + +static bfd_boolean +elf_x86_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_setup_gp (h, info); +} + +/* Set up GP section for __gp symbol. */ + +bfd_boolean +_bfd_x86_elf_final_link (bfd *abfd, struct bfd_link_info *info) +{ + if (!bfd_link_relocatable (info)) + { + struct elf_link_hash_entry *gp; + struct elf_x86_link_hash_table *htab; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + + htab = elf_x86_hash_table (info, bed->target_id); + if (htab == NULL) + return FALSE; + + gp = htab->gp; + if (gp != NULL + && gp->root.type != bfd_link_hash_defined + && gp->root.type != bfd_link_hash_defweak) + { + /* Set up __gp from a symbol with GPOFF relocations. */ + elf_link_hash_traverse (&htab->elf, elf_x86_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 GPOFF + relocations. */ + htab_traverse (htab->loc_hash_table, + elf_x86_setup_gp_from_local_symbol, + info); + } + } + } + + /* Invoke the regular ELF backend linker to do all the work. */ + return bfd_elf_final_link (abfd, info); +} diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h index 8d2a7317eb3..a1bc3021b66 100644 --- a/bfd/elfxx-x86.h +++ b/bfd/elfxx-x86.h @@ -238,6 +238,9 @@ struct elf_x86_link_hash_entry should be resolved to 0 if zero_undefweak > 0. */ unsigned int zero_undefweak : 2; + /* TRUE if symbol has GPOFF relocations. */ + unsigned int has_gpoff_reloc : 1; + /* Don't call finish_dynamic_symbol on this symbol. */ unsigned int no_finish_dynamic_symbol : 1; @@ -433,6 +436,9 @@ struct elf_x86_link_hash_table /* Parameters describing non-lazy PLT generation. */ const struct elf_x86_non_lazy_plt_layout *non_lazy_plt; + /* Cache __gp symbol. */ + struct elf_link_hash_entry *gp; + union { bfd_signed_vma refcount; @@ -663,6 +669,9 @@ extern bfd_boolean _bfd_x86_elf_merge_gnu_properties extern bfd * _bfd_x86_elf_link_setup_gnu_properties (struct bfd_link_info *, struct elf_x86_init_table *); +extern bfd_boolean _bfd_x86_elf_final_link + (bfd *, struct bfd_link_info *); + #define bfd_elf64_mkobject \ _bfd_x86_elf_mkobject #define bfd_elf32_mkobject \ @@ -675,6 +684,10 @@ extern bfd * _bfd_x86_elf_link_setup_gnu_properties _bfd_x86_elf_link_check_relocs #define bfd_elf32_bfd_link_check_relocs \ _bfd_x86_elf_link_check_relocs +#define bfd_elf64_bfd_final_link \ + _bfd_x86_elf_final_link +#define bfd_elf32_bfd_final_link \ + _bfd_x86_elf_final_link #define elf_backend_size_dynamic_sections \ _bfd_x86_elf_size_dynamic_sections diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index fdff30153dd..68aad374fbb 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -669,6 +669,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; @@ -7755,6 +7758,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 ("GPOFF"), { BFD_RELOC_GPREL32, + 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 }, @@ -7827,8 +7833,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; @@ -8485,6 +8502,10 @@ 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.types[this_operand].bitfield.baseindex) + as_bad (_("invalid GPOFF relocation")); + exp_seg = expression (exp); SKIP_WHITESPACE (); @@ -10719,6 +10740,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; } @@ -10878,6 +10914,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/gpoff.d b/gas/testsuite/gas/i386/gpoff.d new file mode 100644 index 00000000000..6a16ba49a7f --- /dev/null +++ b/gas/testsuite/gas/i386/gpoff.d @@ -0,0 +1,11 @@ +#objdump: -drw +#name: i386 gpoff + +.*: +file format .* + +Disassembly of section .text: + +0+ <_start>: + +[a-f0-9]+: 8d 05 00 00 00 00 lea 0x0,%eax 2: R_386_GPOFF foo + +[a-f0-9]+: 64 a1 00 00 00 00 mov %fs:0x0,%eax 8: R_386_GPOFF foo +#pass diff --git a/gas/testsuite/gas/i386/gpoff.s b/gas/testsuite/gas/i386/gpoff.s new file mode 100644 index 00000000000..4b786a24721 --- /dev/null +++ b/gas/testsuite/gas/i386/gpoff.s @@ -0,0 +1,4 @@ + .text +_start: + leal foo@GPOFF, %eax + movl %fs:foo@GPOFF, %eax diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp index 67a7a13b259..542749d57b9 100644 --- a/gas/testsuite/gas/i386/i386.exp +++ b/gas/testsuite/gas/i386/i386.exp @@ -455,6 +455,9 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_32_check]] run_dump_test "addend" + run_dump_test "gpoff" + run_list_test "inval-gpoff" "-al" + if {![istarget "*-*-nacl*"]} then { run_dump_test "iamcu-1" run_dump_test "iamcu-2" @@ -868,6 +871,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-gpoff" + run_list_test "x86-64-inval-gpoff" "-al" } set ASFLAGS "$old_ASFLAGS" diff --git a/gas/testsuite/gas/i386/inval-gpoff.l b/gas/testsuite/gas/i386/inval-gpoff.l new file mode 100644 index 00000000000..3fad845e697 --- /dev/null +++ b/gas/testsuite/gas/i386/inval-gpoff.l @@ -0,0 +1,18 @@ +.*: Assembler messages: +.*:3: Error: invalid GPOFF relocation +.*:4: Error: invalid GPOFF relocation +.*:5: Error: invalid GPOFF relocation +GAS LISTING .* + + +[ ]*1[ ]+\.text +[ ]*2[ ]+_start: +[ ]*3[ ]+\?\?\?\? 648B8000 movl %fs:foo@GPOFF\(%eax\), %eax +\*\*\*\* Error: invalid GPOFF relocation +[ ]*3[ ]+000000 +[ ]*4[ ]+\?\?\?\? 8B844800 movl %ds:foo@GPOFF\(%eax, %ecx, 2\), %eax +\*\*\*\* Error: invalid GPOFF relocation +[ ]*4[ ]+000000 +[ ]*5[ ]+\?\?\?\? 8B800000 movl foo@GPOFF\(%eax\), %eax +\*\*\*\* Error: invalid GPOFF relocation +[ ]*5[ ]+0000 diff --git a/gas/testsuite/gas/i386/inval-gpoff.s b/gas/testsuite/gas/i386/inval-gpoff.s new file mode 100644 index 00000000000..7556de3518e --- /dev/null +++ b/gas/testsuite/gas/i386/inval-gpoff.s @@ -0,0 +1,5 @@ + .text +_start: + movl %fs:foo@GPOFF(%eax), %eax + movl %ds:foo@GPOFF(%eax, %ecx, 2), %eax + movl foo@GPOFF(%eax), %eax diff --git a/gas/testsuite/gas/i386/x86-64-gpoff.d b/gas/testsuite/gas/i386/x86-64-gpoff.d new file mode 100644 index 00000000000..2d5e8bd870c --- /dev/null +++ b/gas/testsuite/gas/i386/x86-64-gpoff.d @@ -0,0 +1,11 @@ +#objdump: -drw +#name: x86-64 gpoff + +.*: +file format .* + +Disassembly of section .text: + +0+ <_start>: + +[a-f0-9]+: 8d 04 25 00 00 00 00 lea 0x0,%eax 3: R_X86_64_GPOFF foo + +[a-f0-9]+: 65 8b 04 25 00 00 00 00 mov %gs:0x0,%eax b: R_X86_64_GPOFF foo +#pass diff --git a/gas/testsuite/gas/i386/x86-64-gpoff.s b/gas/testsuite/gas/i386/x86-64-gpoff.s new file mode 100644 index 00000000000..ccd743506b0 --- /dev/null +++ b/gas/testsuite/gas/i386/x86-64-gpoff.s @@ -0,0 +1,4 @@ + .text +_start: + leal foo@GPOFF, %eax + movl %gs:foo@GPOFF, %eax diff --git a/gas/testsuite/gas/i386/x86-64-inval-gpoff.l b/gas/testsuite/gas/i386/x86-64-inval-gpoff.l new file mode 100644 index 00000000000..e64a8bde1ee --- /dev/null +++ b/gas/testsuite/gas/i386/x86-64-inval-gpoff.l @@ -0,0 +1,30 @@ +.*: Assembler messages: +.*:3: Error: invalid GPOFF relocation +.*:3: Error: non-pc-relative relocation for pc-relative field +.*:4: Error: invalid GPOFF relocation +.*:5: Error: invalid GPOFF relocation +.*:6: Error: invalid GPOFF relocation +.*:6: Error: non-pc-relative relocation for pc-relative field +.*:7: Error: invalid GPOFF relocation +GAS LISTING .* + + +[ ]*1[ ]+\.text +[ ]*2[ ]+_start: +[ ]*3[ ]+\?\?\?\? 648B0500 movl %fs:foo@GPOFF\(%rip\), %eax +\*\*\*\* Error: invalid GPOFF relocation +\*\*\*\* Error: non-pc-relative relocation for pc-relative field +[ ]*3[ ]+000000 +[ ]*4[ ]+\?\?\?\? 648B8000 movl %fs:foo@GPOFF\(%rax\), %eax +\*\*\*\* Error: invalid GPOFF relocation +[ ]*4[ ]+000000 +[ ]*5[ ]+\?\?\?\? 8B844800 movl %ds:foo@GPOFF\(%rax, %rcx, 2\), %eax +\*\*\*\* Error: invalid GPOFF relocation +[ ]*5[ ]+000000 +[ ]*6[ ]+\?\?\?\? 8B050000 movl foo@GPOFF\(%rip\), %eax +\*\*\*\* Error: invalid GPOFF relocation +\*\*\*\* Error: non-pc-relative relocation for pc-relative field +[ ]*6[ ]+0000 +[ ]*7[ ]+\?\?\?\? 8B800000 movl foo@GPOFF\(%rax\), %eax +\*\*\*\* Error: invalid GPOFF relocation +[ ]*7[ ]+0000 diff --git a/gas/testsuite/gas/i386/x86-64-inval-gpoff.s b/gas/testsuite/gas/i386/x86-64-inval-gpoff.s new file mode 100644 index 00000000000..8aacbf84807 --- /dev/null +++ b/gas/testsuite/gas/i386/x86-64-inval-gpoff.s @@ -0,0 +1,7 @@ + .text +_start: + movl %fs:foo@GPOFF(%rip), %eax + movl %fs:foo@GPOFF(%rax), %eax + movl %ds:foo@GPOFF(%rax, %rcx, 2), %eax + movl foo@GPOFF(%rip), %eax + movl foo@GPOFF(%rax), %eax diff --git a/include/elf/i386.h b/include/elf/i386.h index 352e744f233..97a7e8bcc51 100644 --- a/include/elf/i386.h +++ b/include/elf/i386.h @@ -68,6 +68,7 @@ START_RELOC_NUMBERS (elf_i386_reloc_type) RELOC_NUMBER (R_386_IRELATIVE, 42) /* Adjust indirectly by program base */ /* Load from 32 bit GOT entry, relaxable. */ RELOC_NUMBER (R_386_GOT32X, 43) + RELOC_NUMBER (R_386_GPOFF, 44) /* 32 bit offset to __gp */ /* Used by Intel. */ RELOC_NUMBER (R_386_USED_BY_INTEL_200, 200) diff --git a/include/elf/x86-64.h b/include/elf/x86-64.h index 976f4fe347b..280ab7819dc 100644 --- a/include/elf/x86-64.h +++ b/include/elf/x86-64.h @@ -82,6 +82,7 @@ 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_GPOFF, 43) /* 32 bit 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-i386/gpoff-1a.S b/ld/testsuite/ld-i386/gpoff-1a.S new file mode 100644 index 00000000000..5bb9bb5e673 --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-1a.S @@ -0,0 +1,20 @@ + .text + .globl get_foo +get_foo: + movl %fs:foo@GPOFF, %eax + ret + + .globl get_foo_gpoff +get_foo_gpoff: + leal foo@GPOFF, %eax + ret + + .data + .globl foo_gpoff +foo_gpoff: + .long foo@GPOFF + + .data + .globl foo +foo: + .long 0x12345678 diff --git a/ld/testsuite/ld-i386/gpoff-1b.c b/ld/testsuite/ld-i386/gpoff-1b.c new file mode 100644 index 00000000000..30b19cc8ba3 --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-1b.c @@ -0,0 +1,78 @@ +#define _GNU_SOURCE +#include <stdio.h> +#include <unistd.h> +#include <syscall.h> + +extern int foo; +extern int __gp; +extern int foo_gpoff; +extern int get_foo (void); +extern int get_foo_gpoff (void); + +/* Structure passed to 'set_thread_area' syscall. */ +struct user_desc +{ + unsigned int entry_number; + unsigned long int base_addr; + unsigned int limit; + unsigned int seg_32bit:1; + unsigned int contents:2; + unsigned int read_exec_only:1; + unsigned int limit_in_pages:1; + unsigned int seg_not_present:1; + unsigned int useable:1; + unsigned int empty:25; +}; + +/* Initializing bit fields is slow. We speed it up by using a union. */ +union user_desc_init +{ + struct user_desc desc; + unsigned int vals[4]; +}; + +int +setup_gp (void *p) +{ + union user_desc_init segdescr; + int result; + + /* Let the kernel pick a value for the 'entry_number' field. */ + segdescr.vals[0] = -1; + /* The 'base_addr' field. */ + segdescr.vals[1] = (unsigned long int) p; + /* The 'limit' field. We use 4GB which is 0xfffff pages. */ + segdescr.vals[2] = 0xfffff; + /* Collapsed value of the bitfield: + .seg_32bit = 1 + .contents = 0 + .read_exec_only = 0 + .limit_in_pages = 1 + .seg_not_present = 0 + .useable = 1 */ + segdescr.vals[3] = 0x51; + result = syscall (SYS_set_thread_area, &segdescr.desc); + if (result == 0) + /* We know the index in the GDT, now load the segment register. + The use of the GDT is described by the value 3 in the lower + three bits of the segment descriptor value. + Note that we have to do this even if the numeric value of + the descriptor does not change. Loading the segment register + causes the segment information from the GDT to be loaded + which is necessary since we have changed it. */ + asm ("movw %w0, %%fs" :: "q" (segdescr.desc.entry_number * 8 + 3)); + + return result; +} + +int +main () +{ + if (setup_gp (&__gp) == 0 + && foo == 0x12345678 + && *(int *) ((char *) &__gp + foo_gpoff) == 0x12345678 + && *(int *) ((char *) &__gp + get_foo_gpoff ()) == 0x12345678 + && get_foo () == 0x12345678) + printf ("PASS\n"); + return 0; +} diff --git a/ld/testsuite/ld-i386/gpoff-2a.S b/ld/testsuite/ld-i386/gpoff-2a.S new file mode 100644 index 00000000000..b54f316a8f9 --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-2a.S @@ -0,0 +1,19 @@ + .text + .globl get_foo +get_foo: + movl %fs:foo@GPOFF, %eax + ret + + .globl get_foo_gpoff +get_foo_gpoff: + leal foo@GPOFF, %eax + ret + + .data + .globl foo_gpoff +foo_gpoff: + .long foo@GPOFF + + .data +foo: + .long 0x12345678 diff --git a/ld/testsuite/ld-i386/gpoff-2b.c b/ld/testsuite/ld-i386/gpoff-2b.c new file mode 100644 index 00000000000..2a4085a7990 --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-2b.c @@ -0,0 +1,77 @@ +#define _GNU_SOURCE +#include <stdio.h> +#include <unistd.h> +#include <syscall.h> + +extern int __gp; +extern int foo_gpoff; +extern int get_foo (void); +extern int get_foo_gpoff (void); + +/* Structure passed to 'set_thread_area' syscall. */ +struct user_desc +{ + unsigned int entry_number; + unsigned long int base_addr; + unsigned int limit; + unsigned int seg_32bit:1; + unsigned int contents:2; + unsigned int read_exec_only:1; + unsigned int limit_in_pages:1; + unsigned int seg_not_present:1; + unsigned int useable:1; + unsigned int empty:25; +}; + +/* Initializing bit fields is slow. We speed it up by using a union. */ +union user_desc_init +{ + struct user_desc desc; + unsigned int vals[4]; +}; + +int +setup_gp (void *p) +{ + union user_desc_init segdescr; + int result; + + /* Let the kernel pick a value for the 'entry_number' field. */ + segdescr.vals[0] = -1; + /* The 'base_addr' field. */ + segdescr.vals[1] = (unsigned long int) p; + /* The 'limit' field. We use 4GB which is 0xfffff pages. */ + segdescr.vals[2] = 0xfffff; + /* Collapsed value of the bitfield: + .seg_32bit = 1 + .contents = 0 + .read_exec_only = 0 + .limit_in_pages = 1 + .seg_not_present = 0 + .useable = 1 */ + segdescr.vals[3] = 0x51; + result = syscall (SYS_set_thread_area, &segdescr.desc); + if (result == 0) + /* We know the index in the GDT, now load the segment register. + The use of the GDT is described by the value 3 in the lower + three bits of the segment descriptor value. + Note that we have to do this even if the numeric value of + the descriptor does not change. Loading the segment register + causes the segment information from the GDT to be loaded + which is necessary since we have changed it. */ + asm ("movw %w0, %%fs" :: "q" (segdescr.desc.entry_number * 8 + 3)); + + return result; +} + + +int +main () +{ + if (setup_gp (&__gp) == 0 + && *(int *) ((char *) &__gp + foo_gpoff) == 0x12345678 + && *(int *) ((char *) &__gp + get_foo_gpoff ()) == 0x12345678 + && get_foo () == 0x12345678) + printf ("PASS\n"); + return 0; +} diff --git a/ld/testsuite/ld-i386/gpoff-3.d b/ld/testsuite/ld-i386/gpoff-3.d new file mode 100644 index 00000000000..0952484cf9c --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-3.d @@ -0,0 +1,3 @@ +#as: --32 +#ld: -melf_i386 +#error: undefined reference to `foo' diff --git a/ld/testsuite/ld-i386/gpoff-3.s b/ld/testsuite/ld-i386/gpoff-3.s new file mode 100644 index 00000000000..91f9bf8b027 --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-3.s @@ -0,0 +1,4 @@ + .text + .globl _start +_start: + movl %fs:foo@GPOFF, %eax diff --git a/ld/testsuite/ld-i386/gpoff-4.d b/ld/testsuite/ld-i386/gpoff-4.d new file mode 100644 index 00000000000..f87739cb76c --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-4.d @@ -0,0 +1,3 @@ +#as: --32 +#ld: -melf_i386 +#error: GPOFF relocation at 0x2 in section `\.text' must be against symbol defined in GP section `\.rodata' diff --git a/ld/testsuite/ld-i386/gpoff-4.s b/ld/testsuite/ld-i386/gpoff-4.s new file mode 100644 index 00000000000..f138afd0899 --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-4.s @@ -0,0 +1,16 @@ + .text + .globl _start +_start: + movl %fs:foo@GPOFF, %eax + + .data + .globl bar_gpoff +bar_gpoff: + .long bar@GPOFF + +foo: + .long 0x12345678 + + .section .rodata,"a",@progbits +bar: + .long 0x12345678 diff --git a/ld/testsuite/ld-i386/gpoff-5.d b/ld/testsuite/ld-i386/gpoff-5.d new file mode 100644 index 00000000000..0df1ca23e53 --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-5.d @@ -0,0 +1,3 @@ +#as: --32 +#ld: -melf_i386 +#error: symbol `bar' with GPOFF relocation defined in .*\.o\(\.rodata\) isn't in GP section `\.data' diff --git a/ld/testsuite/ld-i386/gpoff-5.s b/ld/testsuite/ld-i386/gpoff-5.s new file mode 100644 index 00000000000..4a9c8d1c937 --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-5.s @@ -0,0 +1,18 @@ + .text + .globl _start +_start: + movl %fs:foo@GPOFF, %eax + + .data + .globl bar_gpoff +bar_gpoff: + .long bar@GPOFF + + .globl foo +foo: + .long 0x12345678 + + .section .rodata,"a",@progbits + .globl bar +bar: + .long 0x12345678 diff --git a/ld/testsuite/ld-i386/gpoff-6.d b/ld/testsuite/ld-i386/gpoff-6.d new file mode 100644 index 00000000000..00bdf7ad1ac --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-6.d @@ -0,0 +1,12 @@ +#as: --32 +#ld: -melf_i386 --gc-sections +#objdump: -dw + +.*: +file format .* + + +Disassembly of section .text: + +0+[a-f0-9]+ <_start>: + +[a-f0-9]+: c3 ret +#pass diff --git a/ld/testsuite/ld-i386/gpoff-6.s b/ld/testsuite/ld-i386/gpoff-6.s new file mode 100644 index 00000000000..592c0ff3c38 --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-6.s @@ -0,0 +1,9 @@ + .text + .globl _start +_start: + ret + + .section .text.bar,"ax",@progbits + .globl bar +bar: + movl %fs:foo@GPOFF, %eax diff --git a/ld/testsuite/ld-i386/gpoff-7.d b/ld/testsuite/ld-i386/gpoff-7.d new file mode 100644 index 00000000000..ecabaf159fc --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-7.d @@ -0,0 +1,16 @@ +#as: --32 +#ld: -melf_i386 +#objdump: -dw --sym + +.*: +file format .* + +SYMBOL TABLE: +#... +[a-f0-9]+ l .data 0+ __gp +#... + +Disassembly of section .text: + +0+[a-f0-9]+ <_start>: + +[a-f0-9]+:[ \t]+64 a1 fe ff ff ff[ \t]+mov[ \t]+%fs:0xfffffffe,%eax +#pass diff --git a/ld/testsuite/ld-i386/gpoff-7.s b/ld/testsuite/ld-i386/gpoff-7.s new file mode 100644 index 00000000000..f5b220aa8a6 --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-7.s @@ -0,0 +1,9 @@ + .text + .globl _start +_start: + movl %fs:foo@GPOFF, %eax + + .data + .globl foo +foo: + .long 0x12345678 diff --git a/ld/testsuite/ld-i386/gpoff-8.s b/ld/testsuite/ld-i386/gpoff-8.s new file mode 100644 index 00000000000..cffe6f06f55 --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-8.s @@ -0,0 +1,10 @@ + .text + .globl _start +_start: + movl %fs:foo@GPOFF, %eax + movl __gp@GOT(%ebx), %eax + + .data + .globl foo +foo: + .long 0x12345678 diff --git a/ld/testsuite/ld-i386/gpoff-8.t b/ld/testsuite/ld-i386/gpoff-8.t new file mode 100644 index 00000000000..1f016440de3 --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-8.t @@ -0,0 +1,39 @@ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS; + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .init : { *(.init) } + .text : { *(.text) } + .fini : { *(.fini) } + .rodata : { *(.rodata) } + . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + .tdata : { *(.tdata) } + .tbss : { *(.tbss) } + .init_array : { *(.init_array) } + .fini_array : { *(.fini_array) } + .jcr : { *(.jcr) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .bar : { *(.bar) } + . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); + .got.plt : { *(.got.plt) } + .data : + { + __gp = .; + *(.data) + } + __bss_start = .; + .bss : + { + *(.bss) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + _end = .; PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /DISCARD/ : { *(.*) } +} diff --git a/ld/testsuite/ld-i386/gpoff-8a.d b/ld/testsuite/ld-i386/gpoff-8a.d new file mode 100644 index 00000000000..94128c955e4 --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-8a.d @@ -0,0 +1,18 @@ +#source: gpoff-8.s +#as: --32 -mrelax-relocations=yes +#ld: -melf_i386 +#objdump: -dw --sym + +.*: +file format .* + +SYMBOL TABLE: +#... +[a-f0-9]+ l .data 0+ __gp +#... + +Disassembly of section .text: + +0+[a-f0-9]+ <_start>: + +[a-f0-9]+:[ \t]+64 a1 fe ff ff ff[ \t]+mov[ \t]+%fs:0xfffffffe,%eax + +[a-f0-9]+:[ \t]+c7 c0 [a-f0-9 \t]+mov[ \t]+\$0x[a-f0-9]+,%eax +#pass diff --git a/ld/testsuite/ld-i386/gpoff-8b.d b/ld/testsuite/ld-i386/gpoff-8b.d new file mode 100644 index 00000000000..9969de39fa3 --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-8b.d @@ -0,0 +1,18 @@ +#source: gpoff-8.s +#as: --32 -mrelax-relocations=yes +#ld: -melf_i386 -pie +#objdump: -dw --sym + +.*: +file format .* + +SYMBOL TABLE: +#... +[a-f0-9]+ l .data 0+ __gp +#... + +Disassembly of section .text: + +0+[a-f0-9]+ <_start>: + +[a-f0-9]+:[ \t]+64 a1 fe ff ff ff[ \t]+mov[ \t]+%fs:0xfffffffe,%eax + +[a-f0-9]+:[ \t]+8d 83 [a-f0-9 \t]+lea[ \t]+0x[a-f0-9]+\(%ebx\),%eax +#pass diff --git a/ld/testsuite/ld-i386/gpoff-8c.d b/ld/testsuite/ld-i386/gpoff-8c.d new file mode 100644 index 00000000000..c11ab46bb4b --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-8c.d @@ -0,0 +1,18 @@ +#source: gpoff-8.s +#as: --32 -mrelax-relocations=yes +#ld: -melf_i386 -shared +#objdump: -dw --sym + +.*: +file format .* + +SYMBOL TABLE: +#... +[a-f0-9]+ l .data 0+ __gp +#... + +Disassembly of section .text: + +0+[a-f0-9]+ <_start>: + +[a-f0-9]+:[ \t]+64 a1 fe ff ff ff[ \t]+mov[ \t]+%fs:0xfffffffe,%eax + +[a-f0-9]+:[ \t]+8d 83 [a-f0-9 \t]+lea[ \t]+0x[a-f0-9]+\(%ebx\),%eax +#pass diff --git a/ld/testsuite/ld-i386/gpoff-8d.d b/ld/testsuite/ld-i386/gpoff-8d.d new file mode 100644 index 00000000000..64d9fcf6c42 --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-8d.d @@ -0,0 +1,18 @@ +#source: gpoff-8.s +#as: --32 -mrelax-relocations=yes +#ld: -melf_i386 -T gpoff-8.t +#objdump: -dw --sym + +.*: +file format .* + +SYMBOL TABLE: +#... +[a-f0-9]+ l .data 0+ __gp +#... + +Disassembly of section .text: + +0+[a-f0-9]+ <_start>: + +[a-f0-9]+:[ \t]+64 a1 00 00 00 00[ \t]+mov[ \t]+%fs:0x0,%eax + +[a-f0-9]+:[ \t]+c7 c0 [a-f0-9 \t]+mov[ \t]+\$0x[a-f0-9]+,%eax +#pass diff --git a/ld/testsuite/ld-i386/gpoff-8e.d b/ld/testsuite/ld-i386/gpoff-8e.d new file mode 100644 index 00000000000..bfa25a28449 --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-8e.d @@ -0,0 +1,18 @@ +#source: gpoff-8.s +#as: --32 -mrelax-relocations=yes +#ld: -melf_i386 -T gpoff-8.t -pie +#objdump: -dw --sym + +.*: +file format .* + +SYMBOL TABLE: +#... +[a-f0-9]+ l .data 0+ __gp +#... + +Disassembly of section .text: + +0+[a-f0-9]+ <_start>: + +[a-f0-9]+:[ \t]+64 a1 00 00 00 00[ \t]+mov[ \t]+%fs:0x0,%eax + +[a-f0-9]+:[ \t]+8d 83 [a-f0-9 \t]+lea[ \t]+0x[a-f0-9]+\(%ebx\),%eax +#pass diff --git a/ld/testsuite/ld-i386/gpoff-8f.d b/ld/testsuite/ld-i386/gpoff-8f.d new file mode 100644 index 00000000000..6cc4a52403e --- /dev/null +++ b/ld/testsuite/ld-i386/gpoff-8f.d @@ -0,0 +1,18 @@ +#source: gpoff-8.s +#as: --32 -mrelax-relocations=yes +#ld: -melf_i386 -T gpoff-8.t -shared +#objdump: -dw --sym + +.*: +file format .* + +SYMBOL TABLE: +#... +[a-f0-9]+ l .data 0+ __gp +#... + +Disassembly of section .text: + +0+[a-f0-9]+ <_start>: + +[a-f0-9]+:[ \t]+64 a1 00 00 00 00[ \t]+mov[ \t]+%fs:0x0,%eax + +[a-f0-9]+:[ \t]+8d 83 [a-f0-9 \t]+lea[ \t]+0x[a-f0-9]+\(%ebx\),%eax +#pass diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp index 07110152771..45b22ef5080 100644 --- a/ld/testsuite/ld-i386/i386.exp +++ b/ld/testsuite/ld-i386/i386.exp @@ -290,6 +290,17 @@ run_dump_test "abs" run_dump_test "pcrel8" run_dump_test "pcrel16" run_dump_test "pcrel16abs" +run_dump_test "gpoff-3" +run_dump_test "gpoff-4" +run_dump_test "gpoff-5" +run_dump_test "gpoff-6" +run_dump_test "gpoff-7" +run_dump_test "gpoff-8a" +run_dump_test "gpoff-8b" +run_dump_test "gpoff-8c" +run_dump_test "gpoff-8d" +run_dump_test "gpoff-8e" +run_dump_test "gpoff-8f" run_dump_test "alloc" run_dump_test "warn1" run_dump_test "tlsgd2" @@ -1385,6 +1396,67 @@ if { [isnative] ] \ ] } + + if { [istarget "i?86-*-linux*"] } { + run_ld_link_exec_tests [list \ + [list \ + "Run GPOFF 1" \ + "" \ + "" \ + {gpoff-1a.S gpoff-1b.c} \ + "gpoff-1" "pass.out" \ + ] \ + [list \ + "Run GPOFF 1 (PIE)" \ + "-pie" \ + "" \ + {gpoff-1a.S gpoff-1b.c} \ + "gpoff-1-pie" "pass.out" "-fPIE" \ + ] \ + [list \ + "Run GPOFF 1 (PIC)" \ + "-pie" \ + "" \ + {gpoff-1a.S gpoff-1b.c} \ + "gpoff-1-pic" "pass.out" "-fPIC" \ + ] \ + [list \ + "Run GPOFF 1 (static)" \ + "-static" \ + "" \ + {gpoff-1a.S gpoff-1b.c} \ + "gpoff-1-static" "pass.out" \ + ] \ + [list \ + "Run GPOFF 2" \ + "" \ + "" \ + {gpoff-2a.S gpoff-2b.c} \ + "gpoff-2" "pass.out" \ + ] \ + [list \ + "Run GPOFF 2 (PIE)" \ + "-pie" \ + "" \ + {gpoff-2a.S gpoff-2b.c} \ + "gpoff-2-pie" "pass.out" "-fPIE" \ + ] \ + [list \ + "Run GPOFF 2 (PIC)" \ + "-pie" \ + "" \ + {gpoff-2a.S gpoff-2b.c} \ + "gpoff-2-pic" "pass.out" "-fPIC" \ + ] \ + [list \ + "Run GPOFF 2 (static)" \ + "-static" \ + "" \ + {gpoff-2a.S gpoff-2b.c} \ + "gpoff-2-static" "pass.out" \ + ] \ + ] + } } if { !([istarget "i?86-*-linux*"] diff --git a/ld/testsuite/ld-x86-64/gpoff-1a.S b/ld/testsuite/ld-x86-64/gpoff-1a.S new file mode 100644 index 00000000000..24e9e649d92 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-1a.S @@ -0,0 +1,20 @@ + .text + .globl get_foo +get_foo: + movl %gs:foo@GPOFF, %eax + ret + + .globl get_foo_gpoff +get_foo_gpoff: + leal foo@GPOFF, %eax + ret + + .data + .globl foo_gpoff +foo_gpoff: + .long foo@GPOFF + + .data + .globl foo +foo: + .long 0x12345678 diff --git a/ld/testsuite/ld-x86-64/gpoff-1b.c b/ld/testsuite/ld-x86-64/gpoff-1b.c new file mode 100644 index 00000000000..185f265b070 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-1b.c @@ -0,0 +1,29 @@ +#define _GNU_SOURCE +#include <stdio.h> +#include <unistd.h> +#include <syscall.h> +#include <asm/prctl.h> + +extern int foo; +extern int __gp; +extern int foo_gpoff; +extern int get_foo (void); +extern int get_foo_gpoff (void); + +int +setup_gp (void *p) +{ + return syscall (SYS_arch_prctl, ARCH_SET_GS, p); +} + +int +main () +{ + if (setup_gp (&__gp) == 0 + && foo == 0x12345678 + && *(int *) ((char *) &__gp + foo_gpoff) == 0x12345678 + && *(int *) ((char *) &__gp + get_foo_gpoff ()) == 0x12345678 + && get_foo () == 0x12345678) + printf ("PASS\n"); + return 0; +} diff --git a/ld/testsuite/ld-x86-64/gpoff-2a.S b/ld/testsuite/ld-x86-64/gpoff-2a.S new file mode 100644 index 00000000000..cb9f26755a7 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-2a.S @@ -0,0 +1,19 @@ + .text + .globl get_foo +get_foo: + movl %gs:foo@GPOFF, %eax + ret + + .globl get_foo_gpoff +get_foo_gpoff: + leal foo@GPOFF, %eax + ret + + .data + .globl foo_gpoff +foo_gpoff: + .long foo@GPOFF + + .data +foo: + .long 0x12345678 diff --git a/ld/testsuite/ld-x86-64/gpoff-2b.c b/ld/testsuite/ld-x86-64/gpoff-2b.c new file mode 100644 index 00000000000..8b91e22721e --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-2b.c @@ -0,0 +1,27 @@ +#define _GNU_SOURCE +#include <stdio.h> +#include <unistd.h> +#include <syscall.h> +#include <asm/prctl.h> + +extern int __gp; +extern int foo_gpoff; +extern int get_foo (void); +extern int get_foo_gpoff (void); + +int +setup_gp (void *p) +{ + return syscall (SYS_arch_prctl, ARCH_SET_GS, p); +} + +int +main () +{ + if (setup_gp (&__gp) == 0 + && *(int *) ((char *) &__gp + foo_gpoff) == 0x12345678 + && *(int *) ((char *) &__gp + get_foo_gpoff ()) == 0x12345678 + && get_foo () == 0x12345678) + printf ("PASS\n"); + return 0; +} diff --git a/ld/testsuite/ld-x86-64/gpoff-3.d b/ld/testsuite/ld-x86-64/gpoff-3.d new file mode 100644 index 00000000000..c8a5e6f9834 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-3.d @@ -0,0 +1,3 @@ +#as: --64 +#ld: -melf_x86_64 +#error: undefined reference to `foo' diff --git a/ld/testsuite/ld-x86-64/gpoff-3.s b/ld/testsuite/ld-x86-64/gpoff-3.s new file mode 100644 index 00000000000..0513d3e4d38 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-3.s @@ -0,0 +1,4 @@ + .text + .globl _start +_start: + movl %gs:foo@GPOFF, %eax diff --git a/ld/testsuite/ld-x86-64/gpoff-4.d b/ld/testsuite/ld-x86-64/gpoff-4.d new file mode 100644 index 00000000000..f8fee15d1d5 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-4.d @@ -0,0 +1,3 @@ +#as: --64 +#ld: -melf_x86_64 +#error: GPOFF relocation at 0x4 in section `\.text' must be against symbol defined in GP section `\.rodata' diff --git a/ld/testsuite/ld-x86-64/gpoff-4.s b/ld/testsuite/ld-x86-64/gpoff-4.s new file mode 100644 index 00000000000..5f6cd4116ec --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-4.s @@ -0,0 +1,16 @@ + .text + .globl _start +_start: + movl %gs:foo@GPOFF, %eax + + .data + .globl bar_gpoff +bar_gpoff: + .long bar@GPOFF + +foo: + .long 0x12345678 + + .section .rodata,"a",@progbits +bar: + .long 0x12345678 diff --git a/ld/testsuite/ld-x86-64/gpoff-5.d b/ld/testsuite/ld-x86-64/gpoff-5.d new file mode 100644 index 00000000000..ddc8498cff8 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-5.d @@ -0,0 +1,3 @@ +#as: --64 +#ld: -melf_x86_64 +#error: symbol `bar' with GPOFF relocation defined in .*\.o\(\.rodata\) isn't in GP section `\.data' diff --git a/ld/testsuite/ld-x86-64/gpoff-5.s b/ld/testsuite/ld-x86-64/gpoff-5.s new file mode 100644 index 00000000000..3a8e6781fc4 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-5.s @@ -0,0 +1,18 @@ + .text + .globl _start +_start: + movl %gs:foo@GPOFF, %eax + + .data + .globl bar_gpoff +bar_gpoff: + .long bar@GPOFF + + .globl foo +foo: + .long 0x12345678 + + .section .rodata,"a",@progbits + .globl bar +bar: + .long 0x12345678 diff --git a/ld/testsuite/ld-x86-64/gpoff-6.d b/ld/testsuite/ld-x86-64/gpoff-6.d new file mode 100644 index 00000000000..1676b0d3ef2 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-6.d @@ -0,0 +1,12 @@ +#as: --64 +#ld: -melf_x86_64 --gc-sections +#objdump: -dw + +.*: +file format .* + + +Disassembly of section .text: + +0+[a-f0-9]+ <_start>: + +[a-f0-9]+: c3 retq +#pass diff --git a/ld/testsuite/ld-x86-64/gpoff-6.s b/ld/testsuite/ld-x86-64/gpoff-6.s new file mode 100644 index 00000000000..3e632f3cea1 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-6.s @@ -0,0 +1,9 @@ + .text + .globl _start +_start: + ret + + .section .text.bar,"ax",@progbits + .globl bar +bar: + movl %gs:foo@GPOFF, %eax diff --git a/ld/testsuite/ld-x86-64/gpoff-7.d b/ld/testsuite/ld-x86-64/gpoff-7.d new file mode 100644 index 00000000000..a6ebefa2652 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-7.d @@ -0,0 +1,16 @@ +#as: --64 +#ld: -melf_x86_64 +#objdump: -dw --sym + +.*: +file format .* + +SYMBOL TABLE: +#... +[a-f0-9]+ l .data 0+ __gp +#... + +Disassembly of section .text: + +0+[a-f0-9]+ <_start>: + +[a-f0-9]+:[ \t]+65 8b 04 25 fe ff ff ff[ \t]+mov[ \t]+%gs:0xfffffffffffffffe,%eax +#pass diff --git a/ld/testsuite/ld-x86-64/gpoff-7.s b/ld/testsuite/ld-x86-64/gpoff-7.s new file mode 100644 index 00000000000..a900661811d --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-7.s @@ -0,0 +1,9 @@ + .text + .globl _start +_start: + movl %gs:foo@GPOFF, %eax + + .data + .globl foo +foo: + .long 0x12345678 diff --git a/ld/testsuite/ld-x86-64/gpoff-8.s b/ld/testsuite/ld-x86-64/gpoff-8.s new file mode 100644 index 00000000000..948bafc498d --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-8.s @@ -0,0 +1,10 @@ + .text + .globl _start +_start: + movl %gs:foo@GPOFF, %eax + movq __gp@GOTPCREL(%rip), %rax + + .data + .globl foo +foo: + .long 0x12345678 diff --git a/ld/testsuite/ld-x86-64/gpoff-8.t b/ld/testsuite/ld-x86-64/gpoff-8.t new file mode 100644 index 00000000000..1f016440de3 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-8.t @@ -0,0 +1,39 @@ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS; + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .init : { *(.init) } + .text : { *(.text) } + .fini : { *(.fini) } + .rodata : { *(.rodata) } + . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + .tdata : { *(.tdata) } + .tbss : { *(.tbss) } + .init_array : { *(.init_array) } + .fini_array : { *(.fini_array) } + .jcr : { *(.jcr) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .bar : { *(.bar) } + . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); + .got.plt : { *(.got.plt) } + .data : + { + __gp = .; + *(.data) + } + __bss_start = .; + .bss : + { + *(.bss) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + _end = .; PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /DISCARD/ : { *(.*) } +} diff --git a/ld/testsuite/ld-x86-64/gpoff-8a.d b/ld/testsuite/ld-x86-64/gpoff-8a.d new file mode 100644 index 00000000000..6c1640d34c2 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-8a.d @@ -0,0 +1,18 @@ +#source: gpoff-8.s +#as: --64 -mrelax-relocations=yes +#ld: -melf_x86_64 +#objdump: -dw --sym + +.*: +file format .* + +SYMBOL TABLE: +#... +[a-f0-9]+ l .data 0+ __gp +#... + +Disassembly of section .text: + +0+[a-f0-9]+ <_start>: + +[a-f0-9]+:[ \t]+65 8b 04 25 fe ff ff ff[ \t]+mov[ \t]+%gs:0xfffffffffffffffe,%eax + +[a-f0-9]+:[ \t]+48 c7 c0 [a-f0-9 \t]+mov[ \t]+\$0x[a-f0-9]+,%rax +#pass diff --git a/ld/testsuite/ld-x86-64/gpoff-8b.d b/ld/testsuite/ld-x86-64/gpoff-8b.d new file mode 100644 index 00000000000..f163bc1d383 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-8b.d @@ -0,0 +1,18 @@ +#source: gpoff-8.s +#as: --64 -mrelax-relocations=yes +#ld: -melf_x86_64 -pie +#objdump: -dw --sym + +.*: +file format .* + +SYMBOL TABLE: +#... +[a-f0-9]+ l .data 0+ __gp +#... + +Disassembly of section .text: + +0+[a-f0-9]+ <_start>: + +[a-f0-9]+:[ \t]+65 8b 04 25 fe ff ff ff[ \t]+mov[ \t]+%gs:0xfffffffffffffffe,%eax + +[a-f0-9]+:[ \t]+48 8d 05 [a-f0-9 \t]+lea[ \t]+0x[a-f0-9]+\(%rip\),%rax[ \t]+# [a-f0-9]+ <__gp> +#pass diff --git a/ld/testsuite/ld-x86-64/gpoff-8c.d b/ld/testsuite/ld-x86-64/gpoff-8c.d new file mode 100644 index 00000000000..d5478bbb2a4 --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-8c.d @@ -0,0 +1,18 @@ +#source: gpoff-8.s +#as: --64 -mrelax-relocations=yes +#ld: -melf_x86_64 -shared +#objdump: -dw --sym + +.*: +file format .* + +SYMBOL TABLE: +#... +[a-f0-9]+ l .data 0+ __gp +#... + +Disassembly of section .text: + +0+[a-f0-9]+ <_start>: + +[a-f0-9]+:[ \t]+65 8b 04 25 fe ff ff ff[ \t]+mov[ \t]+%gs:0xfffffffffffffffe,%eax + +[a-f0-9]+:[ \t]+48 8d 05 [a-f0-9 \t]+lea[ \t]+0x[a-f0-9]+\(%rip\),%rax[ \t]+# [a-f0-9]+ <__gp> +#pass diff --git a/ld/testsuite/ld-x86-64/gpoff-8d.d b/ld/testsuite/ld-x86-64/gpoff-8d.d new file mode 100644 index 00000000000..2e0a330396c --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-8d.d @@ -0,0 +1,18 @@ +#source: gpoff-8.s +#as: --64 -mrelax-relocations=yes +#ld: -melf_x86_64 -T gpoff-8.t +#objdump: -dw --sym + +.*: +file format .* + +SYMBOL TABLE: +#... +[a-f0-9]+ l .data 0+ __gp +#... + +Disassembly of section .text: + +0+[a-f0-9]+ <_start>: + +[a-f0-9]+:[ \t]+65 8b 04 25 00 00 00 00[ \t]+mov[ \t]+%gs:0x0,%eax + +[a-f0-9]+:[ \t]+48 c7 c0 [a-f0-9 \t]+mov[ \t]+\$0x[a-f0-9]+,%rax +#pass diff --git a/ld/testsuite/ld-x86-64/gpoff-8e.d b/ld/testsuite/ld-x86-64/gpoff-8e.d new file mode 100644 index 00000000000..1a1c9d907ed --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-8e.d @@ -0,0 +1,18 @@ +#source: gpoff-8.s +#as: --64 -mrelax-relocations=yes +#ld: -melf_x86_64 -T gpoff-8.t -pie +#objdump: -dw --sym + +.*: +file format .* + +SYMBOL TABLE: +#... +[a-f0-9]+ l .data 0+ __gp +#... + +Disassembly of section .text: + +0+[a-f0-9]+ <_start>: + +[a-f0-9]+:[ \t]+65 8b 04 25 00 00 00 00[ \t]+mov[ \t]+%gs:0x0,%eax + +[a-f0-9]+:[ \t]+48 8d 05 [a-f0-9 \t]+lea[ \t]+0x[a-f0-9]+\(%rip\),%rax[ \t]+# [a-f0-9]+ <foo> +#pass diff --git a/ld/testsuite/ld-x86-64/gpoff-8f.d b/ld/testsuite/ld-x86-64/gpoff-8f.d new file mode 100644 index 00000000000..fb8c3375b8d --- /dev/null +++ b/ld/testsuite/ld-x86-64/gpoff-8f.d @@ -0,0 +1,18 @@ +#source: gpoff-8.s +#as: --64 -mrelax-relocations=yes +#ld: -melf_x86_64 -T gpoff-8.t -shared +#objdump: -dw --sym + +.*: +file format .* + +SYMBOL TABLE: +#... +[a-f0-9]+ l .data 0+ __gp +#... + +Disassembly of section .text: + +0+[a-f0-9]+ <_start>: + +[a-f0-9]+:[ \t]+65 8b 04 25 00 00 00 00[ \t]+mov[ \t]+%gs:0x0,%eax + +[a-f0-9]+:[ \t]+48 8d 05 [a-f0-9 \t]+lea[ \t]+0x[a-f0-9]+\(%rip\),%rax[ \t]+# [a-f0-9]+ <foo> +#pass diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp index ef2cb1551cf..5ed315886e0 100644 --- a/ld/testsuite/ld-x86-64/x86-64.exp +++ b/ld/testsuite/ld-x86-64/x86-64.exp @@ -269,6 +269,17 @@ run_dump_test "abs" run_dump_test "abs-l1om" run_dump_test "pcrel8" run_dump_test "pcrel16" +run_dump_test "gpoff-3" +run_dump_test "gpoff-4" +run_dump_test "gpoff-5" +run_dump_test "gpoff-6" +run_dump_test "gpoff-7" +run_dump_test "gpoff-8a" +run_dump_test "gpoff-8b" +run_dump_test "gpoff-8c" +run_dump_test "gpoff-8d" +run_dump_test "gpoff-8e" +run_dump_test "gpoff-8f" run_dump_test "tlsgd2" run_dump_test "tlsgd3" run_dump_test "tlsgd12" @@ -1720,6 +1731,67 @@ if { [isnative] && [which $CC] != 0 } { } } + if { [istarget "x86_64-*-linux*"] } { + run_ld_link_exec_tests [list \ + [list \ + "Run GPOFF 1" \ + "" \ + "" \ + {gpoff-1a.S gpoff-1b.c} \ + "gpoff-1" "pass.out" \ + ] \ + [list \ + "Run GPOFF 1 (PIE)" \ + "-pie" \ + "" \ + {gpoff-1a.S gpoff-1b.c} \ + "gpoff-1-pie" "pass.out" "-fPIE" \ + ] \ + [list \ + "Run GPOFF 1 (PIC)" \ + "-pie" \ + "" \ + {gpoff-1a.S gpoff-1b.c} \ + "gpoff-1-pic" "pass.out" "-fPIC" \ + ] \ + [list \ + "Run GPOFF 1 (static)" \ + "-static" \ + "" \ + {gpoff-1a.S gpoff-1b.c} \ + "gpoff-1-static" "pass.out" \ + ] \ + [list \ + "Run GPOFF 2" \ + "" \ + "" \ + {gpoff-2a.S gpoff-2b.c} \ + "gpoff-2" "pass.out" \ + ] \ + [list \ + "Run GPOFF 2 (PIE)" \ + "-pie" \ + "" \ + {gpoff-2a.S gpoff-2b.c} \ + "gpoff-2-pie" "pass.out" "-fPIE" \ + ] \ + [list \ + "Run GPOFF 2 (PIC)" \ + "-pie" \ + "" \ + {gpoff-2a.S gpoff-2b.c} \ + "gpoff-2-pic" "pass.out" "-fPIC" \ + ] \ + [list \ + "Run GPOFF 2 (static)" \ + "-static" \ + "" \ + {gpoff-2a.S gpoff-2b.c} \ + "gpoff-2-static" "pass.out" \ + ] \ + ] + } + undefined_weak "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS" undefined_weak "-fPIE" "" undefined_weak "-fPIE" "-pie" |