Compare commits

...

6 Commits

Author SHA1 Message Date
Marcin Kościelnicki
0757c0695b gold/s390: Support partial got relro. 2016-07-04 11:04:48 +02:00
Marcin Kościelnicki
6257e07319 bfd/elf64-s390: Support partial got relro. 2016-07-04 11:04:10 +02:00
Marcin Kościelnicki
6f074b23dc bfd/elf32-s390: Support partial got relro. 2016-07-04 11:04:10 +02:00
Marcin Kościelnicki
137afa28a3 bfd/elf32-s390: Prepare for _GLOBAL_OFFSET_TABLE_ != DT_PLTGOT
This will be used for got relro support.
2016-06-22 13:06:44 +02:00
Marcin Kościelnicki
2dacf3e9c8 bfd/elf64-s390: Prepare for _GLOBAL_OFFSET_TABLE_ != DT_PLTGOT
This will be used for got relro support.
2016-06-22 13:06:44 +02:00
Marcin Kościelnicki
cbbdd10114 ld: Enable using separate linker script for -z relro
This will be used for s390 relro got support.

ld/ChangeLog:

	* emultempl/elf32.em: Use .xo, .xso, .xdo scripts if
	GENERATE_RELRO_SCRIPT is set.
	* genscripts.sh: Create .xo, .xso, .xdo scripts if
	GENERATE_RELRO_SCRIPT is set.
2016-06-22 13:06:44 +02:00
7 changed files with 462 additions and 77 deletions

View File

@@ -629,6 +629,19 @@ static const bfd_byte elf_s390_plt_first_entry[PLT_FIRST_ENTRY_SIZE] =
};
static const bfd_byte elf_s390_plt_pic_first_entry[PLT_FIRST_ENTRY_SIZE] =
{
0x50, 0x10, 0xf0, 0x1c, /* st %r1,28(%r15) */
0x0d, 0x10, /* basr %r1,%r0 */
0x5a, 0x10, 0x10, 0x12, /* a %r1,18(%r1) */
0xd2, 0x03, 0xf0, 0x18, 0x10, 0x04, /* mvc 24(4,%r15),4(%r1) */
0x58, 0x10, 0x10, 0x08, /* l %r1,8(%r1) */
0x07, 0xf1, /* br %r1 */
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00
};
static const bfd_byte elf_s390_plt_pic12_first_entry[PLT_FIRST_ENTRY_SIZE] =
{
0x50, 0x10, 0xf0, 0x1c, /* st %r1,28(%r15) */
0x58, 0x10, 0xc0, 0x04, /* l %r1,4(%r12) */
@@ -740,6 +753,8 @@ struct elf_s390_link_hash_table
asection *srelbss;
asection *irelifunc;
bfd_boolean split_got;
union
{
bfd_signed_vma refcount;
@@ -823,6 +838,8 @@ static bfd_boolean
create_got_section (bfd *dynobj, struct bfd_link_info *info)
{
struct elf_s390_link_hash_table *htab;
struct elf_link_hash_entry *h;
asection *got_section;
if (! _bfd_elf_create_got_section (dynobj, info))
return FALSE;
@@ -834,6 +851,27 @@ create_got_section (bfd *dynobj, struct bfd_link_info *info)
if (!htab->elf.sgot || !htab->elf.sgotplt || !htab->elf.srelgot)
abort ();
/* The condition here has to match linker script selection. */
if (info->combreloc && info->relro && !(info->flags & DF_BIND_NOW))
{
htab->elf.sgot->size += GOT_ENTRY_SIZE;
got_section = htab->elf.sgot;
htab->split_got = TRUE;
}
else
{
got_section = htab->elf.sgotplt;
htab->split_got = FALSE;
}
/* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got
or .got.plt section. */
h = _bfd_elf_define_linkage_sym (dynobj, info, got_section,
"_GLOBAL_OFFSET_TABLE_");
elf_hash_table (info)->hgot = h;
if (h == NULL)
return FALSE;
return TRUE;
}
@@ -2508,9 +2546,10 @@ elf_s390_relocate_section (bfd *output_bfd,
{
plt_index = h->plt.offset / PLT_ENTRY_SIZE;
relocation = (plt_index * GOT_ENTRY_SIZE +
htab->elf.igotplt->output_offset);
if (r_type == R_390_GOTPLTENT)
relocation += htab->elf.igotplt->output_section->vma;
htab->elf.igotplt->output_offset +
htab->elf.igotplt->output_section->vma);
if (r_type != R_390_GOTPLTENT)
relocation -= htab->elf.sgot->output_section->vma;
}
else
{
@@ -2521,9 +2560,11 @@ elf_s390_relocate_section (bfd *output_bfd,
/* Offset in GOT is PLT index plus GOT headers(3)
times 4, addr & GOT addr. */
relocation = (plt_index + 3) * GOT_ENTRY_SIZE;
if (r_type == R_390_GOTPLTENT)
relocation += htab->elf.sgot->output_section->vma;
relocation = (plt_index + 3) * GOT_ENTRY_SIZE +
htab->elf.sgotplt->output_offset +
htab->elf.sgotplt->output_section->vma;
if (r_type != R_390_GOTPLTENT)
relocation -= htab->elf.sgot->output_section->vma;
}
unresolved_reloc = FALSE;
@@ -2671,15 +2712,16 @@ elf_s390_relocate_section (bfd *output_bfd,
if (off >= (bfd_vma) -2)
abort ();
relocation = base_got->output_offset + off;
relocation = base_got->output_offset + off +
base_got->output_section->vma;
/* For @GOTENT the relocation is against the offset between
the instruction and the symbols entry in the GOT and not
between the start of the GOT and the symbols entry. We
add the vma of the GOT to get the correct value. */
if ( r_type == R_390_GOTENT
|| r_type == R_390_GOTPLTENT)
relocation += base_got->output_section->vma;
if ( r_type != R_390_GOTENT
&& r_type != R_390_GOTPLTENT)
relocation -= base_got->output_section->vma;
break;
@@ -3492,7 +3534,9 @@ elf_s390_finish_ifunc_symbol (bfd *output_bfd,
/* Offset into the igot.plt section. */
igotiplt_offset = iplt_index * GOT_ENTRY_SIZE;
/* Offset into the got section. */
got_offset = igotiplt_offset + gotplt->output_offset;
got_offset = igotiplt_offset + gotplt->output_offset +
gotplt->output_section->vma -
htab->elf.sgot->output_section->vma;
/* S390 uses halfwords for relative branch calc! */
relative_offset = - (plt->output_offset +
@@ -3515,7 +3559,7 @@ elf_s390_finish_ifunc_symbol (bfd *output_bfd,
/* Push the GOT offset field. */
bfd_put_32 (output_bfd,
(gotplt->output_section->vma
(htab->elf.sgot->output_section->vma
+ got_offset),
plt->contents + iplt_offset + 24);
}
@@ -3583,7 +3627,7 @@ elf_s390_finish_ifunc_symbol (bfd *output_bfd,
gotplt->contents + igotiplt_offset);
/* Fill in the entry in the .rela.plt section. */
rela.r_offset = gotplt->output_section->vma + got_offset;
rela.r_offset = htab->elf.sgot->output_section->vma + got_offset;
if (!h
|| h->dynindx == -1
@@ -3623,6 +3667,7 @@ elf_s390_finish_dynamic_symbol (bfd *output_bfd,
{
bfd_vma plt_index;
bfd_vma got_offset;
bfd_vma got_plt_offset;
Elf_Internal_Rela rela;
bfd_byte *loc;
bfd_vma relative_offset;
@@ -3653,7 +3698,10 @@ elf_s390_finish_dynamic_symbol (bfd *output_bfd,
/* Offset in GOT is PLT index plus GOT headers(3) times 4,
addr & GOT addr. */
got_offset = (plt_index + 3) * GOT_ENTRY_SIZE;
got_plt_offset = (plt_index + 3) * GOT_ENTRY_SIZE;
got_offset = got_plt_offset + htab->elf.sgotplt->output_offset +
htab->elf.sgotplt->output_section->vma -
htab->elf.sgot->output_section->vma;
/* S390 uses halfwords for relative branch calc! */
relative_offset = - ((PLT_FIRST_ENTRY_SIZE +
@@ -3676,8 +3724,7 @@ elf_s390_finish_dynamic_symbol (bfd *output_bfd,
/* Push the GOT offset field. */
bfd_put_32 (output_bfd,
(htab->elf.sgotplt->output_section->vma
+ htab->elf.sgotplt->output_offset
(htab->elf.sgot->output_section->vma
+ got_offset),
htab->elf.splt->contents + h->plt.offset + 24);
}
@@ -3741,11 +3788,10 @@ elf_s390_finish_dynamic_symbol (bfd *output_bfd,
+ htab->elf.splt->output_offset
+ h->plt.offset
+ 12),
htab->elf.sgotplt->contents + got_offset);
htab->elf.sgotplt->contents + got_plt_offset);
/* Fill in the entry in the .rela.plt section. */
rela.r_offset = (htab->elf.sgotplt->output_section->vma
+ htab->elf.sgotplt->output_offset
rela.r_offset = (htab->elf.sgot->output_section->vma
+ got_offset);
rela.r_info = ELF32_R_INFO (h->dynindx, R_390_JMP_SLOT);
rela.r_addend = 0;
@@ -3921,6 +3967,7 @@ elf_s390_finish_dynamic_sections (bfd *output_bfd,
asection *sdyn;
bfd *ibfd;
unsigned int i;
bfd_vma got_plt_offset;
htab = elf_s390_hash_table (info);
dynobj = htab->elf.dynobj;
@@ -3971,8 +4018,33 @@ elf_s390_finish_dynamic_sections (bfd *output_bfd,
memset (htab->elf.splt->contents, 0, PLT_FIRST_ENTRY_SIZE);
if (bfd_link_pic (info))
{
memcpy (htab->elf.splt->contents, elf_s390_plt_pic_first_entry,
PLT_FIRST_ENTRY_SIZE);
got_plt_offset = htab->elf.sgotplt->output_offset +
htab->elf.sgotplt->output_section->vma -
htab->elf.sgot->output_section->vma;
if (got_plt_offset < 0xff8)
{
memcpy (htab->elf.splt->contents,
elf_s390_plt_pic12_first_entry,
PLT_FIRST_ENTRY_SIZE);
/* Put in the GOT offset as displacement values. The 0xc000
value comes from the first word of the plt entry. Look
at the elf_s390_plt_pic12_first_entry content. */
bfd_put_16 (output_bfd, (bfd_vma)0xc000 | (got_plt_offset + 4),
htab->elf.splt->contents + 6);
bfd_put_16 (output_bfd, (bfd_vma)0xc000 | (got_plt_offset + 8),
htab->elf.splt->contents + 14);
}
else
{
memcpy (htab->elf.splt->contents,
elf_s390_plt_pic_first_entry,
PLT_FIRST_ENTRY_SIZE);
bfd_put_32 (output_bfd,
htab->elf.sgotplt->output_section->vma
+ htab->elf.sgotplt->output_offset
- htab->elf.splt->output_section->vma - 6,
htab->elf.splt->contents + 24);
}
}
else
{
@@ -4007,6 +4079,15 @@ elf_s390_finish_dynamic_sections (bfd *output_bfd,
elf_section_data (htab->elf.sgotplt->output_section)
->this_hdr.sh_entsize = 4;
}
if (htab->elf.sgot && htab->split_got)
{
bfd_put_32 (output_bfd,
(sdyn == NULL ? (bfd_vma) 0
: sdyn->output_section->vma + sdyn->output_offset),
htab->elf.sgot->contents);
}
/* Finish dynamic symbol for local IFUNC symbols. */
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
{
@@ -4109,6 +4190,8 @@ elf32_s390_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
#define elf_backend_want_got_plt 1
#define elf_backend_plt_readonly 1
#define elf_backend_want_plt_sym 0
/* We create got symbol ourselves, since it may not be in .got.plt */
#define elf_backend_want_got_sym 0
#define elf_backend_got_header_size 12
#define elf_backend_rela_normal 1

View File

@@ -653,6 +653,8 @@ struct elf_s390_link_hash_table
asection *srelbss;
asection *irelifunc;
bfd_boolean split_got;
union {
bfd_signed_vma refcount;
bfd_vma offset;
@@ -736,6 +738,8 @@ create_got_section (bfd *dynobj,
struct bfd_link_info *info)
{
struct elf_s390_link_hash_table *htab;
struct elf_link_hash_entry *h;
asection *got_section;
if (! _bfd_elf_create_got_section (dynobj, info))
return FALSE;
@@ -749,6 +753,28 @@ create_got_section (bfd *dynobj,
htab->elf.srelgot = bfd_get_linker_section (dynobj, ".rela.got");
if (!htab->elf.sgot || !htab->elf.sgotplt || !htab->elf.srelgot)
abort ();
/* The condition here has to match linker script selection. */
if (info->combreloc && info->relro && !(info->flags & DF_BIND_NOW))
{
htab->elf.sgot->size += GOT_ENTRY_SIZE;
got_section = htab->elf.sgot;
htab->split_got = TRUE;
}
else
{
got_section = htab->elf.sgotplt;
htab->split_got = FALSE;
}
/* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got
or .got.plt section. */
h = _bfd_elf_define_linkage_sym (dynobj, info, got_section,
"_GLOBAL_OFFSET_TABLE_");
elf_hash_table (info)->hgot = h;
if (h == NULL)
return FALSE;
return TRUE;
}
@@ -2467,9 +2493,10 @@ elf_s390_relocate_section (bfd *output_bfd,
{
plt_index = h->plt.offset / PLT_ENTRY_SIZE;
relocation = (plt_index * GOT_ENTRY_SIZE +
htab->elf.igotplt->output_offset);
if (r_type == R_390_GOTPLTENT)
relocation += htab->elf.igotplt->output_section->vma;
htab->elf.igotplt->output_offset +
htab->elf.igotplt->output_section->vma);
if (r_type != R_390_GOTPLTENT)
relocation -= htab->elf.sgot->output_section->vma;
}
else
{
@@ -2480,9 +2507,11 @@ elf_s390_relocate_section (bfd *output_bfd,
/* Offset in GOT is PLT index plus GOT headers(3)
times 8, addr & GOT addr. */
relocation = (plt_index + 3) * GOT_ENTRY_SIZE;
if (r_type == R_390_GOTPLTENT)
relocation += htab->elf.sgot->output_section->vma;
relocation = (plt_index + 3) * GOT_ENTRY_SIZE +
htab->elf.sgotplt->output_offset +
htab->elf.sgotplt->output_section->vma;
if (r_type != R_390_GOTPLTENT)
relocation -= htab->elf.sgot->output_section->vma;
}
unresolved_reloc = FALSE;
break;
@@ -2631,15 +2660,16 @@ elf_s390_relocate_section (bfd *output_bfd,
if (off >= (bfd_vma) -2)
abort ();
relocation = base_got->output_offset + off;
relocation = base_got->output_offset + off +
base_got->output_section->vma;
/* For @GOTENT the relocation is against the offset between
the instruction and the symbols entry in the GOT and not
between the start of the GOT and the symbols entry. We
add the vma of the GOT to get the correct value. */
if ( r_type == R_390_GOTENT
|| r_type == R_390_GOTPLTENT)
relocation += base_got->output_section->vma;
if ( r_type != R_390_GOTENT
&& r_type != R_390_GOTPLTENT)
relocation -= htab->elf.sgot->output_section->vma;
break;
@@ -3810,6 +3840,14 @@ elf_s390_finish_dynamic_sections (bfd *output_bfd,
->this_hdr.sh_entsize = 8;
}
if (htab->elf.sgot && htab->split_got)
{
bfd_put_64 (output_bfd,
(sdyn == NULL ? (bfd_vma) 0
: sdyn->output_section->vma + sdyn->output_offset),
htab->elf.sgot->contents);
}
/* Finish dynamic symbol for local IFUNC symbols. */
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
{
@@ -3919,6 +3957,8 @@ const struct elf_size_info s390_elf64_size_info =
#define elf_backend_want_got_plt 1
#define elf_backend_plt_readonly 1
#define elf_backend_want_plt_sym 0
/* We create got symbol ourselves, since it may not be in .got.plt */
#define elf_backend_want_got_sym 0
#define elf_backend_got_header_size 24
#define elf_backend_rela_normal 1

View File

@@ -78,6 +78,38 @@ class Output_data_got_plt_s390 : public Output_section_data_build
Layout* layout_;
};
// A class to handle the first entry of .got when partial relro is in use.
template<int size>
class Output_data_got_dynamic_s390 : public Output_section_data_build
{
public:
Output_data_got_dynamic_s390(Layout* layout)
: Output_section_data_build(size/8),
layout_(layout)
{ }
Output_data_got_dynamic_s390(Layout* layout, off_t data_size)
: Output_section_data_build(data_size, size/8),
layout_(layout)
{ }
protected:
// Write out the PLT data.
void
do_write(Output_file*);
// Write to a map file.
void
do_print_to_mapfile(Mapfile* mapfile) const
{ mapfile->print_output_data(this, "** GOT DYNAMIC"); }
private:
// A pointer to the Layout class, so that we can find the .dynamic
// section when we write out the GOT section.
Layout* layout_;
};
// A class to handle the PLT data.
template<int size>
@@ -90,10 +122,11 @@ class Output_data_plt_s390 : public Output_section_data
Output_data_plt_s390(Layout* layout,
Output_data_got<size, true>* got,
Output_data_got_plt_s390<size>* got_plt,
Output_data_space* got_irelative)
Output_data_space* got_irelative,
Output_section_data_build* got_dynamic)
: Output_section_data(4), layout_(layout),
irelative_rel_(NULL), got_(got), got_plt_(got_plt),
got_irelative_(got_irelative), count_(0),
got_irelative_(got_irelative), got_dynamic_(got_dynamic), count_(0),
irelative_count_(0), free_list_()
{ this->init(layout); }
@@ -101,11 +134,13 @@ class Output_data_plt_s390 : public Output_section_data
Output_data_got<size, true>* got,
Output_data_got_plt_s390<size>* got_plt,
Output_data_space* got_irelative,
Output_section_data_build* got_dynamic,
unsigned int plt_count)
: Output_section_data((plt_count + 1) * plt_entry_size,
4, false),
layout_(layout), irelative_rel_(NULL), got_(got),
got_plt_(got_plt), got_irelative_(got_irelative), count_(plt_count),
got_plt_(got_plt), got_irelative_(got_irelative),
got_dynamic_(got_dynamic), count_(plt_count),
irelative_count_(0), free_list_()
{
this->init(layout);
@@ -195,7 +230,8 @@ class Output_data_plt_s390 : public Output_section_data
void
fill_first_plt_entry(unsigned char* pov,
typename elfcpp::Elf_types<size>::Elf_Addr got_address,
typename elfcpp::Elf_types<size>::Elf_Addr plt_address);
typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
unsigned int got_plt_offset);
// Fill in a normal PLT entry. Returns the offset into the entry that
// should be the initial GOT slot value.
@@ -238,6 +274,8 @@ class Output_data_plt_s390 : public Output_section_data
Output_data_got_plt_s390<size>* got_plt_;
// The part of the .got.plt section used for IRELATIVE relocs.
Output_data_space* got_irelative_;
// The header of .got section.
Output_section_data_build* got_dynamic_;
// The number of PLT entries.
unsigned int count_;
// Number of PLT entries with R_TILEGX_IRELATIVE relocs. These
@@ -251,6 +289,7 @@ class Output_data_plt_s390 : public Output_section_data
static const int plt_entry_size = 0x20;
// The first entry in the PLT.
static const unsigned char first_plt_entry_32_abs[plt_entry_size];
static const unsigned char first_plt_entry_32_pic12[plt_entry_size];
static const unsigned char first_plt_entry_32_pic[plt_entry_size];
static const unsigned char first_plt_entry_64[plt_entry_size];
// Other entries in the PLT for an executable.
@@ -646,7 +685,7 @@ class Target_s390 : public Sized_target<size, true>
got_address() const
{
gold_assert(this->got_ != NULL);
return this->got_plt_->address();
return this->got_dynamic_->address();
}
typename elfcpp::Elf_types<size>::Elf_Addr
@@ -741,6 +780,10 @@ class Target_s390 : public Sized_target<size, true>
Output_data_got_plt_s390<size>* got_plt_;
// The GOT section for IRELATIVE relocations.
Output_data_space* got_irelative_;
// The section containing the first GOT entry (_DYNAMIC) - this is
// Output_data_got_dynamic_s390 if partial relro is in use, same
// as got_plt_ otherwise.
Output_section_data_build* got_dynamic_;
// The _GLOBAL_OFFSET_TABLE_ symbol.
Symbol* global_offset_table_;
// The dynamic reloc section.
@@ -1247,18 +1290,18 @@ Output_data_plt_s390<size>::first_plt_entry_32_abs[plt_entry_size] =
0x58, 0x10, 0x10, 0x08, // l %r1, 8(%r1)
0x07, 0xf1, // br %r1
0x00, 0x00, // padding
0x00, 0x00, 0x00, 0x00, // _GLOBAL_OFFSET_TABLE_ (to fill)
0x00, 0x00, 0x00, 0x00, // DT_GOTPLT (to fill)
0x00, 0x00, 0x00, 0x00, // padding
};
template<int size>
const unsigned char
Output_data_plt_s390<size>::first_plt_entry_32_pic[plt_entry_size] =
Output_data_plt_s390<size>::first_plt_entry_32_pic12[plt_entry_size] =
{
0x50, 0x10, 0xf0, 0x1c, // st %r1, 28(%r15)
0x58, 0x10, 0xc0, 0x04, // l %r1, 4(%r12)
0x58, 0x10, 0xc0, 0x00, // l %r1, DT_GOTPLT@got+4(%r12) (to fill)
0x50, 0x10, 0xf0, 0x18, // st %r1, 24(%r15)
0x58, 0x10, 0xc0, 0x08, // l %r1, 8(%r12)
0x58, 0x10, 0xc0, 0x00, // l %r1, DT_GOTPLT@got+8(%r12) (to fill)
0x07, 0xf1, // br %r1
0x00, 0x00, // padding
0x00, 0x00, 0x00, 0x00, // padding
@@ -1266,12 +1309,27 @@ Output_data_plt_s390<size>::first_plt_entry_32_pic[plt_entry_size] =
0x00, 0x00, 0x00, 0x00, // padding
};
template<int size>
const unsigned char
Output_data_plt_s390<size>::first_plt_entry_32_pic[plt_entry_size] =
{
0x50, 0x10, 0xf0, 0x1c, // st %r1, 28(%r15)
0x0d, 0x10, // basr %r1, %r0
0x5a, 0x10, 0x10, 0x12, // a %r1, 18(%r1)
0xd2, 0x03, 0xf0, 0x18, 0x10, 0x04, // mvc 24(4,%r15), 4(%r1)
0x58, 0x10, 0x10, 0x08, // l %r1, 8(%r1)
0x07, 0xf1, // br %r1
0x00, 0x00, // padding
0x00, 0x00, 0x00, 0x00, // DT_GOTPLT - . + 18 (to fill)
0x00, 0x00, 0x00, 0x00, // padding
};
template<int size>
const unsigned char
Output_data_plt_s390<size>::first_plt_entry_64[plt_entry_size] =
{
0xe3, 0x10, 0xf0, 0x38, 0x00, 0x24, // stg %r1, 56(%r15)
0xc0, 0x10, 0x00, 0x00, 0x00, 0x00, // larl %r1, _GLOBAL_OFFSET_TABLE_ (to fill)
0xc0, 0x10, 0x00, 0x00, 0x00, 0x00, // larl %r1, DT_GOTPLT (to fill)
0xd2, 0x07, 0xf0, 0x30, 0x10, 0x08, // mvc 48(8,%r15), 8(%r1)
0xe3, 0x10, 0x10, 0x10, 0x00, 0x04, // lg %r1, 16(%r1)
0x07, 0xf1, // br %r1
@@ -1284,22 +1342,33 @@ template<int size>
void
Output_data_plt_s390<size>::fill_first_plt_entry(
unsigned char* pov,
typename elfcpp::Elf_types<size>::Elf_Addr got_address,
typename elfcpp::Elf_types<size>::Elf_Addr plt_address)
typename elfcpp::Elf_types<size>::Elf_Addr got_plt_address,
typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
unsigned int got_plt_offset)
{
if (size == 64)
{
memcpy(pov, first_plt_entry_64, plt_entry_size);
S390_relocate_functions<size>::pcrela32dbl(pov + 8, got_address, (plt_address + 6));
S390_relocate_functions<size>::pcrela32dbl(pov + 8, got_plt_address, (plt_address + 6));
}
else if (!parameters->options().output_is_position_independent())
{
memcpy(pov, first_plt_entry_32_abs, plt_entry_size);
elfcpp::Swap<32, true>::writeval(pov + 24, got_address);
elfcpp::Swap<32, true>::writeval(pov + 24, got_plt_address);
}
else
{
memcpy(pov, first_plt_entry_32_pic, plt_entry_size);
if (got_plt_offset < 0xff8)
{
memcpy(pov, first_plt_entry_32_pic12, plt_entry_size);
S390_relocate_functions<size>::rela12(pov + 6, got_plt_offset + 4);
S390_relocate_functions<size>::rela12(pov + 14, got_plt_offset + 8);
}
else
{
memcpy(pov, first_plt_entry_32_pic, plt_entry_size);
elfcpp::Swap<32, true>::writeval(pov + 24, got_plt_address - (plt_address + 6));
}
}
}
@@ -1536,9 +1605,12 @@ Output_data_plt_s390<size>::do_write(Output_file* of)
// which is where the GOT pointer will point, and where the
// three reserved GOT entries are located.
typename elfcpp::Elf_types<size>::Elf_Addr got_address
= this->got_plt_->address();
= this->got_dynamic_->address();
this->fill_first_plt_entry(pov, got_address, plt_address);
unsigned int got_plt_offset = this->got_plt_->address() - got_address;
this->fill_first_plt_entry(pov, this->got_plt_->address(), plt_address,
got_plt_offset);
pov += this->get_plt_entry_size();
unsigned char* got_pov = got_view;
@@ -1547,7 +1619,7 @@ Output_data_plt_s390<size>::do_write(Output_file* of)
unsigned int plt_offset = this->get_plt_entry_size();
unsigned int plt_rel_offset = 0;
unsigned int got_offset = 3 * size / 8;
unsigned int got_offset = 3 * size / 8 + got_plt_offset;
const unsigned int count = this->count_ + this->irelative_count_;
// The first three entries in the GOT are reserved, and are written
// by Output_data_got_plt_s390::do_write.
@@ -1590,22 +1662,43 @@ Target_s390<size>::got_section(Symbol_table* symtab, Layout* layout)
{
gold_assert(symtab != NULL && layout != NULL);
// When using -z now, we can treat .got as a relro section.
// Without -z now, it is modified after program startup by lazy
// PLT relocations.
bool is_got_relro = parameters->options().now();
Output_section_order got_order = (is_got_relro
? ORDER_RELRO_LAST
: ORDER_DATA);
bool is_got_relro, is_got_plt_relro;
Output_section_order got_order, got_plt_order;
const char *got_plt_name;
if (parameters->options().relro())
{
// Partial GOT relro.
is_got_relro = true;
is_got_plt_relro = false;
got_order = ORDER_RELRO_LAST;
got_plt_order = ORDER_NON_RELRO_FIRST;
got_plt_name = ".got.plt";
}
else if (parameters->options().now())
{
// When using -z now, we can treat the whole .got as a relro section.
is_got_plt_relro = is_got_relro = true;
got_order = got_plt_order = ORDER_RELRO_LAST;
got_plt_name = ".got";
}
else
{
// Without -z now, it is modified after program startup by lazy
// PLT relocations.
is_got_plt_relro = is_got_relro = false;
got_order = got_plt_order = ORDER_DATA;
got_plt_name = ".got";
}
// The old GNU linker creates a .got.plt section. We just
// create another set of data in the .got section. Note that we
// always create a PLT if we create a GOT, although the PLT
// might be empty.
this->got_plt_ = new Output_data_got_plt_s390<size>(layout);
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
layout->add_output_section_data(got_plt_name, elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE),
this->got_plt_, got_order, is_got_relro);
this->got_plt_, got_plt_order,
is_got_plt_relro);
// The first three entries are reserved.
this->got_plt_->set_current_data_size(3 * size / 8);
@@ -1613,10 +1706,23 @@ Target_s390<size>::got_section(Symbol_table* symtab, Layout* layout)
// If there are any IRELATIVE relocations, they get GOT entries
// in .got.plt after the jump slot entries.
this->got_irelative_ = new Output_data_space(size / 8, "** GOT IRELATIVE PLT");
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
layout->add_output_section_data(got_plt_name, elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE),
this->got_irelative_,
got_order, is_got_relro);
got_plt_order, is_got_plt_relro);
if (parameters->options().relro())
{
// For partial relro, we need a _DYNAMIC pointer at
// _GLOBAL_OFFSET_TABLE_, not at DT_GOTPLT.
this->got_dynamic_ = new Output_data_got_dynamic_s390<size>(layout);
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE),
this->got_dynamic_, got_order, true);
this->got_dynamic_->set_current_data_size(size / 8);
}
else
this->got_dynamic_ = this->got_plt_;
// Unlike some targets (.e.g x86), S/390 does not use separate .got and
// .got.plt sections in output. The output .got section contains both
@@ -1629,9 +1735,9 @@ Target_s390<size>::got_section(Symbol_table* symtab, Layout* layout)
// Define _GLOBAL_OFFSET_TABLE_ at the start of the GOT.
this->global_offset_table_ =
symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
Symbol_table::PREDEFINED,
this->got_plt_,
this->got_dynamic_,
0, 0, elfcpp::STT_OBJECT,
elfcpp::STB_LOCAL,
elfcpp::STV_HIDDEN, 0,
@@ -1693,7 +1799,7 @@ Output_data_got_plt_s390<size>::do_write(Output_file* of)
// The first entry in the GOT is the address of the .dynamic section
// aka the PT_DYNAMIC segment. The next two entries are reserved.
// We saved space for them when we created the section in
// Target_x86_64::got_section.
// Target_s390::got_section.
const off_t got_file_offset = this->offset();
gold_assert(this->data_size() >= 3 * size / 8);
unsigned char* const got_view =
@@ -1705,6 +1811,26 @@ Output_data_got_plt_s390<size>::do_write(Output_file* of)
of->write_output_view(got_file_offset, 3 * size / 8, got_view);
}
// Write the first reserved word of the .got section.
template<int size>
void
Output_data_got_dynamic_s390<size>::do_write(Output_file* of)
{
// The first entry in the GOT is the address of the .dynamic section
// aka the PT_DYNAMIC segment. The next two entries are reserved.
// We saved space for them when we created the section in
// Target_s390::got_section.
const off_t got_file_offset = this->offset();
gold_assert(this->data_size() == size / 8);
unsigned char* const got_view =
of->get_output_view(got_file_offset, size / 8);
Output_section* dynamic = this->layout_->dynamic_section();
uint64_t dynamic_addr = dynamic == NULL ? 0 : dynamic->address();
elfcpp::Swap<size, true>::writeval(got_view, dynamic_addr);
of->write_output_view(got_file_offset, size / 8, got_view);
}
// Create the PLT section.
template<int size>
@@ -1722,7 +1848,8 @@ Target_s390<size>::make_plt_section(Symbol_table* symtab, Layout* layout)
this->rela_dyn_section(layout);
this->plt_ = new Output_data_plt_s390<size>(layout,
this->got_, this->got_plt_, this->got_irelative_);
this->got_, this->got_plt_, this->got_irelative_,
this->got_dynamic_);
// Add unwind information if requested.
if (parameters->options().ld_generated_unwind_info())
@@ -1814,34 +1941,72 @@ Target_s390<size>::init_got_plt_for_update(Symbol_table* symtab,
{
gold_assert(this->got_ == NULL);
bool is_got_relro, is_got_plt_relro;
Output_section_order got_order, got_plt_order;
const char *got_plt_name;
if (parameters->options().relro())
{
// Partial GOT relro.
is_got_relro = true;
is_got_plt_relro = false;
got_order = ORDER_RELRO_LAST;
got_plt_order = ORDER_NON_RELRO_FIRST;
got_plt_name = ".got.plt";
}
else if (parameters->options().now())
{
// When using -z now, we can treat the whole .got as a relro section.
is_got_plt_relro = is_got_relro = true;
got_order = got_plt_order = ORDER_RELRO_LAST;
got_plt_name = ".got";
}
else
{
// Without -z now, it is modified after program startup by lazy
// PLT relocations.
is_got_plt_relro = is_got_relro = false;
got_order = got_plt_order = ORDER_DATA;
got_plt_name = ".got";
}
// Add the three reserved entries.
this->got_plt_ = new Output_data_got_plt_s390<size>(layout, (plt_count + 3) * size / 8);
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
this->got_plt_, ORDER_NON_RELRO_FIRST,
false);
layout->add_output_section_data(got_plt_name, elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE),
this->got_plt_, got_plt_order,
is_got_plt_relro);
// If there are any IRELATIVE relocations, they get GOT entries in
// .got.plt after the jump slot entries.
this->got_irelative_ = new Output_data_space(0, size / 8, "** GOT IRELATIVE PLT");
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
layout->add_output_section_data(got_plt_name, elfcpp::SHT_PROGBITS,
elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
this->got_irelative_,
ORDER_NON_RELRO_FIRST, false);
got_plt_order, is_got_plt_relro);
if (parameters->options().relro())
{
// For partial relro, we need a _DYNAMIC pointer at
// _GLOBAL_OFFSET_TABLE_, not at DT_GOTPLT.
this->got_dynamic_ = new Output_data_got_dynamic_s390<size>(layout);
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE),
this->got_dynamic_, got_order, true);
this->got_dynamic_->set_current_data_size(size / 8);
}
else
this->got_dynamic_ = this->got_plt_;
this->got_ = new Output_data_got<size, true>(got_count * size / 8);
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
this->got_, ORDER_RELRO_LAST,
true);
(elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE),
this->got_, got_order, is_got_relro);
// Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT.
this->global_offset_table_ =
symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
Symbol_table::PREDEFINED,
this->got_plt_,
this->got_dynamic_,
0, 0, elfcpp::STT_OBJECT,
elfcpp::STB_LOCAL,
elfcpp::STV_HIDDEN, 0,
@@ -1849,7 +2014,8 @@ Target_s390<size>::init_got_plt_for_update(Symbol_table* symtab,
// Create the PLT section.
this->plt_ = new Output_data_plt_s390<size>(layout,
this->got_, this->got_plt_, this->got_irelative_, plt_count);
this->got_, this->got_plt_, this->got_irelative_,
this->got_dynamic_, plt_count);
// Add unwind information if requested.
if (parameters->options().ld_generated_unwind_info())
@@ -4051,6 +4217,10 @@ Target_s390<size>::do_finalize_sections(
if (sym != NULL)
{
uint64_t data_size = this->got_->current_data_size();
data_size += this->got_plt_->current_data_size();
data_size += this->got_irelative_->current_data_size();
if (this->got_plt_ != this->got_dynamic_)
data_size += this->got_dynamic_->current_data_size();
symtab->get_sized_symbol<size>(sym)->set_symsize(data_size);
}

View File

@@ -11,8 +11,11 @@ NOP=0x07070707
TEMPLATE_NAME=elf32
GENERATE_SHLIB_SCRIPT=yes
GENERATE_PIE_SCRIPT=yes
GENERATE_RELRO_SCRIPT=yes
NO_SMALL_DATA=yes
IREL_IN_PLT=
SEPARATE_GOTPLT="SIZEOF (.got.plt) >= 24 ? 24 : 0"
test -z "$RELRO" && unset SEPARATE_GOTPLT
# Treat a host that matches the target with the possible exception of "x"
# in the name as if it were native.

View File

@@ -10,5 +10,8 @@ NOP=0x07070707
TEMPLATE_NAME=elf32
GENERATE_SHLIB_SCRIPT=yes
GENERATE_PIE_SCRIPT=yes
GENERATE_RELRO_SCRIPT=yes
NO_SMALL_DATA=yes
IREL_IN_PLT=
SEPARATE_GOTPLT="SIZEOF (.got.plt) >= 12 ? 12 : 0"
test -z "$RELRO" && unset SEPARATE_GOTPLT

View File

@@ -2074,6 +2074,12 @@ echo ' && link_info.combreloc' >> e${EMULATION_NAME}.c
echo ' && link_info.relro' >> e${EMULATION_NAME}.c
echo ' && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xdw >> e${EMULATION_NAME}.c
if test -n "$GENERATE_RELRO_SCRIPT" ; then
echo ' ; else if (bfd_link_pie (&link_info)' >> e${EMULATION_NAME}.c
echo ' && link_info.combreloc' >> e${EMULATION_NAME}.c
echo ' && link_info.relro) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xdo >> e${EMULATION_NAME}.c
fi
echo ' ; else if (bfd_link_pie (&link_info)' >> e${EMULATION_NAME}.c
echo ' && link_info.combreloc) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xdc >> e${EMULATION_NAME}.c
@@ -2087,6 +2093,12 @@ echo ' ; else if (bfd_link_dll (&link_info) && link_info.combreloc' >> e${EMULA
echo ' && link_info.relro' >> e${EMULATION_NAME}.c
echo ' && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xsw >> e${EMULATION_NAME}.c
if test -n "$GENERATE_RELRO_SCRIPT" ; then
echo ' ; else if (bfd_link_dll (&link_info)' >> e${EMULATION_NAME}.c
echo ' && link_info.combreloc' >> e${EMULATION_NAME}.c
echo ' && link_info.relro) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xso >> e${EMULATION_NAME}.c
fi
echo ' ; else if (bfd_link_dll (&link_info) && link_info.combreloc) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xsc >> e${EMULATION_NAME}.c
fi
@@ -2097,6 +2109,11 @@ if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
echo ' ; else if (link_info.combreloc && link_info.relro' >> e${EMULATION_NAME}.c
echo ' && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xw >> e${EMULATION_NAME}.c
if test -n "$GENERATE_RELRO_SCRIPT" ; then
echo ' ; else if (link_info.combreloc' >> e${EMULATION_NAME}.c
echo ' && link_info.relro) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xo >> e${EMULATION_NAME}.c
fi
echo ' ; else if (link_info.combreloc) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xc >> e${EMULATION_NAME}.c
fi
@@ -2133,6 +2150,16 @@ fragment <<EOF
&& link_info.relro
&& (link_info.flags & DF_BIND_NOW))
return "ldscripts/${EMULATION_NAME}.xdw";
EOF
if test -n "$GENERATE_RELRO_SCRIPT" ; then
fragment <<EOF
else if (bfd_link_pie (&link_info)
&& link_info.combreloc
&& link_info.relro)
return "ldscripts/${EMULATION_NAME}.xdo";
EOF
fi
fragment <<EOF
else if (bfd_link_pie (&link_info)
&& link_info.combreloc)
return "ldscripts/${EMULATION_NAME}.xdc";
@@ -2149,6 +2176,15 @@ fragment <<EOF
else if (bfd_link_dll (&link_info) && link_info.combreloc
&& link_info.relro && (link_info.flags & DF_BIND_NOW))
return "ldscripts/${EMULATION_NAME}.xsw";
EOF
if test -n "$GENERATE_RELRO_SCRIPT" ; then
fragment <<EOF
else if (bfd_link_dll (&link_info) && link_info.combreloc
&& link_info.relro)
return "ldscripts/${EMULATION_NAME}.xso";
EOF
fi
fragment <<EOF
else if (bfd_link_dll (&link_info) && link_info.combreloc)
return "ldscripts/${EMULATION_NAME}.xsc";
EOF
@@ -2163,6 +2199,14 @@ fragment <<EOF
else if (link_info.combreloc && link_info.relro
&& (link_info.flags & DF_BIND_NOW))
return "ldscripts/${EMULATION_NAME}.xw";
EOF
if test -n "$GENERATE_RELRO_SCRIPT" ; then
fragment <<EOF
else if (link_info.combreloc && link_info.relro)
return "ldscripts/${EMULATION_NAME}.xo";
EOF
fi
fragment <<EOF
else if (link_info.combreloc)
return "ldscripts/${EMULATION_NAME}.xc";
EOF

View File

@@ -321,6 +321,20 @@ if test -n "$GENERATE_COMBRELOC_SCRIPT"; then
. ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xc
rm -f ${COMBRELOC}
if test -n "$GENERATE_RELRO_SCRIPT"; then
LD_FLAG=o
RELRO=" "
COMBRELOC=ldscripts/${EMULATION_NAME}.xo.tmp
( echo "/* Script for -z combreloc -z relro: combine and sort reloc sections */"
. ${CUSTOMIZER_SCRIPT}
. ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xo
rm -f ${COMBRELOC}
COMBRELOC=
unset RELRO
fi
LD_FLAG=w
RELRO_NOW=" "
COMBRELOC=ldscripts/${EMULATION_NAME}.xw.tmp
@@ -351,6 +365,20 @@ if test -n "$GENERATE_SHLIB_SCRIPT"; then
. ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xsc
rm -f ${COMBRELOC}
if test -n "$GENERATE_RELRO_SCRIPT"; then
LD_FLAG=oshared
RELRO=" "
COMBRELOC=ldscripts/${EMULATION_NAME}.xso.tmp
( echo "/* Script for --shared -z combreloc -z relro: shared library, combine & sort relocs */"
. ${CUSTOMIZER_SCRIPT}
. ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xso
rm -f ${COMBRELOC}
COMBRELOC=
unset RELRO
fi
LD_FLAG=wshared
RELRO_NOW=" "
COMBRELOC=ldscripts/${EMULATION_NAME}.xsw.tmp
@@ -383,6 +411,20 @@ if test -n "$GENERATE_PIE_SCRIPT"; then
. ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xdc
rm -f ${COMBRELOC}
if test -n "$GENERATE_RELRO_SCRIPT"; then
LD_FLAG=opie
RELRO=" "
COMBRELOC=ldscripts/${EMULATION_NAME}.xdo.tmp
( echo "/* Script for -pie -z combreloc -z relro: position independent executable, combine & sort relocs */"
. ${CUSTOMIZER_SCRIPT}
. ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xdo
rm -f ${COMBRELOC}
COMBRELOC=
unset RELRO
fi
LD_FLAG=wpie
RELRO_NOW=" "
COMBRELOC=ldscripts/${EMULATION_NAME}.xdw.tmp