forked from Imagelibrary/binutils-gdb
Compare commits
1 Commits
users/sima
...
hjl/gpoff-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a03433660 |
198
bfd/elf32-i386.c
198
bfd/elf32-i386.c
@@ -150,9 +150,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. */
|
||||
@@ -340,6 +343,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];
|
||||
@@ -986,6 +993,9 @@ struct elf_i386_link_hash_entry
|
||||
/* Symbol is referenced by R_386_GOTOFF relocation. */
|
||||
unsigned int gotoff_ref : 1;
|
||||
|
||||
/* TRUE if symbol has GPOFF relocations. */
|
||||
unsigned int has_gpoff_reloc : 1;
|
||||
|
||||
/* Symbol has GOT or PLT relocations. */
|
||||
unsigned int has_got_reloc : 1;
|
||||
|
||||
@@ -1062,6 +1072,8 @@ struct elf_i386_link_hash_table
|
||||
asection *plt_got;
|
||||
asection *plt_got_eh_frame;
|
||||
|
||||
struct elf_link_hash_entry *gp;
|
||||
|
||||
/* Parameters describing PLT generation. */
|
||||
struct elf_i386_plt_layout plt;
|
||||
|
||||
@@ -1144,6 +1156,7 @@ elf_i386_link_hash_newfunc (struct bfd_hash_entry *entry,
|
||||
eh->dyn_relocs = NULL;
|
||||
eh->tls_type = GOT_UNKNOWN;
|
||||
eh->gotoff_ref = 0;
|
||||
eh->has_gpoff_reloc = 0;
|
||||
eh->has_got_reloc = 0;
|
||||
eh->has_non_got_reloc = 0;
|
||||
eh->no_finish_dynamic_symbol = 0;
|
||||
@@ -1330,6 +1343,7 @@ elf_i386_copy_indirect_symbol (struct bfd_link_info *info,
|
||||
generate a R_386_COPY reloc. */
|
||||
edir->gotoff_ref |= eind->gotoff_ref;
|
||||
|
||||
edir->has_gpoff_reloc |= eind->has_gpoff_reloc;
|
||||
edir->has_got_reloc |= eind->has_got_reloc;
|
||||
edir->has_non_got_reloc |= eind->has_non_got_reloc;
|
||||
|
||||
@@ -2041,17 +2055,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 = elf_i386_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;
|
||||
@@ -2428,6 +2451,11 @@ do_size:
|
||||
goto error_return;
|
||||
break;
|
||||
|
||||
case R_386_GPOFF:
|
||||
if (eh != NULL)
|
||||
eh->has_gpoff_reloc = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -3128,6 +3156,10 @@ elf_i386_allocate_local_dynrelocs (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_i386_link_hash_entry *) h)->has_gpoff_reloc)
|
||||
return TRUE;
|
||||
|
||||
if (h->type != STT_GNU_IFUNC
|
||||
|| !h->def_regular
|
||||
|| !h->ref_regular
|
||||
@@ -5326,6 +5358,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;
|
||||
}
|
||||
@@ -5854,6 +5921,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_i386_link_hash_entry *) h)->has_gpoff_reloc)
|
||||
return TRUE;
|
||||
|
||||
return elf_i386_finish_dynamic_symbol (info->output_bfd, info,
|
||||
h, NULL);
|
||||
}
|
||||
@@ -7137,12 +7208,124 @@ elf_i386_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
|
||||
FALSE, FALSE, FALSE);
|
||||
if (h != NULL)
|
||||
((struct elf_i386_link_hash_entry *) h)->tls_get_addr = 1;
|
||||
|
||||
/* Cache and hide __gp symbol. */
|
||||
h = elf_link_hash_lookup (elf_hash_table (info), "__gp", FALSE,
|
||||
FALSE, FALSE);
|
||||
if (h != NULL)
|
||||
{
|
||||
const struct elf_backend_data *bed;
|
||||
struct elf_i386_link_hash_table *htab;
|
||||
|
||||
htab = elf_i386_hash_table (info);
|
||||
if (htab == NULL)
|
||||
return FALSE;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* Invoke the regular ELF backend linker to do all the work. */
|
||||
return _bfd_elf_link_check_relocs (abfd, info);
|
||||
}
|
||||
|
||||
/* Set up GP section from symbols with GPOFF relocations. */
|
||||
|
||||
static bfd_boolean
|
||||
elf_i386_setup_gp (struct elf_link_hash_entry *h, void * inf)
|
||||
{
|
||||
struct bfd_link_info *info;
|
||||
struct elf_i386_link_hash_table *htab;
|
||||
struct elf_i386_link_hash_entry *eh;
|
||||
struct elf_link_hash_entry *gp;
|
||||
asection *gpsection;
|
||||
bfd_size_type gpsection_size;
|
||||
|
||||
eh = (struct elf_i386_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;
|
||||
htab = elf_i386_hash_table (info);
|
||||
if (htab == NULL)
|
||||
return FALSE;
|
||||
|
||||
gpsection = h->root.u.def.section->output_section;
|
||||
gpsection_size = bfd_get_section_size (gpsection);
|
||||
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_i386_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_i386_setup_gp (h, info);
|
||||
}
|
||||
|
||||
/* Set up GP section for __gp symbol. */
|
||||
|
||||
static bfd_boolean
|
||||
elf_i386_final_link (bfd *abfd, struct bfd_link_info *info)
|
||||
{
|
||||
if (!bfd_link_relocatable (info))
|
||||
{
|
||||
struct elf_link_hash_entry *gp;
|
||||
struct elf_i386_link_hash_table *htab;
|
||||
|
||||
htab = elf_i386_hash_table (info);
|
||||
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_i386_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_i386_setup_gp_from_local_symbol,
|
||||
info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Invoke the regular ELF backend linker to do all the work. */
|
||||
return bfd_elf_final_link (abfd, info);
|
||||
}
|
||||
|
||||
#define TARGET_LITTLE_SYM i386_elf32_vec
|
||||
#define TARGET_LITTLE_NAME "elf32-i386"
|
||||
#define ELF_ARCH bfd_arch_i386
|
||||
@@ -7174,6 +7357,7 @@ elf_i386_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
|
||||
#define bfd_elf32_bfd_reloc_name_lookup elf_i386_reloc_name_lookup
|
||||
#define bfd_elf32_get_synthetic_symtab elf_i386_get_synthetic_symtab
|
||||
#define bfd_elf32_bfd_link_check_relocs elf_i386_link_check_relocs
|
||||
#define bfd_elf32_bfd_final_link elf_i386_final_link
|
||||
|
||||
#define elf_backend_adjust_dynamic_symbol elf_i386_adjust_dynamic_symbol
|
||||
#define elf_backend_relocs_compatible _bfd_elf_relocs_compatible
|
||||
|
||||
@@ -183,12 +183,15 @@ static reloc_howto_type x86_64_elf_howto_table[] =
|
||||
HOWTO(R_X86_64_REX_GOTPCRELX, 0, 2, 32, TRUE, 0, complain_overflow_signed,
|
||||
bfd_elf_generic_reloc, "R_X86_64_REX_GOTPCRELX", FALSE, 0xffffffff,
|
||||
0xffffffff, TRUE),
|
||||
HOWTO(R_X86_64_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. */
|
||||
@@ -264,6 +267,7 @@ static const struct elf_reloc_map x86_64_reloc_map[] =
|
||||
{ BFD_RELOC_X86_64_PLT32_BND, R_X86_64_PLT32_BND, },
|
||||
{ BFD_RELOC_X86_64_GOTPCRELX, R_X86_64_GOTPCRELX, },
|
||||
{ BFD_RELOC_X86_64_REX_GOTPCRELX, R_X86_64_REX_GOTPCRELX, },
|
||||
{ BFD_RELOC_GPREL32, R_X86_64_GPOFF, },
|
||||
{ BFD_RELOC_VTABLE_INHERIT, R_X86_64_GNU_VTINHERIT, },
|
||||
{ BFD_RELOC_VTABLE_ENTRY, R_X86_64_GNU_VTENTRY, },
|
||||
};
|
||||
@@ -1092,6 +1096,9 @@ struct elf_x86_64_link_hash_entry
|
||||
real definition and check it when allowing copy reloc in PIE. */
|
||||
unsigned int needs_copy : 1;
|
||||
|
||||
/* TRUE if symbol has GPOFF relocations. */
|
||||
unsigned int has_gpoff_reloc : 1;
|
||||
|
||||
/* TRUE if symbol has GOT or PLT relocations. */
|
||||
unsigned int has_got_reloc : 1;
|
||||
|
||||
@@ -1169,6 +1176,8 @@ struct elf_x86_64_link_hash_table
|
||||
asection *plt_got;
|
||||
asection *plt_got_eh_frame;
|
||||
|
||||
struct elf_link_hash_entry *gp;
|
||||
|
||||
/* Parameters describing PLT generation, lazy or non-lazy. */
|
||||
struct elf_x86_64_plt_layout plt;
|
||||
|
||||
@@ -1259,6 +1268,7 @@ elf_x86_64_link_hash_newfunc (struct bfd_hash_entry *entry,
|
||||
eh->dyn_relocs = NULL;
|
||||
eh->tls_type = GOT_UNKNOWN;
|
||||
eh->needs_copy = 0;
|
||||
eh->has_gpoff_reloc = 0;
|
||||
eh->has_got_reloc = 0;
|
||||
eh->has_non_got_reloc = 0;
|
||||
eh->no_finish_dynamic_symbol = 0;
|
||||
@@ -1421,6 +1431,7 @@ elf_x86_64_copy_indirect_symbol (struct bfd_link_info *info,
|
||||
edir = (struct elf_x86_64_link_hash_entry *) dir;
|
||||
eind = (struct elf_x86_64_link_hash_entry *) ind;
|
||||
|
||||
edir->has_gpoff_reloc |= eind->has_gpoff_reloc;
|
||||
edir->has_got_reloc |= eind->has_got_reloc;
|
||||
edir->has_non_got_reloc |= eind->has_non_got_reloc;
|
||||
|
||||
@@ -2431,18 +2442,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 = elf_x86_64_get_local_sym_hash (htab, abfd, rel,
|
||||
TRUE);
|
||||
if (h == NULL)
|
||||
goto error_return;
|
||||
|
||||
/* Fake a STT_GNU_IFUNC symbol. */
|
||||
h->root.root.string = bfd_elf_sym_name (abfd, symtab_hdr,
|
||||
isym, NULL);
|
||||
h->type = STT_GNU_IFUNC;
|
||||
if (r_type == R_X86_64_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;
|
||||
@@ -2869,6 +2888,11 @@ do_size:
|
||||
goto error_return;
|
||||
break;
|
||||
|
||||
case R_X86_64_GPOFF:
|
||||
if (eh != NULL)
|
||||
eh->has_gpoff_reloc = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -3526,6 +3550,10 @@ elf_x86_64_allocate_local_dynrelocs (void **slot, void *inf)
|
||||
struct elf_link_hash_entry *h
|
||||
= (struct elf_link_hash_entry *) *slot;
|
||||
|
||||
/* Skip local symbol with GPOFF relocation. */
|
||||
if (((struct elf_x86_64_link_hash_entry *) h)->has_gpoff_reloc)
|
||||
return TRUE;
|
||||
|
||||
if (h->type != STT_GNU_IFUNC
|
||||
|| !h->def_regular
|
||||
|| !h->ref_regular
|
||||
@@ -5694,6 +5722,41 @@ direct:
|
||||
relocation -= elf_x86_64_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;
|
||||
}
|
||||
@@ -6203,8 +6266,12 @@ elf_x86_64_finish_local_dynamic_symbol (void **slot, void *inf)
|
||||
struct bfd_link_info *info
|
||||
= (struct bfd_link_info *) inf;
|
||||
|
||||
/* Skip local symbol with GPOFF relocation. */
|
||||
if (((struct elf_x86_64_link_hash_entry *) h)->has_gpoff_reloc)
|
||||
return TRUE;
|
||||
|
||||
return elf_x86_64_finish_dynamic_symbol (info->output_bfd,
|
||||
info, h, NULL);
|
||||
info, h, NULL);
|
||||
}
|
||||
|
||||
/* Finish up undefined weak symbol handling in PIE. Fill its PLT entry
|
||||
@@ -7696,12 +7763,131 @@ elf_x86_64_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
|
||||
FALSE, FALSE, FALSE);
|
||||
if (h != NULL)
|
||||
((struct elf_x86_64_link_hash_entry *) h)->tls_get_addr = 1;
|
||||
|
||||
/* Cache and hide __gp symbol. */
|
||||
h = elf_link_hash_lookup (elf_hash_table (info), "__gp", FALSE,
|
||||
FALSE, FALSE);
|
||||
if (h != NULL)
|
||||
{
|
||||
const struct elf_backend_data *bed;
|
||||
struct elf_x86_64_link_hash_table *htab;
|
||||
|
||||
htab = elf_x86_64_hash_table (info);
|
||||
if (htab == NULL)
|
||||
return FALSE;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* Invoke the regular ELF backend linker to do all the work. */
|
||||
return _bfd_elf_link_check_relocs (abfd, info);
|
||||
}
|
||||
|
||||
/* Set up GP section from symbols with GPOFF relocations. */
|
||||
|
||||
static bfd_boolean
|
||||
elf_x86_64_setup_gp (struct elf_link_hash_entry *h, void * inf)
|
||||
{
|
||||
struct bfd_link_info *info;
|
||||
struct elf_x86_64_link_hash_table *htab;
|
||||
struct elf_x86_64_link_hash_entry *eh;
|
||||
struct elf_link_hash_entry *gp;
|
||||
asection *gpsection;
|
||||
bfd_size_type gpsection_size;
|
||||
|
||||
eh = (struct elf_x86_64_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;
|
||||
htab = elf_x86_64_hash_table (info);
|
||||
if (htab == NULL)
|
||||
return FALSE;
|
||||
|
||||
gpsection = h->root.u.def.section->output_section;
|
||||
gpsection_size = bfd_get_section_size (gpsection);
|
||||
if (gpsection_size > 0xffffffff)
|
||||
{
|
||||
info->callbacks->einfo (_("%F%B: GP section `%A' size overflow\n"),
|
||||
info->output_bfd, gpsection);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gp = htab->gp;
|
||||
gp->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_64_setup_gp_from_local_symbol (void **slot, void *inf)
|
||||
{
|
||||
struct elf_link_hash_entry *h
|
||||
= (struct elf_link_hash_entry *) *slot;
|
||||
struct bfd_link_info *info
|
||||
= (struct bfd_link_info *) inf;
|
||||
|
||||
return elf_x86_64_setup_gp (h, info);
|
||||
}
|
||||
|
||||
/* Set up GP section for __gp symbol. */
|
||||
|
||||
static bfd_boolean
|
||||
elf_x86_64_final_link (bfd *abfd, struct bfd_link_info *info)
|
||||
{
|
||||
if (!bfd_link_relocatable (info))
|
||||
{
|
||||
struct elf_link_hash_entry *gp;
|
||||
struct elf_x86_64_link_hash_table *htab;
|
||||
|
||||
htab = elf_x86_64_hash_table (info);
|
||||
if (htab == NULL)
|
||||
return FALSE;
|
||||
|
||||
gp = htab->gp;
|
||||
if (gp != NULL
|
||||
&& 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_64_setup_gp,
|
||||
info);
|
||||
|
||||
if (gp->root.type != bfd_link_hash_defined
|
||||
&& gp->root.type != bfd_link_hash_defweak)
|
||||
{
|
||||
/* Set up __gp from a local symbol with GPOFF
|
||||
relocations. */
|
||||
htab_traverse (htab->loc_hash_table,
|
||||
elf_x86_64_setup_gp_from_local_symbol,
|
||||
info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Invoke the regular ELF backend linker to do all the work. */
|
||||
return bfd_elf_final_link (abfd, info);
|
||||
}
|
||||
|
||||
static const struct bfd_elf_special_section
|
||||
elf_x86_64_special_sections[]=
|
||||
{
|
||||
@@ -7767,6 +7953,7 @@ elf_x86_64_special_sections[]=
|
||||
#define bfd_elf64_mkobject elf_x86_64_mkobject
|
||||
#define bfd_elf64_get_synthetic_symtab elf_x86_64_get_synthetic_symtab
|
||||
#define bfd_elf64_bfd_link_check_relocs elf_x86_64_link_check_relocs
|
||||
#define bfd_elf64_bfd_final_link elf_x86_64_final_link
|
||||
|
||||
#define elf_backend_section_from_shdr \
|
||||
elf_x86_64_section_from_shdr
|
||||
@@ -8068,6 +8255,8 @@ elf32_x86_64_nacl_elf_object_p (bfd *abfd)
|
||||
elf_x86_64_get_synthetic_symtab
|
||||
#define bfd_elf32_bfd_link_check_relocs \
|
||||
elf_x86_64_link_check_relocs
|
||||
#define bfd_elf32_bfd_final_link \
|
||||
elf_x86_64_final_link
|
||||
|
||||
#undef elf_backend_object_p
|
||||
#define elf_backend_object_p \
|
||||
|
||||
@@ -672,6 +672,9 @@ static enum rc_type evexrcig = rne;
|
||||
/* Pre-defined "_GLOBAL_OFFSET_TABLE_". */
|
||||
static symbolS *GOT_symbol;
|
||||
|
||||
/* Pre-defined "__gp". */
|
||||
static symbolS *GP_symbol;
|
||||
|
||||
/* The dwarf2 return column, adjusted for 32 or 64 bit. */
|
||||
unsigned int x86_dwarf2_return_column;
|
||||
|
||||
@@ -7776,6 +7779,9 @@ lex_got (enum bfd_reloc_code_real *rel,
|
||||
{ STRING_COMMA_LEN ("GOTPCREL"), { _dummy_first_bfd_reloc_code_real,
|
||||
BFD_RELOC_X86_64_GOTPCREL },
|
||||
OPERAND_TYPE_IMM32_32S_DISP32 },
|
||||
{ STRING_COMMA_LEN ("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 },
|
||||
@@ -7848,8 +7854,19 @@ lex_got (enum bfd_reloc_code_real *rel,
|
||||
*types = gotrel[j].types64;
|
||||
}
|
||||
|
||||
if (j != 0 && GOT_symbol == NULL)
|
||||
GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
|
||||
if (j != 0)
|
||||
{
|
||||
if (gotrel[j].rel[1] == BFD_RELOC_GPREL32)
|
||||
{
|
||||
if (GP_symbol == NULL)
|
||||
GP_symbol = symbol_find_or_make (GLOBAL_POINTER_NAME);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GOT_symbol == NULL)
|
||||
GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
/* The length of the first part of our input line. */
|
||||
first = cp - input_line_pointer;
|
||||
@@ -8506,6 +8523,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 ();
|
||||
@@ -10740,6 +10761,21 @@ md_undefined_symbol (char *name)
|
||||
};
|
||||
return GOT_symbol;
|
||||
}
|
||||
else if (name[0] == GLOBAL_POINTER_NAME[0]
|
||||
&& name[1] == GLOBAL_POINTER_NAME[1]
|
||||
&& name[2] == GLOBAL_POINTER_NAME[2]
|
||||
&& name[3] == GLOBAL_POINTER_NAME[3]
|
||||
&& strcmp (name, GLOBAL_POINTER_NAME) == 0)
|
||||
{
|
||||
if (!GP_symbol)
|
||||
{
|
||||
if (symbol_find (name))
|
||||
as_bad (_("GP already in symbol table"));
|
||||
GP_symbol = symbol_new (name, undefined_section,
|
||||
(valueT) 0, &zero_address_frag);
|
||||
};
|
||||
return GP_symbol;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10899,6 +10935,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:
|
||||
|
||||
@@ -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
|
||||
|
||||
11
gas/testsuite/gas/i386/gpoff.d
Normal file
11
gas/testsuite/gas/i386/gpoff.d
Normal file
@@ -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
|
||||
4
gas/testsuite/gas/i386/gpoff.s
Normal file
4
gas/testsuite/gas/i386/gpoff.s
Normal file
@@ -0,0 +1,4 @@
|
||||
.text
|
||||
_start:
|
||||
leal foo@GPOFF, %eax
|
||||
movl %fs:foo@GPOFF, %eax
|
||||
@@ -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"
|
||||
|
||||
18
gas/testsuite/gas/i386/inval-gpoff.l
Normal file
18
gas/testsuite/gas/i386/inval-gpoff.l
Normal file
@@ -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
|
||||
5
gas/testsuite/gas/i386/inval-gpoff.s
Normal file
5
gas/testsuite/gas/i386/inval-gpoff.s
Normal file
@@ -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
|
||||
11
gas/testsuite/gas/i386/x86-64-gpoff.d
Normal file
11
gas/testsuite/gas/i386/x86-64-gpoff.d
Normal file
@@ -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
|
||||
4
gas/testsuite/gas/i386/x86-64-gpoff.s
Normal file
4
gas/testsuite/gas/i386/x86-64-gpoff.s
Normal file
@@ -0,0 +1,4 @@
|
||||
.text
|
||||
_start:
|
||||
leal foo@GPOFF, %eax
|
||||
movl %gs:foo@GPOFF, %eax
|
||||
30
gas/testsuite/gas/i386/x86-64-inval-gpoff.l
Normal file
30
gas/testsuite/gas/i386/x86-64-inval-gpoff.l
Normal file
@@ -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
|
||||
7
gas/testsuite/gas/i386/x86-64-inval-gpoff.s
Normal file
7
gas/testsuite/gas/i386/x86-64-inval-gpoff.s
Normal file
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
20
ld/testsuite/ld-i386/gpoff-1a.S
Normal file
20
ld/testsuite/ld-i386/gpoff-1a.S
Normal file
@@ -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
|
||||
79
ld/testsuite/ld-i386/gpoff-1b.c
Normal file
79
ld/testsuite/ld-i386/gpoff-1b.c
Normal file
@@ -0,0 +1,79 @@
|
||||
#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);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
19
ld/testsuite/ld-i386/gpoff-2a.S
Normal file
19
ld/testsuite/ld-i386/gpoff-2a.S
Normal file
@@ -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
|
||||
78
ld/testsuite/ld-i386/gpoff-2b.c
Normal file
78
ld/testsuite/ld-i386/gpoff-2b.c
Normal file
@@ -0,0 +1,78 @@
|
||||
#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);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
3
ld/testsuite/ld-i386/gpoff-3.d
Normal file
3
ld/testsuite/ld-i386/gpoff-3.d
Normal file
@@ -0,0 +1,3 @@
|
||||
#as: --32
|
||||
#ld: -melf_i386
|
||||
#error: undefined reference to `foo'
|
||||
4
ld/testsuite/ld-i386/gpoff-3.s
Normal file
4
ld/testsuite/ld-i386/gpoff-3.s
Normal file
@@ -0,0 +1,4 @@
|
||||
.text
|
||||
.globl _start
|
||||
_start:
|
||||
movl %fs:foo@GPOFF, %eax
|
||||
3
ld/testsuite/ld-i386/gpoff-4.d
Normal file
3
ld/testsuite/ld-i386/gpoff-4.d
Normal file
@@ -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'
|
||||
16
ld/testsuite/ld-i386/gpoff-4.s
Normal file
16
ld/testsuite/ld-i386/gpoff-4.s
Normal file
@@ -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
|
||||
3
ld/testsuite/ld-i386/gpoff-5.d
Normal file
3
ld/testsuite/ld-i386/gpoff-5.d
Normal file
@@ -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'
|
||||
18
ld/testsuite/ld-i386/gpoff-5.s
Normal file
18
ld/testsuite/ld-i386/gpoff-5.s
Normal file
@@ -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
|
||||
12
ld/testsuite/ld-i386/gpoff-6.d
Normal file
12
ld/testsuite/ld-i386/gpoff-6.d
Normal file
@@ -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
|
||||
9
ld/testsuite/ld-i386/gpoff-6.s
Normal file
9
ld/testsuite/ld-i386/gpoff-6.s
Normal file
@@ -0,0 +1,9 @@
|
||||
.text
|
||||
.globl _start
|
||||
_start:
|
||||
ret
|
||||
|
||||
.section .text.bar,"ax",@progbits
|
||||
.globl bar
|
||||
bar:
|
||||
movl %fs:foo@GPOFF, %eax
|
||||
16
ld/testsuite/ld-i386/gpoff-7.d
Normal file
16
ld/testsuite/ld-i386/gpoff-7.d
Normal file
@@ -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
|
||||
9
ld/testsuite/ld-i386/gpoff-7.s
Normal file
9
ld/testsuite/ld-i386/gpoff-7.s
Normal file
@@ -0,0 +1,9 @@
|
||||
.text
|
||||
.globl _start
|
||||
_start:
|
||||
movl %fs:foo@GPOFF, %eax
|
||||
|
||||
.data
|
||||
.globl foo
|
||||
foo:
|
||||
.long 0x12345678
|
||||
10
ld/testsuite/ld-i386/gpoff-8.s
Normal file
10
ld/testsuite/ld-i386/gpoff-8.s
Normal file
@@ -0,0 +1,10 @@
|
||||
.text
|
||||
.globl _start
|
||||
_start:
|
||||
movl %fs:foo@GPOFF, %eax
|
||||
movl __gp@GOT(%ebx), %eax
|
||||
|
||||
.data
|
||||
.globl foo
|
||||
foo:
|
||||
.long 0x12345678
|
||||
39
ld/testsuite/ld-i386/gpoff-8.t
Normal file
39
ld/testsuite/ld-i386/gpoff-8.t
Normal file
@@ -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/ : { *(.*) }
|
||||
}
|
||||
18
ld/testsuite/ld-i386/gpoff-8a.d
Normal file
18
ld/testsuite/ld-i386/gpoff-8a.d
Normal file
@@ -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
|
||||
18
ld/testsuite/ld-i386/gpoff-8b.d
Normal file
18
ld/testsuite/ld-i386/gpoff-8b.d
Normal file
@@ -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
|
||||
18
ld/testsuite/ld-i386/gpoff-8c.d
Normal file
18
ld/testsuite/ld-i386/gpoff-8c.d
Normal file
@@ -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
|
||||
18
ld/testsuite/ld-i386/gpoff-8d.d
Normal file
18
ld/testsuite/ld-i386/gpoff-8d.d
Normal file
@@ -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
|
||||
18
ld/testsuite/ld-i386/gpoff-8e.d
Normal file
18
ld/testsuite/ld-i386/gpoff-8e.d
Normal file
@@ -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
|
||||
18
ld/testsuite/ld-i386/gpoff-8f.d
Normal file
18
ld/testsuite/ld-i386/gpoff-8f.d
Normal file
@@ -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
|
||||
@@ -438,6 +438,17 @@ run_dump_test "property-x86-shstk5"
|
||||
run_dump_test "pie1"
|
||||
run_dump_test "pie1-nacl"
|
||||
run_dump_test "pr21884"
|
||||
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"
|
||||
|
||||
if { !([istarget "i?86-*-linux*"]
|
||||
|| [istarget "i?86-*-gnu*"]
|
||||
@@ -1267,6 +1278,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*"]
|
||||
|
||||
20
ld/testsuite/ld-x86-64/gpoff-1a.S
Normal file
20
ld/testsuite/ld-x86-64/gpoff-1a.S
Normal file
@@ -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
|
||||
29
ld/testsuite/ld-x86-64/gpoff-1b.c
Normal file
29
ld/testsuite/ld-x86-64/gpoff-1b.c
Normal file
@@ -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;
|
||||
}
|
||||
19
ld/testsuite/ld-x86-64/gpoff-2a.S
Normal file
19
ld/testsuite/ld-x86-64/gpoff-2a.S
Normal file
@@ -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
|
||||
27
ld/testsuite/ld-x86-64/gpoff-2b.c
Normal file
27
ld/testsuite/ld-x86-64/gpoff-2b.c
Normal file
@@ -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;
|
||||
}
|
||||
3
ld/testsuite/ld-x86-64/gpoff-3.d
Normal file
3
ld/testsuite/ld-x86-64/gpoff-3.d
Normal file
@@ -0,0 +1,3 @@
|
||||
#as: --64
|
||||
#ld: -melf_x86_64
|
||||
#error: undefined reference to `foo'
|
||||
4
ld/testsuite/ld-x86-64/gpoff-3.s
Normal file
4
ld/testsuite/ld-x86-64/gpoff-3.s
Normal file
@@ -0,0 +1,4 @@
|
||||
.text
|
||||
.globl _start
|
||||
_start:
|
||||
movl %gs:foo@GPOFF, %eax
|
||||
3
ld/testsuite/ld-x86-64/gpoff-4.d
Normal file
3
ld/testsuite/ld-x86-64/gpoff-4.d
Normal file
@@ -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'
|
||||
16
ld/testsuite/ld-x86-64/gpoff-4.s
Normal file
16
ld/testsuite/ld-x86-64/gpoff-4.s
Normal file
@@ -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
|
||||
3
ld/testsuite/ld-x86-64/gpoff-5.d
Normal file
3
ld/testsuite/ld-x86-64/gpoff-5.d
Normal file
@@ -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'
|
||||
18
ld/testsuite/ld-x86-64/gpoff-5.s
Normal file
18
ld/testsuite/ld-x86-64/gpoff-5.s
Normal file
@@ -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
|
||||
12
ld/testsuite/ld-x86-64/gpoff-6.d
Normal file
12
ld/testsuite/ld-x86-64/gpoff-6.d
Normal file
@@ -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
|
||||
9
ld/testsuite/ld-x86-64/gpoff-6.s
Normal file
9
ld/testsuite/ld-x86-64/gpoff-6.s
Normal file
@@ -0,0 +1,9 @@
|
||||
.text
|
||||
.globl _start
|
||||
_start:
|
||||
ret
|
||||
|
||||
.section .text.bar,"ax",@progbits
|
||||
.globl bar
|
||||
bar:
|
||||
movl %gs:foo@GPOFF, %eax
|
||||
16
ld/testsuite/ld-x86-64/gpoff-7.d
Normal file
16
ld/testsuite/ld-x86-64/gpoff-7.d
Normal file
@@ -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
|
||||
9
ld/testsuite/ld-x86-64/gpoff-7.s
Normal file
9
ld/testsuite/ld-x86-64/gpoff-7.s
Normal file
@@ -0,0 +1,9 @@
|
||||
.text
|
||||
.globl _start
|
||||
_start:
|
||||
movl %gs:foo@GPOFF, %eax
|
||||
|
||||
.data
|
||||
.globl foo
|
||||
foo:
|
||||
.long 0x12345678
|
||||
10
ld/testsuite/ld-x86-64/gpoff-8.s
Normal file
10
ld/testsuite/ld-x86-64/gpoff-8.s
Normal file
@@ -0,0 +1,10 @@
|
||||
.text
|
||||
.globl _start
|
||||
_start:
|
||||
movl %gs:foo@GPOFF, %eax
|
||||
movq __gp@GOTPCREL(%rip), %rax
|
||||
|
||||
.data
|
||||
.globl foo
|
||||
foo:
|
||||
.long 0x12345678
|
||||
39
ld/testsuite/ld-x86-64/gpoff-8.t
Normal file
39
ld/testsuite/ld-x86-64/gpoff-8.t
Normal file
@@ -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/ : { *(.*) }
|
||||
}
|
||||
18
ld/testsuite/ld-x86-64/gpoff-8a.d
Normal file
18
ld/testsuite/ld-x86-64/gpoff-8a.d
Normal file
@@ -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
|
||||
18
ld/testsuite/ld-x86-64/gpoff-8b.d
Normal file
18
ld/testsuite/ld-x86-64/gpoff-8b.d
Normal file
@@ -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
|
||||
18
ld/testsuite/ld-x86-64/gpoff-8c.d
Normal file
18
ld/testsuite/ld-x86-64/gpoff-8c.d
Normal file
@@ -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
|
||||
18
ld/testsuite/ld-x86-64/gpoff-8d.d
Normal file
18
ld/testsuite/ld-x86-64/gpoff-8d.d
Normal file
@@ -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
|
||||
18
ld/testsuite/ld-x86-64/gpoff-8e.d
Normal file
18
ld/testsuite/ld-x86-64/gpoff-8e.d
Normal file
@@ -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
|
||||
18
ld/testsuite/ld-x86-64/gpoff-8f.d
Normal file
18
ld/testsuite/ld-x86-64/gpoff-8f.d
Normal file
@@ -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
|
||||
@@ -568,6 +568,17 @@ run_dump_test "pr20253-4f"
|
||||
run_dump_test "pr20253-5a"
|
||||
run_dump_test "pr20253-5b"
|
||||
run_dump_test "tlsdesc2"
|
||||
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"
|
||||
|
||||
proc undefined_weak {cflags ldflags} {
|
||||
set testname "Undefined weak symbol"
|
||||
@@ -1531,6 +1542,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"
|
||||
|
||||
Reference in New Issue
Block a user