x86: Add DT_RELR support

DT_RELR is implemented with linker relaxation:

1. During linker relaxation, we scan input relocations with the same
logic in relocate_section to determine if a relative relocation should
be generated and save the relative relocation candidate information for
sizing the DT_RELR section later after all symbols addresses can be
determined.  For these relative relocations which can't be placed in
the DT_RELR section, they will be placed in the rela.dyn/rel.dyn
section.
2. When DT_RELR is enabled, _bfd_elf_map_sections_to_segments calls a
backend function to size the DT_RELR section which will compute the
DT_RELR section size and tell ldelf_map_segments to layout sections
again when the DT_RELR section size has been increased.
3. After regular symbol processing is finished, bfd_elf_final_link calls
a backend function to finish the DT_RELR section.

	* elf32-i386.c (elf_i386_relocate_section): Don't generate
	relative relocation when DT_RELR is enabled.
	(elf_i386_finish_dynamic_symbol): Likewise.
	* elf64-x86-64.c (elf_x86_64_relocate_section): Don't generate
	relative relocation when DT_RELR is enabled.
	(elf_x86_64_finish_dynamic_symbol): Likewise.
	* elfxx-x86.c (_bfd_x86_elf_link_hash_table_create): Initialize
	relative_r_type, relative_r_name, elf_append_reloc,
	elf_write_addend and elf_write_addend_in_got.
	(elf_x86_relative_reloc_record_add): New function.
	(_bfd_x86_elf_link_relax_section): Likewise.
	(elf64_dt_relr_bitmap_add): Likewise.
	(elf32_dt_relr_bitmap_add): Likewise.
	(_bfd_elf32_write_addend): Likewise.
	(_bfd_elf64_write_addend): Likewise.
	(elf_x86_size_or_finish_relative_reloc): Likewise.
	(elf_x86_compute_dl_relr_bitmap): Likewise.
	(elf_x86_write_dl_relr_bitmap): Likewise.
	(elf_x86_relative_reloc_compare ): Likewise.
	(_bfd_elf_x86_size_relative_relocs): Likewise.
	(_bfd_elf_x86_finish_relative_relocs): Likewise.
	(_bfd_x86_elf_size_dynamic_sections): Skip the .relr.dyn section.
	(_bfd_x86_elf_finish_dynamic_sections): Convert 3 spare dynamic
	tags to DT_RELR, DT_RELRSZ and for compact relative relocation.
	* elfxx-x86.h (X86_64_GOT_TYPE_P): New.
	(I386_GOT_TYPE_P): Likewise.
	(X86_GOT_TYPE_P): Likewise.
	(X86_64_RELATIVE_RELOC_TYPE_P): Likewise.
	(I386_RELATIVE_RELOC_TYPE_P): Likewise.
	(X86_RELATIVE_RELOC_TYPE_P): Likewise.
	(X86_LOCAL_GOT_RELATIVE_RELOC_P): Likewise.
	(I386_PCREL_TYPE_P): Likewise.
	(X86_64_PCREL_TYPE_P): Likewise.
	(X86_64_NEED_DYNAMIC_RELOC_TYPE_P): Rewrite.
	(I386_NEED_DYNAMIC_RELOC_TYPE_P): Likewise.
	(GENERATE_DYNAMIC_RELOCATION_P): Also check rel_from_abs.
	(elf_x86_link_hash_entry): Add got_relative_reloc_done.
	(elf_x86_relative_reloc_record): New.
	(elf_x86_relative_reloc_data): Likewise.
	(elf_dt_relr_bitmap): Likewise.
	(elf_x86_link_hash_table): Add dt_relr_bitmap, relative_reloc,
	unaligned_relative_reloc, relative_r_type, relative_r_name,
	elf_append_reloc, elf_write_addend, elf_write_addend_in_got and
	relative_reloc_done.
	(elf_x86_relative_reloc_done): New.
	(relative_reloc_packed): Likewise.
	(_bfd_x86_elf_link_relax_section): Likewise.
	(_bfd_elf_x86_size_relative_relocs): Likewise.
	(_bfd_elf_x86_finish_relative_relocs): Likewise.
	(_bfd_elf32_write_addend): Likewise.
	(_bfd_elf64_write_addend): Likewise.
	(bfd_elf32_bfd_relax_section): Likewise.
	(bfd_elf64_bfd_relax_section): Likewise.
	(elf_backend_size_relative_relocs): Likewise.
	(elf_backend_finish_relative_relocs): Likewise.
	(elf_x86_allocate_local_got_info): Also allocate
	relative_reloc_done.
This commit is contained in:
H.J. Lu 2022-01-02 21:14:46 -08:00
parent f2e37a5c7f
commit 5af6f000d8
4 changed files with 1196 additions and 58 deletions

View File

@ -2473,8 +2473,10 @@ elf_i386_relocate_section (bfd *output_bfd,
bfd_put_32 (output_bfd, relocation,
htab->elf.sgot->contents + off);
h->got.offset |= 1;
if (GENERATE_RELATIVE_RELOC_P (info, h))
/* NB: Don't generate relative relocation here if
it has been generated by DT_RELR. */
if (!info->enable_dt_relr
&& GENERATE_RELATIVE_RELOC_P (info, h))
{
/* PR ld/21402: If this symbol isn't dynamic
in PIC, generate R_386_RELATIVE here. */
@ -2504,7 +2506,9 @@ elf_i386_relocate_section (bfd *output_bfd,
htab->elf.sgot->contents + off);
local_got_offsets[r_symndx] |= 1;
if (bfd_link_pic (info))
/* NB: Don't generate relative relocation here if it
has been generated by DT_RELR. */
if (!info->enable_dt_relr && bfd_link_pic (info))
relative_reloc = true;
}
}
@ -2707,6 +2711,7 @@ elf_i386_relocate_section (bfd *output_bfd,
{
Elf_Internal_Rela outrel;
bool skip, relocate;
bool generate_dynamic_reloc = true;
asection *sreloc;
/* When generating a shared object, these relocations
@ -2734,6 +2739,12 @@ elf_i386_relocate_section (bfd *output_bfd,
{
/* This symbol is local, or marked to become local. */
relocate = true;
/* NB: Don't generate relative relocation here if it
has been generated by DT_RELR. */
if (info->enable_dt_relr)
generate_dynamic_reloc = false;
else
{
outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
if (htab->params->report_relative_reloc)
@ -2741,7 +2752,10 @@ elf_i386_relocate_section (bfd *output_bfd,
(info, input_section, h, sym, "R_386_RELATIVE",
&outrel);
}
}
if (generate_dynamic_reloc)
{
sreloc = elf_section_data (input_section)->sreloc;
if (sreloc == NULL || sreloc->contents == NULL)
@ -2751,6 +2765,7 @@ elf_i386_relocate_section (bfd *output_bfd,
}
elf_append_rel (output_bfd, sreloc, &outrel);
}
/* If this reloc is against an external symbol, we do
not want to fiddle with the addend. Otherwise, we
@ -3776,6 +3791,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
Elf_Internal_Rela rel;
asection *relgot = htab->elf.srelgot;
const char *relative_reloc_name = NULL;
bool generate_dynamic_reloc = true;
/* This symbol has an entry in the global offset table. Set it
up. */
@ -3858,9 +3874,14 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
&& SYMBOL_REFERENCES_LOCAL_P (info, h))
{
BFD_ASSERT((h->got.offset & 1) != 0);
if (info->enable_dt_relr)
generate_dynamic_reloc = false;
else
{
rel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
relative_reloc_name = "R_386_RELATIVE";
}
}
else
{
BFD_ASSERT((h->got.offset & 1) == 0);
@ -3870,6 +3891,8 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
rel.r_info = ELF32_R_INFO (h->dynindx, R_386_GLOB_DAT);
}
if (generate_dynamic_reloc)
{
if (relative_reloc_name != NULL
&& htab->params->report_relative_reloc)
_bfd_x86_elf_link_report_relative_reloc
@ -3877,6 +3900,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
elf_append_rel (output_bfd, relgot, &rel);
}
}
if (h->needs_copy)
{

View File

@ -2867,7 +2867,10 @@ elf_x86_64_relocate_section (bfd *output_bfd,
as -1 | 1 still is -1. */
h->got.offset |= 1;
if (GENERATE_RELATIVE_RELOC_P (info, h))
/* NB: Don't generate relative relocation here if
it has been generated by DT_RELR. */
if (!info->enable_dt_relr
&& GENERATE_RELATIVE_RELOC_P (info, h))
{
/* If this symbol isn't dynamic in PIC,
generate R_X86_64_RELATIVE here. */
@ -2899,8 +2902,11 @@ elf_x86_64_relocate_section (bfd *output_bfd,
/* NB: GOTPCREL relocations against local absolute
symbol store relocation value in the GOT slot
without relative relocation. */
if (bfd_link_pic (info)
without relative relocation. Don't generate
relative relocation here if it has been generated
by DT_RELR. */
if (!info->enable_dt_relr
&& bfd_link_pic (info)
&& !(sym->st_shndx == SHN_ABS
&& (r_type == R_X86_64_GOTPCREL
|| r_type == R_X86_64_GOTPCRELX
@ -3215,6 +3221,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
{
Elf_Internal_Rela outrel;
bool skip, relocate;
bool generate_dynamic_reloc = true;
asection *sreloc;
const char *relative_reloc_name = NULL;
@ -3253,10 +3260,18 @@ elf_x86_64_relocate_section (bfd *output_bfd,
&& htab->params->no_reloc_overflow_check))
{
relocate = true;
outrel.r_info = htab->r_info (0, R_X86_64_RELATIVE);
/* NB: Don't generate relative relocation here if
it has been generated by DT_RELR. */
if (info->enable_dt_relr)
generate_dynamic_reloc = false;
else
{
outrel.r_info =
htab->r_info (0, R_X86_64_RELATIVE);
outrel.r_addend = relocation + rel->r_addend;
relative_reloc_name = "R_X86_64_RELATIVE";
}
}
else if (r_type == R_X86_64_64
&& !ABI_64_P (output_bfd))
{
@ -3323,6 +3338,8 @@ elf_x86_64_relocate_section (bfd *output_bfd,
}
}
if (generate_dynamic_reloc)
{
sreloc = elf_section_data (input_section)->sreloc;
if (sreloc == NULL || sreloc->contents == NULL)
@ -3334,10 +3351,11 @@ elf_x86_64_relocate_section (bfd *output_bfd,
if (relative_reloc_name
&& htab->params->report_relative_reloc)
_bfd_x86_elf_link_report_relative_reloc
(info, input_section, h, sym, relative_reloc_name,
&outrel);
(info, input_section, h, sym,
relative_reloc_name, &outrel);
elf_append_rela (output_bfd, sreloc, &outrel);
}
/* If this reloc is against an external symbol, we do
not want to fiddle with the addend. Otherwise, we
@ -4424,6 +4442,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
Elf_Internal_Rela rela;
asection *relgot = htab->elf.srelgot;
const char *relative_reloc_name = NULL;
bool generate_dynamic_reloc = true;
/* This symbol has an entry in the global offset table. Set it
up. */
@ -4506,12 +4525,17 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
if (!SYMBOL_DEFINED_NON_SHARED_P (h))
return false;
BFD_ASSERT((h->got.offset & 1) != 0);
if (info->enable_dt_relr)
generate_dynamic_reloc = false;
else
{
rela.r_info = htab->r_info (0, R_X86_64_RELATIVE);
rela.r_addend = (h->root.u.def.value
+ h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset);
relative_reloc_name = "R_X86_64_RELATIVE";
}
}
else
{
BFD_ASSERT((h->got.offset & 1) == 0);
@ -4522,6 +4546,8 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
rela.r_addend = 0;
}
if (generate_dynamic_reloc)
{
if (relative_reloc_name != NULL
&& htab->params->report_relative_reloc)
_bfd_x86_elf_link_report_relative_reloc
@ -4529,6 +4555,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
elf_append_rela (output_bfd, relgot, &rela);
}
}
if (h->needs_copy)
{

File diff suppressed because it is too large Load Diff

View File

@ -47,18 +47,35 @@
#define X86_SIZE_TYPE_P(IS_X86_64, TYPE) \
((IS_X86_64) ? X86_64_SIZE_TYPE_P(TYPE) : I386_SIZE_TYPE_P (TYPE))
#define X86_64_NEED_DYNAMIC_RELOC_TYPE_P(TYPE) \
(X86_64_SIZE_TYPE_P (TYPE) \
|| X86_64_PCREL_TYPE_P (TYPE) \
#define X86_64_GOT_TYPE_P(TYPE) \
((TYPE) == R_X86_64_GOTPCREL \
|| (TYPE) == R_X86_64_GOTPCRELX \
|| (TYPE) == R_X86_64_REX_GOTPCRELX)
#define I386_GOT_TYPE_P(TYPE) \
((TYPE) == R_386_GOT32 || (TYPE) == R_386_GOT32X)
#define X86_GOT_TYPE_P(IS_X86_64, TYPE) \
((IS_X86_64) ? X86_64_GOT_TYPE_P (TYPE) : I386_GOT_TYPE_P (TYPE))
#define X86_64_RELATIVE_RELOC_TYPE_P(TYPE) \
(X86_64_PCREL_TYPE_P (TYPE) \
|| (TYPE) == R_X86_64_8 \
|| (TYPE) == R_X86_64_16 \
|| (TYPE) == R_X86_64_32 \
|| (TYPE) == R_X86_64_32S \
|| (TYPE) == R_X86_64_64)
#define I386_RELATIVE_RELOC_TYPE_P(TYPE) \
((TYPE) == R_386_32 || (TYPE) == R_386_PC32)
#define X86_RELATIVE_RELOC_TYPE_P(IS_X86_64, TYPE) \
((IS_X86_64) \
? X86_64_RELATIVE_RELOC_TYPE_P (TYPE) \
: I386_RELATIVE_RELOC_TYPE_P(TYPE))
#define X86_64_NEED_DYNAMIC_RELOC_TYPE_P(TYPE) \
(X86_64_SIZE_TYPE_P (TYPE) \
|| X86_64_RELATIVE_RELOC_TYPE_P (TYPE))
#define I386_NEED_DYNAMIC_RELOC_TYPE_P(TYPE) \
(I386_SIZE_TYPE_P (TYPE) \
|| I386_PCREL_TYPE_P (TYPE) \
|| (TYPE) == R_386_32 \
|| I386_RELATIVE_RELOC_TYPE_P (TYPE) \
|| (TYPE) == R_386_TLS_LE \
|| (TYPE) == R_386_TLS_LE_32)
#define X86_NEED_DYNAMIC_RELOC_TYPE_P(IS_X86_64, TYPE) \
@ -66,11 +83,23 @@
? X86_64_NEED_DYNAMIC_RELOC_TYPE_P (TYPE) \
: I386_NEED_DYNAMIC_RELOC_TYPE_P (TYPE))
#define X86_LOCAL_GOT_RELATIVE_RELOC_P(IS_X86_64, INFO, SYM) \
(bfd_link_pic (INFO) \
&& (!(IS_X86_64) || ((SYM) != NULL && (SYM)->st_shndx != SHN_ABS)))
#define PLT_CIE_LENGTH 20
#define PLT_FDE_LENGTH 36
#define PLT_FDE_START_OFFSET 4 + PLT_CIE_LENGTH + 8
#define PLT_FDE_LEN_OFFSET 4 + PLT_CIE_LENGTH + 12
#define I386_PCREL_TYPE_P(TYPE) ((TYPE) == R_386_PC32)
#define X86_64_PCREL_TYPE_P(TYPE) \
((TYPE) == R_X86_64_PC8 \
|| (TYPE) == R_X86_64_PC16 \
|| (TYPE) == R_X86_64_PC32 \
|| (TYPE) == R_X86_64_PC32_BND \
|| (TYPE) == R_X86_64_PC64)
#define ABI_64_P(abfd) \
(get_elf_backend_data (abfd)->s->elfclass == ELFCLASS64)
@ -160,12 +189,18 @@
relocations against resolved undefined weak symbols in PIE, except
when PC32_RELOC is TRUE. Undefined weak symbol is bound locally
when PIC is false. Don't generate dynamic relocations against
non-preemptible absolute symbol. */
non-preemptible absolute symbol. NB: rel_from_abs is set on symbols
defined by linker scripts from "dot" (also SEGMENT_START or ORIGIN)
outside of an output section statement, which will be converted from
absolute to section-relative in set_sym_sections called from
ldexp_finalize_syms after ldemul_finish. */
#define GENERATE_DYNAMIC_RELOCATION_P(IS_X86_64, INFO, EH, R_TYPE, \
SEC, NEED_COPY_RELOC_IN_PIE, \
RESOLVED_TO_ZERO, PC32_RELOC) \
((bfd_link_pic (INFO) \
&& !(bfd_is_abs_section (SEC) \
&& ((EH) == NULL \
|| (EH)->elf.root.rel_from_abs == 0) \
&& ((EH) == NULL \
|| SYMBOL_REFERENCES_LOCAL (INFO, &(EH)->elf))) \
&& !(NEED_COPY_RELOC_IN_PIE) \
@ -302,6 +337,10 @@ struct elf_x86_link_hash_entry
/* Don't call finish_dynamic_symbol on this symbol. */
unsigned int no_finish_dynamic_symbol : 1;
/* R_*_RELATIVE relocation in GOT for this symbol has been
processed. */
unsigned int got_relative_reloc_done : 1;
/* TRUE if symbol is __tls_get_addr. */
unsigned int tls_get_addr : 1;
@ -481,6 +520,52 @@ struct elf_x86_plt_layout
#define elf_x86_hash_entry(ent) \
((struct elf_x86_link_hash_entry *)(ent))
/* Information of an input relocation used to compute its contribution
to the DT_RELR section size. */
struct elf_x86_relative_reloc_record
{
/* The original relocation info. */
Elf_Internal_Rela rel;
/* The input or the GOT section where the relocation is applied. */
asection *sec;
/* Local symbol info. NULL for global symbol. */
Elf_Internal_Sym *sym;
union
{
/* Section where the local symbol is defined. */
asection *sym_sec;
/* Global symbol hash. */
struct elf_link_hash_entry *h;
} u;
/* The offset into the output section where the relative relocation
will be applied at run-time. */
bfd_vma offset;
/* The run-time address. */
bfd_vma address;
};
struct elf_x86_relative_reloc_data
{
bfd_size_type count;
bfd_size_type size;
struct elf_x86_relative_reloc_record *data;
};
/* DT_RELR bitmap. */
struct elf_dt_relr_bitmap
{
bfd_size_type count;
bfd_size_type size;
union
{
/* 32-bit bitmap. */
uint32_t *elf32;
/* 64-bit bitmap. */
uint64_t *elf64;
} u;
};
/* x86 ELF linker hash table. */
struct elf_x86_link_hash_table
@ -533,6 +618,18 @@ struct elf_x86_link_hash_table
is only used for i386. */
bfd_vma next_tls_desc_index;
/* DT_RELR bitmap. */
struct elf_dt_relr_bitmap dt_relr_bitmap;
/* Relative relocation data. */
struct elf_x86_relative_reloc_data relative_reloc;
/* Unaligned relative relocation data. */
struct elf_x86_relative_reloc_data unaligned_relative_reloc;
/* Number of relative reloc generation pass. */
unsigned int generate_relative_reloc_pass;
/* Value used to fill the unused bytes of the first PLT entry. This
is only used for i386. */
bfd_byte plt0_pad_byte;
@ -554,9 +651,14 @@ struct elf_x86_link_hash_table
unsigned int sizeof_reloc;
unsigned int got_entry_size;
unsigned int pointer_r_type;
unsigned int relative_r_type;
int dynamic_interpreter_size;
const char *dynamic_interpreter;
const char *tls_get_addr;
const char *relative_r_name;
void (*elf_append_reloc) (bfd *, asection *, Elf_Internal_Rela *);
void (*elf_write_addend) (bfd *, uint64_t, void *);
void (*elf_write_addend_in_got) (bfd *, uint64_t, void *);
/* Options passed from the linker. */
struct elf_linker_x86_params *params;
@ -591,6 +693,10 @@ struct elf_x86_obj_tdata
/* GOTPLT entries for TLS descriptors. */
bfd_vma *local_tlsdesc_gotent;
/* R_*_RELATIVE relocation in GOT for this local symbol has been
processed. */
char *relative_reloc_done;
};
enum elf_x86_plt_type
@ -626,6 +732,9 @@ struct elf_x86_plt
#define elf_x86_local_tlsdesc_gotent(abfd) \
(elf_x86_tdata (abfd)->local_tlsdesc_gotent)
#define elf_x86_relative_reloc_done(abfd) \
(elf_x86_tdata (abfd)->relative_reloc_done)
#define elf_x86_compute_jump_table_size(htab) \
((htab)->elf.srelplt->reloc_count * (htab)->got_entry_size)
@ -637,6 +746,7 @@ struct elf_x86_plt
/* Rename some of the generic section flags to better document how they
are used here. */
#define check_relocs_failed sec_flg0
#define relative_reloc_packed sec_flg1
extern bool _bfd_x86_elf_mkobject
(bfd *);
@ -676,6 +786,18 @@ extern bool _bfd_x86_elf_check_relocs
(bfd *, struct bfd_link_info *, asection *,
const Elf_Internal_Rela *);
extern bool _bfd_x86_elf_link_relax_section
(bfd *, asection *, struct bfd_link_info *, bool *);
extern bool _bfd_elf_x86_size_relative_relocs
(struct bfd_link_info *, bool *);
extern bool _bfd_elf_x86_finish_relative_relocs
(struct bfd_link_info *);
extern void _bfd_elf32_write_addend (bfd *, uint64_t, void *);
extern void _bfd_elf64_write_addend (bfd *, uint64_t, void *);
extern bool _bfd_elf_x86_valid_reloc_p
(asection *, struct bfd_link_info *, struct elf_x86_link_hash_table *,
const Elf_Internal_Rela *, struct elf_link_hash_entry *,
@ -752,6 +874,10 @@ extern void _bfd_x86_elf_link_report_relative_reloc
_bfd_x86_elf_link_check_relocs
#define bfd_elf32_bfd_link_check_relocs \
_bfd_x86_elf_link_check_relocs
#define bfd_elf32_bfd_relax_section \
_bfd_x86_elf_link_relax_section
#define bfd_elf64_bfd_relax_section \
_bfd_x86_elf_link_relax_section
#define elf_backend_check_relocs \
_bfd_x86_elf_check_relocs
@ -777,6 +903,10 @@ extern void _bfd_x86_elf_link_report_relative_reloc
_bfd_x86_elf_merge_gnu_properties
#define elf_backend_fixup_gnu_properties \
_bfd_x86_elf_link_fixup_gnu_properties
#define elf_backend_size_relative_relocs \
_bfd_elf_x86_size_relative_relocs
#define elf_backend_finish_relative_relocs \
_bfd_elf_x86_finish_relative_relocs
#define ELF_P_ALIGN ELF_MINPAGESIZE
@ -789,7 +919,8 @@ elf_x86_allocate_local_got_info (bfd *abfd, bfd_size_type count)
if (local_got_refcounts == NULL)
{
bfd_size_type size = count * (sizeof (bfd_signed_vma)
+ sizeof (bfd_vma) + sizeof(char));
+ sizeof (bfd_vma)
+ 2 * sizeof(char));
local_got_refcounts = (bfd_signed_vma *) bfd_zalloc (abfd, size);
if (local_got_refcounts == NULL)
return false;
@ -798,6 +929,8 @@ elf_x86_allocate_local_got_info (bfd *abfd, bfd_size_type count)
(bfd_vma *) (local_got_refcounts + count);
elf_x86_local_got_tls_type (abfd) =
(char *) (local_got_refcounts + 2 * count);
elf_x86_relative_reloc_done (abfd) =
((char *) (local_got_refcounts + 2 * count)) + count;
}
return true;
}