summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2017-08-03 09:43:28 -0700
committerH.J. Lu <hjl.tools@gmail.com>2017-10-14 11:49:36 -0700
commitc3d646723ce1b7d68270ae2b0f8163a9be434576 (patch)
tree4fcc568f0d2aeb66d5d1d7faf6d09b850694bebf
parent851b6fa13707d187e068c8773f21d376391387a9 (diff)
downloadbinutils-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.
-rw-r--r--bfd/elf32-i386.c74
-rw-r--r--bfd/elf64-x86-64.c70
-rw-r--r--bfd/elfxx-x86.c119
-rw-r--r--bfd/elfxx-x86.h13
-rw-r--r--gas/config/tc-i386.c41
-rw-r--r--gas/config/tc-i386.h6
-rw-r--r--gas/testsuite/gas/i386/gpoff.d11
-rw-r--r--gas/testsuite/gas/i386/gpoff.s4
-rw-r--r--gas/testsuite/gas/i386/i386.exp6
-rw-r--r--gas/testsuite/gas/i386/inval-gpoff.l18
-rw-r--r--gas/testsuite/gas/i386/inval-gpoff.s5
-rw-r--r--gas/testsuite/gas/i386/x86-64-gpoff.d11
-rw-r--r--gas/testsuite/gas/i386/x86-64-gpoff.s4
-rw-r--r--gas/testsuite/gas/i386/x86-64-inval-gpoff.l30
-rw-r--r--gas/testsuite/gas/i386/x86-64-inval-gpoff.s7
-rw-r--r--include/elf/i386.h1
-rw-r--r--include/elf/x86-64.h1
-rw-r--r--ld/testsuite/ld-i386/gpoff-1a.S20
-rw-r--r--ld/testsuite/ld-i386/gpoff-1b.c78
-rw-r--r--ld/testsuite/ld-i386/gpoff-2a.S19
-rw-r--r--ld/testsuite/ld-i386/gpoff-2b.c77
-rw-r--r--ld/testsuite/ld-i386/gpoff-3.d3
-rw-r--r--ld/testsuite/ld-i386/gpoff-3.s4
-rw-r--r--ld/testsuite/ld-i386/gpoff-4.d3
-rw-r--r--ld/testsuite/ld-i386/gpoff-4.s16
-rw-r--r--ld/testsuite/ld-i386/gpoff-5.d3
-rw-r--r--ld/testsuite/ld-i386/gpoff-5.s18
-rw-r--r--ld/testsuite/ld-i386/gpoff-6.d12
-rw-r--r--ld/testsuite/ld-i386/gpoff-6.s9
-rw-r--r--ld/testsuite/ld-i386/gpoff-7.d16
-rw-r--r--ld/testsuite/ld-i386/gpoff-7.s9
-rw-r--r--ld/testsuite/ld-i386/gpoff-8.s10
-rw-r--r--ld/testsuite/ld-i386/gpoff-8.t39
-rw-r--r--ld/testsuite/ld-i386/gpoff-8a.d18
-rw-r--r--ld/testsuite/ld-i386/gpoff-8b.d18
-rw-r--r--ld/testsuite/ld-i386/gpoff-8c.d18
-rw-r--r--ld/testsuite/ld-i386/gpoff-8d.d18
-rw-r--r--ld/testsuite/ld-i386/gpoff-8e.d18
-rw-r--r--ld/testsuite/ld-i386/gpoff-8f.d18
-rw-r--r--ld/testsuite/ld-i386/i386.exp72
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-1a.S20
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-1b.c29
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-2a.S19
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-2b.c27
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-3.d3
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-3.s4
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-4.d3
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-4.s16
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-5.d3
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-5.s18
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-6.d12
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-6.s9
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-7.d16
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-7.s9
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-8.s10
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-8.t39
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-8a.d18
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-8b.d18
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-8c.d18
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-8d.d18
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-8e.d18
-rw-r--r--ld/testsuite/ld-x86-64/gpoff-8f.d18
-rw-r--r--ld/testsuite/ld-x86-64/x86-64.exp72
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"