• R/O
  • HTTP
  • SSH
  • HTTPS

提交

标签
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Commit MetaInfo

修订版43025f01a0c99c939e20e90a6e695741c14a925a (tree)
时间2022-10-25 10:20:23
作者Patrick O'Neill <patrick@rivo...>
CommiterNelson Chu

Log Message

RISC-V: Improve link time complexity.

The riscv port does deletion and symbol table update for each relocation
while relaxing, so we are moving section bytes and scanning symbol table once
for each relocation. Compared to microblaze port, they record the relaxation
changes into a table, then do the deletion and symbol table update once per
section, rather than per relocation. Therefore, they should have better link
time complexity than us.

To improve the link time complexity, this patch try to make the deletion in
linear time. Compared to record the relaxation changes into a table, we
replace the unused relocation with R_RISCV_DELETE for the deleted bytes, and
then resolve them at the end of the section. Assuming the number of
R_RISCV_DELETE is m, and the number of symbols is n, the total link complexity
should be O(m) for moving section bytes, and O(m*n2) for symbol table update.
If we record the relaxation changes into the table, and then sort the symbol
table by values, then probably can reduce the time complexity to O(m*n*log(n))
for updating symbol table, but it doesn't seem worth it for now.

bfd/

    • elfnn-riscv.c (_riscv_relax_delete_bytes): Renamed from
      riscv_relax_delete_bytes, updated to reduce the tiem complexity to O(m)
      for memmove.
      (typedef relax_delete_t): Function pointer declaration of delete functions.
      (riscv_relax_delete_bytes): Can choose to use _riscv_relax_delete_piecewise
      or _riscv_relax_delete_immediate for deletion.
      (_riscv_relax_delete_piecewise): Just mark the deleted bytes as R_RISCV_DELETE.
      (_riscv_relax_delete_immediate): Delete some bytes from a section while
      relaxing.
      (riscv_relax_resolve_delete_relocs): Delete the bytes for R_RISCV_DELETE
      relocations from a section, at the end of _bfd_riscv_relax_section.
      (_bfd_riscv_relax_call): Mark deleted bytes as R_RISCV_DELETE by reusing
      R_RISCV_RELAX.
      (_bfd_riscv_relax_lui): Likewise, but reuse R_RISCV_HI20 for lui, and reuse
      R_RISCV_RELAX for c.lui.
      (_bfd_riscv_relax_tls_le): Likewise, but resue R_RISCV_TPREL_HI20 and
      R_RISCV_TPREL_ADD.
      (_bfd_riscv_relax_pc): Likewise, but resue R_RISCV_PCREL_HI20 for auipc.
      (_bfd_riscv_relax_align): Updated, don't need to resue relocation since
      calling _riscv_relax_delete_immediate.
      (_bfd_riscv_relax_delete): Removed.
      (_bfd_riscv_relax_section): Set riscv_relax_delete_bytes for each relax_func,
      to delete bytes immediately or later. Call riscv_relax_resolve_delete_relocs
      to delete bytes for DELETE relocations from a section.

更改概述

差异

--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -4043,27 +4043,32 @@ riscv_update_pcgp_relocs (riscv_pcgp_relocs *p, asection *deleted_sec,
40434043 }
40444044 }
40454045
4046-/* Delete some bytes from a section while relaxing. */
4046+/* Delete some bytes, adjust relcocations and symbol table from a section. */
40474047
40484048 static bool
4049-riscv_relax_delete_bytes (bfd *abfd,
4050- asection *sec,
4051- bfd_vma addr,
4052- size_t count,
4053- struct bfd_link_info *link_info,
4054- riscv_pcgp_relocs *p)
4049+_riscv_relax_delete_bytes (bfd *abfd,
4050+ asection *sec,
4051+ bfd_vma addr,
4052+ size_t count,
4053+ struct bfd_link_info *link_info,
4054+ riscv_pcgp_relocs *p,
4055+ bfd_vma delete_total,
4056+ bfd_vma toaddr)
40554057 {
40564058 unsigned int i, symcount;
4057- bfd_vma toaddr = sec->size;
40584059 struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (abfd);
40594060 Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
40604061 unsigned int sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
40614062 struct bfd_elf_section_data *data = elf_section_data (sec);
40624063 bfd_byte *contents = data->this_hdr.contents;
4064+ size_t bytes_to_move = toaddr - addr - count;
40634065
40644066 /* Actually delete the bytes. */
40654067 sec->size -= count;
4066- memmove (contents + addr, contents + addr + count, toaddr - addr - count);
4068+ memmove (contents + addr, contents + addr + count + delete_total, bytes_to_move);
4069+
4070+ /* Still adjust relocations and symbols in non-linear times. */
4071+ toaddr = sec->size + count;
40674072
40684073 /* Adjust the location of all of the relocs. Note that we need not
40694074 adjust the addends, since all PC-relative references must be against
@@ -4161,6 +4166,99 @@ riscv_relax_delete_bytes (bfd *abfd,
41614166 return true;
41624167 }
41634168
4169+typedef bool (*relax_delete_t) (bfd *, asection *,
4170+ bfd_vma, size_t,
4171+ struct bfd_link_info *,
4172+ riscv_pcgp_relocs *,
4173+ Elf_Internal_Rela *);
4174+
4175+static relax_delete_t riscv_relax_delete_bytes;
4176+
4177+/* Do not delete some bytes from a section while relaxing.
4178+ Just mark the deleted bytes as R_RISCV_DELETE. */
4179+
4180+static bool
4181+_riscv_relax_delete_piecewise (bfd *abfd ATTRIBUTE_UNUSED,
4182+ asection *sec ATTRIBUTE_UNUSED,
4183+ bfd_vma addr,
4184+ size_t count,
4185+ struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
4186+ riscv_pcgp_relocs *p ATTRIBUTE_UNUSED,
4187+ Elf_Internal_Rela *rel)
4188+{
4189+ if (rel == NULL)
4190+ return false;
4191+ rel->r_info = ELFNN_R_INFO (0, R_RISCV_DELETE);
4192+ rel->r_offset = addr;
4193+ rel->r_addend = count;
4194+ return true;
4195+}
4196+
4197+/* Delete some bytes from a section while relaxing. */
4198+
4199+static bool
4200+_riscv_relax_delete_immediate (bfd *abfd,
4201+ asection *sec,
4202+ bfd_vma addr,
4203+ size_t count,
4204+ struct bfd_link_info *link_info,
4205+ riscv_pcgp_relocs *p,
4206+ Elf_Internal_Rela *rel)
4207+{
4208+ if (rel != NULL)
4209+ rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE);
4210+ return _riscv_relax_delete_bytes (abfd, sec, addr, count,
4211+ link_info, p, 0, sec->size);
4212+}
4213+
4214+/* Delete the bytes for R_RISCV_DELETE relocs. */
4215+
4216+static bool
4217+riscv_relax_resolve_delete_relocs (bfd *abfd,
4218+ asection *sec,
4219+ struct bfd_link_info *link_info,
4220+ Elf_Internal_Rela *relocs)
4221+{
4222+ bfd_vma delete_total = 0;
4223+ unsigned int i;
4224+
4225+ for (i = 0; i < sec->reloc_count; i++)
4226+ {
4227+ Elf_Internal_Rela *rel = relocs + i;
4228+ if (ELFNN_R_TYPE (rel->r_info) != R_RISCV_DELETE)
4229+ continue;
4230+
4231+ /* Find the next R_RISCV_DELETE reloc if possible. */
4232+ Elf_Internal_Rela *rel_next = NULL;
4233+ unsigned int start = rel - relocs;
4234+ for (i = start; i < sec->reloc_count; i++)
4235+ {
4236+ /* Since we only replace existing relocs and don't add new relocs, the
4237+ relocs are in sequential order. We can skip the relocs prior to this
4238+ one, making this search linear time. */
4239+ rel_next = relocs + i;
4240+ if (ELFNN_R_TYPE ((rel_next)->r_info) == R_RISCV_DELETE
4241+ && (rel_next)->r_offset > rel->r_offset)
4242+ break;
4243+ else
4244+ rel_next = NULL;
4245+ }
4246+
4247+ bfd_vma toaddr = rel_next == NULL ? sec->size : rel_next->r_offset;
4248+ if (!_riscv_relax_delete_bytes (abfd, sec, rel->r_offset, rel->r_addend,
4249+ link_info, NULL, delete_total, toaddr))
4250+ return false;
4251+
4252+ delete_total += rel->r_addend;
4253+ rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE);
4254+
4255+ /* Skip ahead to the next delete reloc. */
4256+ i = rel_next != NULL ? rel_next - relocs - 1 : sec->reloc_count;
4257+ }
4258+
4259+ return true;
4260+}
4261+
41644262 typedef bool (*relax_func_t) (bfd *, asection *, asection *,
41654263 struct bfd_link_info *,
41664264 Elf_Internal_Rela *,
@@ -4239,10 +4337,10 @@ _bfd_riscv_relax_call (bfd *abfd, asection *sec, asection *sym_sec,
42394337 /* Replace the AUIPC. */
42404338 riscv_put_insn (8 * len, auipc, contents + rel->r_offset);
42414339
4242- /* Delete unnecessary JALR. */
4340+ /* Delete unnecessary JALR and reuse the R_RISCV_RELAX reloc. */
42434341 *again = true;
42444342 return riscv_relax_delete_bytes (abfd, sec, rel->r_offset + len, 8 - len,
4245- link_info, pcgp_relocs);
4343+ link_info, pcgp_relocs, rel + 1);
42464344 }
42474345
42484346 /* Traverse all output sections and return the max alignment. */
@@ -4332,11 +4430,10 @@ _bfd_riscv_relax_lui (bfd *abfd,
43324430 return true;
43334431
43344432 case R_RISCV_HI20:
4335- /* We can delete the unnecessary LUI and reloc. */
4336- rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE);
4433+ /* Delete unnecessary LUI and reuse the reloc. */
43374434 *again = true;
43384435 return riscv_relax_delete_bytes (abfd, sec, rel->r_offset, 4,
4339- link_info, pcgp_relocs);
4436+ link_info, pcgp_relocs, rel);
43404437
43414438 default:
43424439 abort ();
@@ -4367,9 +4464,10 @@ _bfd_riscv_relax_lui (bfd *abfd,
43674464 /* Replace the R_RISCV_HI20 reloc. */
43684465 rel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel->r_info), R_RISCV_RVC_LUI);
43694466
4467+ /* Delete extra bytes and reuse the R_RISCV_RELAX reloc. */
43704468 *again = true;
43714469 return riscv_relax_delete_bytes (abfd, sec, rel->r_offset + 2, 2,
4372- link_info, pcgp_relocs);
4470+ link_info, pcgp_relocs, rel + 1);
43734471 }
43744472
43754473 return true;
@@ -4407,11 +4505,10 @@ _bfd_riscv_relax_tls_le (bfd *abfd,
44074505
44084506 case R_RISCV_TPREL_HI20:
44094507 case R_RISCV_TPREL_ADD:
4410- /* We can delete the unnecessary instruction and reloc. */
4411- rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE);
4508+ /* Delete unnecessary instruction and reuse the reloc. */
44124509 *again = true;
44134510 return riscv_relax_delete_bytes (abfd, sec, rel->r_offset, 4, link_info,
4414- pcgp_relocs);
4511+ pcgp_relocs, rel);
44154512
44164513 default:
44174514 abort ();
@@ -4472,10 +4569,10 @@ _bfd_riscv_relax_align (bfd *abfd, asection *sec,
44724569 if (nop_bytes % 4 != 0)
44734570 bfd_putl16 (RVC_NOP, contents + rel->r_offset + pos);
44744571
4475- /* Delete the excess bytes. */
4572+ /* Delete excess bytes. */
44764573 return riscv_relax_delete_bytes (abfd, sec, rel->r_offset + nop_bytes,
44774574 rel->r_addend - nop_bytes, link_info,
4478- NULL);
4575+ NULL, NULL);
44794576 }
44804577
44814578 /* Relax PC-relative references to GP-relative references. */
@@ -4617,9 +4714,9 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED,
46174714 ELFNN_R_SYM(rel->r_info),
46184715 sym_sec,
46194716 undefined_weak);
4620- /* We can delete the unnecessary AUIPC and reloc. */
4621- rel->r_info = ELFNN_R_INFO (0, R_RISCV_DELETE);
4622- rel->r_addend = 4;
4717+ /* Delete unnecessary AUIPC and reuse the reloc. */
4718+ riscv_relax_delete_bytes (abfd, sec, rel->r_offset, 4, link_info,
4719+ pcgp_relocs, rel);
46234720 return true;
46244721
46254722 default:
@@ -4630,28 +4727,6 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED,
46304727 return true;
46314728 }
46324729
4633-/* Delete the bytes for R_RISCV_DELETE. */
4634-
4635-static bool
4636-_bfd_riscv_relax_delete (bfd *abfd,
4637- asection *sec,
4638- asection *sym_sec ATTRIBUTE_UNUSED,
4639- struct bfd_link_info *link_info,
4640- Elf_Internal_Rela *rel,
4641- bfd_vma symval ATTRIBUTE_UNUSED,
4642- bfd_vma max_alignment ATTRIBUTE_UNUSED,
4643- bfd_vma reserve_size ATTRIBUTE_UNUSED,
4644- bool *again ATTRIBUTE_UNUSED,
4645- riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED,
4646- bool undefined_weak ATTRIBUTE_UNUSED)
4647-{
4648- if (!riscv_relax_delete_bytes (abfd, sec, rel->r_offset, rel->r_addend,
4649- link_info, NULL))
4650- return false;
4651- rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE);
4652- return true;
4653-}
4654-
46554730 /* Called by after_allocation to set the information of data segment
46564731 before relaxing. */
46574732
@@ -4729,6 +4804,7 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
47294804 bool undefined_weak = false;
47304805
47314806 relax_func = NULL;
4807+ riscv_relax_delete_bytes = NULL;
47324808 if (info->relax_pass == 0)
47334809 {
47344810 if (type == R_RISCV_CALL
@@ -4750,6 +4826,7 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
47504826 relax_func = _bfd_riscv_relax_pc;
47514827 else
47524828 continue;
4829+ riscv_relax_delete_bytes = _riscv_relax_delete_piecewise;
47534830
47544831 /* Only relax this reloc if it is paired with R_RISCV_RELAX. */
47554832 if (i == sec->reloc_count - 1
@@ -4760,10 +4837,11 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
47604837 /* Skip over the R_RISCV_RELAX. */
47614838 i++;
47624839 }
4763- else if (info->relax_pass == 1 && type == R_RISCV_DELETE)
4764- relax_func = _bfd_riscv_relax_delete;
4765- else if (info->relax_pass == 2 && type == R_RISCV_ALIGN)
4766- relax_func = _bfd_riscv_relax_align;
4840+ else if (info->relax_pass == 1 && type == R_RISCV_ALIGN)
4841+ {
4842+ relax_func = _bfd_riscv_relax_align;
4843+ riscv_relax_delete_bytes = _riscv_relax_delete_immediate;
4844+ }
47674845 else
47684846 continue;
47694847
@@ -4921,6 +4999,10 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
49214999 goto fail;
49225000 }
49235001
5002+ /* Resolve R_RISCV_DELETE relocations. */
5003+ if (!riscv_relax_resolve_delete_relocs (abfd, sec, info, relocs))
5004+ goto fail;
5005+
49245006 ret = true;
49255007
49265008 fail: