mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 18:14:13 +08:00
RISC-V: Don't separate pcgp relaxation to another relax pass.
Commitabd20cb637
andebdcad3fdd
introduced additional complexity into the paths run by the RISC-V relaxation pass in order to resolve the issue of accurately keeping track of pcrel_hi and pcrel_lo pairs. The first commit split up relaxation of these relocs into a pass which occurred after other relaxations in order to prevent the situation where bytes were deleted in between a pcrel_lo/pcrel_hi pair, inhibiting our ability to find the corresponding pcrel_hi relocation from the address attached to the pcrel_lo. Since the relaxation was split into two passes the 'again' parameter could not be used to perform the entire relaxation process again and so the second commit added a way to restart ldelf_map_segments, thus starting the whole process again. Unfortunately this process could not account for the fact that we were not finished with the relaxation process so in some cases - such as the case where code would not fit in a memory region before the R_RISCV_ALIGN relocation was relaxed - sanity checks in generic code would fail. This patch fixes all three of these concerns by reverting back to a system of having only one target relax pass but updating entries in the table of pcrel_hi/pcrel_lo relocs every time any bytes are deleted. Thus we can keep track of the pairs accurately, and we can use the 'again' parameter to restart the entire target relax pass, behaving in the way that generic code expects. Unfortunately we must still have an additional pass to delay deleting AUIPC bytes to avoid ambiguity between pcrel_hi relocs stored in the table after deletion. This pass can only be run once so we may potentially miss out on relaxation opportunities but this is likely to be rare. https://sourceware.org/bugzilla/show_bug.cgi?id=28410 bfd/ * elfnn-riscv.c (riscv_elf_link_hash_table): Removed restart_relax. (riscv_elf_link_hash_table_create): Updated. (riscv_relax_delete_bytes): Moved after the riscv_update_pcgp_relocs. Update the pcgp_relocs table whenever bytes are deleted. (riscv_update_pcgp_relocs): Add function to update the section offset of pcrel_hi and pcrel_lo, and also update the symbol value of pcrel_hi. (_bfd_riscv_relax_call): Need to update the pcgp_relocs table when deleting codes. (_bfd_riscv_relax_lui): Likewise. (_bfd_riscv_relax_tls_le): Likewise. (_bfd_riscv_relax_align): Once we've handled an R_RISCV_ALIGN, we can't relax anything else, so set the sec->sec_flg0 to true. Besides, we don't need to update the pcgp_relocs table at this stage, so just pass NULL pointer as the pcgp_relocs table for riscv_relax_delete_bytes. (_bfd_riscv_relax_section): Use only one pass for all target relaxations. (_bfd_riscv_relax_delete): Likewise, we don't need to update the pcgp_relocs table at this stage, and don't need to set the `again' since restart_relax mechanism is abandoned. (bfd_elfNN_riscv_restart_relax_sections): Removed. (_bfd_riscv_relax_section): Updated. * elfxx-riscv.h (bfd_elf32_riscv_restart_relax_sections): Removed. (bfd_elf64_riscv_restart_relax_sections): Likewise. ld/ * emultempl/riscvelf.em: Revert restart_relax changes and set relax_pass to 3. * testsuite/ld-riscv-elf/align-small-region.d: New testcase. * testsuite/ld-riscv-elf/align-small-region.ld: Likewise. * testsuite/ld-riscv-elf/align-small-region.s: Likewise. * testsuite/ld-riscv-elf/restart-relax.d: Removed sine the restart_relax mechanism is abandoned. * testsuite/ld-riscv-elf/restart-relax.s: Likewise. * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Updated.
This commit is contained in:
parent
66cc044255
commit
9abcdc10b2
@ -131,9 +131,6 @@ struct riscv_elf_link_hash_table
|
||||
/* The index of the last unused .rel.iplt slot. */
|
||||
bfd_vma last_iplt_index;
|
||||
|
||||
/* Re-run the relaxations from relax pass 0 if TRUE. */
|
||||
bool restart_relax;
|
||||
|
||||
/* The data segment phase, don't relax the section
|
||||
when it is exp_seg_relro_adjust. */
|
||||
int *data_segment_phase;
|
||||
@ -405,7 +402,6 @@ riscv_elf_link_hash_table_create (bfd *abfd)
|
||||
}
|
||||
|
||||
ret->max_alignment = (bfd_vma) -1;
|
||||
ret->restart_relax = false;
|
||||
|
||||
/* Create hash table for local ifunc. */
|
||||
ret->loc_hash_table = htab_try_create (1024,
|
||||
@ -3923,115 +3919,6 @@ _bfd_riscv_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Delete some bytes from a section while relaxing. */
|
||||
|
||||
static bool
|
||||
riscv_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, size_t count,
|
||||
struct bfd_link_info *link_info)
|
||||
{
|
||||
unsigned int i, symcount;
|
||||
bfd_vma toaddr = sec->size;
|
||||
struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (abfd);
|
||||
Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
|
||||
unsigned int sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
|
||||
struct bfd_elf_section_data *data = elf_section_data (sec);
|
||||
bfd_byte *contents = data->this_hdr.contents;
|
||||
|
||||
/* Actually delete the bytes. */
|
||||
sec->size -= count;
|
||||
memmove (contents + addr, contents + addr + count, toaddr - addr - count);
|
||||
|
||||
/* Adjust the location of all of the relocs. Note that we need not
|
||||
adjust the addends, since all PC-relative references must be against
|
||||
symbols, which we will adjust below. */
|
||||
for (i = 0; i < sec->reloc_count; i++)
|
||||
if (data->relocs[i].r_offset > addr && data->relocs[i].r_offset < toaddr)
|
||||
data->relocs[i].r_offset -= count;
|
||||
|
||||
/* Adjust the local symbols defined in this section. */
|
||||
for (i = 0; i < symtab_hdr->sh_info; i++)
|
||||
{
|
||||
Elf_Internal_Sym *sym = (Elf_Internal_Sym *) symtab_hdr->contents + i;
|
||||
if (sym->st_shndx == sec_shndx)
|
||||
{
|
||||
/* If the symbol is in the range of memory we just moved, we
|
||||
have to adjust its value. */
|
||||
if (sym->st_value > addr && sym->st_value <= toaddr)
|
||||
sym->st_value -= count;
|
||||
|
||||
/* If the symbol *spans* the bytes we just deleted (i.e. its
|
||||
*end* is in the moved bytes but its *start* isn't), then we
|
||||
must adjust its size.
|
||||
|
||||
This test needs to use the original value of st_value, otherwise
|
||||
we might accidentally decrease size when deleting bytes right
|
||||
before the symbol. But since deleted relocs can't span across
|
||||
symbols, we can't have both a st_value and a st_size decrease,
|
||||
so it is simpler to just use an else. */
|
||||
else if (sym->st_value <= addr
|
||||
&& sym->st_value + sym->st_size > addr
|
||||
&& sym->st_value + sym->st_size <= toaddr)
|
||||
sym->st_size -= count;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now adjust the global symbols defined in this section. */
|
||||
symcount = ((symtab_hdr->sh_size / sizeof (ElfNN_External_Sym))
|
||||
- symtab_hdr->sh_info);
|
||||
|
||||
for (i = 0; i < symcount; i++)
|
||||
{
|
||||
struct elf_link_hash_entry *sym_hash = sym_hashes[i];
|
||||
|
||||
/* The '--wrap SYMBOL' option is causing a pain when the object file,
|
||||
containing the definition of __wrap_SYMBOL, includes a direct
|
||||
call to SYMBOL as well. Since both __wrap_SYMBOL and SYMBOL reference
|
||||
the same symbol (which is __wrap_SYMBOL), but still exist as two
|
||||
different symbols in 'sym_hashes', we don't want to adjust
|
||||
the global symbol __wrap_SYMBOL twice.
|
||||
|
||||
The same problem occurs with symbols that are versioned_hidden, as
|
||||
foo becomes an alias for foo@BAR, and hence they need the same
|
||||
treatment. */
|
||||
if (link_info->wrap_hash != NULL
|
||||
|| sym_hash->versioned != unversioned)
|
||||
{
|
||||
struct elf_link_hash_entry **cur_sym_hashes;
|
||||
|
||||
/* Loop only over the symbols which have already been checked. */
|
||||
for (cur_sym_hashes = sym_hashes; cur_sym_hashes < &sym_hashes[i];
|
||||
cur_sym_hashes++)
|
||||
{
|
||||
/* If the current symbol is identical to 'sym_hash', that means
|
||||
the symbol was already adjusted (or at least checked). */
|
||||
if (*cur_sym_hashes == sym_hash)
|
||||
break;
|
||||
}
|
||||
/* Don't adjust the symbol again. */
|
||||
if (cur_sym_hashes < &sym_hashes[i])
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((sym_hash->root.type == bfd_link_hash_defined
|
||||
|| sym_hash->root.type == bfd_link_hash_defweak)
|
||||
&& sym_hash->root.u.def.section == sec)
|
||||
{
|
||||
/* As above, adjust the value if needed. */
|
||||
if (sym_hash->root.u.def.value > addr
|
||||
&& sym_hash->root.u.def.value <= toaddr)
|
||||
sym_hash->root.u.def.value -= count;
|
||||
|
||||
/* As above, adjust the size if needed. */
|
||||
else if (sym_hash->root.u.def.value <= addr
|
||||
&& sym_hash->root.u.def.value + sym_hash->size > addr
|
||||
&& sym_hash->root.u.def.value + sym_hash->size <= toaddr)
|
||||
sym_hash->size -= count;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* A second format for recording PC-relative hi relocations. This stores the
|
||||
information required to relax them to GP-relative addresses. */
|
||||
|
||||
@ -4162,6 +4049,155 @@ riscv_find_pcgp_lo_reloc (riscv_pcgp_relocs *p, bfd_vma hi_sec_off)
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
riscv_update_pcgp_relocs (riscv_pcgp_relocs *p, asection *deleted_sec,
|
||||
bfd_vma deleted_addr, size_t deleted_count)
|
||||
{
|
||||
/* Bytes have already been deleted and toaddr should match the old section
|
||||
size for our checks, so adjust it here. */
|
||||
bfd_vma toaddr = deleted_sec->size + deleted_count;
|
||||
riscv_pcgp_lo_reloc *l;
|
||||
riscv_pcgp_hi_reloc *h;
|
||||
|
||||
/* Update section offsets of corresponding pcrel_hi relocs for the pcrel_lo
|
||||
entries where they occur after the deleted bytes. */
|
||||
for (l = p->lo; l != NULL; l = l->next)
|
||||
if (l->hi_sec_off > deleted_addr
|
||||
&& l->hi_sec_off < toaddr)
|
||||
l->hi_sec_off -= deleted_count;
|
||||
|
||||
/* Update both section offsets, and symbol values of pcrel_hi relocs where
|
||||
these values occur after the deleted bytes. */
|
||||
for (h = p->hi; h != NULL; h = h->next)
|
||||
{
|
||||
if (h->hi_sec_off > deleted_addr
|
||||
&& h->hi_sec_off < toaddr)
|
||||
h->hi_sec_off -= deleted_count;
|
||||
if (h->sym_sec == deleted_sec
|
||||
&& h->hi_addr > deleted_addr
|
||||
&& h->hi_addr < toaddr)
|
||||
h->hi_addr -= deleted_count;
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete some bytes from a section while relaxing. */
|
||||
|
||||
static bool
|
||||
riscv_relax_delete_bytes (bfd *abfd,
|
||||
asection *sec,
|
||||
bfd_vma addr,
|
||||
size_t count,
|
||||
struct bfd_link_info *link_info,
|
||||
riscv_pcgp_relocs *p)
|
||||
{
|
||||
unsigned int i, symcount;
|
||||
bfd_vma toaddr = sec->size;
|
||||
struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (abfd);
|
||||
Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
|
||||
unsigned int sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
|
||||
struct bfd_elf_section_data *data = elf_section_data (sec);
|
||||
bfd_byte *contents = data->this_hdr.contents;
|
||||
|
||||
/* Actually delete the bytes. */
|
||||
sec->size -= count;
|
||||
memmove (contents + addr, contents + addr + count, toaddr - addr - count);
|
||||
|
||||
/* Adjust the location of all of the relocs. Note that we need not
|
||||
adjust the addends, since all PC-relative references must be against
|
||||
symbols, which we will adjust below. */
|
||||
for (i = 0; i < sec->reloc_count; i++)
|
||||
if (data->relocs[i].r_offset > addr && data->relocs[i].r_offset < toaddr)
|
||||
data->relocs[i].r_offset -= count;
|
||||
|
||||
/* Adjust the hi_sec_off, and the hi_addr of any entries in the pcgp relocs
|
||||
table for which these values occur after the deleted bytes. */
|
||||
if (p)
|
||||
riscv_update_pcgp_relocs (p, sec, addr, count);
|
||||
|
||||
/* Adjust the local symbols defined in this section. */
|
||||
for (i = 0; i < symtab_hdr->sh_info; i++)
|
||||
{
|
||||
Elf_Internal_Sym *sym = (Elf_Internal_Sym *) symtab_hdr->contents + i;
|
||||
if (sym->st_shndx == sec_shndx)
|
||||
{
|
||||
/* If the symbol is in the range of memory we just moved, we
|
||||
have to adjust its value. */
|
||||
if (sym->st_value > addr && sym->st_value <= toaddr)
|
||||
sym->st_value -= count;
|
||||
|
||||
/* If the symbol *spans* the bytes we just deleted (i.e. its
|
||||
*end* is in the moved bytes but its *start* isn't), then we
|
||||
must adjust its size.
|
||||
|
||||
This test needs to use the original value of st_value, otherwise
|
||||
we might accidentally decrease size when deleting bytes right
|
||||
before the symbol. But since deleted relocs can't span across
|
||||
symbols, we can't have both a st_value and a st_size decrease,
|
||||
so it is simpler to just use an else. */
|
||||
else if (sym->st_value <= addr
|
||||
&& sym->st_value + sym->st_size > addr
|
||||
&& sym->st_value + sym->st_size <= toaddr)
|
||||
sym->st_size -= count;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now adjust the global symbols defined in this section. */
|
||||
symcount = ((symtab_hdr->sh_size / sizeof (ElfNN_External_Sym))
|
||||
- symtab_hdr->sh_info);
|
||||
|
||||
for (i = 0; i < symcount; i++)
|
||||
{
|
||||
struct elf_link_hash_entry *sym_hash = sym_hashes[i];
|
||||
|
||||
/* The '--wrap SYMBOL' option is causing a pain when the object file,
|
||||
containing the definition of __wrap_SYMBOL, includes a direct
|
||||
call to SYMBOL as well. Since both __wrap_SYMBOL and SYMBOL reference
|
||||
the same symbol (which is __wrap_SYMBOL), but still exist as two
|
||||
different symbols in 'sym_hashes', we don't want to adjust
|
||||
the global symbol __wrap_SYMBOL twice.
|
||||
|
||||
The same problem occurs with symbols that are versioned_hidden, as
|
||||
foo becomes an alias for foo@BAR, and hence they need the same
|
||||
treatment. */
|
||||
if (link_info->wrap_hash != NULL
|
||||
|| sym_hash->versioned != unversioned)
|
||||
{
|
||||
struct elf_link_hash_entry **cur_sym_hashes;
|
||||
|
||||
/* Loop only over the symbols which have already been checked. */
|
||||
for (cur_sym_hashes = sym_hashes; cur_sym_hashes < &sym_hashes[i];
|
||||
cur_sym_hashes++)
|
||||
{
|
||||
/* If the current symbol is identical to 'sym_hash', that means
|
||||
the symbol was already adjusted (or at least checked). */
|
||||
if (*cur_sym_hashes == sym_hash)
|
||||
break;
|
||||
}
|
||||
/* Don't adjust the symbol again. */
|
||||
if (cur_sym_hashes < &sym_hashes[i])
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((sym_hash->root.type == bfd_link_hash_defined
|
||||
|| sym_hash->root.type == bfd_link_hash_defweak)
|
||||
&& sym_hash->root.u.def.section == sec)
|
||||
{
|
||||
/* As above, adjust the value if needed. */
|
||||
if (sym_hash->root.u.def.value > addr
|
||||
&& sym_hash->root.u.def.value <= toaddr)
|
||||
sym_hash->root.u.def.value -= count;
|
||||
|
||||
/* As above, adjust the size if needed. */
|
||||
else if (sym_hash->root.u.def.value <= addr
|
||||
&& sym_hash->root.u.def.value + sym_hash->size > addr
|
||||
&& sym_hash->root.u.def.value + sym_hash->size <= toaddr)
|
||||
sym_hash->size -= count;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*relax_func_t) (bfd *, asection *, asection *,
|
||||
struct bfd_link_info *,
|
||||
Elf_Internal_Rela *,
|
||||
@ -4179,7 +4215,7 @@ _bfd_riscv_relax_call (bfd *abfd, asection *sec, asection *sym_sec,
|
||||
bfd_vma max_alignment,
|
||||
bfd_vma reserve_size ATTRIBUTE_UNUSED,
|
||||
bool *again,
|
||||
riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED,
|
||||
riscv_pcgp_relocs *pcgp_relocs,
|
||||
bool undefined_weak ATTRIBUTE_UNUSED)
|
||||
{
|
||||
bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
|
||||
@ -4243,7 +4279,7 @@ _bfd_riscv_relax_call (bfd *abfd, asection *sec, asection *sym_sec,
|
||||
/* Delete unnecessary JALR. */
|
||||
*again = true;
|
||||
return riscv_relax_delete_bytes (abfd, sec, rel->r_offset + len, 8 - len,
|
||||
link_info);
|
||||
link_info, pcgp_relocs);
|
||||
}
|
||||
|
||||
/* Traverse all output sections and return the max alignment. */
|
||||
@ -4275,7 +4311,7 @@ _bfd_riscv_relax_lui (bfd *abfd,
|
||||
bfd_vma max_alignment,
|
||||
bfd_vma reserve_size,
|
||||
bool *again,
|
||||
riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED,
|
||||
riscv_pcgp_relocs *pcgp_relocs,
|
||||
bool undefined_weak)
|
||||
{
|
||||
bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
|
||||
@ -4337,7 +4373,7 @@ _bfd_riscv_relax_lui (bfd *abfd,
|
||||
rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE);
|
||||
*again = true;
|
||||
return riscv_relax_delete_bytes (abfd, sec, rel->r_offset, 4,
|
||||
link_info);
|
||||
link_info, pcgp_relocs);
|
||||
|
||||
default:
|
||||
abort ();
|
||||
@ -4370,7 +4406,7 @@ _bfd_riscv_relax_lui (bfd *abfd,
|
||||
|
||||
*again = true;
|
||||
return riscv_relax_delete_bytes (abfd, sec, rel->r_offset + 2, 2,
|
||||
link_info);
|
||||
link_info, pcgp_relocs);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -4388,7 +4424,7 @@ _bfd_riscv_relax_tls_le (bfd *abfd,
|
||||
bfd_vma max_alignment ATTRIBUTE_UNUSED,
|
||||
bfd_vma reserve_size ATTRIBUTE_UNUSED,
|
||||
bool *again,
|
||||
riscv_pcgp_relocs *prcel_relocs ATTRIBUTE_UNUSED,
|
||||
riscv_pcgp_relocs *pcgp_relocs,
|
||||
bool undefined_weak ATTRIBUTE_UNUSED)
|
||||
{
|
||||
/* See if this symbol is in range of tp. */
|
||||
@ -4411,7 +4447,8 @@ _bfd_riscv_relax_tls_le (bfd *abfd,
|
||||
/* We can delete the unnecessary instruction and reloc. */
|
||||
rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE);
|
||||
*again = true;
|
||||
return riscv_relax_delete_bytes (abfd, sec, rel->r_offset, 4, link_info);
|
||||
return riscv_relax_delete_bytes (abfd, sec, rel->r_offset, 4, link_info,
|
||||
pcgp_relocs);
|
||||
|
||||
default:
|
||||
abort ();
|
||||
@ -4430,7 +4467,7 @@ _bfd_riscv_relax_align (bfd *abfd, asection *sec,
|
||||
bfd_vma max_alignment ATTRIBUTE_UNUSED,
|
||||
bfd_vma reserve_size ATTRIBUTE_UNUSED,
|
||||
bool *again ATTRIBUTE_UNUSED,
|
||||
riscv_pcgp_relocs *pcrel_relocs ATTRIBUTE_UNUSED,
|
||||
riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED,
|
||||
bool undefined_weak ATTRIBUTE_UNUSED)
|
||||
{
|
||||
bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
|
||||
@ -4442,6 +4479,9 @@ _bfd_riscv_relax_align (bfd *abfd, asection *sec,
|
||||
bfd_vma aligned_addr = ((symval - 1) & ~(alignment - 1)) + alignment;
|
||||
bfd_vma nop_bytes = aligned_addr - symval;
|
||||
|
||||
/* Once we've handled an R_RISCV_ALIGN, we can't relax anything else. */
|
||||
sec->sec_flg0 = true;
|
||||
|
||||
/* Make sure there are enough NOPs to actually achieve the alignment. */
|
||||
if (rel->r_addend < nop_bytes)
|
||||
{
|
||||
@ -4471,7 +4511,8 @@ _bfd_riscv_relax_align (bfd *abfd, asection *sec,
|
||||
|
||||
/* Delete the excess bytes. */
|
||||
return riscv_relax_delete_bytes (abfd, sec, rel->r_offset + nop_bytes,
|
||||
rel->r_addend - nop_bytes, link_info);
|
||||
rel->r_addend - nop_bytes, link_info,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/* Relax PC-relative references to GP-relative references. */
|
||||
@ -4637,15 +4678,14 @@ _bfd_riscv_relax_delete (bfd *abfd,
|
||||
bfd_vma symval ATTRIBUTE_UNUSED,
|
||||
bfd_vma max_alignment ATTRIBUTE_UNUSED,
|
||||
bfd_vma reserve_size ATTRIBUTE_UNUSED,
|
||||
bool *again,
|
||||
bool *again ATTRIBUTE_UNUSED,
|
||||
riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED,
|
||||
bool undefined_weak ATTRIBUTE_UNUSED)
|
||||
{
|
||||
if (!riscv_relax_delete_bytes (abfd, sec, rel->r_offset, rel->r_addend,
|
||||
link_info))
|
||||
link_info, NULL))
|
||||
return false;
|
||||
rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE);
|
||||
*again = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -4660,35 +4700,11 @@ bfd_elfNN_riscv_set_data_segment_info (struct bfd_link_info *info,
|
||||
htab->data_segment_phase = data_segment_phase;
|
||||
}
|
||||
|
||||
/* Called by after_allocation to check if we need to run the whole
|
||||
relaxations again. */
|
||||
|
||||
bool
|
||||
bfd_elfNN_riscv_restart_relax_sections (struct bfd_link_info *info)
|
||||
{
|
||||
struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info);
|
||||
bool restart = htab->restart_relax;
|
||||
/* Reset the flag. */
|
||||
htab->restart_relax = false;
|
||||
return restart;
|
||||
}
|
||||
|
||||
/* Relax a section.
|
||||
|
||||
Pass 0: Shortens code sequences for LUI/CALL/TPREL relocs.
|
||||
Pass 1: Shortens code sequences for PCREL relocs.
|
||||
Pass 2: Deletes the bytes that pass 1 made obsolete.
|
||||
Pass 3: Which cannot be disabled, handles code alignment directives.
|
||||
|
||||
The `again` is used to determine whether the relax pass itself needs to
|
||||
run again. And the `restart_relax` is used to determine if we need to
|
||||
run the whole relax passes again from 0 to 2. Once we have deleted the
|
||||
code between relax pass 0 to 2, the restart_relax will be set to TRUE,
|
||||
and we should run the whole relaxations again to give them more chances
|
||||
to shorten the code.
|
||||
|
||||
Since we can't relax anything else once we start to handle the alignments,
|
||||
we will only enter into the relax pass 3 when the restart_relax is FALSE. */
|
||||
Pass 0: Shortens code sequences for LUI/CALL/TPREL/PCREL relocs.
|
||||
Pass 1: Deletes the bytes that PCREL relaxation in pass 0 made obsolete.
|
||||
Pass 2: Which cannot be disabled, handles code alignment directives. */
|
||||
|
||||
static bool
|
||||
_bfd_riscv_relax_section (bfd *abfd, asection *sec,
|
||||
@ -4707,12 +4723,11 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
|
||||
*again = false;
|
||||
|
||||
if (bfd_link_relocatable (info)
|
||||
|| sec->sec_flg0
|
||||
|| (sec->flags & SEC_RELOC) == 0
|
||||
|| sec->reloc_count == 0
|
||||
|| (info->disable_target_specific_optimizations
|
||||
&& info->relax_pass < 2)
|
||||
|| (htab->restart_relax
|
||||
&& info->relax_pass == 3)
|
||||
&& info->relax_pass == 0)
|
||||
/* The exp_seg_relro_adjust is enum phase_enum (0x4),
|
||||
and defined in ld/ldexp.h. */
|
||||
|| *(htab->data_segment_phase) == 4)
|
||||
@ -4765,24 +4780,14 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
|
||||
|| type == R_RISCV_TPREL_LO12_I
|
||||
|| type == R_RISCV_TPREL_LO12_S)
|
||||
relax_func = _bfd_riscv_relax_tls_le;
|
||||
else if (!bfd_link_pic (info)
|
||||
&& (type == R_RISCV_PCREL_HI20
|
||||
|| type == R_RISCV_PCREL_LO12_I
|
||||
|| type == R_RISCV_PCREL_LO12_S))
|
||||
relax_func = _bfd_riscv_relax_pc;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
else if (info->relax_pass == 1
|
||||
&& !bfd_link_pic (info)
|
||||
&& (type == R_RISCV_PCREL_HI20
|
||||
|| type == R_RISCV_PCREL_LO12_I
|
||||
|| type == R_RISCV_PCREL_LO12_S))
|
||||
relax_func = _bfd_riscv_relax_pc;
|
||||
else if (info->relax_pass == 2 && type == R_RISCV_DELETE)
|
||||
relax_func = _bfd_riscv_relax_delete;
|
||||
else if (info->relax_pass == 3 && type == R_RISCV_ALIGN)
|
||||
relax_func = _bfd_riscv_relax_align;
|
||||
else
|
||||
continue;
|
||||
|
||||
if (info->relax_pass < 2)
|
||||
{
|
||||
/* Only relax this reloc if it is paired with R_RISCV_RELAX. */
|
||||
if (i == sec->reloc_count - 1
|
||||
|| ELFNN_R_TYPE ((rel + 1)->r_info) != R_RISCV_RELAX
|
||||
@ -4792,6 +4797,12 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
|
||||
/* Skip over the R_RISCV_RELAX. */
|
||||
i++;
|
||||
}
|
||||
else if (info->relax_pass == 1 && type == R_RISCV_DELETE)
|
||||
relax_func = _bfd_riscv_relax_delete;
|
||||
else if (info->relax_pass == 2 && type == R_RISCV_ALIGN)
|
||||
relax_func = _bfd_riscv_relax_align;
|
||||
else
|
||||
continue;
|
||||
|
||||
data->relocs = relocs;
|
||||
|
||||
@ -4954,9 +4965,6 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
|
||||
free (relocs);
|
||||
riscv_free_pcgp_relocs (&pcgp_relocs, abfd, sec);
|
||||
|
||||
if (*again)
|
||||
htab->restart_relax = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -92,11 +92,6 @@ riscv_estimate_digit (unsigned);
|
||||
extern int
|
||||
riscv_compare_subsets (const char *, const char *);
|
||||
|
||||
extern bool
|
||||
bfd_elf32_riscv_restart_relax_sections (struct bfd_link_info *);
|
||||
extern bool
|
||||
bfd_elf64_riscv_restart_relax_sections (struct bfd_link_info *);
|
||||
|
||||
extern void
|
||||
bfd_elf32_riscv_set_data_segment_info (struct bfd_link_info *, int *);
|
||||
extern void
|
||||
|
@ -42,7 +42,7 @@ riscv_elf_before_allocation (void)
|
||||
ENABLE_RELAXATION;
|
||||
}
|
||||
|
||||
link_info.relax_pass = 4;
|
||||
link_info.relax_pass = 3;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -76,11 +76,7 @@ gld${EMULATION_NAME}_after_allocation (void)
|
||||
enum phase_enum *phase = &(expld.dataseg.phase);
|
||||
bfd_elf${ELFSIZE}_riscv_set_data_segment_info (&link_info, (int *) phase);
|
||||
|
||||
do
|
||||
{
|
||||
ldelf_map_segments (need_layout);
|
||||
}
|
||||
while (bfd_elf${ELFSIZE}_riscv_restart_relax_sections (&link_info));
|
||||
ldelf_map_segments (need_layout);
|
||||
}
|
||||
|
||||
/* This is a convenient point to tell BFD about target specific flags.
|
||||
|
12
ld/testsuite/ld-riscv-elf/align-small-region.d
Normal file
12
ld/testsuite/ld-riscv-elf/align-small-region.d
Normal file
@ -0,0 +1,12 @@
|
||||
#source: align-small-region.s
|
||||
#as: -march=rv32i
|
||||
#ld: -melf32lriscv --relax -Talign-small-region.ld --defsym=_start=0x100
|
||||
#objdump: -d
|
||||
|
||||
.*:[ ]+file format .*
|
||||
|
||||
Disassembly of section \.entry:
|
||||
|
||||
00000000 <_reset>:
|
||||
.*:[ ]+[0-9a-f]+[ ]+j[ ]+100[ ]+<_start>
|
||||
#pass
|
12
ld/testsuite/ld-riscv-elf/align-small-region.ld
Normal file
12
ld/testsuite/ld-riscv-elf/align-small-region.ld
Normal file
@ -0,0 +1,12 @@
|
||||
MEMORY
|
||||
{
|
||||
reset : ORIGIN = 0x0, LENGTH = 32
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.entry :
|
||||
{
|
||||
KEEP (*(.entry))
|
||||
} > reset
|
||||
}
|
7
ld/testsuite/ld-riscv-elf/align-small-region.s
Normal file
7
ld/testsuite/ld-riscv-elf/align-small-region.s
Normal file
@ -0,0 +1,7 @@
|
||||
.section .entry, "xa"
|
||||
.align 5
|
||||
.globl _reset
|
||||
.type _reset, @function
|
||||
_reset:
|
||||
tail _start
|
||||
.size _reset, . - _reset
|
@ -119,6 +119,7 @@ proc run_relax_twice_test {} {
|
||||
}
|
||||
|
||||
if [istarget "riscv*-*-*"] {
|
||||
run_dump_test "align-small-region"
|
||||
run_dump_test "call-relax"
|
||||
run_dump_test "pcgp-relax"
|
||||
run_dump_test "c-lui"
|
||||
@ -130,7 +131,6 @@ if [istarget "riscv*-*-*"] {
|
||||
run_dump_test "pcrel-lo-addend-3a"
|
||||
run_dump_test "pcrel-lo-addend-3b"
|
||||
run_dump_test "pcrel-lo-addend-3c"
|
||||
run_dump_test "restart-relax"
|
||||
run_dump_test "attr-merge-arch-01"
|
||||
run_dump_test "attr-merge-arch-02"
|
||||
run_dump_test "attr-merge-arch-03"
|
||||
|
@ -1,14 +0,0 @@
|
||||
#source: restart-relax.s
|
||||
#as:
|
||||
#ld:
|
||||
#objdump: -d
|
||||
|
||||
#...
|
||||
Disassembly of section .text:
|
||||
|
||||
0+[0-9a-f]+ <_start>:
|
||||
.*:[ ]+[0-9a-f]+[ ]+addi[ ]+.*
|
||||
#...
|
||||
.*:[ ]+[0-9a-f]+[ ]+jal[ ]+ra,[0-9a-f]+ <_start>
|
||||
.*:[ ]+[0-9a-f]+[ ]+add[ ]+a0,a1,a2
|
||||
#pass
|
@ -1,17 +0,0 @@
|
||||
.text
|
||||
.global _start
|
||||
_start:
|
||||
lla a0, data_g
|
||||
.rept 0x3fffe
|
||||
nop
|
||||
.endr
|
||||
call _start
|
||||
.option rvc
|
||||
.align 2
|
||||
add a0, a1, a2
|
||||
|
||||
.data
|
||||
.global data_g
|
||||
.dword 0x0
|
||||
data_g:
|
||||
.word 0x1000
|
Loading…
Reference in New Issue
Block a user