From 864a29346d50b293d1526f60a6b72392c14119fe Mon Sep 17 00:00:00 2001 From: Edward Jones Date: Tue, 22 Feb 2022 12:20:59 +0000 Subject: [PATCH] Add support for RISC-V overlay system This adds changes to allow objects which use the RISC-V overlay system to be linked together. It manages the creation and layout of overlay sections for use by the overlay runtime, and handles overlay specific relocations. bfd/ * Makefile.am: Add elfxx-riscv-overlay.c and elfxx-riscv-overlay.h to files included in the build. * Makefile.in: Regenerated. * bfd-in2.h: Likewise. * bfd.c (bfd_get_section_overlay_sort_data): Define. * binary.c (binary_bfd_get_section_overlay_sort_data): Likewise. * configure: Regenerated. * configure.ac: Add elfxx-riscv-overlay.lo to riscv backend .o files. * elfnn-riscv.c (struct riscv_elf_link_hash_entry): (struct riscv_elf_link_hash_table) (riscv_elf_hash_entry riscv_elf_hash_table is_riscv_elf) (sec_addr): Move to elfxx-riscv.h. (link_hash_newfunc): Initialize overlay members of struct riscv_elf_link_hash_entry. (riscv_elf_link_hash_table_create): Call out to riscv_elf_overlay_link_hash_table_init to initialization overlay data structure. (riscv_elf_check_relocs): Add handling of overlay relocations, call out to riscv_elf_overlay_check_relocation. Update handling of R_RISCV_CALL. Mark symbols referred through non-overlay relocations and error for both overlay and non-overlay relocations to the same symbol. (riscv_elf_check_sections): New function. (riscv_elf_gc_mark_hook): Call out to riscv_overlay_set_use_gcmark. (perform_relocation): Add handling of overlay relocations. (riscv_elf_relocate_section): Add handling of new overlay relocations. Call out to riscv_overlay_handle_relocation. (riscv_elf_finish_dynamic_sections): Call out to riscv_overlay_finish_sections. (riscv_relax_delete_bytes): Add call out to riscv_overlay_relax_delete_bytes. (riscv_elf_overlay_hook_elfNNlriscv) (riscv_elf_overlay_hook_elfNNbriscv): New functions. (bfd_elfNN_bfd_get_section_overlay_sort_data): New define. (elf_backend_check_directives): Likewise. * elfxx-riscv-overlay.c: New file. * elfxx-riscv-overlay.h: Likewise. * elfxx-riscv.c (howto_table): Add HOWTO entries for R_RISCV_OVLTOK_HI20, R_RISCV_OVLTOK_LO12_I, R_RISCV_OVLTOK32, R_RISCV_OVLPLT_HI20, R_RISCV_OVLPLT_LO12_I, and R_RISCV_OVLPLT32. (riscv_reloc_map): Add mappings for overlay relocations. (riscv_reloc_type_lookup): Add workaround to correctly map from overlay relocation numbers to howto table entries. (riscv_elf_rtype_to_howto): Correctly map relocation types to howto entries. * elfxx-riscv.h (struct riscv_elf_link_hash_entry): (struct riscv_elf_link_hash_table) (riscv_elf_hash_entry riscv_elf_hash_table is_riscv_elf) (sec_addr): Move definitions from elfnn-riscv.c. * elfxx-target.h (bfd_elfNN_bfd_get_section_overlay_sort_data): Add define. * ihex.c (ihex_bfd_get_section_overlay_sort_data): Add define. * libbfd-in.h (_bfd_nolink_bfd_get_section_overlay_sort_data): Add define. * libbfd.h: Regenerated. * plugin.c (bfd_plugin_bfd_get_section_overlay_sort_data): Add define. * reloc.c: Add ENUMX entries for BFD_RELOC_RISCV_OVLTOK_HI20, BFD_RELOC_RISCV_OVLTOK_LO12_I, BFD_RELOC_RISCV_OVLTOK32, BFD_RELOC_RISCV_OVLPLT_HI20, BFD_RELOC_RISCV_OVLPLT_LO12_I, and BFD_RELOC_RISCV_OVLPLT32. * section.c (bfd_generic_get_section_overlay_sort_data): Add function. * srec.c (srec_bfd_get_section_overlay_sort_data): Add define. * target.c (BFD_JUMP_TABLE_LINK): Add _bfd_get_section_overlay_sort_data entry. (bfd_copy_link_hash_symbol_type): Likewise. * tekhex.c (tekhex_bfd_get_section_overlay_sort_data): Add define. gas/ * config/tc-riscv.c (percent_op_utype): Add mappings for BFD_RELOC_RISCV_OVLTOK_HI20 and BFD_RELOC_RISCV_OVLPLT_HI20 relocs. (percent_op_itype): Add mappings for BFD_RELOC_RISCV_OVLTOK_LO12_I and BFD_RELOC_RISCV_OVLPLT_LO12_I relocs. (md_apply_fix): Add handling of overlay relocations. include/ * elf/riscv.h: Add R_RISCV_OVLTOK_HI20, R_RISCV_OVLTOK_LO12_I, R_RISCV_OVLTOK32, R_RISCV_OVLPLT_HI20, R_RISCV_OVLPLT_LO12_I, R_RISCV_OVLPLT32 for reloc numbers from 220 to 225. * opcode/riscv.h (X_ZERO X_T5 X_T6): Add defines. ld/ * emultempl/emulation.em (LDEMUL_EXTRA_EARLY_MAP_FILE_TEST): Default to NULL. * emultempl/riscvelf.em (riscv_grouping_file): Forward declare. (DEFAULT_CRC_INIT DEFAULT_CRC_POLY DEFAULT_CRC_XOROUT) (DEFAULT_CRC_REFIN DEFAULT_CRC_REFOUT): New defines. (elf_riscv_before_parse): New function. (riscv_elf_before_allocation): Add error for .ovlinput prefixed input sections not assigned to .ovlgrps output section. (riscv_elf_after_check_relocs): New function. (get_type_from_name_and_flags): Likewise. (riscv_ovl_additional_link_map_text): Likewise. (PARSE_AND_LIST_PROLOGUE): Set to add various defines to the standard elf argument parsing. (PARSE_AND_LIST_LONGOPTS): Add various overlay options to standard option list. (PARSE_AND_LIST_OPTIONS): Add various overlay short options to standard elf option list. (PARSE_AND_LIST_ARGS_CASES): Set to add cases to standard elf argument parsing. (LDEMUL_BEFORE_PARSE): Define to elf_riscv_before_parse. (LDEMUL_AFTER_CHECK_RELOCS): Define to riscv_elf_after_check_relocs. (LDEMUL_EXTRA_EARLY_MAP_FILE_TEXT): Define to =riscv_ovl_additional_link_map_text * ld.h (sort_type): Add by_overlay sort type. * ldemul.c (ldemul_extra_early_map_file_text): Add new entry point. * ldemul.h (ldemul_extra_early_map_file_text): Add forward declaration. (struct ld_emulation_xfer_struct): Add extra_early_map_file_text member. * ldlang.c (compare_section): Add handling of by_overlay sort type. (get_lang_memory_region_list): Add function. (lang_map): Call ldemul_extra_early_map_text at start of map file printing. (set_overlay_sort_default): Add function. (update_wild_statements): Force unsorted sections assigned to the .ovlgrps output section to use by_overlay sorting. (print_wild_statement): Handle by_overlay sorting type. (size_input_section): Force alignment of overlay padding sections. * ldlang.h (get_lang_memory_region_list): Add forward declaration. * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add run_dump_test calls for overlay tests. (riscv_get_testdir): Add procedure. * testsuite/ld-riscv-elf/overlay-assign-dead.csv: Added file. * testsuite/ld-riscv-elf/overlay-assing-dead.d: Likewise. * testsuite/ld-riscv-elf/overlay-assign-group0.csv: Likewise. * testsuite/ld-riscv-elf/overlay-assign-group0.d: Likewise. * testsuite/ld-riscv-elf/overlay-assign-missing.csv: Likewise. * testsuite/ld-riscv-elf/overlay-assign-missing.d: Likewise. * testsuite/ld-riscv-elf/overlay-assign-non-contiguous.csv: Likewise. * testsuite/ld-riscv-elf/overlay-assign-non-contiguous.d: Likewise. * testsuite/ld-riscv-elf/overlay-autoassign-01.d: Likewise. * testsuite/ld-riscv-elf/overlay-autoassign-02.d: Likewise. * testsuite/ld-riscv-elf/overlay-autoassign-dead.d: Likewise. * testsuite/ld-riscv-elf/overlay-big-funcs.s: Likewise. * testsuite/ld-riscv-elf/overlay-dead-symbol.s: Likewise. * testsuite/ld-riscv-elf/overlay-invalid-group-number.csv: Likewise. * testsuite/ld-riscv-elf/overlay-invalid-group-number.d: Likewise. * testsuite/ld-riscv-elf/overlay-many-func-group.csv: Likewise. * testsuite/ld-riscv-elf/overlay-many-func-group.d: Likewise. * testsuite/ld-riscv-elf/overlay-many-funcs.s: Likewise. * testsuite/ld-riscv-elf/overlay-max-group-number.csv: Likewise. * testsuite/ld-riscv-elf/overlay-max-group-number.d: Likewise. * testsuite/ld-riscv-elf/overlay-max-size-group.csv: Likewise. * testsuite/ld-riscv-elf/overlay-max-size-group.d: Likewise. * testsuite/ld-riscv-elf/overlay-multigroup-01.csv: Likewise. * testsuite/ld-riscv-elf/overlay-multigroup-01.d: Likewise. * testsuite/ld-riscv-elf/overlay-multigroup-02.csv: Likewise. * testsuite/ld-riscv-elf/overlay-multigroup-02.d: Likewise. * testsuite/ld-riscv-elf/overlay-no-grouping-file.d: Likewise. * testsuite/ld-riscv-elf/overlay-partial-assign.csv: Likewise. * testsuite/ld-riscv-elf/overlay-partial-assign.d: Likewise. * testsuite/ld-riscv-elf/overlay-plt.csv: Likewise. * testsuite/ld-riscv-elf/overlay-plt.d: Likewise. * testsuite/ld-riscv-elf/overlay-plt.s: Likewise. * testsuite/ld-riscv-elf/overlay-relax-01.d: Likewise. * testsuite/ld-riscv-elf/overlay-relax-02.csv: Likewise. * testsuite/ld-riscv-elf/overlay-relax-02.d: Likewise. * testsuite/ld-riscv-elf/overlay-relax-multigroup.csv: Likewise. * testsuite/ld-riscv-elf/overlay-relax-multigroup.d: Likewise. * testsuite/ld-riscv-elf/overlay-relax.s: Likewise. * testsuite/ld-riscv-elf/overlay-symbol-not-in-ovlinput.d: Likewise. * testsuite/ld-riscv-elf/overlay-symbol-not-in-ovlinput.s: Likewise. * testsuite/ld-riscv-elf/overlay-trivial.s: Likewise. * testsuite/ld-riscv-elf/overlay.ld: Likewise. --- bfd/ChangeLog | 79 + bfd/Makefile.am | 5 +- bfd/Makefile.in | 6 +- bfd/bfd-in2.h | 19 +- bfd/bfd.c | 3 + bfd/binary.c | 1 + bfd/configure | 8 +- bfd/configure.ac | 8 +- bfd/elfnn-riscv.c | 204 +- bfd/elfxx-riscv-overlay.c | 2563 +++++++++++++++++ bfd/elfxx-riscv-overlay.h | 205 ++ bfd/elfxx-riscv.c | 129 +- bfd/elfxx-riscv.h | 66 + bfd/elfxx-target.h | 4 + bfd/ihex.c | 1 + bfd/libbfd-in.h | 2 + bfd/libbfd.h | 8 + bfd/plugin.c | 1 + bfd/reloc.c | 12 + bfd/section.c | 19 + bfd/srec.c | 1 + bfd/targets.c | 7 +- bfd/tekhex.c | 1 + gas/ChangeLog | 11 + gas/config/tc-riscv.c | 12 + include/ChangeLog | 10 + include/elf/riscv.h | 6 + include/opcode/riscv.h | 3 + ld/ChangeLog | 107 + ld/emultempl/emulation.em | 1 + ld/emultempl/riscvelf.em | 333 +++ ld/ld.h | 2 +- ld/ldemul.c | 8 + ld/ldemul.h | 8 + ld/ldlang.c | 48 + ld/ldlang.h | 2 + ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp | 27 + .../ld-riscv-elf/overlay-assign-dead.csv | 1 + .../ld-riscv-elf/overlay-assign-dead.d | 12 + .../ld-riscv-elf/overlay-assign-group0.csv | 1 + .../ld-riscv-elf/overlay-assign-group0.d | 4 + .../ld-riscv-elf/overlay-assign-missing.csv | 1 + .../ld-riscv-elf/overlay-assign-missing.d | 31 + .../overlay-assign-non-contiguous.csv | 6 + .../overlay-assign-non-contiguous.d | 89 + .../ld-riscv-elf/overlay-autoassign-01.d | 31 + .../ld-riscv-elf/overlay-autoassign-02.d | 85 + .../ld-riscv-elf/overlay-autoassign-dead.d | 12 + ld/testsuite/ld-riscv-elf/overlay-big-funcs.s | 64 + .../ld-riscv-elf/overlay-dead-symbol.s | 12 + .../overlay-invalid-group-number.csv | 1 + .../overlay-invalid-group-number.d | 4 + .../ld-riscv-elf/overlay-many-func-group.csv | 6 + .../ld-riscv-elf/overlay-many-func-group.d | 68 + .../ld-riscv-elf/overlay-many-funcs.s | 58 + .../ld-riscv-elf/overlay-max-group-number.csv | 1 + .../ld-riscv-elf/overlay-max-group-number.d | 33 + .../ld-riscv-elf/overlay-max-size-group.csv | 6 + .../ld-riscv-elf/overlay-max-size-group.d | 4 + .../ld-riscv-elf/overlay-multigroup-01.csv | 1 + .../ld-riscv-elf/overlay-multigroup-01.d | 114 + .../ld-riscv-elf/overlay-multigroup-02.csv | 6 + .../ld-riscv-elf/overlay-multigroup-02.d | 154 + .../ld-riscv-elf/overlay-no-grouping-file.d | 4 + .../ld-riscv-elf/overlay-partial-assign.csv | 3 + .../ld-riscv-elf/overlay-partial-assign.d | 85 + ld/testsuite/ld-riscv-elf/overlay-plt.csv | 4 + ld/testsuite/ld-riscv-elf/overlay-plt.d | 72 + ld/testsuite/ld-riscv-elf/overlay-plt.s | 40 + ld/testsuite/ld-riscv-elf/overlay-relax-01.d | 19 + .../ld-riscv-elf/overlay-relax-02.csv | 3 + ld/testsuite/ld-riscv-elf/overlay-relax-02.d | 19 + .../ld-riscv-elf/overlay-relax-multigroup.csv | 3 + .../ld-riscv-elf/overlay-relax-multigroup.d | 19 + ld/testsuite/ld-riscv-elf/overlay-relax.s | 55 + .../overlay-symbol-not-in-ovlinput.d | 4 + .../overlay-symbol-not-in-ovlinput.s | 10 + ld/testsuite/ld-riscv-elf/overlay-trivial.s | 12 + ld/testsuite/ld-riscv-elf/overlay.ld | 17 + 79 files changed, 5027 insertions(+), 77 deletions(-) create mode 100644 bfd/elfxx-riscv-overlay.c create mode 100644 bfd/elfxx-riscv-overlay.h create mode 100644 ld/testsuite/ld-riscv-elf/overlay-assign-dead.csv create mode 100644 ld/testsuite/ld-riscv-elf/overlay-assign-dead.d create mode 100644 ld/testsuite/ld-riscv-elf/overlay-assign-group0.csv create mode 100644 ld/testsuite/ld-riscv-elf/overlay-assign-group0.d create mode 100644 ld/testsuite/ld-riscv-elf/overlay-assign-missing.csv create mode 100644 ld/testsuite/ld-riscv-elf/overlay-assign-missing.d create mode 100644 ld/testsuite/ld-riscv-elf/overlay-assign-non-contiguous.csv create mode 100644 ld/testsuite/ld-riscv-elf/overlay-assign-non-contiguous.d create mode 100644 ld/testsuite/ld-riscv-elf/overlay-autoassign-01.d create mode 100644 ld/testsuite/ld-riscv-elf/overlay-autoassign-02.d create mode 100644 ld/testsuite/ld-riscv-elf/overlay-autoassign-dead.d create mode 100644 ld/testsuite/ld-riscv-elf/overlay-big-funcs.s create mode 100644 ld/testsuite/ld-riscv-elf/overlay-dead-symbol.s create mode 100644 ld/testsuite/ld-riscv-elf/overlay-invalid-group-number.csv create mode 100644 ld/testsuite/ld-riscv-elf/overlay-invalid-group-number.d create mode 100644 ld/testsuite/ld-riscv-elf/overlay-many-func-group.csv create mode 100644 ld/testsuite/ld-riscv-elf/overlay-many-func-group.d create mode 100644 ld/testsuite/ld-riscv-elf/overlay-many-funcs.s create mode 100644 ld/testsuite/ld-riscv-elf/overlay-max-group-number.csv create mode 100644 ld/testsuite/ld-riscv-elf/overlay-max-group-number.d create mode 100644 ld/testsuite/ld-riscv-elf/overlay-max-size-group.csv create mode 100644 ld/testsuite/ld-riscv-elf/overlay-max-size-group.d create mode 100644 ld/testsuite/ld-riscv-elf/overlay-multigroup-01.csv create mode 100644 ld/testsuite/ld-riscv-elf/overlay-multigroup-01.d create mode 100644 ld/testsuite/ld-riscv-elf/overlay-multigroup-02.csv create mode 100644 ld/testsuite/ld-riscv-elf/overlay-multigroup-02.d create mode 100644 ld/testsuite/ld-riscv-elf/overlay-no-grouping-file.d create mode 100644 ld/testsuite/ld-riscv-elf/overlay-partial-assign.csv create mode 100644 ld/testsuite/ld-riscv-elf/overlay-partial-assign.d create mode 100644 ld/testsuite/ld-riscv-elf/overlay-plt.csv create mode 100644 ld/testsuite/ld-riscv-elf/overlay-plt.d create mode 100644 ld/testsuite/ld-riscv-elf/overlay-plt.s create mode 100644 ld/testsuite/ld-riscv-elf/overlay-relax-01.d create mode 100644 ld/testsuite/ld-riscv-elf/overlay-relax-02.csv create mode 100644 ld/testsuite/ld-riscv-elf/overlay-relax-02.d create mode 100644 ld/testsuite/ld-riscv-elf/overlay-relax-multigroup.csv create mode 100644 ld/testsuite/ld-riscv-elf/overlay-relax-multigroup.d create mode 100644 ld/testsuite/ld-riscv-elf/overlay-relax.s create mode 100644 ld/testsuite/ld-riscv-elf/overlay-symbol-not-in-ovlinput.d create mode 100644 ld/testsuite/ld-riscv-elf/overlay-symbol-not-in-ovlinput.s create mode 100644 ld/testsuite/ld-riscv-elf/overlay-trivial.s create mode 100644 ld/testsuite/ld-riscv-elf/overlay.ld diff --git a/bfd/ChangeLog b/bfd/ChangeLog index d64a705abf6..a9e6546f6df 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,82 @@ +2022-02-28 Edward Jones + + * Makefile.am: Add elfxx-riscv-overlay.c and + elfxx-riscv-overlay.h to files included in the + build. + * Makefile.in: Regenerated. + * bfd-in2.h: Likewise. + * bfd.c (bfd_get_section_overlay_sort_data): Define. + * binary.c (binary_bfd_get_section_overlay_sort_data): + Likewise. + * configure: Regenerated. + * configure.ac: Add elfxx-riscv-overlay.lo to riscv + backend .o files. + * elfnn-riscv.c (struct riscv_elf_link_hash_entry): + (struct riscv_elf_link_hash_table) + (riscv_elf_hash_entry riscv_elf_hash_table is_riscv_elf) + (sec_addr): Move to elfxx-riscv.h. + (link_hash_newfunc): Initialize overlay members of + struct riscv_elf_link_hash_entry. + (riscv_elf_link_hash_table_create): Call out to + riscv_elf_overlay_link_hash_table_init to initialization + overlay data structure. + (riscv_elf_check_relocs): Add handling of overlay + relocations, call out to riscv_elf_overlay_check_relocation. + Update handling of R_RISCV_CALL. Mark symbols referred + through non-overlay relocations and error for both + overlay and non-overlay relocations to the same symbol. + (riscv_elf_check_sections): New function. + (riscv_elf_gc_mark_hook): Call out to + riscv_overlay_set_use_gcmark. + (perform_relocation): Add handling of overlay relocations. + (riscv_elf_relocate_section): Add handling of new overlay + relocations. Call out to riscv_overlay_handle_relocation. + (riscv_elf_finish_dynamic_sections): Call out to + riscv_overlay_finish_sections. + (riscv_relax_delete_bytes): Add call out to + riscv_overlay_relax_delete_bytes. + (riscv_elf_overlay_hook_elfNNlriscv) + (riscv_elf_overlay_hook_elfNNbriscv): New functions. + (bfd_elfNN_bfd_get_section_overlay_sort_data): New define. + (elf_backend_check_directives): Likewise. + * elfxx-riscv-overlay.c: New file. + * elfxx-riscv-overlay.h: Likewise. + * elfxx-riscv.c (howto_table): Add HOWTO entries for + R_RISCV_OVLTOK_HI20, R_RISCV_OVLTOK_LO12_I, + R_RISCV_OVLTOK32, R_RISCV_OVLPLT_HI20, + R_RISCV_OVLPLT_LO12_I, and R_RISCV_OVLPLT32. + (riscv_reloc_map): Add mappings for overlay + relocations. + (riscv_reloc_type_lookup): Add workaround to + correctly map from overlay relocation numbers to + howto table entries. + (riscv_elf_rtype_to_howto): Correctly map relocation + types to howto entries. + * elfxx-riscv.h (struct riscv_elf_link_hash_entry): + (struct riscv_elf_link_hash_table) + (riscv_elf_hash_entry riscv_elf_hash_table is_riscv_elf) + (sec_addr): Move definitions from elfnn-riscv.c. + * elfxx-target.h (bfd_elfNN_bfd_get_section_overlay_sort_data): + Add define. + * ihex.c (ihex_bfd_get_section_overlay_sort_data): Add define. + * libbfd-in.h (_bfd_nolink_bfd_get_section_overlay_sort_data): + Add define. + * libbfd.h: Regenerated. + * plugin.c (bfd_plugin_bfd_get_section_overlay_sort_data): + Add define. + * reloc.c: Add ENUMX entries for BFD_RELOC_RISCV_OVLTOK_HI20, + BFD_RELOC_RISCV_OVLTOK_LO12_I, BFD_RELOC_RISCV_OVLTOK32, + BFD_RELOC_RISCV_OVLPLT_HI20, BFD_RELOC_RISCV_OVLPLT_LO12_I, + and BFD_RELOC_RISCV_OVLPLT32. + * section.c (bfd_generic_get_section_overlay_sort_data): + Add function. + * srec.c (srec_bfd_get_section_overlay_sort_data): Add define. + * target.c (BFD_JUMP_TABLE_LINK): Add + _bfd_get_section_overlay_sort_data entry. + (bfd_copy_link_hash_symbol_type): Likewise. + * tekhex.c (tekhex_bfd_get_section_overlay_sort_data): + Add define. + 2022-02-17 Nick Clifton * po/sr.po: Updated Serbian translation. diff --git a/bfd/Makefile.am b/bfd/Makefile.am index 0f0138408ce..a42b87c4de7 100644 --- a/bfd/Makefile.am +++ b/bfd/Makefile.am @@ -567,6 +567,7 @@ BFD64_BACKENDS = \ elf32-riscv.lo \ elf64-riscv.lo \ elfxx-riscv.lo \ + elfxx-riscv-overlay.lo \ elf64-s390.lo \ elf64-sparc.lo \ elf64-tilegx.lo \ @@ -616,6 +617,7 @@ BFD64_BACKENDS_CFILES = \ elfxx-loongarch.c \ elfxx-mips.c \ elfxx-riscv.c \ + elfxx-riscv-overlay.c \ mach-o-aarch64.c \ mach-o-x86-64.c \ mmo.c \ @@ -701,7 +703,8 @@ SOURCE_HFILES = \ elf-bfd.h elfcode.h elfcore.h elf-hppa.h elf-linker-x86.h \ elf-linux-core.h elf-nacl.h elf-s390.h elf-vxworks.h \ elfxx-aarch64.h elfxx-ia64.h elfxx-mips.h elfxx-riscv.h \ - elfxx-sparc.h elfxx-tilegx.h elfxx-x86.h elfxx-loongarch.h \ + elfxx-riscv.overlay.h elfxx-sparc.h elfxx-tilegx.h elfxx-x86.h \ + elfxx-loongarch.h \ genlink.h go32stub.h \ libaout.h libbfd.h libcoff.h libecoff.h libhppa.h \ libpei.h libxcoff.h \ diff --git a/bfd/Makefile.in b/bfd/Makefile.in index b8e5ea0153f..00dffb8bda8 100644 --- a/bfd/Makefile.in +++ b/bfd/Makefile.in @@ -1036,6 +1036,7 @@ BFD64_BACKENDS = \ elf32-riscv.lo \ elf64-riscv.lo \ elfxx-riscv.lo \ + elfxx-riscv-overlay.lo \ elf64-s390.lo \ elf64-sparc.lo \ elf64-tilegx.lo \ @@ -1085,6 +1086,7 @@ BFD64_BACKENDS_CFILES = \ elfxx-loongarch.c \ elfxx-mips.c \ elfxx-riscv.c \ + elfxx-riscv-overlay.c \ mach-o-aarch64.c \ mach-o-x86-64.c \ mmo.c \ @@ -1166,7 +1168,8 @@ SOURCE_HFILES = \ elf-bfd.h elfcode.h elfcore.h elf-hppa.h elf-linker-x86.h \ elf-linux-core.h elf-nacl.h elf-s390.h elf-vxworks.h \ elfxx-aarch64.h elfxx-ia64.h elfxx-mips.h elfxx-riscv.h \ - elfxx-sparc.h elfxx-tilegx.h elfxx-x86.h elfxx-loongarch.h \ + elfxx-riscv.overlay.h elfxx-sparc.h elfxx-tilegx.h elfxx-x86.h \ + elfxx-loongarch.h \ genlink.h go32stub.h \ libaout.h libbfd.h libcoff.h libecoff.h libhppa.h \ libpei.h libxcoff.h \ @@ -1668,6 +1671,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-ia64.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-loongarch.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-mips.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-riscv-overlay.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-riscv.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-sparc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-tilegx.Plo@am__quote@ diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 78a0a1dea42..827cec436c5 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -1441,6 +1441,9 @@ const char *bfd_generic_group_name (bfd *, const asection *sec); bool bfd_generic_discard_group (bfd *abfd, asection *group); +int bfd_generic_get_section_overlay_sort_data + (asection *sec, struct bfd_link_info *info); + /* Extracted from archures.c. */ enum bfd_architecture { @@ -4403,6 +4406,12 @@ number for the SBIC, SBIS, SBI and CBI instructions */ BFD_RELOC_RISCV_SET16, BFD_RELOC_RISCV_SET32, BFD_RELOC_RISCV_32_PCREL, + BFD_RELOC_RISCV_OVLTOK_HI20, + BFD_RELOC_RISCV_OVLTOK_LO12_I, + BFD_RELOC_RISCV_OVLTOK32, + BFD_RELOC_RISCV_OVLPLT_HI20, + BFD_RELOC_RISCV_OVLPLT_LO12_I, + BFD_RELOC_RISCV_OVLPLT32, /* Renesas RL78 Relocations. */ BFD_RELOC_RL78_NEG8, @@ -7272,6 +7281,9 @@ extern bfd_byte *bfd_get_relocated_section_contents (bfd *, struct bfd_link_info *, struct bfd_link_order *, bfd_byte *, bool, asymbol **); +/* Hook for getting BFD specific sort data for a section. */ +#define bfd_get_section_overlay_sort_data(abfd, sec, info) \ + BFD_SEND (abfd, _bfd_get_section_overlay_sort_data, (sec, info)) bool bfd_alt_mach_code (bfd *abfd, int alternative); bfd_vma bfd_emul_get_maxpagesize (const char *); @@ -7670,7 +7682,8 @@ typedef struct bfd_target NAME##_section_already_linked, \ NAME##_bfd_define_common_symbol, \ NAME##_bfd_link_hide_symbol, \ - NAME##_bfd_define_start_stop + NAME##_bfd_define_start_stop, \ + NAME##_bfd_get_section_overlay_sort_data int (*_bfd_sizeof_headers) (bfd *, struct bfd_link_info *); bfd_byte * @@ -7749,6 +7762,10 @@ typedef struct bfd_target (*_bfd_define_start_stop) (struct bfd_link_info *, const char *, asection *); + /* Get section specific sort data. */ + int (*_bfd_get_section_overlay_sort_data) (asection *, + struct bfd_link_info *); + /* Routines to handle dynamic symbols and relocs. */ #define BFD_JUMP_TABLE_DYNAMIC(NAME) \ NAME##_get_dynamic_symtab_upper_bound, \ diff --git a/bfd/bfd.c b/bfd/bfd.c index 913ce2d6abe..c5345e63a37 100644 --- a/bfd/bfd.c +++ b/bfd/bfd.c @@ -2138,6 +2138,9 @@ DESCRIPTION . (bfd *, struct bfd_link_info *, struct bfd_link_order *, bfd_byte *, . bool, asymbol **); . +.{* Hook for getting BFD specific sort data for a section. *} +.#define bfd_get_section_overlay_sort_data(abfd, sec, info) \ +. BFD_SEND (abfd, _bfd_get_section_overlay_sort_data, (sec, info)) */ diff --git a/bfd/binary.c b/bfd/binary.c index 999d41c0611..edb1197a7f1 100644 --- a/bfd/binary.c +++ b/bfd/binary.c @@ -321,6 +321,7 @@ binary_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED, #define binary_bfd_link_split_section _bfd_generic_link_split_section #define binary_get_section_contents_in_window _bfd_generic_get_section_contents_in_window #define binary_bfd_link_check_relocs _bfd_generic_link_check_relocs +#define binary_bfd_get_section_overlay_sort_data bfd_generic_get_section_overlay_sort_data const bfd_target binary_vec = { diff --git a/bfd/configure b/bfd/configure index 4502e52decb..b0447686fbb 100755 --- a/bfd/configure +++ b/bfd/configure @@ -13532,10 +13532,10 @@ do powerpc_elf64_fbsd_le_vec) tb="$tb elf64-ppc.lo elf64-gen.lo elf64.lo $elf" target_size=64 ;; powerpc_xcoff_vec) tb="$tb coff-rs6000.lo $xcoff" ;; pru_elf32_vec) tb="$tb elf32-pru.lo elf32.lo $elf" ;; - riscv_elf32_vec) tb="$tb elf32-riscv.lo elfxx-riscv.lo elf-ifunc.lo elf32.lo $elf" ;; - riscv_elf64_vec) tb="$tb elf64-riscv.lo elf64.lo elfxx-riscv.lo elf-ifunc.lo elf32.lo $elf"; target_size=64 ;; - riscv_elf32_be_vec) tb="$tb elf32-riscv.lo elfxx-riscv.lo elf-ifunc.lo elf32.lo $elf" ;; - riscv_elf64_be_vec) tb="$tb elf64-riscv.lo elf64.lo elfxx-riscv.lo elf-ifunc.lo elf32.lo $elf"; target_size=64 ;; + riscv_elf32_vec) tb="$tb elf32-riscv.lo elfxx-riscv.lo elfxx-riscv-overlay.lo elf-ifunc.lo elf32.lo $elf" ;; + riscv_elf64_vec) tb="$tb elf64-riscv.lo elf64.lo elfxx-riscv.lo elfxx-riscv-overlay.lo elf-ifunc.lo elf32.lo $elf"; target_size=64 ;; + riscv_elf32_be_vec) tb="$tb elf32-riscv.lo elfxx-riscv.lo elfxx-riscv-overlay.lo elf-ifunc.lo elf32.lo $elf" ;; + riscv_elf64_be_vec) tb="$tb elf64-riscv.lo elf64.lo elfxx-riscv.lo elfxx-riscv-overlay.lo elf-ifunc.lo elf32.lo $elf"; target_size=64 ;; rl78_elf32_vec) tb="$tb elf32-rl78.lo elf32.lo $elf" ;; rs6000_xcoff64_vec) tb="$tb coff64-rs6000.lo aix5ppc-core.lo $xcoff"; target_size=64 ;; rs6000_xcoff64_aix_vec) tb="$tb coff64-rs6000.lo aix5ppc-core.lo $xcoff"; target_size=64 ;; diff --git a/bfd/configure.ac b/bfd/configure.ac index 07f2074770f..f1553402d7c 100644 --- a/bfd/configure.ac +++ b/bfd/configure.ac @@ -611,10 +611,10 @@ do powerpc_elf64_fbsd_le_vec) tb="$tb elf64-ppc.lo elf64-gen.lo elf64.lo $elf" target_size=64 ;; powerpc_xcoff_vec) tb="$tb coff-rs6000.lo $xcoff" ;; pru_elf32_vec) tb="$tb elf32-pru.lo elf32.lo $elf" ;; - riscv_elf32_vec) tb="$tb elf32-riscv.lo elfxx-riscv.lo elf-ifunc.lo elf32.lo $elf" ;; - riscv_elf64_vec) tb="$tb elf64-riscv.lo elf64.lo elfxx-riscv.lo elf-ifunc.lo elf32.lo $elf"; target_size=64 ;; - riscv_elf32_be_vec) tb="$tb elf32-riscv.lo elfxx-riscv.lo elf-ifunc.lo elf32.lo $elf" ;; - riscv_elf64_be_vec) tb="$tb elf64-riscv.lo elf64.lo elfxx-riscv.lo elf-ifunc.lo elf32.lo $elf"; target_size=64 ;; + riscv_elf32_vec) tb="$tb elf32-riscv.lo elfxx-riscv.lo elfxx-riscv-overlay.lo elf-ifunc.lo elf32.lo $elf" ;; + riscv_elf64_vec) tb="$tb elf64-riscv.lo elf64.lo elfxx-riscv.lo elfxx-riscv-overlay.lo elf-ifunc.lo elf32.lo $elf"; target_size=64 ;; + riscv_elf32_be_vec) tb="$tb elf32-riscv.lo elfxx-riscv.lo elfxx-riscv-overlay.lo elf-ifunc.lo elf32.lo $elf" ;; + riscv_elf64_be_vec) tb="$tb elf64-riscv.lo elf64.lo elfxx-riscv.lo elfxx-riscv-overlay.lo elf-ifunc.lo elf32.lo $elf"; target_size=64 ;; rl78_elf32_vec) tb="$tb elf32-rl78.lo elf32.lo $elf" ;; rs6000_xcoff64_vec) tb="$tb coff64-rs6000.lo aix5ppc-core.lo $xcoff"; target_size=64 ;; rs6000_xcoff64_aix_vec) tb="$tb coff64-rs6000.lo aix5ppc-core.lo $xcoff"; target_size=64 ;; diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c index 8f9f0d8a86a..f5050d00fb2 100644 --- a/bfd/elfnn-riscv.c +++ b/bfd/elfnn-riscv.c @@ -63,23 +63,6 @@ #define RISCV_ATTRIBUTES_SECTION_NAME ".riscv.attributes" -/* RISC-V ELF linker hash entry. */ - -struct riscv_elf_link_hash_entry -{ - struct elf_link_hash_entry elf; - -#define GOT_UNKNOWN 0 -#define GOT_NORMAL 1 -#define GOT_TLS_GD 2 -#define GOT_TLS_IE 4 -#define GOT_TLS_LE 8 - char tls_type; -}; - -#define riscv_elf_hash_entry(ent) \ - ((struct riscv_elf_link_hash_entry *) (ent)) - struct _bfd_riscv_elf_obj_tdata { struct elf_obj_tdata root; @@ -98,11 +81,6 @@ struct _bfd_riscv_elf_obj_tdata (*((h) != NULL ? &riscv_elf_hash_entry (h)->tls_type \ : &_bfd_riscv_elf_local_got_tls_type (abfd) [symndx])) -#define is_riscv_elf(bfd) \ - (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ - && elf_tdata (bfd) != NULL \ - && elf_object_id (bfd) == RISCV_ELF_DATA) - static bool elfNN_riscv_mkobject (bfd *abfd) { @@ -114,31 +92,6 @@ elfNN_riscv_mkobject (bfd *abfd) #include "elf/common.h" #include "elf/internal.h" -struct riscv_elf_link_hash_table -{ - struct elf_link_hash_table elf; - - /* Short-cuts to get to dynamic linker sections. */ - asection *sdyntdata; - - /* The max alignment of output sections. */ - bfd_vma max_alignment; - - /* Used by local STT_GNU_IFUNC symbols. */ - htab_t loc_hash_table; - void * loc_hash_memory; - - /* The index of the last unused .rel.iplt slot. */ - bfd_vma last_iplt_index; - - /* The data segment phase, don't relax the section - when it is exp_seg_relro_adjust. */ - int *data_segment_phase; - - /* Relocations for variant CC symbols may be present. */ - int variant_cc; -}; - /* Instruction access functions. */ #define riscv_get_insn(bits, ptr) \ ((bits) == 16 ? bfd_getl16 (ptr) \ @@ -151,12 +104,6 @@ struct riscv_elf_link_hash_table : (bits) == 64 ? bfd_putl64 (val, ptr) \ : (abort (), (void) 0)) -/* Get the RISC-V ELF linker hash table from a link_info structure. */ -#define riscv_elf_hash_table(p) \ - ((is_elf_hash_table ((p)->hash) \ - && elf_hash_table_id (elf_hash_table (p)) == RISCV_ELF_DATA) \ - ? (struct riscv_elf_link_hash_table *) (p)->hash : NULL) - static bool riscv_info_to_howto_rela (bfd *abfd, arelent *cache_ptr, @@ -201,8 +148,6 @@ riscv_is_insn_reloc (const reloc_howto_type *howto) entry used for runtime profile? */ #define GOTPLT_HEADER_SIZE (2 * GOT_ENTRY_SIZE) -#define sec_addr(sec) ((sec)->output_section->vma + (sec)->output_offset) - #if ARCH_SIZE == 32 # define MATCH_LREG MATCH_LW #else @@ -299,6 +244,10 @@ link_hash_newfunc (struct bfd_hash_entry *entry, eh = (struct riscv_elf_link_hash_entry *) entry; eh->tls_type = GOT_UNKNOWN; + eh->ovl.needs_ovlplt_entry = false; + eh->ovl.needs_overlay_group = false; + eh->ovl.non_overlay_reference = false; + eh->ovl.overlay_groups_resolved = false; } return entry; @@ -419,6 +368,9 @@ riscv_elf_link_hash_table_create (bfd *abfd) } ret->elf.root.hash_table_free = riscv_elf_link_hash_table_free; + if (!riscv_elf_overlay_link_hash_table_init (&ret->ovl)) + return NULL; + return &ret->elf.root; } @@ -725,6 +677,25 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, switch (r_type) { + case R_RISCV_OVLTOK_HI20: + case R_RISCV_OVLTOK_LO12_I: + case R_RISCV_OVLTOK32: + case R_RISCV_OVLPLT_HI20: + case R_RISCV_OVLPLT_LO12_I: + case R_RISCV_OVLPLT32: + { + struct riscv_elf_link_hash_entry *eh = NULL; + struct riscv_elf_link_hash_entry_overlay *ovl = NULL; + eh = (struct riscv_elf_link_hash_entry *) h; + if (eh) + ovl = &eh->ovl; + if (!riscv_elf_overlay_check_relocation (htab->elf.dynobj, + info, ovl, &htab->ovl, + r_type)) + return false; + } + break; + case R_RISCV_TLS_GD_HI20: if (!riscv_elf_record_got_reference (abfd, info, h, r_symndx) || !riscv_elf_record_tls_type (abfd, h, r_symndx, GOT_TLS_GD)) @@ -746,6 +717,15 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, break; case R_RISCV_CALL: + if (h != NULL) + { + /* Note this symbol as a non-overlay function. */ + struct riscv_elf_link_hash_entry *eh = + (struct riscv_elf_link_hash_entry *)h; + eh->ovl.non_overlay_reference = true; + } + /* fallthrough */ + case R_RISCV_CALL_PLT: /* These symbol requires a procedure linkage table entry. We actually build the entry in adjust_dynamic_symbol, @@ -773,6 +753,11 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, so we always need the plt when it refers to ifunc symbol. */ h->plt.refcount += 1; + + /* Note this symbol as a non-overlay function. */ + struct riscv_elf_link_hash_entry *eh = + (struct riscv_elf_link_hash_entry *)h; + eh->ovl.non_overlay_reference = true; } /* Fall through. */ @@ -945,11 +930,45 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, default: break; } + + if (h) + { + struct riscv_elf_link_hash_entry *eh = + (struct riscv_elf_link_hash_entry *)h; + if (eh->ovl.needs_overlay_group && eh->ovl.non_overlay_reference) + { + (*_bfd_error_handler) (_("%pB: Symbol '%s` referred to by both " + "overlay and non-overlay relocations"), + abfd, h->root.root.string); + return false; + } + } } return true; } +/* Look at all sections in abfd and enable overlay support if any contains + overlay references. */ + +static bool +riscv_elf_check_sections (bfd *abfd, struct bfd_link_info *info) +{ + struct riscv_elf_link_hash_table *htab; + + if (bfd_link_relocatable (info)) + return true; + + htab = riscv_elf_hash_table (info); + + if (htab->elf.dynobj == NULL) + htab->elf.dynobj = abfd; + + riscv_elf_overlay_check_sections (abfd, info, &htab->ovl); + + return true; +} + static asection * riscv_elf_gc_mark_hook (asection *sec, struct bfd_link_info *info, @@ -957,6 +976,11 @@ riscv_elf_gc_mark_hook (asection *sec, struct elf_link_hash_entry *h, Elf_Internal_Sym *sym) { + /* Note that gc-sections has been used, allowing some overlay table + generation to be skipped for dead functions (i.e sec->gc_mark is + reliable). */ + riscv_overlay_set_use_gcmark (); + if (h != NULL) switch (ELFNN_R_TYPE (rel->r_info)) { @@ -1638,6 +1662,8 @@ perform_relocation (const reloc_howto_type *howto, case R_RISCV_GOT_HI20: case R_RISCV_TLS_GOT_HI20: case R_RISCV_TLS_GD_HI20: + case R_RISCV_OVLTOK_HI20: + case R_RISCV_OVLPLT_HI20: if (ARCH_SIZE > 32 && !VALID_UTYPE_IMM (RISCV_CONST_HIGH_PART (value))) return bfd_reloc_overflow; value = ENCODE_UTYPE_IMM (RISCV_CONST_HIGH_PART (value)); @@ -1648,6 +1674,8 @@ perform_relocation (const reloc_howto_type *howto, case R_RISCV_TPREL_LO12_I: case R_RISCV_TPREL_I: case R_RISCV_PCREL_LO12_I: + case R_RISCV_OVLTOK_LO12_I: + case R_RISCV_OVLPLT_LO12_I: value = ENCODE_ITYPE_IMM (value); break; @@ -1727,6 +1755,8 @@ perform_relocation (const reloc_howto_type *howto, case R_RISCV_32_PCREL: case R_RISCV_TLS_DTPREL32: case R_RISCV_TLS_DTPREL64: + case R_RISCV_OVLTOK32: + case R_RISCV_OVLPLT32: break; case R_RISCV_DELETE: @@ -2771,6 +2801,18 @@ riscv_elf_relocate_section (bfd *output_bfd, unresolved_reloc = false; break; + case R_RISCV_OVLTOK_HI20: + case R_RISCV_OVLTOK_LO12_I: + case R_RISCV_OVLTOK32: + case R_RISCV_OVLPLT_HI20: + case R_RISCV_OVLPLT_LO12_I: + case R_RISCV_OVLPLT32: + if (riscv_overlay_handle_relocation (&relocation, output_bfd, + info, h, &htab->ovl, sym, + r_type)) + unresolved_reloc = false; + break; + default: r = bfd_reloc_notsupported; } @@ -3259,6 +3301,10 @@ riscv_elf_finish_dynamic_sections (bfd *output_bfd, } } + if (htab->ovl.overlay_enabled + && !riscv_overlay_finish_sections (&htab->elf, &htab->ovl, info)) + return false; + if (htab->elf.sgotplt) { asection *output_section = htab->elf.sgotplt->output_section; @@ -4074,6 +4120,7 @@ riscv_relax_delete_bytes (bfd *abfd, /* Actually delete the bytes. */ sec->size -= count; + riscv_overlay_relax_delete_bytes (sec, count, link_info); memmove (contents + addr, contents + addr + count, toaddr - addr - count); /* Adjust the location of all of the relocs. Note that we need not @@ -5238,6 +5285,50 @@ riscv_elf_merge_symbol_attribute (struct elf_link_hash_entry *h, h->other |= STO_RISCV_VARIANT_CC; } +void +riscv_elf_overlay_hook_elfNNlriscv(struct bfd_link_info *info); +void +riscv_elf_overlay_hook_elfNNbriscv(struct bfd_link_info *info); + +/* Prepare overlay data structures. + + This function is called by the LDEMUL_AFTER_CHECK_RELOCS hook. */ + +void +riscv_elf_overlay_hook_elfNNlriscv(struct bfd_link_info *info) +{ + bool ret; + struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info); + BFD_ASSERT (htab != NULL); + + if (!htab->ovl.overlay_enabled || htab->elf.dynobj == NULL) + return; + + const struct elf_backend_data *bed = get_elf_backend_data (htab->elf.dynobj); + + ret = riscv_elf_overlay_generate_tables (info->output_bfd, info, + sizeof(ElfNN_External_Sym)); + if (!ret) + return; + + riscv_elf_overlay_create_ovlgrps (&htab->elf, &htab->ovl, bed, info); + riscv_elf_overlay_duplicate_multigroup_sections (&htab->elf, &htab->ovl, + bed, info, + sizeof(ElfNN_External_Sym)); + riscv_elf_overlay_pad_groups (&htab->elf, &htab->ovl, bed, info); +} + +/* Overlays are not supported for big-endian but this hook is needed to be able + to build the tools. It just outputs an error. */ + +void +riscv_elf_overlay_hook_elfNNbriscv(struct bfd_link_info *info) +{ + info->callbacks->einfo (_("%F%P: overlays are not yet supported for " + "big-endian RISC-V"), + info->output_bfd); +} + #define TARGET_LITTLE_SYM riscv_elfNN_vec #define TARGET_LITTLE_NAME "elfNN-littleriscv" #define TARGET_BIG_SYM riscv_elfNN_be_vec @@ -5251,10 +5342,13 @@ riscv_elf_merge_symbol_attribute (struct elf_link_hash_entry *h, #define bfd_elfNN_bfd_merge_private_bfd_data \ _bfd_riscv_elf_merge_private_bfd_data #define bfd_elfNN_bfd_is_target_special_symbol riscv_elf_is_target_special_symbol +#define bfd_elfNN_bfd_get_section_overlay_sort_data \ + riscv_elf_overlay_sort_value #define elf_backend_copy_indirect_symbol riscv_elf_copy_indirect_symbol #define elf_backend_create_dynamic_sections riscv_elf_create_dynamic_sections #define elf_backend_check_relocs riscv_elf_check_relocs +#define elf_backend_check_directives riscv_elf_check_sections #define elf_backend_adjust_dynamic_symbol riscv_elf_adjust_dynamic_symbol #define elf_backend_size_dynamic_sections riscv_elf_size_dynamic_sections #define elf_backend_relocate_section riscv_elf_relocate_section diff --git a/bfd/elfxx-riscv-overlay.c b/bfd/elfxx-riscv-overlay.c new file mode 100644 index 00000000000..575841505d1 --- /dev/null +++ b/bfd/elfxx-riscv-overlay.c @@ -0,0 +1,2563 @@ +/* RISC-V overlay support for ELF. + Copyright (C) 2022 Free Software Foundation, Inc. + + Contributed by Edward Jones (ed.jones@embecosm.com). + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING3. If not, + see . */ + +/* The RISC-V overlay system allows functions and data to exist in + one or more overlay groups which are swapped in and out of active + memory on demand by the runtime engine. This file contains the + hooks into BFD to achieve this behaviour. + + All symbols which exist in an overlay eventually end up in a + specially formatted output section called `.ovlgrps'. This + output section contains both the loadable contents of each overlay + group and the metadata tables required by the runtime engine. + + The `.ovlgrps' output section is itself built from the + user-provided sections with the prefix `.ovlinput.', and a + number of internal sections generated by the linker with the + prefix `.ovlinput.__internal.'. These linker-generated sections + are as follows: + + - `.ovlinput.__internal.grouptables' + + Section containing the contents of the group table and the + multigroup table. This section occupies the first group + (group 0) in `.ovlgrps'. + + - `.ovlinput.__internal.padding.' + + A special padding section which is placed after the last + `.ovlinput.' section assigned to `'. This + pads the group size up to the next OVL_GROUP_PAGE_SIZE. + This section is filled with the 16-bit group number as + padding, and the final 32-bits contains a CRC of the + group contents. + + - `.ovlinput.__internal.duplicate..' + + When a symbol exists in multiple overlay group the contents + need to be duplicated into each output group. The + duplicate sections fulfill this role. Note that the + original symbol and its debug information is always associated + with the first group it is assigned to. + + In addition to the above input sections there is also a + '.ovlplt` section, and unlike the other linker generated sections + this section is always held in resident memory. The '.ovlplt` + section is used to hold stub functions which materialize an + overlay token value and jump into the overlay engine. The + address of the stub function can then be used in a normal + indirect call sequence. The '.ovlplt` entries are generated + for symbols referred to by the 'R_RISCV_OVLPLT_LO12_I`, + 'R_RISCV_OVLPLT_HI20` and `R_RISCV_OVLPLT32' relocations. + + When the linker maps the '.ovlinput` groups into '.ovlgrps`, + it does a custom sort which lays them out in the correct order. + This ordering is as follows: + + - '.ovlinput.__internal.grouptables` + - '.ovlinput.__internal.padding.0` + - for group 1 to N: + for each symbol in group: + '.ovlinput.` + or '.ovlinput.__internal.duplicate..` + '.ovlinput.__internal.padding.` + + Essentially all of the sections which make up the contents of a + given overlay group are then followed by the padding section which + contains the padding, crc, and rounds the size up to the next + page boundary. + + The group and offset of each '.ovlinput.` section is + tracked, and this is used to populate the group table in + '.ovlinput.__internal.grouptables` and also when materializing the + token values to fill in 'R_RISCV_OVLTOK_LO12_I`, + 'R_RISCV_OVLTOK_HI20` and 'R_RISCV_OVLTOK32` relocations. + + Symbols which are assigned to multiple groups also generate + entries in the multigroup table in '.ovlinput.__internal.grouptables`, + and affect the token values which are materialized - the tokens + refer into the multigroup table instead of the grouping table. + + To achieve all of the above, the following order of operations + takes place: + + # riscv_elf_overlay_check_relocation + + - Mark symbols as requiring a group assignment if they + are referred to by overlay relocations. + - Creates and allocates space in '.ovlplt` for any overlay + 'plt` references to a symbol. + + # riscv_elf_overlay_generate_tables + + - Initialize internal data structures to track group + assignments. + - Populate data structures with symbols that require + an assignment. + - Assign groups using an external tool, a provided + '.csv` grouping file, or automatically. + + # riscv_elf_overlay_create_ovlgrps + + - Create the '.ovlinput.__internal.grouptables` section. + + # riscv_elf_overlay_duplicate_multigroup_sections + + - Generate '.ovlinput.__internal.duplicate..` + sections for any symbol assigned to multiple groups. + + # riscv_elf_overlay_pad_groups + + - Generate the padding section for each group. + + # riscv_elf_overlay_sort_value + + - Correctly lay out the user provided and linker generated + input sections assigned to '.ovlgrps` + + # riscv_overlay_relax_delete_bytes + + - Resize the padding section for a group when any of the + input sections are resized due to relaxation. Ensures + the group ends on an overlay page boundary. + - Resize any overlay duplicate sections for the same + symbol to match. + + # riscv_overlay_handle_relocation + + - Materialize token values and use them to fill in overlay + relocations. + + # riscv_overlay_finish_sections + + - Fill in the '.ovlplt` entries and the grouping table and + multigroup table in '.ovlinput.__internal.grouptables`. + - Duplicate the contents for multigroup symbols in '.ovlgrps` + to all of their assigned groups. + - Emit the padding and crc at the end of each group. +*/ + +#include "sysdep.h" +#include "bfd.h" +#include "libbfd.h" +#include "elf-bfd.h" +#include "elf/riscv.h" +#include "opcode/riscv.h" +#include "libiberty.h" +#include "elfxx-riscv.h" +#include "elfxx-riscv-overlay.h" +#include "safe-ctype.h" +#include "objalloc.h" + +/* Byte size of the crc at the end of an overlay group. */ +#define OVL_CRC_SZ 4 + +/* Size in bytes of a 'page' of an overlay group. Overlay groups are always a + multiple of the page size. */ +#define OVL_GROUP_PAGE_SIZE_POW2 9 +#define OVL_GROUP_PAGE_SIZE (1 << OVL_GROUP_PAGE_SIZE_POW2) + +/* Maximum size in bytes of an overlay group. This will be a multiple of + the page size. */ +#define OVL_MAX_GROUP_SIZE 4096 + +/* The maximum group number that a symbol can be assigned to. */ +#define OVL_MAX_GROUP_ID 65535 + +/* Alignment in bytes of symbols within an overlay group. */ +#define OVL_SYM_ALIGN 4 + +/* The default first group to which overlay symbols can be allocated to. + Group number 0 is always reserved to store the group table and multigroup + tables themselves. */ +#define OVL_DEFAULT_FIRST_FREE_GROUP 1 + +/* Size in bytes of a multigroup entry. */ +#define OVL_MULTIGROUP_ENTRY_SIZE 4 + +/* Number of (32-bit) instructions in an overlay PLT table entry. */ +#define OVLPLT_ENTRY_INSNS 3 + +/* Size in bytes of an entry in the overlay plt table. */ +#define OVLPLT_ENTRY_SIZE OVLPLT_ENTRY_INSNS * 4 + +/* Prefixes for internal section names used for overlays. */ +#define OVL_INPUT_SEC_PREFIX ".ovlinput." +#define OVL_INTERNAL_SEC_PREFIX OVL_INPUT_SEC_PREFIX "__internal." +#define OVL_DUPLICATE_SEC_PREFIX OVL_INTERNAL_SEC_PREFIX "duplicate." +#define OVL_PADDING_SEC_PREFIX OVL_INTERNAL_SEC_PREFIX "padding." +#define OVL_GROUPTABLES_SEC_NAME OVL_INTERNAL_SEC_PREFIX "grouptables" + + +/* An entry in the list of overlay group. This tracks the information + about each group needed to layout functions in their groups, + build the sections and populate the contents. */ + +struct ovl_group_list_entry +{ + /* A group is not initialized until it is known that it will have some + contents. This happens when either the first function is assigned + to the group, or group 0 (which holds the group table) needs to be + populated. */ + bool is_initialized; + + /* A list of the names of functions assigned to this group. The order + in this list defines the order they will be laid out in memory. */ + int n_functions; + const char **functions; + + /* Size of the contents of the group. This corresponds to the size of + all of the assigned functions and any padding in between them. */ + + /* Size of the groups contents, size of it when padded, and the offset + to the start of the group in the .ovlgrps output section. */ + bfd_vma group_size; + + /* Size of the group after it has been padded up to the page size. This + is *not* the same as 'group_size' rounded up to the next page size + as 'group_size' does not account for the size of the CRC. + + This value will be 0 until after the 'group_size' has been settled. */ + bfd_vma padded_group_size; + + /* Offset of the contents of this group in the .ovlgrps output section. */ + bfd_vma ovlgrpdata_offset; + + /* The calculated CRC for this group. These bytes are written at the + end of the padding, bringing the group up to the 'padded_group_size' */ + unsigned int crc; + + /* Symbols names for the first and last functions allocated to this + group. */ + const char *first_func; + const char *last_func; +}; + +/* Hash entry storing the groups to which a function belongs. */ + +struct ovl_func_hash_entry +{ + struct bfd_hash_entry root; + + /* Linked list of the overlay groups which hold the current function. */ + struct ovl_func_group_info *groups; + + /* Tail of the linked list of overlay groups for this function. */ + struct ovl_func_group_info *tail; + + /* True if this function exists in more than one overlay group. */ + bool multigroup; + + /* Offset of the entry for this function in the multigroup table. */ + bfd_vma multigroup_offset; + + /* Token value to refer to the multigroup entry for this function. */ + bfd_vma multigroup_token; + + /* Tracks whether an overlay PLT entry is required for this function. */ + bool plt_entry; + + /* Offset of an overlay PLT entry if required for this function. */ + bfd_vma plt_offset; +}; + +/* A flag noting whether the gc mark and sweep pass has run, and therefore can + reliably determine which functions should be treated as deleted. */ +static bool overlay_use_gcmark = 0; + +/* Mark that the gc mark and sweep has run. */ +void +riscv_overlay_set_use_gcmark (void) +{ + overlay_use_gcmark = 1; +} + +static struct +bfd_hash_entry *ovl_func_hash_newfunc (struct bfd_hash_entry *entry, + struct bfd_hash_table *table, + const char *string); + +/* Create a new overlay grouping hash table. */ + +static bool +ovl_func_hash_table_init (struct bfd_hash_table *table) +{ + return bfd_hash_table_init (table, ovl_func_hash_newfunc, + sizeof (struct ovl_func_hash_entry)); +} + +static void +ovl_group_list_init (struct ovl_group_list *list) +{ + BFD_ASSERT (list != NULL); + list->n_groups = 0; + + /* Allocate space for a single group even though there are none needed yet. + This means bfd_realloc can be used unconditionally when new groups are + added. */ + list->groups = bfd_zmalloc (sizeof (*list->groups)); +} + +/* Store grouping info in a hash table. */ + +static bool +create_ovl_group_table (struct bfd_hash_table *ovl_func_table, + struct ovl_group_list *ovl_group_list, + bool * ovl_tables_populated) +{ + *ovl_tables_populated = false; + + if (!ovl_func_hash_table_init (ovl_func_table)) + return false; + + ovl_group_list_init (ovl_group_list); + return true; +} + +/* Print functions for debugging. */ + +static void print_group_list (struct ovl_group_list *list); +static void print_func_table (struct bfd_hash_table *table); + +bool +riscv_elf_overlay_link_hash_table_init ( + struct riscv_elf_overlay_link_hash_table *ovl) +{ + ovl->sovlplt = NULL; + ovl->next_ovlplt_offset = 0; + ovl->ovl_group_table_size = 0; + ovl->ovl_group_table_max_group = 0; + ovl->ovl_multigroup_table_size = 0; + + if (!create_ovl_group_table (&ovl->ovl_func_table, &ovl->ovl_group_list, + &ovl->ovl_tables_populated)) + return false; + + if (riscv_overlay_debug) + { + print_group_list (&ovl->ovl_group_list); + print_func_table (&ovl->ovl_func_table); + } + return true; +} + +/* Highest group number seen so far. */ +static unsigned ovl_max_group = 0; + +/* Linked list of overlay group ids. + NOTE: Offset will not change with relaxation, so this value MUST NOT be + relied upon for token generation, use the output_offset instead. + NOTE: processed_offset is used for mapfile generation and is calculated + during the final link stage. */ + +struct ovl_func_group_info +{ + bfd_vma id; + bfd_vma unrelaxed_offset; + bfd_vma processed_offset; + struct ovl_func_group_info *next; +}; + +static struct ovl_group_list_entry * +ovl_group_list_newfunc (struct ovl_group_list *list, int group) +{ + BFD_ASSERT (list != NULL); + BFD_ASSERT (list->groups != NULL); + + if (group >= list->n_groups) + { + list->groups = bfd_realloc (list->groups, + sizeof (*list->groups) * (group + 1)); + for (; list->n_groups < (group + 1); list->n_groups++) + list->groups[list->n_groups].is_initialized = false; + } + else + BFD_ASSERT (!list->groups[group].is_initialized); + + struct ovl_group_list_entry *ret = &list->groups[group]; + + ret->n_functions = 0; + ret->functions = NULL; + ret->group_size = 0; + ret->padded_group_size = 0; + ret->ovlgrpdata_offset = 0; + ret->first_func = NULL; + ret->last_func = NULL; + + ret->is_initialized = true; + return ret; +} + +/* Retrieve or create a new entry in the overlay group list. */ +static struct ovl_group_list_entry * +ovl_group_list_lookup (struct ovl_group_list *ovl_group_list, + int group, bool create) +{ + BFD_ASSERT (ovl_group_list); + BFD_ASSERT (ovl_group_list->groups); + + if (group >= ovl_group_list->n_groups) + { + if (create) + return ovl_group_list_newfunc (ovl_group_list, group); + else + return NULL; + } + else + { + if (ovl_group_list->groups[group].is_initialized) + return &ovl_group_list->groups[group]; + else if (create) + return ovl_group_list_newfunc (ovl_group_list, group); + else + return NULL; + } +} + +static bool +ovl_group_list_traverse (struct ovl_group_list *ovl_group_list, + bool (*func) (struct ovl_group_list_entry *, + int, void *), void *info) +{ + bool ret = true; + for (int i = 0; i < ovl_group_list->n_groups; i++) + { + struct ovl_group_list_entry *entry = &ovl_group_list->groups[i]; + if (entry->is_initialized) + ret = func (entry, i, info); + if (ret == false) + break; + } + return ret; +} + +static void +ovl_update_group (struct ovl_group_list *list, int group_id, const char *func) +{ + struct ovl_group_list_entry *group_entry; + + /* Update the entry in the group list. */ + group_entry = ovl_group_list_lookup (list, group_id, true); + BFD_ASSERT (group_entry != NULL); + + int n_functions = group_entry->n_functions + 1; + if (group_entry->functions == NULL) + { + group_entry->functions = + bfd_malloc (n_functions * sizeof (*group_entry->functions)); + } + else + { + group_entry->functions = + bfd_realloc (group_entry->functions, + n_functions * sizeof (*group_entry->functions)); + } + /* Take a copy of the function name. */ + char *func_name = bfd_malloc (strlen (func) + 1); + strcpy (func_name, func); + + group_entry->functions[group_entry->n_functions] = func_name; + group_entry->n_functions = n_functions; +} + +/* Create a new entry in an overlay grouping hash_table. */ +static struct bfd_hash_entry * +ovl_func_hash_newfunc (struct bfd_hash_entry *entry, + struct bfd_hash_table *table, const char *string) +{ + struct ovl_func_hash_entry *ret = (struct ovl_func_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + derived class. */ + if (ret == NULL) + { + ret = bfd_hash_allocate (table, sizeof (*ret)); + if (ret == NULL) + return NULL; + } + + /* Call the allocation method of the base class. */ + ret = ((struct ovl_func_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + + /* Initialize local fields. */ + ret->groups = NULL; + ret->tail = NULL; + ret->multigroup = false; + ret->multigroup_offset = 0; + + return (struct bfd_hash_entry *) ret; +} + +/* Look up an entry in an overlay grouping hash table. */ + +#define ovl_func_hash_lookup(table, string, create, copy) \ + ((struct ovl_func_hash_entry *) \ + bfd_hash_lookup (table, (string), (create), (copy))) + +/* Traverse an overlay group hash table. */ + +#define ovl_func_hash_traverse(table, func, info) \ + (bfd_hash_traverse \ + (table, \ + (bool (*) (struct bfd_hash_entry *, void *)) (func), \ + (info))) + +static void +ovl_update_func (struct bfd_hash_table *table, const char *func, + bfd_vma group) +{ + struct ovl_func_hash_entry *entry; + struct ovl_func_group_info *this_node; + + entry = ovl_func_hash_lookup (table, func, true, true); + BFD_ASSERT (entry != NULL); + + this_node = objalloc_alloc ((struct objalloc *) table->memory, + sizeof (struct ovl_func_group_info)); + this_node->id = group; + this_node->unrelaxed_offset = 0; + this_node->processed_offset = 0; + this_node->next = NULL; + + if (entry->groups == NULL) + entry->groups = this_node; + else + { + entry->tail->next = this_node; + entry->multigroup = true; + entry->multigroup_offset = 0; + } + entry->tail = this_node; +} + +/* Run through abfd and return the asection for the group with the + provided id. */ + +static asection * +get_ovl_input_section (bfd * abfd, const char *sym_name) +{ + ssize_t sec_len; + char *sec_name; + asection *sec; + + sec_len = strlen (OVL_INPUT_SEC_PREFIX) + strlen (sym_name) + 1; + sec_name = bfd_zmalloc (sec_len); + snprintf (sec_name, sec_len, OVL_INPUT_SEC_PREFIX "%s", sym_name); + + sec = bfd_get_section_by_name (abfd, sec_name); + free (sec_name); + return sec; +} + +/* Run through abfd and return the asection for the duplicate overlay group + for the provided group id and symbol name. */ + +static asection * +get_ovl_duplicate_section (bfd * abfd, bfd_vma group_id, const char *sym_name) +{ + ssize_t sec_len; + char *sec_name; + asection *sec; + + sec_len = strlen (OVL_DUPLICATE_SEC_PREFIX) + /*group_id */ 10 + 1 + + strlen (sym_name) + 1; + sec_name = bfd_zmalloc (sec_len); + snprintf (sec_name, sec_len, + OVL_DUPLICATE_SEC_PREFIX "%" BFD_VMA_FMT "u.%s", group_id, + sym_name); + + sec = bfd_get_section_by_name (abfd, sec_name); + free (sec_name); + return sec; +} + +/* Run through abfd and return the internal padding section associated with + the provided group id. */ + +static asection * +get_ovl_padding_section (bfd * abfd, bfd_vma group_id) +{ + ssize_t sec_len; + char *sec_name; + asection *sec; + + sec_len = strlen (OVL_PADDING_SEC_PREFIX) + /*group_id */ 10 + 1; + sec_name = bfd_zmalloc (sec_len); + snprintf (sec_name, sec_len, OVL_PADDING_SEC_PREFIX "%" BFD_VMA_FMT "u", + group_id); + + sec = bfd_get_section_by_name (abfd, sec_name); + free (sec_name); + return sec; +} + +/* Create a new section for a duplicate overlay group and attach it to the + end of the chain of sections for abfd. */ + +static asection * +make_ovl_duplicate_section (bfd * abfd, bfd_vma group_id, + const char *sym_name, flagword flags) +{ + ssize_t sec_len; + char *sec_name; + + sec_len = strlen (OVL_DUPLICATE_SEC_PREFIX) + /*group_id */ 10 + 1 + + strlen (sym_name) + 1; + sec_name = bfd_alloc (abfd, sec_len); + snprintf (sec_name, sec_len, + OVL_DUPLICATE_SEC_PREFIX "%" BFD_VMA_FMT "u.%s", group_id, + sym_name); + + return bfd_make_section_anyway_with_flags (abfd, sec_name, flags); +} + +/* Create a new section for padding for an overlay group and attach it to the + end of the chain of sections for abfd. */ + +static asection * +make_ovl_padding_section (bfd * abfd, bfd_vma group_id, flagword flags) +{ + ssize_t sec_len; + char *sec_name; + + sec_len = strlen (OVL_PADDING_SEC_PREFIX) + /*group_id */ 10 + 1; + sec_name = bfd_alloc (abfd, sec_len); + snprintf (sec_name, sec_len, OVL_PADDING_SEC_PREFIX "%" BFD_VMA_FMT "u", + group_id); + + return bfd_make_section_anyway_with_flags (abfd, sec_name, flags); +} + +/* For a function in the overlay grouping file, return whether this is a valid + function, or whether it should be skipped (either because it doesn't exist, + or GC sections has removed it.) If a function is being ignored, REASON is + updated to provide a reason why. */ + +static bool +ovl_enable_grouping_for_func (const char *func, struct bfd_link_info *info, + char **reason) +{ + bfd *ibfd; + + if (func == NULL) + return false; + + /* Search for a section for this symbol, and check whether the function + has been deleted. */ + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) + { + if (!is_riscv_elf (ibfd)) + continue; + + asection *sec = get_ovl_input_section (ibfd, func); + if (sec) + { + /* If GC sections not in use, return true to indicate found. */ + if (!overlay_use_gcmark) + return true; + /* Otherwise return the GC Mark value */ + if (sec->gc_mark == 1) + return true; + *reason = "section removed by gc-sections"; + return false; + } + } + + /* The function was not found, return false to not create its entry. */ + *reason = "section not found"; + return false; +} + +/* Generate an overlay PLT entry. */ + +static bool +make_ovlplt_entry (bfd_vma addr, uint32_t * entry) +{ + /* lui x30, %hi(.ovlplt entry) + addi x30, x30, %lo(.ovlplt entry) + jalr zero, x31, 0 */ + entry[0] = RISCV_UTYPE (LUI, X_T5, RISCV_CONST_HIGH_PART (addr)); + entry[1] = RISCV_ITYPE (ADDI, X_T5, X_T5, RISCV_CONST_LOW_PART (addr)); + entry[2] = RISCV_ITYPE (JALR, X_ZERO, X_T6, 0); + + return true; +} + +/* Fill in all of the overlay PLT entries in turn, based on the token value at + the start of each entry. */ + +static bool +fill_ovlplt_sections (bfd * output_bfd, + struct riscv_elf_overlay_link_hash_table *ovl) +{ + if (ovl->sovlplt) + { + bfd_vma off, i, token; + uint32_t ovlplt_entry[OVLPLT_ENTRY_INSNS]; + + for (off = 0; off < ovl->next_ovlplt_offset; off += OVLPLT_ENTRY_SIZE) + { + token = bfd_get_32 (output_bfd, ovl->sovlplt->contents + off); + if (!make_ovlplt_entry (token, ovlplt_entry)) + return false; + + for (i = 0; i < OVLPLT_ENTRY_INSNS; i++) + bfd_put_32 (output_bfd, ovlplt_entry[i], + ovl->sovlplt->contents + off + 4 * i); + } + } + + return true; +} + +/* Fill in all the .ovlgrptbl table entries. */ +static bool +fill_ovlgrptbl (struct elf_link_hash_table *elf, + struct riscv_elf_overlay_link_hash_table *ovl) +{ + asection *group_table_sec = + bfd_get_section_by_name (elf->dynobj, OVL_GROUPTABLES_SEC_NAME); + + bfd_vma offset = 0; + unsigned group = 0; + unsigned max_group = ovl->ovl_group_table_max_group; + for (group = 0; group <= (max_group + 1); group++) + { + /* Store current offset. */ + uint16_t offset_stored = offset / OVL_GROUP_PAGE_SIZE; + bfd_put_16 (elf->dynobj, offset_stored, + group_table_sec->contents + group * 2); + + struct ovl_group_list_entry *group_list_entry = + ovl_group_list_lookup (&ovl->ovl_group_list, group, false); + if (group_list_entry) + offset += group_list_entry->padded_group_size; + } + /* The last entry in the .ovlgrptbl is a null terminator. */ + bfd_put_16 (elf->dynobj, 0, + group_table_sec->contents + ((max_group + 2) * 2)); + /* There might also be some space after .ovlgrptbl to bring the + subsequent multigroup table into alignment. Fill that with nulls + too. */ + unsigned i; + for (i = (max_group + 3) * 2; i < ovl->ovl_group_table_size; i++) + bfd_put_8 (elf->dynobj, 0, group_table_sec->contents + i); + + return true; +} + +/* Build a version of the current ovl section based on what is currently loaded. */ + +static bool +build_current_ovl_section (struct bfd_link_info *info, void **data) +{ + bfd *output_bfd = info->output_bfd; + asection *sec = bfd_get_section_by_name (output_bfd, ".ovlgrps"); + BFD_ASSERT (sec != NULL); + + /* Nasty hack: When the .ovlgrps output section is created it + is created with its flags initialized to the same flags as the + last constituent input section. Because the last input section + is a dynamic section, the output section erroneously picks up the + SEC_IN_MEMORY flag which causes bfd_get_section_contents to + fail when it tries to read from the "contents" of .ovlgrps. */ + sec->flags &= ~SEC_IN_MEMORY; + + void *section_data = bfd_malloc (sec->size); + BFD_ASSERT (section_data != NULL); + *data = section_data; + /* Start by loading the entire contents of this section, this will cover non + dynamic sections. */ + bool res = + bfd_get_section_contents (output_bfd, sec, section_data, 0, sec->size); + BFD_ASSERT (res == true); + + /* Look at all the input sections, if the output section matches this, then + load the contents into that section. */ + bfd *ibfd; + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) + { + asection *isec; + for (isec = ibfd->sections; isec != NULL; isec = isec->next) + { + if (isec->contents != NULL && isec->output_section == sec) + memcpy (section_data + isec->output_offset, isec->contents, + isec->size); + } + } + + return true; +} + +/* Fill in duplicates for multigroup overlay sections. */ +static bool +fill_multigrp_duplicates (struct elf_link_hash_table *elf, + struct riscv_elf_overlay_link_hash_table *ovl, + struct bfd_link_info *info) +{ + bfd *ibfd; + unsigned char *current_data; + build_current_ovl_section (info, (void *) ¤t_data); + BFD_ASSERT (current_data != NULL); + + bfd *output_bfd = info->output_bfd; + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) + { + asection *isec; + for (isec = ibfd->sections; isec != NULL; isec = isec->next) + { + if (!strncmp (isec->name, OVL_INPUT_SEC_PREFIX, + strlen (OVL_INPUT_SEC_PREFIX))) + { + struct ovl_func_hash_entry *sym_groups = + ovl_func_hash_lookup (&ovl->ovl_func_table, + isec->name + + strlen (OVL_INPUT_SEC_PREFIX), + false, false); + if (sym_groups == NULL) + continue; + + struct ovl_func_group_info *func_group_info; + for (func_group_info = sym_groups->groups->next; + func_group_info != NULL; + func_group_info = func_group_info->next) + { + const char *sym_name; + asection *sym_duplicate_sec; + + sym_name = isec->name + strlen (OVL_INPUT_SEC_PREFIX); + + if (riscv_overlay_debug) + fprintf (stderr, "- Copy of %s in group %lu\n", + sym_name, func_group_info->id); + sym_duplicate_sec = + get_ovl_duplicate_section (elf->dynobj, + func_group_info->id, sym_name); + BFD_ASSERT (sym_duplicate_sec != NULL); + + /* Nasty hack: When the .ovlgrps output section is created it + is created with its flags initialized to the same flags as the + last constituent input section. Because the last input section + is a dynamic section, the output section erroneously picks up the + SEC_IN_MEMORY flag which causes bfd_get_section_contents to + fail when it tries to read from the "contents" of .ovlgrps. */ + isec->output_section->flags &= ~SEC_IN_MEMORY; + + bfd_get_section_contents (output_bfd, isec->output_section, + sym_duplicate_sec->contents, + isec->output_offset, + sym_duplicate_sec->size); + } + } + } + } + free (current_data); + + return true; +} + +/* Custom CRC implementation, derived from the implementation in libiberty. */ + +static unsigned int +bitrev32 (unsigned int x) +{ + x = (x & 0x55555555) << 1 | (x & 0xaaaaaaaa) >> 1; + x = (x & 0x33333333) << 2 | (x & 0xcccccccc) >> 2; + x = (x & 0x0f0f0f0f) << 4 | (x & 0xf0f0f0f0) >> 4; + x = (x & 0x00ff00ff) << 8 | (x & 0xff00ff00) >> 8; + x = (x & 0x0000ffff) << 16 | (x & 0xffff0000) >> 16; + return x; +} + +static unsigned char +bitrev8 (unsigned char x) +{ + x = (x & 0x55) << 1 | (x & 0xaa) >> 1; + x = (x & 0x33) << 2 | (x & 0xcc) >> 2; + x = (x & 0x0f) << 4 | (x & 0xf0) >> 4; + return x; +} + +/* Array for holding the table for the CRC. */ +static unsigned int crc32_table[256]; + +/* Update the crc32_table for a given polynomial. */ + +static void +update_crc32_table (unsigned poly) +{ + unsigned int i, j, k; + unsigned int c; + + for (k = 0; k < 256; k++) + { + i = k; + for (c = i << 24, j = 8; j > 0; --j) + c = c & 0x80000000 ? (c << 1) ^ poly : (c << 1); + crc32_table[k] = c; + } +} + +/* This differs from the "standard" CRC-32 algorithm in that the values + are not reflected, and there is no final XOR value. These differences + make it easy to compose the values of multiple blocks. */ + +static unsigned int +xcrc32_custom (const unsigned char *buf, int len, unsigned int init, + unsigned int poly, unsigned int xorout, int refin, int refout) +{ + static unsigned int last_poly = 0; + + if (last_poly != poly) + { + update_crc32_table (poly); + last_poly = poly; + } + + unsigned int crc = init; + while (len--) + { + if (refin) + crc = + (crc << 8) ^ crc32_table[((crc >> 24) ^ (bitrev8 (*buf))) & 255]; + else + crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buf) & 255]; + buf++; + } + + if (refout) + crc = bitrev32 (crc); + + crc ^= xorout; + + return crc; +} + +struct emit_ovl_padding_and_crc_args +{ + struct bfd_link_info *info; + void *section_data; +}; + +/* Calculate and insert the overlay section padding and CRC. */ +static bool +emit_ovl_padding_and_crc_entry (struct ovl_group_list_entry *entry, + int group, void *data) +{ + struct emit_ovl_padding_and_crc_args *args = data; + + if (riscv_overlay_debug) + fprintf (stderr, "Group %d*: ", group); + + if (entry->group_size == 0) + { + if (riscv_overlay_debug) + fprintf (stderr, "(empty, skipping)\n"); + return true; + } + + BFD_ASSERT (args->section_data != NULL); + + /* Load the padding section. */ + struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (args->info); + asection *padding_sec = get_ovl_padding_section (htab->elf.dynobj, group); + BFD_ASSERT (padding_sec != NULL); + + /* Emit the padding into the padding section. This is copied to the cached + data so a CRC can be run over the entire block in one pass. */ + for (bfd_vma offs = 0; offs < padding_sec->size; offs += 2) + bfd_put_16 (htab->elf.dynobj, group, padding_sec->contents + offs); + memcpy (args->section_data + padding_sec->output_offset, + padding_sec->contents, padding_sec->size); + + /* Calculate the CRC of the group. */ + unsigned int crc; + + /* This shouldn't happen, except in the case of something going wrong + previously. Warn if this is the case. */ + BFD_ASSERT ((entry->ovlgrpdata_offset + entry->padded_group_size) == + (padding_sec->output_offset + padding_sec->size)); + if ((entry->ovlgrpdata_offset + entry->padded_group_size) != + (padding_sec->output_offset + padding_sec->size)) + crc = 0; + else + crc = xcrc32_custom (args->section_data + entry->ovlgrpdata_offset, + entry->padded_group_size - OVL_CRC_SZ, + riscv_crc_init, riscv_crc_poly, riscv_crc_xorout, + riscv_crc_refin, riscv_crc_refout); + + /* Put the 32-bit CRC at the end after the padding. */ + bfd_put_32 (args->info->output_bfd, crc, + padding_sec->contents + padding_sec->size - OVL_CRC_SZ); + + /* Store the CRC for printing in the mapfile. */ + entry->crc = crc; + + if (riscv_overlay_debug) + fprintf (stderr, "%x\n", crc); + return true; +} + +/* Calculate and insert all overlay group sections CRC values. */ +static void +emit_ovl_padding_and_crc (struct ovl_group_list *list, + struct bfd_link_info *info) +{ + if (riscv_overlay_debug) + fprintf (stderr, "Calculating CRCs\n================\n"); + + struct emit_ovl_padding_and_crc_args args; + args.info = info; + build_current_ovl_section (args.info, &args.section_data); + + BFD_ASSERT (args.section_data != NULL); + ovl_group_list_traverse (list, emit_ovl_padding_and_crc_entry, &args); + free (args.section_data); +} + +/* Finish overlay sections by filling in: + * .ovlplt entries + * .ovlgrptbl + * duplicates of multigroup overlay sections + * overlay section padding and crc +*/ +bool +riscv_overlay_finish_sections (struct elf_link_hash_table *elf, + struct riscv_elf_overlay_link_hash_table *ovl, + struct bfd_link_info *info) +{ + bfd *output_bfd = info->output_bfd; + if (!fill_ovlplt_sections (output_bfd, ovl)) + return false; + if (!fill_ovlgrptbl (elf, ovl)) + return false; + if (!fill_multigrp_duplicates (elf, ovl, info)) + return false; + /* Now all functions have been copied, calculate and insert the overlay + section padding and CRC. */ + emit_ovl_padding_and_crc (&ovl->ovl_group_list, info); + + return true; +} + +/* If deleted sec is in any overlay group, then the corresponding padding + sections for those groups need to be resized, as do any duplicates. */ +void +riscv_overlay_relax_delete_bytes (asection * sec, size_t count, + struct bfd_link_info *link_info) +{ + if (!strncmp + (sec->name, OVL_INPUT_SEC_PREFIX, strlen (OVL_INPUT_SEC_PREFIX))) + { + const char *sym_name = sec->name + strlen (OVL_INPUT_SEC_PREFIX); + struct riscv_elf_link_hash_table *htab = + riscv_elf_hash_table (link_info); + + struct ovl_func_hash_entry *func_entry = + ovl_func_hash_lookup (&htab->ovl.ovl_func_table, sym_name, false, + false); + if (func_entry) + { + struct ovl_func_group_info *groups; + /* Get the accompanying padding sections and increase their size. */ + for (groups = func_entry->groups; groups != NULL; + groups = groups->next) + { + asection *group_padding_section = + get_ovl_padding_section (htab->elf.dynobj, groups->id); + if (group_padding_section) + group_padding_section->size += count; + } + + /* Get any duplicated sections and reduce their size. */ + for (groups = func_entry->groups; groups != NULL; + groups = groups->next) + { + asection *sym_duplicate_section = + get_ovl_duplicate_section (htab->elf.dynobj, groups->id, + sym_name); + if (sym_duplicate_section) + sym_duplicate_section->size -= count; + } + } + } +} + +/* Create the .ovlplt section, and .rela.ovlplt. */ + +static bool +create_ovlplt_section (bfd * abfd, + struct riscv_elf_overlay_link_hash_table *ovl) +{ + flagword flags; + asection *s; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + + /* This function may be called more than once. */ + if (ovl->sovlplt != NULL) + return true; + + flags = bed->dynamic_sec_flags | SEC_READONLY | SEC_CODE; + + s = bfd_make_section_anyway_with_flags (abfd, ".ovlplt", flags); + if (s == NULL || !bfd_set_section_alignment (s, bed->s->log_file_align)) + return false; + /* The size of the overlay plt section is calculated later. */ + s->size = 0; + ovl->sovlplt = s; + + return true; +} + +bool +riscv_elf_overlay_check_relocation ( + bfd * abfd, + struct bfd_link_info *info, + struct riscv_elf_link_hash_entry_overlay *eh, + struct riscv_elf_overlay_link_hash_table *ovl, + int r_type) +{ + switch (r_type) + { + default: + return false; + case R_RISCV_OVLPLT_LO12_I: + case R_RISCV_OVLPLT_HI20: + case R_RISCV_OVLPLT32: + /* Create the overlay PLT section if it doesn't already exist. */ + if (!ovl->sovlplt) + { + if (!create_ovlplt_section (abfd, ovl)) + return false; + /* Enables analysis of dynamic sections. This is needed so + that we can resize the overlay PLT section after we + know how many entries will be needed. */ + info->dynamic = 1; + } + + if (eh && !eh->needs_ovlplt_entry) + { + eh->needs_ovlplt_entry = true; + ovl->sovlplt->size += OVLPLT_ENTRY_SIZE; + } + /* fallthrough */ + + case R_RISCV_OVLTOK_LO12_I: + case R_RISCV_OVLTOK_HI20: + case R_RISCV_OVLTOK32: + /* Enable analysis of dynamic sections since the size of the + created sections needs to be calculated later. */ + info->dynamic = 1; + ovl->overlay_enabled = 1; + if (eh) + eh->needs_overlay_group = true; + + return true; + } + return false; +} + +/* Parse a line from the overlay grouping csv and insert into hash table. */ + +static bool +parse_grouping_line (char *line, struct bfd_hash_table *ovl_func_table, + struct ovl_group_list *ovl_group_list, + struct bfd_link_info *info) +{ + char *group_str, *endptr; + char *func = NULL; + char *reason = NULL; + long int group; + int group_cnt = 0; + + /* Parse function name. */ + func = strtok (line, ","); + + /* Skip functions which have been garbage collected, they should not appear + in any group. */ + if (!ovl_enable_grouping_for_func (func, info, &reason)) + return true; + + /* Parse group ids. */ + while ((group_str = strtok (NULL, ",")) != NULL) + { + group = strtol (group_str, &endptr, 10); + if (*endptr != 0) + info->callbacks->einfo (_ + ("%F%P: Malformed group id '%s` in overlay grouping file\n"), + group_str); + + if (group == 0) + info-> + callbacks->einfo (_ + ("%F%P: Invalid group id '0` in overlay grouping file\n")); + + if (group < 0) + info->callbacks->einfo (_ + ("%F%P: Invalid group id '%ld` in overlay grouping file: " + "group numbers cannot be negative.\n"), + group); + + if (group > OVL_MAX_GROUP_ID) + info->callbacks->einfo (_ + ("%F%P: Invalid group id '%ld` in overlay grouping file: " + "group number greater than maximum (%ld).\n"), + group, OVL_MAX_GROUP_ID); + + ovl_update_func (ovl_func_table, func, (bfd_vma) group); + ovl_update_group (ovl_group_list, (bfd_vma) group, func); + group_cnt++; + } + + if (group_cnt == 0) + info-> + callbacks->einfo (_ + ("%F%P: No groups found for '%s` in overlay grouping file\n"), + func); + + return true; +} + +/* Parse a csv containg grouping information for each function. */ + +static bool +parse_grouping_file (FILE * f, + struct bfd_hash_table *ovl_func_table, + struct ovl_group_list *ovl_group_list, + struct bfd_link_info *info) +{ + int c; + int i = 0; + int BUFSIZE = 1024; + char *line = bfd_zmalloc (BUFSIZE); + bool retcode; + + while (1) + { + c = fgetc (f); + + if (i >= BUFSIZE) + { + /* Line too long for buffer, increase buffer size. */ + BUFSIZE *= 2; + line = bfd_realloc (line, BUFSIZE); + } + + if (c == '\n' || c == '\r' || c == EOF) + { + /* Parse line if not blank. */ + if (i > 0) + { + line[i++] = '\0'; + if (!parse_grouping_line + (line, ovl_func_table, ovl_group_list, info)) + goto return_error; + + /* Line parsed, goto start of buffer. */ + i = 0; + } + if (c == EOF) + break; + } + else + line[i++] = c; + } + + retcode = true; + goto done; + +return_error: + retcode = false; + +done: + free (line); + return retcode; +} + +static void +run_grouping_tool (struct riscv_elf_link_hash_table *htab, + struct bfd_link_info *info, unsigned sizeof_external_sym) +{ + bfd *ibfd; + int n_fixed_args, n_extra_args, n_total_args; + int grouping_tool_argc; + char **grouping_tool_argv; + int arg_len; + const char *arg_start; + + /* Check that the --grouping-tool option was provided. */ + if (!riscv_grouping_tool) + info->callbacks->einfo (_ + ("%F%P: '--grouping-tool` option not provided, so the grouping tool " + "cannot be called\n")); + + /* Setup the arguments for the grouping tool. */ + /* Arguments in riscv_grouping_tool_args are semicolon separated, so there + will be one more argument than the number of semicolons. */ + n_extra_args = 0; + if (riscv_grouping_tool_args) + { + n_extra_args = 1; + for (int i = 0; i < (int) strlen (riscv_grouping_tool_args); i++) + if (riscv_grouping_tool_args[i] == ';') + n_extra_args++; + } + + /* Build argv for the grouping tool. */ + n_fixed_args = 2; + n_total_args = n_fixed_args + n_extra_args; + grouping_tool_argv = + bfd_zmalloc (n_total_args * sizeof (*grouping_tool_argv)); + + /* Copy the command word to the first argument. */ + arg_len = strlen (riscv_grouping_tool); + grouping_tool_argv[0] = bfd_zmalloc (arg_len + 1); + strncpy (grouping_tool_argv[0], riscv_grouping_tool, arg_len); + + /* Copy the extra arguments from riscv_group_tools_args, each argument + is separated by a ';' */ + arg_start = riscv_grouping_tool_args; + for (int i = 0; i < n_extra_args; i++) + { + char *tmp_arg; + const char *arg_end = strchr (arg_start, ';'); + + if (arg_end == NULL) + arg_len = strlen (arg_start); + else + arg_len = arg_end - arg_start; + + tmp_arg = bfd_zmalloc (arg_len + 1); + strncpy (tmp_arg, arg_start, arg_len); + tmp_arg[arg_len] = '\0'; + + grouping_tool_argv[i + 1] = tmp_arg; + arg_start = arg_end + 1; + } + + /* Null terminate the argv list. */ + grouping_tool_argc = 1 + n_extra_args; + grouping_tool_argv[grouping_tool_argc] = NULL; + BFD_ASSERT (grouping_tool_argc < n_total_args); + + /* Search for the input and output filenames in the list of arguments + provided. These arguments will also be forwarded as-is to the + grouping tool. */ + int in_file_arg_index = 0; + int out_file_arg_index = 0; + for (int i = 0; i < grouping_tool_argc; i++) + { + if (!strcmp (grouping_tool_argv[i], "--in-file")) + in_file_arg_index = i + 1; + else if (!strcmp (grouping_tool_argv[i], "--out-file")) + out_file_arg_index = i + 1; + } + /* Check that both --in-file and --out-file options were provided, and + they were followed by file names. */ + if (in_file_arg_index == grouping_tool_argc) + info->callbacks->einfo (_ + ("%F%P: Missing file name for '--in-file` option to " + "'--grouping-tool-args`\n")); + + if (out_file_arg_index == grouping_tool_argc) + info->callbacks->einfo (_ + ("%F%P: Missing file name for '--out-file` option to " + "'--grouping-tool-args`\n")); + + if (in_file_arg_index == 0) + info->callbacks->einfo (_ + ("%F%P: No option '--in-file` provided to '--grouping-tool-args`\n")); + + if (out_file_arg_index == 0) + info->callbacks->einfo (_ + ("%F%P: No option '--out-file` provided to '--grouping-tool-args`\n")); + + char *grouping_tool_in_filename = grouping_tool_argv[in_file_arg_index]; + char *grouping_tool_out_filename = grouping_tool_argv[out_file_arg_index]; + + FILE *grouping_tool_file = fopen (grouping_tool_in_filename, FOPEN_WT); + if (!grouping_tool_file) + info->callbacks->einfo (_ + ("%F%P: Could not open file '%s` to write input for grouping tool.\n"), + grouping_tool_in_filename); + + BFD_ASSERT (grouping_tool_file != NULL); + + /* Emit all of the symbols which need to be grouped, plus their + sizes to the input .csv file for the grouping tool. */ + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) + { + unsigned int i, symcount; + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd); + + if (!is_riscv_elf (ibfd)) + continue; + + symtab_hdr = &elf_symtab_hdr (ibfd); + symcount = ((symtab_hdr->sh_size / sizeof_external_sym) + - symtab_hdr->sh_info); + + for (i = 0; i < symcount; i++) + { + struct riscv_elf_link_hash_entry *eh = + (struct riscv_elf_link_hash_entry *) sym_hashes[i]; + asection *sec = eh->elf.root.u.def.section; + + if (!eh->ovl.needs_overlay_group) + continue; + + /* Skip this symbols if it's not a definition. This avoids + accidentally assigning the same symbol more than once. */ + if (eh->elf.root.type != bfd_link_hash_defined + && eh->elf.root.type != bfd_link_hash_defweak) + continue; + + /* Also skip the symbol if it's already had its overlay + group assigned. */ + if (eh->ovl.overlay_groups_resolved == true) + continue; + else + eh->ovl.overlay_groups_resolved = true; + + /* A symbol which needs an overlay group will be in a section with + a name of the format .ovlinput.. */ + BFD_ASSERT (!strncmp (sec->name, OVL_INPUT_SEC_PREFIX, + strlen (OVL_INPUT_SEC_PREFIX))); + const char *sym_name = sec->name + strlen (OVL_INPUT_SEC_PREFIX); + + fprintf (grouping_tool_file, "%s,%lu\n", sym_name, sec->size); + } + } + fclose (grouping_tool_file); + + /* call the grouping tool with the appropriate arguments. */ + /* NOTE: The documentation for pex_one says that the flags are restricted + to only PEX_SEARCH, PEX_STDERR_TO_STDOUT and PEX_BINARY_OUTPUT, and + that the output filename (outname) is interpreted as if PEX_LAST + were set. However if this were the case then an output filename of + NULL (as below) should cause the output to go to stdout, which it + doesn't. In order to get the output to actually go to stdout we must + also specify PEX_LAST in the flag field. */ + int status, err; + const char *errmsg = pex_one (PEX_LAST | PEX_SEARCH, + grouping_tool_argv[0], + grouping_tool_argv, + "grouping tool", NULL, NULL, + &status, &err); + + if (errmsg == NULL) + { + /* Populate the tables based on the output from the grouping tool. */ + bool ret; + FILE *grouping_tool_out_file = + fopen (grouping_tool_out_filename, FOPEN_RT); + if (!grouping_tool_out_file) + info->callbacks->einfo (_ + ("%F%P: Could not open file '%s` to read output from grouping tool\n"), + grouping_tool_out_filename); + + ret = parse_grouping_file (grouping_tool_out_file, + &htab->ovl.ovl_func_table, + &htab->ovl.ovl_group_list, info); + if (!ret) + info->callbacks->einfo (_ + ("%F%P: Failed to create overlay grouping table from groupings " + "returned from grouping tool.\n")); + + htab->ovl.ovl_tables_populated = true; + } + else + info->callbacks->einfo (_("%F%P: Failed to call grouping tool '%s`\n"), + grouping_tool_argv[0]); +} + +/* Put any overlay function that has not been assigned a group into its own + group. */ + +static void +autogroup_assign (struct riscv_elf_link_hash_table *htab, + struct bfd_link_info *info) +{ + bfd *ibfd; + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) + { + if (!is_riscv_elf (ibfd)) + continue; + + unsigned next_empty_group; + if (riscv_ovl_first_group_number != 0) + next_empty_group = riscv_ovl_first_group_number; + else + next_empty_group = OVL_DEFAULT_FIRST_FREE_GROUP; + + for (asection * sec = ibfd->sections; sec != NULL; sec = sec->next) + { + if (strncmp + (sec->name, OVL_INPUT_SEC_PREFIX, + strlen (OVL_INPUT_SEC_PREFIX)) != 0) + continue; + + const char *sym_name = sec->name + strlen (OVL_INPUT_SEC_PREFIX); + + /* Skip the symbol if it's already been assigned a group - either + because it was assigned by the grouping file or grouping tool, + or because it has just been auto assigned. */ + struct ovl_func_hash_entry *sym_groups = + ovl_func_hash_lookup (&htab->ovl.ovl_func_table, + sym_name, false, false); + if (sym_groups != NULL) + continue; + + /* Skip the symbol if it has been garbage collected. */ + if (overlay_use_gcmark && !sec->gc_mark) + continue; + + /* Find the next group which is empty, starting from the + current value in 'next_empty_group'. */ + for (;; next_empty_group++) + { + /* Also look it up in the group list. */ + struct ovl_group_list_entry *group_list_entry = + ovl_group_list_lookup (&htab->ovl.ovl_group_list, + next_empty_group, false); + if (group_list_entry == NULL) + break; + } + + ovl_update_func (&htab->ovl.ovl_func_table, sym_name, + next_empty_group); + ovl_update_group (&htab->ovl.ovl_group_list, next_empty_group, + sym_name); + + /* The search for the next empty group will start from the group + number after this one. */ + next_empty_group += 1; + } + htab->ovl.ovl_tables_populated = true; + } +} + +/* Assign each overlay symbol to one or more groups. */ +static void +assign_groups (struct riscv_elf_link_hash_table *htab, + struct bfd_link_info *info, unsigned sizeof_external_sym) +{ + /* If a grouping file has been provided, populate the tables with valid + entries. */ + if (!htab->ovl.ovl_tables_populated && riscv_grouping_file != NULL) + { + bool ret; + ret = + parse_grouping_file (riscv_grouping_file, &htab->ovl.ovl_func_table, + &htab->ovl.ovl_group_list, info); + if (!ret) + info-> + callbacks->einfo (_ + ("%F%P: Failed to parse overlay grouping file\n")); + + htab->ovl.ovl_tables_populated = true; + fclose (riscv_grouping_file); + } + + /* If a grouping has not yet been specified, then try calling the + grouping tool. */ + if (!htab->ovl.ovl_tables_populated && riscv_use_grouping_tool) + run_grouping_tool (htab, info, sizeof_external_sym); + + /* If there are any symbols which weren't grouped by the grouping file + or grouping tool, then those symbols need to be put into a group on + their own. */ + autogroup_assign (htab, info); +} + +/* Build up a token for the overlay system. */ +static bfd_vma +ovltoken (bfd_vma multigroup, bfd_vma from_plt, bfd_vma func_off, + bfd_vma group_id) +{ + BFD_ASSERT (multigroup <= 1); + BFD_ASSERT (from_plt <= 1); + BFD_ASSERT (func_off <= 1023); + BFD_ASSERT (group_id <= 65535); + + /* +--------+------+----------+----------+---------+---------+---------+ + | 31 |30-29 | 28 | 27 | 26-17 | 16-1 | 0 | + +--------+------+----------+----------+---------+---------+---------+ + | Multi- | Heap | Reserved | PLT |Function | Overlay | Overlay | + | group | ID | | |Offset | Group | Address | + | Token | | | | | ID | Token | + +--------+------+----------+----------+---------+---------+---------+ */ + bfd_vma token = 0; + token |= (multigroup & 0x1) << 31; /* Multi-group token. */ + token |= (0 & 0x3) << 29; /* Heap ID. */ + token |= (from_plt & 0x1) << 27; /* From PLT. */ + token |= (func_off & 0x3ff) << 17; /* Function Offset. */ + token |= (group_id & 0xffff) << 1; /* Overlay Group ID. */ + token |= (1 & 0x1) << 0; /* Overlay Address Token. */ + return token; +} + +/* Return the relocation value for the token in the overlay system. */ + +static bfd_vma +ovloff (struct bfd_link_info *info, bfd_vma from_plt, + struct elf_link_hash_entry *entry) +{ + struct riscv_elf_link_hash_table *htab; + htab = riscv_elf_hash_table (info); + + /* Return -1 if there is an error with this link. */ + if (!entry) + return 0xffffffff; + + /* Get the group(s) for the symbol. */ + struct ovl_func_hash_entry *func_groups = + ovl_func_hash_lookup (&htab->ovl.ovl_func_table, entry->root.root.string, + false, false); + BFD_ASSERT (func_groups != NULL); + + if (func_groups->multigroup == false) + { + struct ovl_group_list_entry *group_list_entry = + ovl_group_list_lookup (&htab->ovl.ovl_group_list, + func_groups->groups->id, false); + + bfd *ibfd; + + /* First find the input section for the first function in this + group. */ + asection *group_first_input_sec = NULL; + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) + { + group_first_input_sec = + get_ovl_duplicate_section (ibfd, func_groups->groups->id, + group_list_entry->first_func); + if (group_first_input_sec) + break; + } + if (!group_first_input_sec) + { + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) + { + group_first_input_sec = + get_ovl_input_section (ibfd, group_list_entry->first_func); + if (group_first_input_sec) + break; + } + } + + /* Now find the input section for the target function in this + group. */ + asection *target_sym_input_sec = NULL; + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) + { + target_sym_input_sec = + get_ovl_input_section (ibfd, entry->root.root.string); + if (target_sym_input_sec) + break; + } + BFD_ASSERT (group_first_input_sec != NULL); + BFD_ASSERT (target_sym_input_sec != NULL); + + bfd_vma offset_into_group = target_sym_input_sec->output_offset + - group_first_input_sec->output_offset; + func_groups->groups->processed_offset = offset_into_group; + + if (riscv_overlay_debug) + { + fprintf (stderr, "group_first_input_sec->name: %s\n", + group_first_input_sec->name); + fprintf (stderr, "target_sym_input_sec->name: %s\n", + target_sym_input_sec->name); + + fprintf (stderr, "group_first_input_sec->output_offset: %lu\n", + group_first_input_sec->output_offset); + fprintf (stderr, "target_sym_input_sec->output_offset: %lu\n", + target_sym_input_sec->output_offset); + + fprintf (stderr, "OFFSET INTO GROUP: %lu\n", offset_into_group); + } + BFD_ASSERT ((offset_into_group % 4) == 0); + + return ovltoken (0, from_plt, offset_into_group / 4, + func_groups->groups->id); + } + else + { + asection *group_table_sec = + bfd_get_section_by_name (htab->elf.dynobj, OVL_GROUPTABLES_SEC_NAME); + + /* The multigroup table is immediately after the group table. So add + the group table size to the offset. */ + bfd_byte *loc = group_table_sec->contents + + htab->ovl.ovl_group_table_size + func_groups->multigroup_offset; + + /* Check if the entry in the multigroup table needs to be filled in. */ + if (bfd_get_32 (htab->elf.dynobj, loc) == 0) + { + /* Create the multigroup table entry, filling it with tokens + for the function in each of the groups it is contained within. */ + struct ovl_func_group_info *func_group_info; + for (func_group_info = func_groups->groups; func_group_info != NULL; + func_group_info = func_group_info->next) + { + bfd_vma token; + struct ovl_group_list_entry *group_list_entry = + ovl_group_list_lookup (&htab->ovl.ovl_group_list, + func_group_info->id, false); + bfd *ibfd; + + /* First find the input section for the first function in this + group. */ + asection *group_first_input_sec = NULL; + for (ibfd = info->input_bfds; ibfd != NULL; + ibfd = ibfd->link.next) + { + group_first_input_sec = + get_ovl_duplicate_section (ibfd, + func_group_info->id, + group_list_entry->first_func); + if (group_first_input_sec) + break; + } + if (!group_first_input_sec) + { + for (ibfd = info->input_bfds; ibfd != NULL; + ibfd = ibfd->link.next) + { + group_first_input_sec = + get_ovl_input_section (ibfd, + group_list_entry->first_func); + if (group_first_input_sec) + break; + } + } + + /* Now find the input section for the target function in this + group. */ + asection *target_sym_input_sec = NULL; + for (ibfd = info->input_bfds; ibfd != NULL; + ibfd = ibfd->link.next) + { + target_sym_input_sec = + get_ovl_duplicate_section (ibfd, + func_group_info->id, + entry->root.root.string); + if (target_sym_input_sec) + break; + } + if (!target_sym_input_sec) + { + for (ibfd = info->input_bfds; ibfd != NULL; + ibfd = ibfd->link.next) + { + target_sym_input_sec = + get_ovl_input_section (ibfd, entry->root.root.string); + if (target_sym_input_sec) + break; + } + } + BFD_ASSERT (group_first_input_sec != NULL); + BFD_ASSERT (target_sym_input_sec != NULL); + + bfd_vma offset_into_group = target_sym_input_sec->output_offset + - group_first_input_sec->output_offset; + func_group_info->processed_offset = offset_into_group; + + if (riscv_overlay_debug) + { + fprintf (stderr, "group_first_input_sec->name: %s\n", + group_first_input_sec->name); + fprintf (stderr, "target_sym_input_sec->name: %s\n", + target_sym_input_sec->name); + + fprintf (stderr, + "group_first_input_sec->output_offset: %lu\n", + group_first_input_sec->output_offset); + fprintf (stderr, + "target_sym_input_sec->output_offset: %lu\n", + target_sym_input_sec->output_offset); + + fprintf (stderr, "OFFSET INTO GROUP: %lu\n", + offset_into_group); + } + BFD_ASSERT ((offset_into_group % 4) == 0); + + token = ovltoken (0, 0, offset_into_group / 4, + func_group_info->id); + + bfd_put_32 (htab->elf.dynobj, token, loc); + loc += OVL_MULTIGROUP_ENTRY_SIZE; + } + /* The list of tokens is NULL terminated. */ + bfd_put_32 (htab->elf.dynobj, 0, loc); + } + + /* Create the token referring to the multigroup. */ + bfd_vma multigroup_id; + multigroup_id = + func_groups->multigroup_offset / OVL_MULTIGROUP_ENTRY_SIZE; + func_groups->multigroup_token = + ovltoken (1, from_plt, 0, multigroup_id); + return func_groups->multigroup_token; + } +} + +bool +riscv_overlay_handle_relocation ( + bfd_vma * relocation, + bfd * output_bfd, + struct bfd_link_info *info, + struct elf_link_hash_entry *h, + struct riscv_elf_overlay_link_hash_table *ovl, + Elf_Internal_Sym * sym, + int r_type) +{ + switch (r_type) + { + default: + return false; + + case R_RISCV_OVLTOK_HI20: + case R_RISCV_OVLTOK_LO12_I: + case R_RISCV_OVLTOK32: + *relocation = ovloff (info, /*from_plt */ 0, h); + return true; + + case R_RISCV_OVLPLT_HI20: + case R_RISCV_OVLPLT_LO12_I: + case R_RISCV_OVLPLT32: + *relocation = ovloff (info, /*from_plt */ 1, h); + + BFD_ASSERT (ovl->sovlplt != NULL); + /* For now, each entry in the PLT is either empty, or the first + 32-bits contains a previously encountered token value. First + try to find the index of an existing token in the PLT, if it + can't be found, append the token in the next unallocated entry + at the end. */ + bfd_vma offset; + bfd_vma next_ovlplt_offset = ovl->next_ovlplt_offset; + + for (offset = 0; offset < next_ovlplt_offset; + offset += OVLPLT_ENTRY_SIZE) + { + bfd_vma entry = bfd_get_32 (output_bfd, + ovl->sovlplt->contents + offset); + if (entry == *relocation) + break; + } + + if (offset >= next_ovlplt_offset) + { + if (h == NULL) + return true; + /* Store the PLT offset for this function in its metadata, this is + used to print the linker map later on. */ + struct ovl_func_hash_entry *func_groups = + ovl_func_hash_lookup (&ovl->ovl_func_table, h->root.root.string, + false, false); + BFD_ASSERT (func_groups != NULL); + BFD_ASSERT (ovl->sovlplt != NULL); + if (func_groups == NULL || ovl->sovlplt == NULL) + return true; + func_groups->plt_entry = true; + func_groups->plt_offset = offset; + + bfd_put_32 (output_bfd, *relocation, + ovl->sovlplt->contents + offset); + ovl->next_ovlplt_offset += OVLPLT_ENTRY_SIZE; + } + + *relocation = sec_addr (ovl->sovlplt) + offset; + + if (!h->def_regular) + { + /* Mark the symbol as undefined, rather than as defined in + the .plt section. Leave the value alone. */ + sym->st_shndx = SHN_UNDEF; + /* If the symbol is weak, we do need to clear the value. + Otherwise, the PLT entry would provide a definition for + the symbol even if the symbol wasn't defined anywhere, + and so the symbol would never be NULL. */ + if (!h->ref_regular_nonweak) + sym->st_value = 0; + } + + return true; + } + + return false; +} + +static bool +create_ovl_dup_symbol (struct bfd_link_info *info, const char *name, + bfd_vma group, asection * s, bfd_vma size) +{ + char *symbol_name; + ssize_t symbol_len; + struct bfd_link_hash_entry *bfdh; + struct elf_link_hash_entry *elfh; + bool res; + + symbol_len = strlen (name) + strlen ("$group") + /*group */ 10 + 1; + symbol_name = bfd_zmalloc (symbol_len); + sprintf (symbol_name, "%s$group%lu", name, group); + + /* Create a new symbol */ + bfdh = NULL; + res = _bfd_generic_link_add_one_symbol (info, s->owner, symbol_name, + BSF_GLOBAL, s, size, NULL, true, + false, &bfdh); + free (symbol_name); + if (!res) + return false; + + /* Set ELF flags */ + elfh = (struct elf_link_hash_entry *) bfdh; + elfh->type = ELF_ST_INFO (STB_GLOBAL, STT_FUNC); + elfh->size = size; + return true; +} + +void +riscv_elf_overlay_pad_groups (struct elf_link_hash_table *elf, + struct riscv_elf_overlay_link_hash_table *ovl, + const struct elf_backend_data *bed, + struct bfd_link_info *info) +{ + bfd *ibfd; + /* For each group, create a padding section that will hold the group number + and SHA. */ + for (unsigned i = 0; i <= ovl_max_group; i++) + { + struct ovl_group_list_entry *group_list_entry = + ovl_group_list_lookup (&ovl->ovl_group_list, i, false); + if (group_list_entry) + { + /* Get the first input section allocated to this group and set + its alignment to OVL_PAGE_SIZE bytes. */ + if (group_list_entry->n_functions != 0 + && group_list_entry->first_func) + { + /* First look for a duplicate, if one is not found, then it is the + original verison. */ + asection *isec = get_ovl_duplicate_section (elf->dynobj, + i, + group_list_entry->first_func); + if (isec == NULL) + for (ibfd = info->input_bfds; isec == NULL && ibfd != NULL; + ibfd = ibfd->link.next) + isec = + get_ovl_input_section (ibfd, + group_list_entry->first_func); + + if (!isec) + continue; + + if (riscv_overlay_debug) + fprintf (stderr, + "* Setting '%s` in '%s` to page byte alignment.\n", + isec->name, isec->owner->filename); + + /* assign the section to the page size. */ + bfd_set_section_alignment (isec, OVL_GROUP_PAGE_SIZE_POW2); + } + + flagword flags; + asection *s; + bfd_vma padding = group_list_entry->padded_group_size - + group_list_entry->group_size; + + /* It should be the case that there is always padding for the group + SHA? */ + BFD_ASSERT (padding > 0); + + flags = bed->dynamic_sec_flags | SEC_READONLY | SEC_CODE; + s = make_ovl_padding_section (elf->dynobj, i, flags); + + if (riscv_overlay_debug) + fprintf (stderr, "- Created padding section `%s` with size %lx\n", + s->name, padding); + + s->size = padding; + s->contents = bfd_zalloc (elf->dynobj, OVL_GROUP_PAGE_SIZE); + BFD_ASSERT (s != NULL); + bfd_set_section_alignment (s, 0); + } + } +} + +/* Create duplicate sections for symbols in multigroups. */ +void +riscv_elf_overlay_duplicate_multigroup_sections ( + struct elf_link_hash_table *elf, + struct riscv_elf_overlay_link_hash_table *ovl, + const struct elf_backend_data *bed, + struct bfd_link_info *info, + unsigned sizeof_external_sym) +{ + bfd *ibfd; + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) + { + unsigned int i, symcount; + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd); + + if (!is_riscv_elf (ibfd)) + continue; + + symtab_hdr = &elf_symtab_hdr (ibfd); + symcount = ((symtab_hdr->sh_size / sizeof_external_sym) + - symtab_hdr->sh_info); + + for (i = 0; i < symcount; i++) + { + flagword flags; + struct elf_link_hash_entry *h = sym_hashes[i]; + asection *sec = h->root.u.def.section; + flags = bed->dynamic_sec_flags | SEC_READONLY | SEC_CODE; + + /* A symbol in an overlay group will be in a section with a + name of the format .ovlinput.. */ + if (strncmp (sec->name, OVL_INPUT_SEC_PREFIX, + strlen (OVL_INPUT_SEC_PREFIX))) + continue; + const char *sym_name = sec->name + strlen (OVL_INPUT_SEC_PREFIX); + + /* Lookup all of the groups that this symbol exists in. */ + struct ovl_func_hash_entry *sym_groups = + ovl_func_hash_lookup (&ovl->ovl_func_table, sym_name, false, + false); + if (sym_groups == NULL) + continue; + + /* For all but the first group in this list, create a duplicate + section for that group based on the name. */ + struct ovl_func_group_info *func_group_info; + BFD_ASSERT (sym_groups->groups != NULL); + for (func_group_info = sym_groups->groups->next; + func_group_info != NULL; + func_group_info = func_group_info->next) + { + /* Don't create the same duplicate section more than once. */ + if (get_ovl_duplicate_section (elf->dynobj, func_group_info->id, + sym_name)) + continue; + + asection *s = + make_ovl_duplicate_section (elf->dynobj, func_group_info->id, + sym_name, flags); + BFD_ASSERT (s != NULL); + if (riscv_overlay_debug) + fprintf (stderr, + "- Created duplicate section `%s` with size 0x%lx\n", + s->name, sec->size); + + bfd_set_section_alignment (s, bed->s->log_file_align); + s->contents = (unsigned char *) bfd_zalloc (elf->dynobj, + sec->size); + s->size = sec->size; + /* Create a symbol for this duplicate. */ + create_ovl_dup_symbol (info, sym_name, func_group_info->id, + s, /*size */ 0); + } + } + } +} + +/* For group 0, create a special input section that will hold the + group table and multigroup table. */ +void +riscv_elf_overlay_create_ovlgrps ( + struct elf_link_hash_table *elf, + struct riscv_elf_overlay_link_hash_table *ovl, + const struct elf_backend_data *bed, + struct bfd_link_info *info) +{ + flagword flags; + asection *s; + bfd_vma size = ovl->ovl_group_table_size + ovl->ovl_multigroup_table_size; + + flags = bed->dynamic_sec_flags | SEC_READONLY | SEC_CODE; + s = bfd_make_section_anyway_with_flags (elf->dynobj, + OVL_GROUPTABLES_SEC_NAME, flags); + BFD_ASSERT (s != NULL); + s->contents = (unsigned char *) bfd_zalloc (elf->dynobj, size); + s->size = size; + + /* Add symbols for the start of the group table, and a symbol + for the start of the multigroup table (which will be populated + later). */ + bool res; + struct bfd_link_hash_entry *bfdh; + struct elf_link_hash_entry *elfh; + + bfdh = NULL; + res = _bfd_generic_link_add_one_symbol (info, elf->dynobj, + "__OVERLAY_GROUP_TABLE_START", + BSF_GLOBAL, s, + 0, NULL, true, false, &bfdh); + BFD_ASSERT (res != false); + /* Set ELF flags */ + elfh = (struct elf_link_hash_entry *) bfdh; + elfh->type = ELF_ST_INFO (STB_GLOBAL, STT_OBJECT); + elfh->size = ovl->ovl_group_table_size; + + bfdh = NULL; + res = _bfd_generic_link_add_one_symbol (info, elf->dynobj, + "__OVERLAY_MULTIGROUP_TABLE_START", + BSF_GLOBAL, s, + ovl->ovl_group_table_size, + NULL, true, false, &bfdh); + BFD_ASSERT (res != false); + elfh = (struct elf_link_hash_entry *) bfdh; + elfh->type = ELF_ST_INFO (STB_GLOBAL, STT_OBJECT); + elfh->size = ovl->ovl_multigroup_table_size; + + bfdh = NULL; + res = _bfd_generic_link_add_one_symbol (info, elf->dynobj, + "__OVERLAY_MULTIGROUP_TABLE_END", + BSF_GLOBAL, s, + ovl->ovl_group_table_size + + ovl->ovl_multigroup_table_size, + NULL, true, false, &bfdh); + BFD_ASSERT (res != false); + elfh = (struct elf_link_hash_entry *) bfdh; + elfh->type = ELF_ST_INFO (STB_GLOBAL, STT_OBJECT); + elfh->size = 0; +} + +/* Generate overlay group and multigroup tables. */ + +bool +riscv_elf_overlay_generate_tables (bfd * output_bfd, + struct bfd_link_info *info, + unsigned sizeof_external_sym) +{ + if (riscv_overlay_debug) + fprintf (stderr, " * riscv_elf_overlay_generate_tables\n"); + struct riscv_elf_link_hash_table *htab; + bfd *ibfd; + + htab = riscv_elf_hash_table (info); + BFD_ASSERT (htab != NULL); + if (htab->elf.dynobj == NULL) + return true; + + /* Allocate space for the overlay PLT table based on it's size + (determined when checking the relocs). */ + if (htab->ovl.sovlplt) + htab->ovl.sovlplt->contents = + (unsigned char *) bfd_zalloc (output_bfd, htab->ovl.sovlplt->size); + + assign_groups (htab, info, sizeof_external_sym); + + /* Make sure that group 0 is allocated, since the group table and multi + group tables will be put into this section. */ + struct ovl_group_list_entry *group0_list_entry = + ovl_group_list_lookup (&htab->ovl.ovl_group_list, 0, true); + + BFD_ASSERT (htab->ovl.ovl_tables_populated == true); + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) + { + unsigned int i, symcount; + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd); + + if (!is_riscv_elf (ibfd)) + continue; + + symtab_hdr = &elf_symtab_hdr (ibfd); + symcount = ((symtab_hdr->sh_size / sizeof_external_sym) + - symtab_hdr->sh_info); + + /* Iterate through the input symbols and if they are allocated to an + overlay group allocate them to the next offset in that group. */ + for (i = 0; i < symcount; i++) + { + struct riscv_elf_link_hash_entry *eh = + (struct riscv_elf_link_hash_entry *) sym_hashes[i]; + asection *sec = eh->elf.root.u.def.section; + + /* Skip this symbol if it's not a definition. */ + if (eh->elf.root.type != bfd_link_hash_defined + && eh->elf.root.type != bfd_link_hash_defweak) + continue; + + /* Also skip the symbol if it's already been handled here. */ + if (eh->ovl.overlay_groups_resolved == true) + continue; + else + eh->ovl.overlay_groups_resolved = true; + + /* A symbol in an overlay group will be in a section with a + name of the format .ovlinput.. */ + if (strncmp (sec->name, OVL_INPUT_SEC_PREFIX, + strlen (OVL_INPUT_SEC_PREFIX))) + { + if (!eh->ovl.needs_overlay_group) + continue; + + info->callbacks->einfo + (_("%F%P: A symbol in section '%s` is referred to by an " + "overlay relocation, but the section does not have a " + "'" OVL_INPUT_SEC_PREFIX "` prefix.\n"), sec->name); + } + const char *sym_name = sec->name + strlen (OVL_INPUT_SEC_PREFIX); + + /* Lookup all of the groups that this symbol exists in. */ + struct ovl_func_hash_entry *sym_groups = + ovl_func_hash_lookup (&htab->ovl.ovl_func_table, sym_name, false, + false); + /* Every symbol that is referred to by an overlay relocation should + have been allocated to a group by this point. The group should + be provided by the grouping file, the grouping tool, or have been + autoassigned. */ + if (eh->ovl.needs_overlay_group && sym_groups == NULL) + info->callbacks->einfo + (_("%F%P: Symbol '%s` is not assigned to an overlay group " + "but is referenced by an overlay relocation.\n"), sym_name); + + if (sym_groups == NULL) + continue; + + /* The symbol has been assigned to an overlay group, but there + also exist non-overlay references to it!. */ + if (eh->ovl.non_overlay_reference) + info->callbacks->einfo + (_("%F%P: Symbol '%s` is assigned to an overlay group " + "but it is referenced by a non-overlay relocation.\n"), + sym_name); + + /* If this is in multiple groups, then a multigroup entry needs + to be allocated. */ + if (sym_groups->multigroup == true) + { + /* Calculate the size of the entry in the multigroup + table. A multigroup entry consists of a list of tokens + (4-bytes each) followed by a 4-byte 0 terminator. */ + int multigroup_entry_size; + struct ovl_func_group_info *func_group_info; + + multigroup_entry_size = 0; + for (func_group_info = sym_groups->groups; + func_group_info != NULL; + func_group_info = func_group_info->next) + multigroup_entry_size += 4; + /* NULL terminator. */ + multigroup_entry_size += 4; + + sym_groups->multigroup_offset = + htab->ovl.ovl_multigroup_table_size; + htab->ovl.ovl_multigroup_table_size += multigroup_entry_size; + } + + struct ovl_func_group_info *func_group_info; + for (func_group_info = sym_groups->groups; func_group_info != NULL; + func_group_info = func_group_info->next) + { + ovl_max_group = func_group_info->id > ovl_max_group + ? func_group_info->id : ovl_max_group; + + struct ovl_group_list_entry *group_list_entry = + ovl_group_list_lookup (&htab->ovl.ovl_group_list, + func_group_info->id, false); + BFD_ASSERT (group_list_entry != NULL); + + /* Allocate the symbol's offset into the output section for the + group. This corresponds to the current size of the output + section. */ + func_group_info->unrelaxed_offset = + group_list_entry->group_size; + + /* Keep track of the first function which was allocated to this + group. */ + if (group_list_entry->group_size == 0) + group_list_entry->first_func = sym_name; + group_list_entry->last_func = sym_name; + + /* Allocate space in the output group for the contents of the + input section corresponding to the symbol, and re-pad to a + 4-byte boundary to allow offsets to remain valid. */ + group_list_entry->group_size += sec->size; + if ((group_list_entry->group_size % OVL_SYM_ALIGN) != 0) + group_list_entry->group_size += + (OVL_SYM_ALIGN + - group_list_entry->group_size % OVL_SYM_ALIGN); + + if (group_list_entry->group_size + OVL_CRC_SZ + > OVL_MAX_GROUP_SIZE) + info->callbacks->einfo + (_("%F%P: overlay group %d exceeds maximum group size\n"), + (int) func_group_info->id); + } + } + } + + /* Now the size of any multigroups has been determined, so space for the + multigroup table can be allocated. */ + /* Set the size of .ovlgrptbl section, adding a placeholder last entry and + space for a null terminator. */ + htab->ovl.ovl_group_table_size = (ovl_max_group + 3) * 2; + htab->ovl.ovl_group_table_max_group = ovl_max_group; + if (htab->ovl.ovl_group_table_size % 4) + htab->ovl.ovl_group_table_size += + 4 - (htab->ovl.ovl_group_table_size % 4); + + /* Now that the size of the group table and multigroup table has been + determined, we can use the sum of these as the size of group 0, which + will hold these tables. */ + group0_list_entry->group_size = + htab->ovl.ovl_group_table_size + htab->ovl.ovl_multigroup_table_size; + + if (riscv_overlay_debug) + { + fprintf (stderr, "Pre-size Table\n===========\n"); + print_group_list (&htab->ovl.ovl_group_list); + print_func_table (&htab->ovl.ovl_func_table); + } + + /* Now that the size of the groups is fixed calculated the padded size + of each group, finalize the offset of each group, and calculate the + total size needed in ".ovlgrps". */ + unsigned int i; + bfd_vma next_group_offset = 0; + for (i = 0; i <= ovl_max_group; i++) + { + struct ovl_group_list_entry *group_list_entry = + ovl_group_list_lookup (&htab->ovl.ovl_group_list, + i, false); + /* Ignore any gaps in the table. */ + if (group_list_entry == NULL) + continue; + + /* Calculate the padded size of the group. */ + group_list_entry->padded_group_size = group_list_entry->group_size; + group_list_entry->padded_group_size += OVL_CRC_SZ; + if (group_list_entry->padded_group_size % OVL_GROUP_PAGE_SIZE) + group_list_entry->padded_group_size = + ((group_list_entry->padded_group_size / OVL_GROUP_PAGE_SIZE) + + 1) * OVL_GROUP_PAGE_SIZE; + + /* Set the offset of the group to the next available offset. */ + group_list_entry->ovlgrpdata_offset = next_group_offset; + + /* Add the padded group size to get the offet for the next group. + The padding will be filled in once contents for the output + section have been allocated. */ + next_group_offset += group_list_entry->padded_group_size; + } + + if (riscv_overlay_debug) + { + fprintf (stderr, "Final Table\n===========\n"); + print_group_list (&htab->ovl.ovl_group_list); + print_func_table (&htab->ovl.ovl_func_table); + } + return true; +} + +/* Function to determine sorting of input sections when being placed. For + overlay functions, return the offset of that section in the output. + NOTE: Due to how the linker uses this value, this function has to return + a *NEGATIVE* offset in order to sort correctly. */ +int +riscv_elf_overlay_sort_value (asection * s, struct bfd_link_info *info) +{ + struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info); + BFD_ASSERT (s != NULL); + BFD_ASSERT (htab != NULL); + + /* If this is not an overlay function, return 1. */ + if (strncmp (s->name, OVL_INPUT_SEC_PREFIX, strlen (OVL_INPUT_SEC_PREFIX))) + return 1; + + /* If this is the group table, it will always be the first thing + to appear in the output section. */ + if (!strncmp (s->name, OVL_GROUPTABLES_SEC_NAME, + strlen (OVL_GROUPTABLES_SEC_NAME))) + { + /* The group tables are always the first things to appear in the + output section. */ + return 0; + } + + /* If this is an internal padding value, look at the group number, and use + its offset to return an offset. */ + if (!strncmp (s->name, OVL_PADDING_SEC_PREFIX, + strlen (OVL_PADDING_SEC_PREFIX))) + { + const char *group_id_str = s->name + strlen (OVL_PADDING_SEC_PREFIX); + + int group_id = atoi (group_id_str); + struct ovl_group_list_entry *group_list_entry = + ovl_group_list_lookup (&htab->ovl.ovl_group_list, group_id, false); + BFD_ASSERT (group_list_entry != NULL); + + bfd_vma padding_offset = group_list_entry->group_size; + + if (riscv_overlay_debug) + fprintf (stderr, " - Offset of %s is %lx\n", s->name, + group_list_entry->ovlgrpdata_offset + padding_offset); + + return -(group_list_entry->ovlgrpdata_offset + padding_offset); + } + + /* If this is a duplicate of a function, look up its symbol hash and find the + offset corresponding to that group, otherwise it must be the first entry. */ + struct ovl_func_group_info *func_group_info = NULL; + if (!strncmp (s->name, OVL_DUPLICATE_SEC_PREFIX, + strlen (OVL_DUPLICATE_SEC_PREFIX))) + { + const char *name_and_group = + s->name + strlen (OVL_DUPLICATE_SEC_PREFIX); + const char *sym_name = strchr (name_and_group, '.') + 1; + BFD_ASSERT (sym_name != (char *) 1); + bfd_vma group_id; + int matched = sscanf (name_and_group, "%lu.", &group_id); + BFD_ASSERT (matched = 1); + + struct ovl_func_hash_entry *sym_groups = + ovl_func_hash_lookup (&htab->ovl.ovl_func_table, sym_name, false, + false); + BFD_ASSERT (sym_groups != NULL); + BFD_ASSERT (sym_groups->groups != NULL); + + /* Start with the second group info, since the first one cannot be a + duplicate. */ + for (func_group_info = sym_groups->groups->next; + func_group_info != NULL; func_group_info = func_group_info->next) + { + if (func_group_info->id == group_id) + break; + } + } + else + { + /* Future proof against further internal types. */ + BFD_ASSERT (strncmp (s->name, OVL_INTERNAL_SEC_PREFIX, + strlen (OVL_INTERNAL_SEC_PREFIX)) != 0); + + /* Return an offset of 0 for functions that have been GC'd. */ + if (overlay_use_gcmark && !s->gc_mark) + return 0; + + const char *sym_name = s->name + strlen (OVL_INPUT_SEC_PREFIX); + + /* This is not a duplicate, therefore it is the first group in the list. */ + struct ovl_func_hash_entry *sym_groups = + ovl_func_hash_lookup (&htab->ovl.ovl_func_table, sym_name, false, + false); + BFD_ASSERT (sym_groups != NULL); + BFD_ASSERT (sym_groups->groups != NULL); + func_group_info = sym_groups->groups; + } + + BFD_ASSERT (func_group_info != NULL); + + /* func_group_info holds current group and offset, need to find full offset. */ + struct ovl_group_list_entry *group_list_entry = + ovl_group_list_lookup (&htab->ovl.ovl_group_list, func_group_info->id, + false); + BFD_ASSERT (group_list_entry != NULL); + + bfd_vma offset = group_list_entry->ovlgrpdata_offset + + func_group_info->unrelaxed_offset; + + if (riscv_overlay_debug) + fprintf (stderr, " - Offset of %s is %lx\n", s->name, offset); + + return -offset; +} + +void +riscv_elf_overlay_check_sections ( + bfd * abfd, + struct bfd_link_info *info, + struct riscv_elf_overlay_link_hash_table *ovl) +{ + asection *sec; + for (sec = abfd->sections; sec != NULL; sec = sec->next) + { + /* If this is an overlay input section, flag the link as being overlay + enabled. */ + if (strncmp + (sec->name, OVL_INPUT_SEC_PREFIX, + strlen (OVL_INPUT_SEC_PREFIX) == 0)) + { + info->dynamic = 1; + ovl->overlay_enabled = 1; + } + } +} + +/* Print an entry from an overlay grouping list. */ +static bool +print_group_list_entry (struct ovl_group_list_entry *entry, int index, + void *info ATTRIBUTE_UNUSED) +{ + fprintf (stderr, "Group %d", index); + fprintf (stderr, + " (output section offset: 0x%lx, size 0x%lx, padded size 0x%lx)", + entry->ovlgrpdata_offset, entry->group_size, + entry->padded_group_size); + fputc (':', stderr); + + for (int i = 0; i < entry->n_functions; i++) + fprintf (stderr, " %s", entry->functions[i]); + fprintf (stderr, "\n"); + + return true; +} + +/* Print each entry in a group to function list. */ +static void +print_group_list (struct ovl_group_list *list) +{ + ovl_group_list_traverse (list, print_group_list_entry, NULL); +} + +/* Print an entry from an overlay grouping hash table. */ +static bool +print_func_entry (struct ovl_func_hash_entry *entry, + void *info ATTRIBUTE_UNUSED) +{ + fprintf (stderr, "Function %s:", entry->root.string); + struct ovl_func_group_info *head = entry->groups; + while (head != NULL) + { + fprintf (stderr, " %lu (@%lu)", head->id, head->unrelaxed_offset); + head = head->next; + } + fprintf (stderr, "\n"); + + return true; +} + +/* Print each entry in an overlay grouping hash table. */ + +static void +print_func_table (struct bfd_hash_table *table) +{ + ovl_func_hash_traverse (table, print_func_entry, NULL); +} diff --git a/bfd/elfxx-riscv-overlay.h b/bfd/elfxx-riscv-overlay.h new file mode 100644 index 00000000000..f6a8d1621d9 --- /dev/null +++ b/bfd/elfxx-riscv-overlay.h @@ -0,0 +1,205 @@ +#ifndef ELFXX_RISCV_OVERLAY_H +#define ELFXX_RISCV_OVERLAY_H + +#include "elfxx-riscv.h" + +struct ovl_group_list_entry; + +/* Additional members for the riscv_elf_link_hash_entry structure, + needed for the overlay system. */ + +struct riscv_elf_link_hash_entry_overlay +{ + /* Track whether this symbol needs an overlay PLT entry. */ + int needs_ovlplt_entry; + + /* Track whether this symbols is referred to by an overlay relocation, + and therefore needs to exist in at least one overlay group. */ + int needs_overlay_group; + + /* Track whether this symbol is referred to by a non-overlay relocation. */ + int non_overlay_reference; + + /* Track whether this symbol has already been handled and any overlay + groups have already been generated. */ + int overlay_groups_resolved; +}; + +/* List tracking all (populated or unpopulated) overlay groups. */ + +struct ovl_group_list +{ + int n_groups; + struct ovl_group_list_entry *groups; +}; + +/* Additional members for the riscv_elf_link_hash_table structure, + needed for the overlay system. */ + +struct riscv_elf_overlay_link_hash_table +{ + /* Note whether linking overlay-enabled binary. */ + bool overlay_enabled; + + /* Short cut to overlay plt section. */ + asection *sovlplt; + + /* Offset to the next free space in the overlay plt section for a + new plt entry. */ + bfd_vma next_ovlplt_offset; + + /* Sizes for the group table and multigroup table, which together + will populated group 0. */ + bfd_vma ovl_group_table_size; + bfd_vma ovl_multigroup_table_size; + + /* The maximum group number for any group in the group table. */ + bfd_vma ovl_group_table_max_group; + + /* One to many mapping from a function to the groups it is contained in. */ + struct bfd_hash_table ovl_func_table; + + /* List of all of the groups, which includes a list of the contained + functions for that group. */ + struct ovl_group_list ovl_group_list; + + /* Tracks whether the overlay tables have finished being populated. */ + bool ovl_tables_populated; +}; + +/* File containing user defined groupings for each overlay symbol. */ +FILE *riscv_grouping_file; + +/* Marks whether the grouping tool is being used to assign overlay symbols + to groups. */ +bool riscv_use_grouping_tool; + +/* Command for the grouping tool, and command line arguments. */ +char *riscv_grouping_tool; +char *riscv_grouping_tool_args; + +bfd_vma riscv_ovl_first_group_number; +bool riscv_overlay_debug; +bfd_vma riscv_crc_init; +bfd_vma riscv_crc_poly; +bfd_vma riscv_crc_xorout; +bool riscv_crc_refin; +bool riscv_crc_refout; + +/* Used to assert that garbage collection is being performed, which means + some overlay operations can be skipped for dead functions. */ + +void riscv_overlay_set_use_gcmark (void); + +/* Initialize riscv_elf_overlay_link_hash_table struct. */ + +bool +riscv_elf_overlay_link_hash_table_init ( + struct riscv_elf_overlay_link_hash_table *ovl); + +/* Finishes various sections used by the overlay system. This fills in + the overlay plt section and the group table, populates the duplicates + for any symbol in a multigroup, and performs padding and computes + the CRC for the end of groups. */ + +bool +riscv_overlay_finish_sections (struct elf_link_hash_table *elf, + struct riscv_elf_overlay_link_hash_table *ovl, + struct bfd_link_info *info); + +/* When bytes are deleted from a section in an overlay group, the + accompanying padding section which follows the group needs to be + adjusted to ensure that the total size of the section ends on a + multiple of the overlay page size. This performs that operation. */ + +void +riscv_overlay_relax_delete_bytes (asection * sec, size_t count, + struct bfd_link_info *link_info); + +/* Handle the check of overlay specific relocations. Called from + riscv_elf_check_relocs. */ + +bool +riscv_elf_overlay_check_relocation ( + bfd * abfd, + struct bfd_link_info *info, + struct riscv_elf_link_hash_entry_overlay *eh, + struct riscv_elf_overlay_link_hash_table *ovl, + int r_type); + +/* Resolve the value for overlay specific relocations. Called from + riscv_elf_relocate_section. */ + +bool +riscv_overlay_handle_relocation ( + bfd_vma * relocation, + bfd * output_bfd, + struct bfd_link_info *info, + struct elf_link_hash_entry *h, + struct riscv_elf_overlay_link_hash_table *ovl, + Elf_Internal_Sym * sym, + int r_type); + +/* Function to determine the sorting of input sections when being placed. For + overlay functions this returns the offset of that section in the output. + + NOTE: Due to how the linker uses this value, this function returns a + *negative* offset in order to sort correctly. */ + +int riscv_elf_overlay_sort_value (asection * s, struct bfd_link_info *info); + +/* Check sections which may be in an overlay. Called from + riscv_elf_overlay_check_sections. */ + +void +riscv_elf_overlay_check_sections ( + bfd * abfd, + struct bfd_link_info *info, + struct riscv_elf_overlay_link_hash_table *ovl); + +/* Generate the overlay group and multigroup tables. This also assigns + symbols to the groups themselves. */ +bool +riscv_elf_overlay_generate_tables (bfd * output_bfd, + struct bfd_link_info *info, + unsigned sizeof_external_sym); + +/* Create a special input section containing the metadata for the + group and multigroup assignments. This section is used to populate + group number 0. */ + +void +riscv_elf_overlay_create_ovlgrps ( + struct elf_link_hash_table *elf, + struct riscv_elf_overlay_link_hash_table *ovl, + const struct elf_backend_data *bed, + struct bfd_link_info *info); + +/* Create duplicate sections for symbols which exist in multigroups. */ + +void +riscv_elf_overlay_duplicate_multigroup_sections ( + struct elf_link_hash_table *elf, + struct riscv_elf_overlay_link_hash_table *ovl, + const struct elf_backend_data *bed, + struct bfd_link_info *info, + unsigned sizeof_external_sym); + +/* For each group, create a padding section after the group which will + round the group up to the page size. The padding section will contain + padding followed by the CRC at the end. */ + +void +riscv_elf_overlay_pad_groups (struct elf_link_hash_table *elf, + struct riscv_elf_overlay_link_hash_table *ovl, + const struct elf_backend_data *bed, + struct bfd_link_info *info); + +/* Print an summary of overlay assignments to the map file. */ + +void +riscv_elf_overlay_printmap (bfd * obfd, struct elf_link_hash_table *elf, + struct riscv_elf_overlay_link_hash_table *ovl, + FILE * mapfile); + +#endif /* ELFXX_RISCV_OVERLAY_H */ diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c index 9f52bb545ac..fca584038fb 100644 --- a/bfd/elfxx-riscv.c +++ b/bfd/elfxx-riscv.c @@ -870,6 +870,96 @@ static reloc_howto_type howto_table[] = 0, /* src_mask */ 0xffffffff, /* dst_mask */ false), /* pcrel_offset */ + + /* High 20 bits of overlay table offset. */ + HOWTO (R_RISCV_OVLTOK_HI20, /* type */ + 0, /* rightshift */ + 2, /* size */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_RISCV_OVLTOK_HI20", /* name */ + true, /* partial_inplace */ + 0, /* src_mask */ + ENCODE_UTYPE_IMM (-1U), /* dst_mask */ + false), /* pcrel_offset */ + + /* Low 12 bits of overlay table offset. */ + HOWTO (R_RISCV_OVLTOK_LO12_I, /* type */ + 0, /* rightshift */ + 2, /* size */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_RISCV_OVLTOK_LO12_I", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + ENCODE_ITYPE_IMM (-1U), /* dst_mask */ + false), /* pcrel_offset */ + + /* 32-bit overlay token. */ + HOWTO (R_RISCV_OVLTOK32, /* type */ + 0, /* rightshift */ + 2, /* size */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_RISCV_OVLTOK32", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* High 20 bits of the PLT entry for an overlay function. */ + HOWTO (R_RISCV_OVLPLT_HI20, /* type */ + 0, /* rightshift */ + 2, /* size */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_RISCV_OVLPLT_HI20", /* name */ + true, /* partial_inplace */ + 0, /* src_mask */ + ENCODE_UTYPE_IMM (-1U), /* dst_mask */ + false), /* pcrel_offset */ + + /* Low 12 bits of the PLT entry for an overlay function. */ + HOWTO (R_RISCV_OVLPLT_LO12_I, /* type */ + 0, /* rightshift */ + 2, /* size */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_RISCV_OVLPLT_LO12_I", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + ENCODE_ITYPE_IMM (-1U), /* dst_mask */ + false), /* pcrel_offset */ + + /* 32-bit overlay PLT address. */ + HOWTO (R_RISCV_OVLPLT32, /* type */ + 0, /* rightshift */ + 2, /* size */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_RISCV_OVLPLT32", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0xffffffff, /* dst_mask */ + false), /* pcrel_offset */ }; /* A mapping from BFD reloc types to RISC-V ELF reloc types. */ @@ -931,6 +1021,12 @@ static const struct elf_reloc_map riscv_reloc_map[] = { BFD_RELOC_RISCV_SET16, R_RISCV_SET16 }, { BFD_RELOC_RISCV_SET32, R_RISCV_SET32 }, { BFD_RELOC_RISCV_32_PCREL, R_RISCV_32_PCREL }, + { BFD_RELOC_RISCV_OVLTOK_HI20, R_RISCV_OVLTOK_HI20 }, + { BFD_RELOC_RISCV_OVLTOK_LO12_I, R_RISCV_OVLTOK_LO12_I }, + { BFD_RELOC_RISCV_OVLTOK32, R_RISCV_OVLTOK32 }, + { BFD_RELOC_RISCV_OVLPLT_HI20, R_RISCV_OVLPLT_HI20 }, + { BFD_RELOC_RISCV_OVLPLT_LO12_I, R_RISCV_OVLPLT_LO12_I }, + { BFD_RELOC_RISCV_OVLPLT32, R_RISCV_OVLPLT32 }, }; /* Given a BFD reloc type, return a howto structure. */ @@ -943,7 +1039,21 @@ riscv_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, for (i = 0; i < ARRAY_SIZE (riscv_reloc_map); i++) if (riscv_reloc_map[i].bfd_val == code) - return &howto_table[(int) riscv_reloc_map[i].elf_val]; + { + int elf_val = riscv_reloc_map[i].elf_val; + /* FIXME: There's a big discontinuity in the howto table for the + overlay relocations which don't yet have official relocation ids. + This means `elf_val' needs to be adjusted down to close the gap. + + The official relocation numbers should be nearly contiguous + with the existing relocations, at which point this problem will + either go away or can be properly resolved by inserting padding + entries into the howto table instead. */ + if (elf_val >= R_RISCV_OVLTOK_HI20) + elf_val -= R_RISCV_OVLTOK_HI20 - R_RISCV_IRELATIVE - 1; + + return &howto_table[elf_val]; + } bfd_set_error (bfd_error_bad_value); return NULL; @@ -964,14 +1074,15 @@ riscv_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) reloc_howto_type * riscv_elf_rtype_to_howto (bfd *abfd, unsigned int r_type) { - if (r_type >= ARRAY_SIZE (howto_table)) - { - (*_bfd_error_handler) (_("%pB: unsupported relocation type %#x"), - abfd, r_type); - bfd_set_error (bfd_error_bad_value); - return NULL; - } - return &howto_table[r_type]; + unsigned int i; + for (i = 0; i < ARRAY_SIZE (howto_table); i++) + if (howto_table[i].type == r_type) + return &howto_table[i]; + + (*_bfd_error_handler) (_("%pB: unsupported relocation type %#x"), + abfd, r_type); + bfd_set_error (bfd_error_bad_value); + return NULL; } /* Special_function of RISCV_ADD and RISCV_SUB relocations. */ diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h index 67b7d078232..1fc1b750859 100644 --- a/bfd/elfxx-riscv.h +++ b/bfd/elfxx-riscv.h @@ -20,13 +20,77 @@ along with this program; see the file COPYING3. If not, see . */ +#ifndef ELFXX_RISCV_H +#define ELFXX_RISCV_H + +#include "libbfd.h" #include "elf/common.h" #include "elf/internal.h" #include "opcode/riscv.h" #include "cpu-riscv.h" +#include "elfxx-riscv-overlay.h" #define RISCV_UNKNOWN_VERSION -1 +/* RISC-V ELF linker hash entry. */ + +struct riscv_elf_link_hash_entry +{ + struct elf_link_hash_entry elf; + +#define GOT_UNKNOWN 0 +#define GOT_NORMAL 1 +#define GOT_TLS_GD 2 +#define GOT_TLS_IE 4 +#define GOT_TLS_LE 8 + char tls_type; + + struct riscv_elf_link_hash_entry_overlay ovl; +}; + +struct riscv_elf_link_hash_table +{ + struct elf_link_hash_table elf; + + /* Short-cuts to get to dynamic linker sections. */ + asection *sdyntdata; + + /* The max alignment of output sections. */ + bfd_vma max_alignment; + + /* Used by local STT_GNU_IFUNC symbols. */ + htab_t loc_hash_table; + void * loc_hash_memory; + + /* The index of the last unused .rel.iplt slot. */ + bfd_vma last_iplt_index; + + /* The data segment phase, don't relax the section + when it is exp_seg_relro_adjust. */ + int *data_segment_phase; + + /* Relocations for variant CC symbols may be present. */ + int variant_cc; + + struct riscv_elf_overlay_link_hash_table ovl; +}; + +#define riscv_elf_hash_entry(ent) \ + ((struct riscv_elf_link_hash_entry *) (ent)) + +/* Get the RISC-V ELF linker hash table from a link_info structure. */ +#define riscv_elf_hash_table(p) \ + ((is_elf_hash_table ((p)->hash) \ + && elf_hash_table_id (elf_hash_table (p)) == RISCV_ELF_DATA) \ + ? (struct riscv_elf_link_hash_table *) (p)->hash : NULL) + +#define is_riscv_elf(bfd) \ + (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ + && elf_tdata (bfd) != NULL \ + && elf_object_id (bfd) == RISCV_ELF_DATA) + +#define sec_addr(sec) ((sec)->output_section->vma + (sec)->output_offset) + extern reloc_howto_type * riscv_reloc_name_lookup (bfd *, const char *); @@ -108,3 +172,5 @@ extern void bfd_elf32_riscv_set_data_segment_info (struct bfd_link_info *, int *); extern void bfd_elf64_riscv_set_data_segment_info (struct bfd_link_info *, int *); + +#endif /* ELFXX_RISCV_H */ diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h index 0579f64d1a0..153d1594328 100644 --- a/bfd/elfxx-target.h +++ b/bfd/elfxx-target.h @@ -318,6 +318,10 @@ #define bfd_elfNN_bfd_link_check_relocs _bfd_elf_link_check_relocs #endif +#ifndef bfd_elfNN_bfd_get_section_overlay_sort_data +#define bfd_elfNN_bfd_get_section_overlay_sort_data bfd_generic_get_section_overlay_sort_data +#endif + #ifndef bfd_elfNN_archive_p #define bfd_elfNN_archive_p bfd_generic_archive_p #endif diff --git a/bfd/ihex.c b/bfd/ihex.c index cccec8f164e..d80b9a0f1d2 100644 --- a/bfd/ihex.c +++ b/bfd/ihex.c @@ -966,6 +966,7 @@ ihex_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED, #define ihex_bfd_final_link _bfd_generic_final_link #define ihex_bfd_link_split_section _bfd_generic_link_split_section #define ihex_bfd_link_check_relocs _bfd_generic_link_check_relocs +#define ihex_bfd_get_section_overlay_sort_data bfd_generic_get_section_overlay_sort_data /* The Intel Hex target vector. */ diff --git a/bfd/libbfd-in.h b/bfd/libbfd-in.h index 2905de8ef92..82168d51b41 100644 --- a/bfd/libbfd-in.h +++ b/bfd/libbfd-in.h @@ -534,6 +534,8 @@ extern struct bfd_link_hash_entry *_bfd_nolink_bfd_define_start_stop (struct bfd_link_info *, const char *, asection *) ATTRIBUTE_HIDDEN; #define _bfd_nolink_bfd_link_check_relocs \ _bfd_generic_link_check_relocs +#define _bfd_nolink_bfd_get_section_overlay_sort_data \ + bfd_generic_get_section_overlay_sort_data /* Routines to use for BFD_JUMP_TABLE_DYNAMIC for targets which do not have dynamic symbols or relocs. Use BFD_JUMP_TABLE_DYNAMIC diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 6e62e556962..40b3d2b7b51 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -539,6 +539,8 @@ extern struct bfd_link_hash_entry *_bfd_nolink_bfd_define_start_stop (struct bfd_link_info *, const char *, asection *) ATTRIBUTE_HIDDEN; #define _bfd_nolink_bfd_link_check_relocs \ _bfd_generic_link_check_relocs +#define _bfd_nolink_bfd_get_section_overlay_sort_data \ + bfd_generic_get_section_overlay_sort_data /* Routines to use for BFD_JUMP_TABLE_DYNAMIC for targets which do not have dynamic symbols or relocs. Use BFD_JUMP_TABLE_DYNAMIC @@ -2400,6 +2402,12 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_RISCV_SET16", "BFD_RELOC_RISCV_SET32", "BFD_RELOC_RISCV_32_PCREL", + "BFD_RELOC_RISCV_OVLTOK_HI20", + "BFD_RELOC_RISCV_OVLTOK_LO12_I", + "BFD_RELOC_RISCV_OVLTOK32", + "BFD_RELOC_RISCV_OVLPLT_HI20", + "BFD_RELOC_RISCV_OVLPLT_LO12_I", + "BFD_RELOC_RISCV_OVLPLT32", "BFD_RELOC_RL78_NEG8", "BFD_RELOC_RL78_NEG16", "BFD_RELOC_RL78_NEG24", diff --git a/bfd/plugin.c b/bfd/plugin.c index fb45cbee514..02a3fd58b58 100644 --- a/bfd/plugin.c +++ b/bfd/plugin.c @@ -110,6 +110,7 @@ dlerror (void) #define bfd_plugin_bfd_define_start_stop bfd_generic_define_start_stop #define bfd_plugin_bfd_copy_link_hash_symbol_type _bfd_generic_copy_link_hash_symbol_type #define bfd_plugin_bfd_link_check_relocs _bfd_generic_link_check_relocs +#define bfd_plugin_bfd_get_section_overlay_sort_data bfd_generic_get_section_overlay_sort_data static enum ld_plugin_status message (int level ATTRIBUTE_UNUSED, diff --git a/bfd/reloc.c b/bfd/reloc.c index 164060361a9..4c5cb71517c 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -5245,6 +5245,18 @@ ENUMX BFD_RELOC_RISCV_SET32 ENUMX BFD_RELOC_RISCV_32_PCREL +ENUMX + BFD_RELOC_RISCV_OVLTOK_HI20 +ENUMX + BFD_RELOC_RISCV_OVLTOK_LO12_I +ENUMX + BFD_RELOC_RISCV_OVLTOK32 +ENUMX + BFD_RELOC_RISCV_OVLPLT_HI20 +ENUMX + BFD_RELOC_RISCV_OVLPLT_LO12_I +ENUMX + BFD_RELOC_RISCV_OVLPLT32 ENUMDOC RISC-V relocations. diff --git a/bfd/section.c b/bfd/section.c index 2de7dbf661a..0f593dcd3a8 100644 --- a/bfd/section.c +++ b/bfd/section.c @@ -1713,3 +1713,22 @@ _bfd_nowrite_set_section_contents (bfd *abfd, { return _bfd_bool_bfd_false_error (abfd); } + +/* +FUNCTION + bfd_generic_get_section_overlay_sort_data + +SYNOPSIS + int bfd_generic_get_section_overlay_sort_data + (asection *sec, struct bfd_link_info *info); + +DESCRIPTION + Get the user sort data for the section @var{sec} under @var{info}. +*/ + +int +bfd_generic_get_section_overlay_sort_data (asection *sec ATTRIBUTE_UNUSED, + struct bfd_link_info *info ATTRIBUTE_UNUSED) +{ + return 0; +} diff --git a/bfd/srec.c b/bfd/srec.c index 5f8c8c18087..facd3898167 100644 --- a/bfd/srec.c +++ b/bfd/srec.c @@ -1283,6 +1283,7 @@ srec_print_symbol (bfd *abfd, #define srec_bfd_final_link _bfd_generic_final_link #define srec_bfd_link_split_section _bfd_generic_link_split_section #define srec_bfd_link_check_relocs _bfd_generic_link_check_relocs +#define srec_bfd_get_section_overlay_sort_data bfd_generic_get_section_overlay_sort_data const bfd_target srec_vec = { diff --git a/bfd/targets.c b/bfd/targets.c index 18fec45f02a..84cc0b9c445 100644 --- a/bfd/targets.c +++ b/bfd/targets.c @@ -474,7 +474,8 @@ BFD_JUMP_TABLE macros. . NAME##_section_already_linked, \ . NAME##_bfd_define_common_symbol, \ . NAME##_bfd_link_hide_symbol, \ -. NAME##_bfd_define_start_stop +. NAME##_bfd_define_start_stop, \ +. NAME##_bfd_get_section_overlay_sort_data . . int (*_bfd_sizeof_headers) (bfd *, struct bfd_link_info *); . bfd_byte * @@ -553,6 +554,10 @@ BFD_JUMP_TABLE macros. . (*_bfd_define_start_stop) (struct bfd_link_info *, const char *, . asection *); . +. {* Get section specific sort data. *} +. int (*_bfd_get_section_overlay_sort_data) (asection *, +. struct bfd_link_info *); +. . {* Routines to handle dynamic symbols and relocs. *} .#define BFD_JUMP_TABLE_DYNAMIC(NAME) \ . NAME##_get_dynamic_symtab_upper_bound, \ diff --git a/bfd/tekhex.c b/bfd/tekhex.c index 7ff87af8a9d..d12f02005a3 100644 --- a/bfd/tekhex.c +++ b/bfd/tekhex.c @@ -992,6 +992,7 @@ tekhex_print_symbol (bfd *abfd, #define tekhex_bfd_link_split_section _bfd_generic_link_split_section #define tekhex_get_section_contents_in_window _bfd_generic_get_section_contents_in_window #define tekhex_bfd_link_check_relocs _bfd_generic_link_check_relocs +#define tekhex_bfd_get_section_overlay_sort_data bfd_generic_get_section_overlay_sort_data const bfd_target tekhex_vec = { diff --git a/gas/ChangeLog b/gas/ChangeLog index e2e48973204..165c2ef832f 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,14 @@ +2022-02-28 Edward Jones + + * config/tc-riscv.c (percent_op_utype): + Add mappings for BFD_RELOC_RISCV_OVLTOK_HI20 + and BFD_RELOC_RISCV_OVLPLT_HI20 relocs. + (percent_op_itype): + Add mappings for BFD_RELOC_RISCV_OVLTOK_LO12_I + and BFD_RELOC_RISCV_OVLPLT_LO12_I relocs. + (md_apply_fix): Add handling of overlay + relocations. + 2022-01-28 Nick Clifton * po/fr.po: Updated French translation. diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c index 25908597436..0483bf0991d 100644 --- a/gas/config/tc-riscv.c +++ b/gas/config/tc-riscv.c @@ -1901,6 +1901,8 @@ static const struct percent_op_match percent_op_utype[] = {"%tls_ie_pcrel_hi", BFD_RELOC_RISCV_TLS_GOT_HI20}, {"%tls_gd_pcrel_hi", BFD_RELOC_RISCV_TLS_GD_HI20}, {"%hi", BFD_RELOC_RISCV_HI20}, + {"%ovltok_hi", BFD_RELOC_RISCV_OVLTOK_HI20}, + {"%ovlplt_hi", BFD_RELOC_RISCV_OVLPLT_HI20}, {0, 0} }; @@ -1909,6 +1911,8 @@ static const struct percent_op_match percent_op_itype[] = {"%lo", BFD_RELOC_RISCV_LO12_I}, {"%tprel_lo", BFD_RELOC_RISCV_TPREL_LO12_I}, {"%pcrel_lo", BFD_RELOC_RISCV_PCREL_LO12_I}, + {"%ovltok_lo", BFD_RELOC_RISCV_OVLTOK_LO12_I}, + {"%ovlplt_lo", BFD_RELOC_RISCV_OVLPLT_LO12_I}, {0, 0} }; @@ -3669,6 +3673,14 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) case BFD_RELOC_RISCV_ALIGN: break; + case BFD_RELOC_RISCV_OVLTOK_LO12_I: + case BFD_RELOC_RISCV_OVLTOK_HI20: + case BFD_RELOC_RISCV_OVLTOK32: + case BFD_RELOC_RISCV_OVLPLT_LO12_I: + case BFD_RELOC_RISCV_OVLPLT_HI20: + case BFD_RELOC_RISCV_OVLPLT32: + break; + default: /* We ignore generic BFD relocations we don't know about. */ if (bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type) != NULL) diff --git a/include/ChangeLog b/include/ChangeLog index 416fb6b8778..489f1f42435 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,13 @@ +2022-02-28 Edward Jones + + * elf/riscv.h: Add R_RISCV_OVLTOK_HI20, + R_RISCV_OVLTOK_LO12_I, R_RISCV_OVLTOK32, + R_RISCV_OVLPLT_HI20, R_RISCV_OVLPLT_LO12_I, + R_RISCV_OVLPLT32 for reloc numbers from 220 + to 225. + * opcode/riscv.h (X_ZERO X_T5 X_T6): Add + defines. + 2022-01-25 Klaus Ziegler PR 28816 diff --git a/include/elf/riscv.h b/include/elf/riscv.h index d0acf6886d8..07a19ba81fc 100644 --- a/include/elf/riscv.h +++ b/include/elf/riscv.h @@ -89,6 +89,12 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type) RELOC_NUMBER (R_RISCV_SET32, 56) RELOC_NUMBER (R_RISCV_32_PCREL, 57) RELOC_NUMBER (R_RISCV_IRELATIVE, 58) + RELOC_NUMBER (R_RISCV_OVLTOK_HI20, 220) + RELOC_NUMBER (R_RISCV_OVLTOK_LO12_I, 221) + RELOC_NUMBER (R_RISCV_OVLTOK32, 222) + RELOC_NUMBER (R_RISCV_OVLPLT_HI20, 223) + RELOC_NUMBER (R_RISCV_OVLPLT_LO12_I, 224) + RELOC_NUMBER (R_RISCV_OVLPLT32, 225) END_RELOC_NUMBERS (R_RISCV_max) /* Processor specific flags for the ELF header e_flags field. */ diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h index 048ab0a5d68..1e6807dc437 100644 --- a/include/opcode/riscv.h +++ b/include/opcode/riscv.h @@ -314,6 +314,7 @@ static const char * const riscv_pred_succ[16] = /* ABI names for selected x-registers. */ +#define X_ZERO 0 #define X_RA 1 #define X_SP 2 #define X_GP 3 @@ -322,6 +323,8 @@ static const char * const riscv_pred_succ[16] = #define X_T1 6 #define X_T2 7 #define X_T3 28 +#define X_T5 30 +#define X_T6 31 #define NGPR 32 #define NFPR 32 diff --git a/ld/ChangeLog b/ld/ChangeLog index 3fea7995481..d897d4150a3 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,110 @@ +2022-03-06 Edward Jones + + * emultempl/emulation.em (LDEMUL_EXTRA_EARLY_MAP_FILE_TEST): + Default to NULL. + * emultempl/riscvelf.em (riscv_grouping_file): Forward declare. + (DEFAULT_CRC_INIT DEFAULT_CRC_POLY DEFAULT_CRC_XOROUT) + (DEFAULT_CRC_REFIN DEFAULT_CRC_REFOUT): New defines. + (elf_riscv_before_parse): New function. + (riscv_elf_before_allocation): Add error for .ovlinput + prefixed input sections not assigned to .ovlgrps output + section. + (riscv_elf_after_check_relocs): New function. + (get_type_from_name_and_flags): Likewise. + (riscv_ovl_additional_link_map_text): Likewise. + (PARSE_AND_LIST_PROLOGUE): Set to add various + defines to the standard elf argument parsing. + (PARSE_AND_LIST_LONGOPTS): Add various overlay options + to standard option list. + (PARSE_AND_LIST_OPTIONS): Add various overlay short + options to standard elf option list. + (PARSE_AND_LIST_ARGS_CASES): Set to add cases to + standard elf argument parsing. + (LDEMUL_BEFORE_PARSE): Define to elf_riscv_before_parse. + (LDEMUL_AFTER_CHECK_RELOCS): Define to + riscv_elf_after_check_relocs. + (LDEMUL_EXTRA_EARLY_MAP_FILE_TEXT): + Define to =riscv_ovl_additional_link_map_text + * ld.h (sort_type): Add by_overlay sort type. + * ldemul.c (ldemul_extra_early_map_file_text): Add + new entry point. + * ldemul.h (ldemul_extra_early_map_file_text): Add + forward declaration. + (struct ld_emulation_xfer_struct): Add + extra_early_map_file_text member. + * ldlang.c (compare_section): Add handling of + by_overlay sort type. + (get_lang_memory_region_list): Add function. + (lang_map): Call ldemul_extra_early_map_text + at start of map file printing. + (set_overlay_sort_default): Add function. + (update_wild_statements): Force unsorted sections + assigned to the .ovlgrps output section to use + by_overlay sorting. + (print_wild_statement): Handle by_overlay sorting type. + (size_input_section): Force alignment of overlay + padding sections. + * ldlang.h (get_lang_memory_region_list): Add forward + declaration. + * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add + run_dump_test calls for overlay tests. + (riscv_get_testdir): Add procedure. + * testsuite/ld-riscv-elf/overlay-assign-dead.csv: + Added file. + * testsuite/ld-riscv-elf/overlay-assing-dead.d: Likewise. + * testsuite/ld-riscv-elf/overlay-assign-group0.csv: Likewise. + * testsuite/ld-riscv-elf/overlay-assign-group0.d: Likewise. + * testsuite/ld-riscv-elf/overlay-assign-missing.csv: + Likewise. + * testsuite/ld-riscv-elf/overlay-assign-missing.d: Likewise. + * testsuite/ld-riscv-elf/overlay-assign-non-contiguous.csv: + Likewise. + * testsuite/ld-riscv-elf/overlay-assign-non-contiguous.d: + Likewise. + * testsuite/ld-riscv-elf/overlay-autoassign-01.d: Likewise. + * testsuite/ld-riscv-elf/overlay-autoassign-02.d: Likewise. + * testsuite/ld-riscv-elf/overlay-autoassign-dead.d: Likewise. + * testsuite/ld-riscv-elf/overlay-big-funcs.s: Likewise. + * testsuite/ld-riscv-elf/overlay-dead-symbol.s: Likewise. + * testsuite/ld-riscv-elf/overlay-invalid-group-number.csv: + Likewise. + * testsuite/ld-riscv-elf/overlay-invalid-group-number.d: + Likewise. + * testsuite/ld-riscv-elf/overlay-many-func-group.csv: + Likewise. + * testsuite/ld-riscv-elf/overlay-many-func-group.d: Likewise. + * testsuite/ld-riscv-elf/overlay-many-funcs.s: Likewise. + * testsuite/ld-riscv-elf/overlay-max-group-number.csv: + Likewise. + * testsuite/ld-riscv-elf/overlay-max-group-number.d: + Likewise. + * testsuite/ld-riscv-elf/overlay-max-size-group.csv: Likewise. + * testsuite/ld-riscv-elf/overlay-max-size-group.d: Likewise. + * testsuite/ld-riscv-elf/overlay-multigroup-01.csv: Likewise. + * testsuite/ld-riscv-elf/overlay-multigroup-01.d: Likewise. + * testsuite/ld-riscv-elf/overlay-multigroup-02.csv: Likewise. + * testsuite/ld-riscv-elf/overlay-multigroup-02.d: Likewise. + * testsuite/ld-riscv-elf/overlay-no-grouping-file.d: Likewise. + * testsuite/ld-riscv-elf/overlay-partial-assign.csv: Likewise. + * testsuite/ld-riscv-elf/overlay-partial-assign.d: Likewise. + * testsuite/ld-riscv-elf/overlay-plt.csv: Likewise. + * testsuite/ld-riscv-elf/overlay-plt.d: Likewise. + * testsuite/ld-riscv-elf/overlay-plt.s: Likewise. + * testsuite/ld-riscv-elf/overlay-relax-01.d: Likewise. + * testsuite/ld-riscv-elf/overlay-relax-02.csv: Likewise. + * testsuite/ld-riscv-elf/overlay-relax-02.d: Likewise. + * testsuite/ld-riscv-elf/overlay-relax-multigroup.csv: + Likewise. + * testsuite/ld-riscv-elf/overlay-relax-multigroup.d: + Likewise. + * testsuite/ld-riscv-elf/overlay-relax.s: Likewise. + * testsuite/ld-riscv-elf/overlay-symbol-not-in-ovlinput.d: + Likewise. + * testsuite/ld-riscv-elf/overlay-symbol-not-in-ovlinput.s: + Likewise. + * testsuite/ld-riscv-elf/overlay-trivial.s: Likewise. + * testsuite/ld-riscv-elf/overlay.ld: Likewise. + 2022-02-17 Roland McGrath * ld.texi (Output Section Type): Fix typo in @code syntax. diff --git a/ld/emultempl/emulation.em b/ld/emultempl/emulation.em index cfa6567ac2b..6fdbb559afe 100644 --- a/ld/emultempl/emulation.em +++ b/ld/emultempl/emulation.em @@ -32,6 +32,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL}, ${LDEMUL_NEW_VERS_PATTERN-NULL}, ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL}, + ${LDEMUL_EXTRA_EARLY_MAP_FILE_TEXT-NULL}, ${LDEMUL_EMIT_CTF_EARLY-NULL}, ${LDEMUL_ACQUIRE_STRINGS_FOR_CTF-NULL}, ${LDEMUL_NEW_DYNSYM_FOR_CTF-NULL}, diff --git a/ld/emultempl/riscvelf.em b/ld/emultempl/riscvelf.em index 645a807f239..f750e47b359 100644 --- a/ld/emultempl/riscvelf.em +++ b/ld/emultempl/riscvelf.em @@ -25,11 +25,54 @@ fragment <the_bfd->sections; + while (sec != NULL) + { + const char *secname = sec->name; + const char *dstname = sec->output_section + ? sec->output_section->name : ""; + /* Produce an error if the input section name starts with ".ovlinput" + and the output name is not ".ovlgrps". Don't error if marked as + excluded. */ + if (!strncmp (secname, ".ovlinput", strlen (".ovlinput")) + && strcmp (dstname, ".ovlgrps") + && !(sec->flags & SEC_EXCLUDE)) + { + einfo(_("%F%P: Input section %s not correctly placed in " + ".ovlgrps\n"), secname); + } + sec = sec->next; + } + } + if (link_info.discard == discard_sec_merge) link_info.discard = discard_l; @@ -98,8 +141,298 @@ riscv_create_output_section_statements (void) } } +extern void +riscv_elf_overlay_hook_${EMULATION_NAME} (struct bfd_link_info *info); + +static void +riscv_elf_after_check_relocs (void) +{ + riscv_elf_overlay_hook_${EMULATION_NAME} (&link_info); +} + +static const char * +get_type_from_name_and_flags (const char *name, flagword flags, + bfd_vma elftype) +{ + if (flags & SEC_DEBUGGING) + return "Debug Information"; + if (flags & SEC_CODE) + { + if (!strcmp (name, ".ovlgrps")) + return "Overlay Group Data"; + return "Code"; + } + if (flags & SEC_DATA) + { + if (elftype == SHT_INIT_ARRAY) + return "Constructor Array"; + if (elftype == SHT_FINI_ARRAY) + return "Destructor Array"; + if (!strcmp (name, ".eh_frame")) + return "Exception Handling Frame Information"; + if (flags & SEC_READONLY) + return "Read-only Data"; + return "Data"; + } + if (elftype == SHT_NOBITS) + { + if (!strcmp (name, ".bss")) + return "BSS"; + if (!strcmp (name, ".stack")) + return "Stack"; + return "NOBITS"; + } + if (elftype == 1879048195) + return "RISC-V Attributes"; + if (elftype == SHT_PROGBITS) + return "PROGBITS"; + return "Unknown"; +} + +static void +riscv_ovl_additional_link_map_text (bfd *obfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + FILE *mapfile) +{ + if (mapfile == NULL) + return; + + lang_memory_region_type *m; + + /* 1.1 Map file size summary */ + minfo ("\nMemory summary\n\n"); + minfo ("MEMORY REGION MEMORY USED\n"); + minfo (" SECTION SECTION SIZE TYPE\n"); + for (m = get_lang_memory_region_list (); m!= NULL; m = m->next) + { + char szbuf[100]; + bfd_vma memsize; + lang_output_section_statement_type *s; + + /* Don't print the default memory region. */ + if (!strcmp (m->name_list.name, DEFAULT_MEMORY_REGION)) + continue; + + memsize = m->current - m->origin; + float memsizef = memsize / 1024.0; + char *suffix = "KiB"; + if (memsizef >= 1024.0) + { + memsizef /= 1024.0; + suffix = "MiB"; + } + if (memsizef >= 1024.0) + { + memsizef /= 1024.0; + suffix = "GiB"; + } + sprintf (szbuf, "%3.2f", memsizef); + fprintf (config.map_file, "%-24s= %8li (%6s %s)\n", m->name_list.name, + memsize, szbuf, suffix); + + s = &lang_os_list.head->output_section_statement; + while (s != NULL) + { + if (s->bfd_section != NULL && s->region == m) + { + asection *section = s->bfd_section; + if (section->size > 0) + { + float sectsizef = section->size / 1024.0; + sprintf (szbuf, "%3.2f", sectsizef); + fprintf (config.map_file, " %-20s= %8li (%6s KiB)", + section->name, section->size, szbuf); + + flagword flags = section->flags; + unsigned sec_shndx = + _bfd_elf_section_from_bfd_section (section->owner, + section); + Elf_Internal_Shdr *hdr = + elf_elfsections (section->owner)[sec_shndx]; + fprintf (config.map_file, " %s\n", + get_type_from_name_and_flags (section->name, + flags, + hdr->sh_type)); + } + } + s = s->next; + } + } + + /* 1.2 Map file sections summary. */ + minfo ("\nSection summary\n\n"); + minfo ("NAME START END TYPE\n"); + { + lang_output_section_statement_type *s; + s = &lang_os_list.head->output_section_statement; + while (s != NULL) + { + if (s->bfd_section != NULL && s->bfd_section->owner == obfd) + { + asection *section = s->bfd_section; + bfd_vma end = section->vma + section->size; + flagword flags = section->flags; + if (!(flags & SEC_EXCLUDE || flags & SEC_DEBUGGING)) + { + unsigned sec_shndx = + _bfd_elf_section_from_bfd_section (section->owner, section); + Elf_Internal_Shdr *hdr = + elf_elfsections (section->owner)[sec_shndx]; + fprintf (config.map_file, "%-20s [%08lx-%08lx)", + section->name, section->vma, end); + fprintf (config.map_file, " %s\n", + get_type_from_name_and_flags (section->name, flags, + hdr->sh_type)); + } + } + s = s->next; + } + } + + minfo ("\n"); +} + EOF +# Define some shell vars to insert bits of code into the standard elf +# parse_args and list_options functions. +# +PARSE_AND_LIST_PROLOGUE=' +#define OPTION_GROUPING_FILE 301 +#define OPTION_GROUPING_TOOL 302 +#define OPTION_GROUPING_TOOL_ARGS 303 +#define OPTION_FIRST_GROUP_NUMBER 304 +#define OPTION_OVERLAY_DEBUG 305 +#define OPTION_OVERLAY_CRC_INIT 306 +#define OPTION_OVERLAY_CRC_POLY 307 +#define OPTION_OVERLAY_CRC_XOROUT 308 +#define OPTION_OVERLAY_CRC_REFIN_ON 309 +#define OPTION_OVERLAY_CRC_REFIN_OFF 310 +#define OPTION_OVERLAY_CRC_REFOUT_ON 311 +#define OPTION_OVERLAY_CRC_REFOUT_OFF 312 +' + +PARSE_AND_LIST_LONGOPTS=' + { "grouping-file", required_argument, NULL, OPTION_GROUPING_FILE }, + { "grouping-tool", required_argument, NULL, OPTION_GROUPING_TOOL }, + { "grouping-tool-args", required_argument, NULL, OPTION_GROUPING_TOOL_ARGS }, + { "first-group-number", required_argument, NULL, OPTION_FIRST_GROUP_NUMBER }, + { "overlay-debug", no_argument, NULL, OPTION_OVERLAY_DEBUG }, + { "overlay-crcinit", required_argument, NULL, OPTION_OVERLAY_CRC_INIT }, + { "overlay-crcpolynomial",required_argument, NULL, OPTION_OVERLAY_CRC_POLY }, + { "overlay-crcxorout", required_argument, NULL, OPTION_OVERLAY_CRC_XOROUT }, + { "overlay-crcrefin", no_argument, NULL, OPTION_OVERLAY_CRC_REFIN_ON }, + { "overlay-crcnorefin", no_argument, NULL, OPTION_OVERLAY_CRC_REFIN_OFF }, + { "overlay-crcrefout", no_argument, NULL, OPTION_OVERLAY_CRC_REFOUT_ON }, + { "overlay-crcnorefout", no_argument, NULL, OPTION_OVERLAY_CRC_REFOUT_OFF }, +' + +PARSE_AND_LIST_OPTIONS=' + fprintf (file, _("--grouping-file Grouping file name\n")); + fprintf (file, _("--grouping-tool Name of the grouping tool command\n")); + fprintf (file, _("--grouping-tool-args Arguments to the grouping tool\n")); + fprintf (file, _("--first-group-number First group number for autogrouping\n")); + fprintf (file, _("--overlay-crcinit Initilization value used for CRCs\n")); + fprintf (file, _("--overlay-crcpolynomial Polynomial used for overlay CRCs\n")); + fprintf (file, _("--overlay-crcxorout Final XOR value used for overlay CRCs\n")); + fprintf (file, _("--overlay-crcrefin Enable input reflection for overlay CRCs\n")); + fprintf (file, _("--overlay-crcnorefin Disable input reflection for overlay CRCs\n")); + fprintf (file, _("--overlay-crcrefout Enable output reflection for overlay CRCs\n")); + fprintf (file, _("--overlay-crcnorefout Disable output reflection for overlay CRCs\n")); +' + +PARSE_AND_LIST_ARGS_CASES=' + case OPTION_GROUPING_FILE: + if (riscv_use_grouping_tool) + einfo (_("--grouping-file provided, but --grouping-tools-args already " + "specified"), optarg); + riscv_grouping_file = fopen (optarg, FOPEN_RT); + if (riscv_grouping_file == NULL) + einfo (_("%F%P: cannot open grouping file %s\n"), optarg); + break; + case OPTION_GROUPING_TOOL: + if (riscv_grouping_file != NULL) + einfo (_("--grouping-tool provided, but --grouping-file already " + "specified"), optarg); + riscv_use_grouping_tool = true; + riscv_grouping_tool = malloc (strlen (optarg) + 1); + strcpy (riscv_grouping_tool, optarg); + riscv_grouping_tool[strlen (optarg)] = '\0'; + break; + case OPTION_GROUPING_TOOL_ARGS: + if (riscv_grouping_file != NULL) + einfo (_("--grouping-tool-args provided, but --grouping-file already " + "specified"), optarg); + riscv_use_grouping_tool = true; + riscv_grouping_tool_args = malloc (strlen (optarg) + 1); + strcpy (riscv_grouping_tool_args, optarg); + riscv_grouping_tool_args[strlen (optarg)] = '\0'; + break; + case OPTION_FIRST_GROUP_NUMBER: + { + const char *end; + riscv_ovl_first_group_number = bfd_scan_vma (optarg, &end, 0); + if (*end != '\0' || riscv_ovl_first_group_number <= 0) + einfo (_("%P: warning: ignoring invalid --first-group-number value " + "%s\n"), optarg); + } + break; + case OPTION_OVERLAY_DEBUG: + riscv_overlay_debug = true; + break; + case OPTION_OVERLAY_CRC_INIT: + { + const char *end; + riscv_crc_init = bfd_scan_vma (optarg, &end, 0); + if (*end != 0 || riscv_crc_init >= 0xffffffffU) + { + einfo (_("%P: warning: ignoring invalid overlay CRC inital value " + "%s\n"), optarg); + riscv_crc_init = DEFAULT_CRC_INIT; + } + } + break; + case OPTION_OVERLAY_CRC_POLY: + { + const char *end; + riscv_crc_poly = bfd_scan_vma (optarg, &end, 0); + if (*end != 0 || riscv_crc_poly >= 0xffffffffU) + { + einfo (_("%P: warning: ignoring invalid overlay CRC polynomial " + "%s\n"), optarg); + riscv_crc_poly = DEFAULT_CRC_POLY; + } + } + break; + case OPTION_OVERLAY_CRC_XOROUT: + { + const char *end; + riscv_crc_xorout = bfd_scan_vma (optarg, &end, 0); + if (*end != 0 || riscv_crc_xorout >= 0xffffffffU) + { + einfo (_("%P: warning: ignoring invalid overlay CRC xorout %s\n"), + optarg); + riscv_crc_xorout = DEFAULT_CRC_XOROUT; + } + } + break; + case OPTION_OVERLAY_CRC_REFIN_ON: + riscv_crc_refin = true; + break; + case OPTION_OVERLAY_CRC_REFIN_OFF: + riscv_crc_refin = false; + break; + case OPTION_OVERLAY_CRC_REFOUT_ON: + riscv_crc_refout = true; + break; + case OPTION_OVERLAY_CRC_REFOUT_OFF: + riscv_crc_refout = false; + break; +' + +LDEMUL_BEFORE_PARSE=elf_riscv_before_parse LDEMUL_BEFORE_ALLOCATION=riscv_elf_before_allocation LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=riscv_create_output_section_statements +LDEMUL_AFTER_CHECK_RELOCS=riscv_elf_after_check_relocs +LDEMUL_EXTRA_EARLY_MAP_FILE_TEXT=riscv_ovl_additional_link_map_text diff --git a/ld/ld.h b/ld/ld.h index f3086bf30de..9e21ca29f69 100644 --- a/ld/ld.h +++ b/ld/ld.h @@ -89,7 +89,7 @@ typedef enum {sort_none, sort_ascending, sort_descending} sort_order; typedef enum { none, by_name, by_alignment, by_name_alignment, by_alignment_name, - by_none, by_init_priority + by_none, by_init_priority, by_overlay } sort_type; extern sort_type sort_section; diff --git a/ld/ldemul.c b/ld/ldemul.c index 85c00ded75e..b82ff87a83d 100644 --- a/ld/ldemul.c +++ b/ld/ldemul.c @@ -403,6 +403,14 @@ ldemul_extra_map_file_text (bfd *abfd, struct bfd_link_info *info, FILE *mapf) ld_emulation->extra_map_file_text (abfd, info, mapf); } +void +ldemul_extra_early_map_file_text (bfd *abfd, struct bfd_link_info *info, + FILE *mapf) +{ + if (ld_emulation->extra_early_map_file_text) + ld_emulation->extra_early_map_file_text (abfd, info, mapf); +} + int ldemul_emit_ctf_early (void) { diff --git a/ld/ldemul.h b/ld/ldemul.h index 33e690d78ac..6fa0279ecdc 100644 --- a/ld/ldemul.h +++ b/ld/ldemul.h @@ -104,6 +104,8 @@ extern struct bfd_elf_version_expr *ldemul_new_vers_pattern (struct bfd_elf_version_expr *); extern void ldemul_extra_map_file_text (bfd *, struct bfd_link_info *, FILE *); +extern void ldemul_extra_early_map_file_text + (bfd *, struct bfd_link_info *, FILE *); /* Return 1 if we are emitting CTF early, and 0 if ldemul_examine_strtab_for_ctf will be called by the target. */ extern int ldemul_emit_ctf_early @@ -227,6 +229,12 @@ typedef struct ld_emulation_xfer_struct { void (*extra_map_file_text) (bfd *, struct bfd_link_info *, FILE *); + /* Called when printing the map file, in case there are + emulation-specific sections for it, before most of the file is + printed. */ + void (*extra_early_map_file_text) + (bfd *, struct bfd_link_info *, FILE *); + /* If this returns true, we emit CTF as early as possible: if false, we emit CTF once the strtab and symtab are laid out. */ int (*emit_ctf_early) diff --git a/ld/ldlang.c b/ld/ldlang.c index 1733f8e65c4..d0f7b408591 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -521,6 +521,11 @@ compare_section (sort_type sort, asection *asec, asection *bsec) case by_alignment: ret = bfd_section_alignment (bsec) - bfd_section_alignment (asec); break; + + case by_overlay: + ret = bfd_get_section_overlay_sort_data (bsec->owner, bsec, &link_info) + - bfd_get_section_overlay_sort_data (asec->owner, asec, &link_info); + break; } return ret; @@ -1390,6 +1395,12 @@ lang_memory_region_lookup (const char *const name, bool create) return new_region; } +lang_memory_region_type * +get_lang_memory_region_list (void) +{ + return lang_memory_region_list; +} + void lang_memory_region_alias (const char *alias, const char *region_name) { @@ -2267,6 +2278,9 @@ lang_map (void) lang_memory_region_type *m; bool dis_header_printed = false; + ldemul_extra_early_map_file_text (link_info.output_bfd, &link_info, + config.map_file); + LANG_FOR_EACH_INPUT_STATEMENT (file) { asection *s; @@ -4134,6 +4148,18 @@ check_input_sections } } +static void +set_overlay_sort_default (lang_statement_union_type *s) +{ + struct wildcard_list *sec; + + for (; s != NULL; s = s->header.next) + if (s->header.type == lang_wild_statement_enum) + for (sec = s->wild_statement.section_list; sec != NULL; + sec = sec->next) + sec->spec.sorted = by_overlay; +} + /* Update wildcard statements if needed. */ static void @@ -4147,6 +4173,12 @@ update_wild_statements (lang_statement_union_type *s) FAIL (); case none: + /* The case of no user provided default, set the .ovlgrps output section + to always use by_overlay sorting. */ + for (; s != NULL; s = s->header.next) + if (s->header.type == lang_output_section_statement_enum) + if (!strcmp (s->output_section_statement.name, ".ovlgrps")) + set_overlay_sort_default (s->output_section_statement.children.head); break; case by_name: @@ -5147,6 +5179,11 @@ print_wild_statement (lang_wild_statement_type *w, minfo ("SORT_BY_INIT_PRIORITY("); closing_paren = 1; break; + + case by_overlay: + minfo ("SORT_BY_OVERLAY("); + closing_paren = 1; + break; } if (sec->spec.exclude_name_list != NULL) @@ -5442,6 +5479,17 @@ size_input_section /* Remember where in the output section this input section goes. */ i->output_offset = dot - o->vma; + /* FIXME: Where to put this? */ + /* If the section is a target-specific alignment section, size it + accordingly. */ + if (!strncmp (i->name, ".ovlinput.__internal.padding.", + strlen (".ovlinput.__internal.padding."))) + { + i->size = align_power (dot, 9) - dot; + if (i->size < 4 /*CRC_SZ*/) + i->size += 512; + } + /* Mark how big the output section must be to contain this now. */ dot += TO_ADDR (i->size); if (!(o->flags & SEC_FIXED_SIZE)) diff --git a/ld/ldlang.h b/ld/ldlang.h index 95f6e468b30..5c01e311112 100644 --- a/ld/ldlang.h +++ b/ld/ldlang.h @@ -538,6 +538,8 @@ extern void lang_finish (void); extern lang_memory_region_type * lang_memory_region_lookup (const char * const, bool); +extern lang_memory_region_type * get_lang_memory_region_list + (void); extern void lang_memory_region_alias (const char *, const char *); extern void lang_map diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp index 272424b33e3..a8cfcc9fb3e 100644 --- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp +++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp @@ -37,6 +37,12 @@ proc riscv_choose_lp64_emul {} { return "elf64lriscv" } +proc riscv_get_testdir {} { + global srcdir + global subdir + return $srcdir/$subdir +} + # target: rv32 or rv64. # output: Which output you want? (exe, pie, .so) proc run_dump_test_ifunc { name target output} { @@ -177,6 +183,27 @@ if [istarget "riscv*-*-*"] { "-march=rv64i -mabi=lp64" {weakref64.s} \ {{objdump -d weakref64.d}} "weakref64"]] + run_dump_test "overlay-assign-dead" + run_dump_test "overlay-assign-group0" + run_dump_test "overlay-assign-missing" + run_dump_test "overlay-assign-non-contiguous" + run_dump_test "overlay-autoassign-01" + run_dump_test "overlay-autoassign-02" + run_dump_test "overlay-autoassign-dead" + run_dump_test "overlay-invalid-group-number" + run_dump_test "overlay-many-func-group" + run_dump_test "overlay-max-group-number" + run_dump_test "overlay-max-size-group" + run_dump_test "overlay-multigroup-01" + run_dump_test "overlay-multigroup-02" + run_dump_test "overlay-no-grouping-file" + run_dump_test "overlay-partial-assign" + run_dump_test "overlay-plt" + run_dump_test "overlay-relax-01" + run_dump_test "overlay-relax-02" + run_dump_test "overlay-relax-multigroup" + run_dump_test "overlay-symbol-not-in-ovlinput" + # The following tests require shared library support. if ![check_shared_lib_support] { return diff --git a/ld/testsuite/ld-riscv-elf/overlay-assign-dead.csv b/ld/testsuite/ld-riscv-elf/overlay-assign-dead.csv new file mode 100644 index 00000000000..71b68600b66 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-assign-dead.csv @@ -0,0 +1 @@ +dead_symbol,3 diff --git a/ld/testsuite/ld-riscv-elf/overlay-assign-dead.d b/ld/testsuite/ld-riscv-elf/overlay-assign-dead.d new file mode 100644 index 00000000000..86e26d6ca1c --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-assign-dead.d @@ -0,0 +1,12 @@ +#source: overlay-dead-symbol.s +#as: -march=rv32i -mabi=ilp32 +#ld: -T overlay.ld --grouping-file [riscv_get_testdir]/overlay-assign-dead.csv -m[riscv_choose_ilp32_emul] -relax -gc-sections +#objdump: -d + +.*:[ ]+file format .* + + +Disassembly of section .text: + +00000000 <_start>: + 0: 00008067 ret diff --git a/ld/testsuite/ld-riscv-elf/overlay-assign-group0.csv b/ld/testsuite/ld-riscv-elf/overlay-assign-group0.csv new file mode 100644 index 00000000000..2e3cf5b018d --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-assign-group0.csv @@ -0,0 +1 @@ +apple,0 diff --git a/ld/testsuite/ld-riscv-elf/overlay-assign-group0.d b/ld/testsuite/ld-riscv-elf/overlay-assign-group0.d new file mode 100644 index 00000000000..3f96513a828 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-assign-group0.d @@ -0,0 +1,4 @@ +#source: overlay-trivial.s +#as: -march=rv32i -mabi=ilp32 +#ld: -T overlay.ld --grouping-file [riscv_get_testdir]/overlay-assign-group0.csv -m[riscv_choose_ilp32_emul] -relax -gc-sections +#error: .*Invalid group id.*0.*in overlay grouping file.* diff --git a/ld/testsuite/ld-riscv-elf/overlay-assign-missing.csv b/ld/testsuite/ld-riscv-elf/overlay-assign-missing.csv new file mode 100644 index 00000000000..c5c6c8682e4 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-assign-missing.csv @@ -0,0 +1 @@ +missing_function,23 diff --git a/ld/testsuite/ld-riscv-elf/overlay-assign-missing.d b/ld/testsuite/ld-riscv-elf/overlay-assign-missing.d new file mode 100644 index 00000000000..ecd409ffce4 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-assign-missing.d @@ -0,0 +1,31 @@ +#source: overlay-trivial.s +#as: -march=rv32i -mabi=ilp32 +#ld: -T overlay.ld --grouping-file [riscv_get_testdir]/overlay-assign-missing.csv -m[riscv_choose_ilp32_emul] -relax -gc-sections +#objdump: -d + +.*:[ ]+file format .* + + +Disassembly of section .text: + +00000000 <_start>: + 0: 000000b7 lui ra,0x0 + 4: 00308093 addi ra,ra,3.* + +Disassembly of section .ovlgrps: + +00800000 <__OVERLAY_GROUP_TABLE_START>: + 800000: 00010000 00000002.* + +00800008 <__OVERLAY_MULTIGROUP_TABLE_END>: + ... + 8001fc: feef78de.* + +00800200 : + 800200: 00008067 ret + 800204: 0001.* + 800206: 0001.* +#... + 8003f8: 0001.* + 8003fa: 0001.* +#... diff --git a/ld/testsuite/ld-riscv-elf/overlay-assign-non-contiguous.csv b/ld/testsuite/ld-riscv-elf/overlay-assign-non-contiguous.csv new file mode 100644 index 00000000000..187827ffac7 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-assign-non-contiguous.csv @@ -0,0 +1,6 @@ +apple,5 +banana,8 +duck,11 +elephant,12 +cabbage,45 +food,1 diff --git a/ld/testsuite/ld-riscv-elf/overlay-assign-non-contiguous.d b/ld/testsuite/ld-riscv-elf/overlay-assign-non-contiguous.d new file mode 100644 index 00000000000..7580c69a33a --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-assign-non-contiguous.d @@ -0,0 +1,89 @@ +#source: overlay-many-funcs.s +#as: -march=rv32i -mabi=ilp32 +#ld: -T overlay.ld --grouping-file [riscv_get_testdir]/overlay-assign-non-contiguous.csv -m[riscv_choose_ilp32_emul] -relax -gc-sections +#objdump: -d + +.*:[ ]+file format .* + + +Disassembly of section .text: + +00000000 <_start>: + 0: 000000b7 lui ra,0x0 + 4: 00b08093 addi ra,ra,11.* + 8: 000000b7 lui ra,0x0 + c: 01108093 addi ra,ra,17.* + 10: 000000b7 lui ra,0x0 + 14: 05b08093 addi ra,ra,91.* + 18: 000000b7 lui ra,0x0 + 1c: 01708093 addi ra,ra,23.* + 20: 000000b7 lui ra,0x0 + 24: 01908093 addi ra,ra,25.* + 28: 000000b7 lui ra,0x0 + 2c: 00308093 addi ra,ra,3.* + +Disassembly of section .ovlgrps: + +00800000 <__OVERLAY_GROUP_TABLE_START>: + 800000: 00010000 00020002 00020002 00030003.* + 800010: 00040003 00040004 00060005 00060006.* + 800020: 00060006 00060006 00060006 00060006.* + 800030: 00060006 00060006 00060006 00060006.* + 800040: 00060006 00060006 00060006 00060006.* + 800050: 00060006 00060006 00060006 00000007.* + +00800060 <__OVERLAY_MULTIGROUP_TABLE_END>: + ... + 8001fc: 652501e5.* + +00800200 : + 800200: 00008067 ret + 800204: 0001.* + 800206: 0001.* +#... + 8003f8: 0001.* + 8003fa: 0001.* +#... + +00800400 : + 800400: 00008067 ret + 800404: 0005.* + 800406: 0005.* +#... + 8005f8: 0005.* + 8005fa: 0005.* +#... + +00800600 : + 800600: 00008067 ret + 800604: 0008.* + 800606: 0008.* +#... + 8007f8: 0008.* + 8007fa: 0008.* +#... + +00800800 : + 800800: 00008067 ret + 800804: 000b000b.* +#... + 8009f8: 000b000b.* +#... + +00800a00 : + 800a00: 00008067 ret + 800a04: 000c.* + 800a06: 000c.* +#... + 800bf8: 000c.* + 800bfa: 000c.* +#... + +00800c00 : + 800c00: 00008067 ret + 800c04: 002d.* + 800c06: 002d.* +#... + 800df8: 002d.* + 800dfa: 002d.* +#... diff --git a/ld/testsuite/ld-riscv-elf/overlay-autoassign-01.d b/ld/testsuite/ld-riscv-elf/overlay-autoassign-01.d new file mode 100644 index 00000000000..9f1fcd7185d --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-autoassign-01.d @@ -0,0 +1,31 @@ +#source: overlay-trivial.s +#as: -march=rv32i -mabi=ilp32 +#ld: -T overlay.ld -m[riscv_choose_ilp32_emul] -relax -gc-sections +#objdump: -d + +.*:[ ]+file format .* + + +Disassembly of section .text: + +00000000 <_start>: + 0: 000000b7 lui ra,0x0 + 4: 00308093 addi ra,ra,3.* + +Disassembly of section .ovlgrps: + +00800000 <__OVERLAY_GROUP_TABLE_START>: + 800000: 00010000 00000002.* + +00800008 <__OVERLAY_MULTIGROUP_TABLE_END>: + ... + 8001fc: feef78de.* + +00800200 : + 800200: 00008067 ret + 800204: 0001.* + 800206: 0001.* +#... + 8003f8: 0001.* + 8003fa: 0001.* +#... diff --git a/ld/testsuite/ld-riscv-elf/overlay-autoassign-02.d b/ld/testsuite/ld-riscv-elf/overlay-autoassign-02.d new file mode 100644 index 00000000000..3b2396223be --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-autoassign-02.d @@ -0,0 +1,85 @@ +#source: overlay-many-funcs.s +#as: -march=rv32i -mabi=ilp32 +#ld: -T overlay.ld -m[riscv_choose_ilp32_emul] -relax -gc-sections +#objdump: -d + +.*:[ ]+file format .* + + +Disassembly of section .text: + +00000000 <_start>: + 0: 000000b7 lui ra,0x0 + 4: 00308093 addi ra,ra,3.* + 8: 000000b7 lui ra,0x0 + c: 00508093 addi ra,ra,5.* + 10: 000000b7 lui ra,0x0 + 14: 00708093 addi ra,ra,7.* + 18: 000000b7 lui ra,0x0 + 1c: 00908093 addi ra,ra,9.* + 20: 000000b7 lui ra,0x0 + 24: 00b08093 addi ra,ra,11.* + 28: 000000b7 lui ra,0x0 + 2c: 00d08093 addi ra,ra,13.* + +Disassembly of section .ovlgrps: + +00800000 <__OVERLAY_GROUP_TABLE_START>: + 800000: 00010000 00030002 00050004 00070006.* + 800010: 00000000.* + +00800014 <__OVERLAY_MULTIGROUP_TABLE_END>: + ... + 8001fc: 47b66d24.* + +00800200 : + 800200: 00008067 ret + 800204: 0001.* + 800206: 0001.* +#... + 8003f8: 0001.* + 8003fa: 0001.* +#... + +00800400 : + 800400: 00008067 ret + 800404: 0002.* + 800406: 0002.* +#... + 8005f8: 0002.* + 8005fa: 0002.* +#... + +00800600 : + 800600: 00008067 ret + 800604: 00030003.* +#... + 8007f8: 00030003.* +#... + +00800800 : + 800800: 00008067 ret + 800804: 0004.* + 800806: 0004.* +#... + 8009f8: 0004.* + 8009fa: 0004.* +#... + +00800a00 : + 800a00: 00008067 ret + 800a04: 0005.* + 800a06: 0005.* +#... + 800bf8: 0005.* + 800bfa: 0005.* +#... + +00800c00 : + 800c00: 00008067 ret + 800c04: 0006.* + 800c06: 0006.* +#... + 800df8: 0006.* + 800dfa: 0006.* +#... diff --git a/ld/testsuite/ld-riscv-elf/overlay-autoassign-dead.d b/ld/testsuite/ld-riscv-elf/overlay-autoassign-dead.d new file mode 100644 index 00000000000..4d1e3ee57eb --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-autoassign-dead.d @@ -0,0 +1,12 @@ +#source: overlay-dead-symbol.s +#as: -march=rv32i -mabi=ilp32 +#ld: -T overlay.ld -m[riscv_choose_ilp32_emul] -relax -gc-sections +#objdump: -d + +.*:[ ]+file format .* + + +Disassembly of section .text: + +00000000 <_start>: + 0: 00008067 ret diff --git a/ld/testsuite/ld-riscv-elf/overlay-big-funcs.s b/ld/testsuite/ld-riscv-elf/overlay-big-funcs.s new file mode 100644 index 00000000000..1970f3584b1 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-big-funcs.s @@ -0,0 +1,64 @@ + .section .ovlinput.apple,"ax",@progbits + .global apple + .p2align 2 + .type apple,@function +apple: + .fill 64, 1, 0xa + ret + + .section .ovlinput.banana,"ax",@progbits + .global banana + .p2align 2 + .type banana,@function +banana: + .fill 128, 1, 0xb + ret + + .section .ovlinput.cabbage,"ax",@progbits + .global cabbage + .p2align 2 + .type cabbage,@function +cabbage: + .fill 256, 1, 0xc + ret + + .section .ovlinput.duck,"ax",@progbits + .global duck + .p2align 2 + .type duck,@function +duck: + .fill 512, 1, 0xd + ret + + .section .ovlinput.elephant,"ax",@progbits + .global elephant + .p2align 2 + .type elephant,@function +elephant: + .fill 2048, 1, 0xe + ret + + .section .ovlinput.food,"ax",@progbits + .global food + .p2align 2 + .type food,@function +food: + .fill 2048, 1, 0xf + ret + + .text + .global _start + .type _start,@function +_start: + lui x1, %ovltok_hi(apple) + addi x1, x1, %ovltok_lo(apple) + lui x1, %ovltok_hi(banana) + addi x1, x1, %ovltok_lo(banana) + lui x1, %ovltok_hi(cabbage) + addi x1, x1, %ovltok_lo(cabbage) + lui x1, %ovltok_hi(duck) + addi x1, x1, %ovltok_lo(duck) + lui x1, %ovltok_hi(elephant) + addi x1, x1, %ovltok_lo(elephant) + lui x1, %ovltok_hi(food) + addi x1, x1, %ovltok_lo(food) diff --git a/ld/testsuite/ld-riscv-elf/overlay-dead-symbol.s b/ld/testsuite/ld-riscv-elf/overlay-dead-symbol.s new file mode 100644 index 00000000000..b7ed395bed7 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-dead-symbol.s @@ -0,0 +1,12 @@ + .section .ovlinput.dead_symbol,"ax",@progbits + .global dead_symbol + .p2align 2 + .type dead_symbol,@function +dead_symbol: + ret + + .text + .global _start + .type _start,@function +_start: + ret diff --git a/ld/testsuite/ld-riscv-elf/overlay-invalid-group-number.csv b/ld/testsuite/ld-riscv-elf/overlay-invalid-group-number.csv new file mode 100644 index 00000000000..598eaafa47a --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-invalid-group-number.csv @@ -0,0 +1 @@ +apple,65536 diff --git a/ld/testsuite/ld-riscv-elf/overlay-invalid-group-number.d b/ld/testsuite/ld-riscv-elf/overlay-invalid-group-number.d new file mode 100644 index 00000000000..ff532591a41 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-invalid-group-number.d @@ -0,0 +1,4 @@ +#source: overlay-trivial.s +#as: -march=rv32i -mabi=ilp32 +#ld: -T overlay.ld --grouping-file [riscv_get_testdir]/overlay-invalid-group-number.csv -m[riscv_choose_ilp32_emul] -relax -gc-sections +#error: .*Invalid group id.*in overlay grouping file: group number greater than maximum \(65535\)\..* diff --git a/ld/testsuite/ld-riscv-elf/overlay-many-func-group.csv b/ld/testsuite/ld-riscv-elf/overlay-many-func-group.csv new file mode 100644 index 00000000000..216484713a3 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-many-func-group.csv @@ -0,0 +1,6 @@ +apple,1 +banana,1 +cabbage,1 +duck,4 +elephant,4 +food,2 diff --git a/ld/testsuite/ld-riscv-elf/overlay-many-func-group.d b/ld/testsuite/ld-riscv-elf/overlay-many-func-group.d new file mode 100644 index 00000000000..be71dbde819 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-many-func-group.d @@ -0,0 +1,68 @@ +#source: overlay-many-funcs.s +#as: -march=rv32i -mabi=ilp32 +#ld: -T overlay.ld --grouping-file [riscv_get_testdir]/overlay-many-func-group.csv -m[riscv_choose_ilp32_emul] -relax -gc-sections +#objdump: -d + +.*:[ ]+file format .* + + +Disassembly of section .text: + +00000000 <_start>: + 0: 000000b7 lui ra,0x0 + 4: 00308093 addi ra,ra,3.* + 8: 000200b7 lui ra,0x20 + c: 00308093 addi ra,ra,3.* + 10: 000400b7 lui ra,0x40 + 14: 00308093 addi ra,ra,3.* + 18: 000000b7 lui ra,0x0 + 1c: 00908093 addi ra,ra,9.* + 20: 000200b7 lui ra,0x20 + 24: 00908093 addi ra,ra,9.* + 28: 000000b7 lui ra,0x0 + 2c: 00508093 addi ra,ra,5.* + +Disassembly of section .ovlgrps: + +00800000 <__OVERLAY_GROUP_TABLE_START>: + 800000: 00010000 00030002 00040003 00000000.* + +00800010 <__OVERLAY_MULTIGROUP_TABLE_END>: + ... + 8001fc: 5a03df8d.* + +00800200 : + 800200: 00008067 ret + +00800204 : + 800204: 00008067 ret + +00800208 : + 800208: 00008067 ret + 80020c: 0001.* + 80020e: 0001.* +#... + 8003f8: 0001.* + 8003fa: 0001.* +#... + +00800400 : + 800400: 00008067 ret + 800404: 0002.* + 800406: 0002.* +#... + 8005f8: 0002.* + 8005fa: 0002.* +#... + +00800600 : + 800600: 00008067 ret + +00800604 : + 800604: 00008067 ret + 800608: 0004.* + 80060a: 0004.* +#... + 8007f8: 0004.* + 8007fa: 0004.* +#... diff --git a/ld/testsuite/ld-riscv-elf/overlay-many-funcs.s b/ld/testsuite/ld-riscv-elf/overlay-many-funcs.s new file mode 100644 index 00000000000..03413507b9c --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-many-funcs.s @@ -0,0 +1,58 @@ + .section .ovlinput.apple,"ax",@progbits + .global apple + .p2align 2 + .type apple,@function +apple: + ret + + .section .ovlinput.banana,"ax",@progbits + .global banana + .p2align 2 + .type banana,@function +banana: + ret + + .section .ovlinput.cabbage,"ax",@progbits + .global cabbage + .p2align 2 + .type cabbage,@function +cabbage: + ret + + .section .ovlinput.duck,"ax",@progbits + .global duck + .p2align 2 + .type duck,@function +duck: + ret + + .section .ovlinput.elephant,"ax",@progbits + .global elephant + .p2align 2 + .type elephant,@function +elephant: + ret + + .section .ovlinput.food,"ax",@progbits + .global food + .p2align 2 + .type food,@function +food: + ret + + .text + .global _start + .type _start,@function +_start: + lui x1, %ovltok_hi(apple) + addi x1, x1, %ovltok_lo(apple) + lui x1, %ovltok_hi(banana) + addi x1, x1, %ovltok_lo(banana) + lui x1, %ovltok_hi(cabbage) + addi x1, x1, %ovltok_lo(cabbage) + lui x1, %ovltok_hi(duck) + addi x1, x1, %ovltok_lo(duck) + lui x1, %ovltok_hi(elephant) + addi x1, x1, %ovltok_lo(elephant) + lui x1, %ovltok_hi(food) + addi x1, x1, %ovltok_lo(food) diff --git a/ld/testsuite/ld-riscv-elf/overlay-max-group-number.csv b/ld/testsuite/ld-riscv-elf/overlay-max-group-number.csv new file mode 100644 index 00000000000..5d3ddd54153 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-max-group-number.csv @@ -0,0 +1 @@ +apple,65535 diff --git a/ld/testsuite/ld-riscv-elf/overlay-max-group-number.d b/ld/testsuite/ld-riscv-elf/overlay-max-group-number.d new file mode 100644 index 00000000000..6faf7be43f1 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-max-group-number.d @@ -0,0 +1,33 @@ +#source: overlay-trivial.s +#as: -march=rv32i -mabi=ilp32 +#ld: -T overlay.ld --grouping-file [riscv_get_testdir]/overlay-max-group-number.csv -m[riscv_choose_ilp32_emul] -relax -gc-sections +#objdump: -d + +.*:[ ]+file format .* + + +Disassembly of section .text: + +00000000 <_start>: + 0: 000200b7 lui ra,0x20 + 4: fff08093 addi ra,ra,-1.* + +Disassembly of section .ovlgrps: + +00800000 <__OVERLAY_GROUP_TABLE_START>: + 800000: 01010000 01010101 01010101 01010101.* +#... + 81fff0: 01010101 01010101 01010101 01010101.* + 820000: 00000102.* + +00820004 <__OVERLAY_MULTIGROUP_TABLE_END>: + ... + 8201fc: a720db76.* + +00820200 : + 820200: 00008067 ret + 820204: ffff.* +#... + 8203f8: ffff.* + 8203fa: ffff.* +#... diff --git a/ld/testsuite/ld-riscv-elf/overlay-max-size-group.csv b/ld/testsuite/ld-riscv-elf/overlay-max-size-group.csv new file mode 100644 index 00000000000..b6c26ce3e58 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-max-size-group.csv @@ -0,0 +1,6 @@ +apple,1 +banana,1 +cabbage,1 +duck,2 +elephant,2 +food,2 diff --git a/ld/testsuite/ld-riscv-elf/overlay-max-size-group.d b/ld/testsuite/ld-riscv-elf/overlay-max-size-group.d new file mode 100644 index 00000000000..3a936feb12f --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-max-size-group.d @@ -0,0 +1,4 @@ +#source: overlay-big-funcs.s +#as: -march=rv32i -mabi=ilp32 +#ld: -T overlay.ld --grouping-file [riscv_get_testdir]/overlay-max-size-group.csv -m[riscv_choose_ilp32_emul] -relax -gc-sections +#error: .*overlay group .* exceeds maximum group size.* diff --git a/ld/testsuite/ld-riscv-elf/overlay-multigroup-01.csv b/ld/testsuite/ld-riscv-elf/overlay-multigroup-01.csv new file mode 100644 index 00000000000..42d808412f1 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-multigroup-01.csv @@ -0,0 +1 @@ +apple,1,2,3,4,5,6,7,8,9,10 diff --git a/ld/testsuite/ld-riscv-elf/overlay-multigroup-01.d b/ld/testsuite/ld-riscv-elf/overlay-multigroup-01.d new file mode 100644 index 00000000000..14cfa091eb8 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-multigroup-01.d @@ -0,0 +1,114 @@ +#source: overlay-trivial.s +#as: -march=rv32i -mabi=ilp32 +#ld: -T overlay.ld --grouping-file [riscv_get_testdir]/overlay-multigroup-01.csv -m[riscv_choose_ilp32_emul] -relax -gc-sections +#objdump: -d + +.*:[ ]+file format .* + + +Disassembly of section .text: + +00000000 <_start>: + 0: 800000b7 lui ra,0x80000 + 4: 00108093 addi ra,ra,1.* + +Disassembly of section .ovlgrps: + +00800000 <__OVERLAY_GROUP_TABLE_START>: + 800000: 00010000 00030002 00050004 00070006.* + 800010: 00090008 000b000a 00000000.* + +0080001c <__OVERLAY_MULTIGROUP_TABLE_START>: + 80001c: 00000003 00000005 00000007 00000009.* + 80002c: 0000000b 0000000d 0000000f 00000011.* + 80003c: 00000013 00000015 00000000.* + +00800048 <__OVERLAY_MULTIGROUP_TABLE_END>: + ... + 8001fc: 1157296b.* + +00800200 : + 800200: 00008067 ret + 800204: 0001.* + 800206: 0001.* +#... + 8003f8: 0001.* + 8003fa: 0001.* +#... + +00800400 : + 800400: 00008067 ret + 800404: 0002.* + 800406: 0002.* +#... + 8005f8: 0002.* + 8005fa: 0002.* +#... + +00800600 : + 800600: 00008067 ret + 800604: 00030003.* +#... + 8007f8: 00030003.* +#... + +00800800 : + 800800: 00008067 ret + 800804: 0004.* + 800806: 0004.* +#... + 8009f8: 0004.* + 8009fa: 0004.* +#... + +00800a00 : + 800a00: 00008067 ret + 800a04: 0005.* + 800a06: 0005.* +#... + 800bf8: 0005.* + 800bfa: 0005.* +#... + +00800c00 : + 800c00: 00008067 ret + 800c04: 0006.* + 800c06: 0006.* +#... + 800df8: 0006.* + 800dfa: 0006.* +#... + +00800e00 : + 800e00: 00008067 ret + 800e04: 00070007.* +#... + 800ff8: 00070007.* +#... + +00801000 : + 801000: 00008067 ret + 801004: 0008.* + 801006: 0008.* +#... + 8011f8: 0008.* + 8011fa: 0008.* +#... + +00801200 : + 801200: 00008067 ret + 801204: 0009.* + 801206: 0009.* +#... + 8013f8: 0009.* + 8013fa: 0009.* +#... + +00801400 : + 801400: 00008067 ret + 801404: 000a.* + 801406: 000a.* +#... + 8015f8: 000a.* + 8015fa: 000a.* +#... diff --git a/ld/testsuite/ld-riscv-elf/overlay-multigroup-02.csv b/ld/testsuite/ld-riscv-elf/overlay-multigroup-02.csv new file mode 100644 index 00000000000..e1bf0c5d2b5 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-multigroup-02.csv @@ -0,0 +1,6 @@ +apple,1,2 +banana,2,3 +cabbage,3,4,5,6 +duck,5,6 +elephant,5,6,23 +food,1,2,3,5,22,23,24 diff --git a/ld/testsuite/ld-riscv-elf/overlay-multigroup-02.d b/ld/testsuite/ld-riscv-elf/overlay-multigroup-02.d new file mode 100644 index 00000000000..25502906407 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-multigroup-02.d @@ -0,0 +1,154 @@ +#source: overlay-many-funcs.s +#as: -march=rv32i -mabi=ilp32 +#ld: -T overlay.ld --grouping-file [riscv_get_testdir]/overlay-multigroup-02.csv -m[riscv_choose_ilp32_emul] -relax -gc-sections +#objdump: -d + +.*:[ ]+file format .* + + +Disassembly of section .text: + +00000000 <_start>: + 0: 800000b7 lui ra,0x80000 + 4: 00108093 addi ra,ra,1.* + 8: 800000b7 lui ra,0x80000 + c: 00708093 addi ra,ra,7.* + 10: 800000b7 lui ra,0x80000 + 14: 00d08093 addi ra,ra,13.* + 18: 800000b7 lui ra,0x80000 + 1c: 01708093 addi ra,ra,23.* + 20: 800000b7 lui ra,0x80000 + 24: 01d08093 addi ra,ra,29.* + 28: 800000b7 lui ra,0x80000 + 2c: 02508093 addi ra,ra,37.* + +Disassembly of section .ovlgrps: + +00800000 <__OVERLAY_GROUP_TABLE_START>: + 800000: 00010000 00030002 00050004 00070006.* + 800010: 00070007 00070007 00070007 00070007.* + 800020: 00070007 00070007 00070007 00080007.* + 800030: 000a0009 00000000.* + +00800038 <__OVERLAY_MULTIGROUP_TABLE_START>: + 800038: 00000003 00000005 00000000 00020005.* + 800048: 00000007 00000000 00020007 00000009.* + 800058: 0000000b 0000000d 00000000 0002000b.* + 800068: 0002000d 00000000 0004000b 0004000d.* + 800078: 0000002f 00000000 00020003 00040005.* + 800088: 00040007 0006000b 0000002d 0002002f.* + 800098: 00000031 00000000.* + +008000a0 <__OVERLAY_MULTIGROUP_TABLE_END>: + ... + 8001fc: b8df17d7.* + +00800200 : + 800200: 00008067 ret + +00800204 : + 800204: 00008067 ret + 800208: 0001.* + 80020a: 0001.* +#... + 8003f8: 0001.* + 8003fa: 0001.* +#... + +00800400 : + 800400: 00008067 ret + +00800404 : + 800404: 00008067 ret + +00800408 : + 800408: 00008067 ret + 80040c: 0002.* + 80040e: 0002.* +#... + 8005f8: 0002.* + 8005fa: 0002.* +#... + +00800600 : + 800600: 00008067 ret + +00800604 : + 800604: 00008067 ret + +00800608 : + 800608: 00008067 ret + 80060c: 00030003.* +#... + 8007f8: 00030003.* +#... + +00800800 : + 800800: 00008067 ret + 800804: 0004.* + 800806: 0004.* +#... + 8009f8: 0004.* + 8009fa: 0004.* +#... + +00800a00 : + 800a00: 00008067 ret + +00800a04 : + 800a04: 00008067 ret + +00800a08 : + 800a08: 00008067 ret + +00800a0c : + 800a0c: 00008067 ret + 800a10: 0005.* + 800a12: 0005.* +#... + 800bf8: 0005.* + 800bfa: 0005.* +#... + +00800c00 : + 800c00: 00008067 ret + +00800c04 : + 800c04: 00008067 ret + +00800c08 : + 800c08: 00008067 ret + 800c0c: 0006.* + 800c0e: 0006.* +#... + 800df8: 0006.* + 800dfa: 0006.* +#... + +00800e00 : + 800e00: 00008067 ret + 800e04: 0016.* + 800e06: 0016.* +#... + 800ff8: 0016.* + 800ffa: 0016.* +#... + +00801000 : + 801000: 00008067 ret + +00801004 : + 801004: 00008067 ret + 801008: 00170017.* +#... + 8011f8: 00170017.* +#... + +00801200 : + 801200: 00008067 ret + 801204: 0018.* + 801206: 0018.* +#... + 8013f8: 0018.* + 8013fa: 0018.* +#... diff --git a/ld/testsuite/ld-riscv-elf/overlay-no-grouping-file.d b/ld/testsuite/ld-riscv-elf/overlay-no-grouping-file.d new file mode 100644 index 00000000000..29613ce47f9 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-no-grouping-file.d @@ -0,0 +1,4 @@ +#source: overlay-trivial.s +#as: -march=rv32i -mabi=ilp32 +#ld: -T overlay.ld --grouping-file overlay-non-existent-file.csv -m[riscv_choose_ilp32_emul] -relax -gc-sections +#error: .*cannot open grouping file.*overlay-non-existent-file\.csv diff --git a/ld/testsuite/ld-riscv-elf/overlay-partial-assign.csv b/ld/testsuite/ld-riscv-elf/overlay-partial-assign.csv new file mode 100644 index 00000000000..b035c8c021f --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-partial-assign.csv @@ -0,0 +1,3 @@ +banana,1 +elephant,3 +food,5 diff --git a/ld/testsuite/ld-riscv-elf/overlay-partial-assign.d b/ld/testsuite/ld-riscv-elf/overlay-partial-assign.d new file mode 100644 index 00000000000..89591016d81 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-partial-assign.d @@ -0,0 +1,85 @@ +#source: overlay-many-funcs.s +#as: -march=rv32i -mabi=ilp32 +#ld: -T overlay.ld --grouping-file [riscv_get_testdir]/overlay-partial-assign.csv -m[riscv_choose_ilp32_emul] -relax -gc-sections +#objdump: -d + +.*:[ ]+file format .* + + +Disassembly of section .text: + +00000000 <_start>: + 0: 000000b7 lui ra,0x0 + 4: 00508093 addi ra,ra,5.* + 8: 000000b7 lui ra,0x0 + c: 00308093 addi ra,ra,3.* + 10: 000000b7 lui ra,0x0 + 14: 00908093 addi ra,ra,9.* + 18: 000000b7 lui ra,0x0 + 1c: 00d08093 addi ra,ra,13.* + 20: 000000b7 lui ra,0x0 + 24: 00708093 addi ra,ra,7.* + 28: 000000b7 lui ra,0x0 + 2c: 00b08093 addi ra,ra,11.* + +Disassembly of section .ovlgrps: + +00800000 <__OVERLAY_GROUP_TABLE_START>: + 800000: 00010000 00030002 00050004 00070006.* + 800010: 00000000.* + +00800014 <__OVERLAY_MULTIGROUP_TABLE_END>: + ... + 8001fc: 47b66d24.* + +00800200 : + 800200: 00008067 ret + 800204: 0001.* + 800206: 0001.* +#... + 8003f8: 0001.* + 8003fa: 0001.* +#... + +00800400 : + 800400: 00008067 ret + 800404: 0002.* + 800406: 0002.* +#... + 8005f8: 0002.* + 8005fa: 0002.* +#... + +00800600 : + 800600: 00008067 ret + 800604: 00030003.* +#... + 8007f8: 00030003.* +#... + +00800800 : + 800800: 00008067 ret + 800804: 0004.* + 800806: 0004.* +#... + 8009f8: 0004.* + 8009fa: 0004.* +#... + +00800a00 : + 800a00: 00008067 ret + 800a04: 0005.* + 800a06: 0005.* +#... + 800bf8: 0005.* + 800bfa: 0005.* +#... + +00800c00 : + 800c00: 00008067 ret + 800c04: 0006.* + 800c06: 0006.* +#... + 800df8: 0006.* + 800dfa: 0006.* +#... diff --git a/ld/testsuite/ld-riscv-elf/overlay-plt.csv b/ld/testsuite/ld-riscv-elf/overlay-plt.csv new file mode 100644 index 00000000000..0eeeac18995 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-plt.csv @@ -0,0 +1,4 @@ +apple,3 +banana,3 +cabbage,5 +duck,5,3 diff --git a/ld/testsuite/ld-riscv-elf/overlay-plt.d b/ld/testsuite/ld-riscv-elf/overlay-plt.d new file mode 100644 index 00000000000..d18241398f7 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-plt.d @@ -0,0 +1,72 @@ +#source: overlay-plt.s +#as: -march=rv32i -mabi=ilp32 +#ld: -T overlay.ld --grouping-file [riscv_get_testdir]/overlay-plt.csv -m[riscv_choose_ilp32_emul] -relax -gc-sections +#objdump: -d + +.*:[ ]+file format .* + + +Disassembly of section .text: + +00000000 <_start>: + 0: 000000b7 lui ra,0x0 + 4: 02008093 addi ra,ra,32.* + 8: 000000b7 lui ra,0x0 + c: 02c08093 addi ra,ra,44.* + 10: 000000b7 lui ra,0x0 + 14: 03808093 addi ra,ra,56.* + 18: 000000b7 lui ra,0x0 + 1c: 04408093 addi ra,ra,68.* + +Disassembly of section .ovlplt: + +00000020 <.ovlplt>: + 20: 08000f37 lui t5,0x8000 + 24: 007f0f13 addi t5,t5,7.* + 28: 000f8067 jr t6 + 2c: 08000f37 lui t5,0x8000 + 30: 00bf0f13 addi t5,t5,11.* + 34: 000f8067 jr t6 + 38: 08020f37 lui t5,0x8020 + 3c: 007f0f13 addi t5,t5,7.* + 40: 000f8067 jr t6 + 44: 88000f37 lui t5,0x88000 + 48: 001f0f13 addi t5,t5,1.* + 4c: 000f8067 jr t6 + +Disassembly of section .ovlgrps: + +00800000 <__OVERLAY_GROUP_TABLE_START>: + 800000: 00010000 00010001 00020002 00000003.* + +00800010 <__OVERLAY_MULTIGROUP_TABLE_START>: + 800010: 0002000b 00040007 00000000.* + +0080001c <__OVERLAY_MULTIGROUP_TABLE_END>: + ... + 8001fc: 56ee8bfb.* + +00800200 : + 800200: 00008067 ret + +00800204 : + 800204: 00008067 ret + +00800208 : + 800208: 00008067 ret + 80020c: 00030003.* +#... + 8003f8: 00030003.* +#... + +00800400 : + 800400: 00008067 ret + +00800404 : + 800404: 00008067 ret + 800408: 0005.* + 80040a: 0005.* +#... + 8005f8: 0005.* + 8005fa: 0005.* +#... diff --git a/ld/testsuite/ld-riscv-elf/overlay-plt.s b/ld/testsuite/ld-riscv-elf/overlay-plt.s new file mode 100644 index 00000000000..d3bdc5c6ade --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-plt.s @@ -0,0 +1,40 @@ + .section .ovlinput.apple,"ax",@progbits + .global apple + .p2align 2 + .type apple,@function +apple: + ret + + .section .ovlinput.banana,"ax",@progbits + .global banana + .p2align 2 + .type banana,@function +banana: + ret + + .section .ovlinput.cabbage,"ax",@progbits + .global cabbage + .p2align 2 + .type cabbage,@function +cabbage: + ret + + .section .ovlinput.duck,"ax",@progbits + .global duck + .p2align 2 + .type duck,@function +duck: + ret + + .text + .global _start + .type _start,@function +_start: + lui x1, %ovlplt_hi(apple) + addi x1, x1, %ovlplt_lo(apple) + lui x1, %ovlplt_hi(cabbage) + addi x1, x1, %ovlplt_lo(cabbage) + lui x1, %ovlplt_hi(banana) + addi x1, x1, %ovlplt_lo(banana) + lui x1, %ovlplt_hi(duck) + addi x1, x1, %ovlplt_lo(duck) diff --git a/ld/testsuite/ld-riscv-elf/overlay-relax-01.d b/ld/testsuite/ld-riscv-elf/overlay-relax-01.d new file mode 100644 index 00000000000..0a400e9bfd1 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-relax-01.d @@ -0,0 +1,19 @@ +#source: overlay-relax.s +#as: -march=rv32ic -mabi=ilp32 +#ld: -T overlay.ld -m[riscv_choose_ilp32_emul] -relax -gc-sections +#objdump: -d + +.*:[ ]+file format .* + +#... + +Disassembly of section \.ovlgrps: + +.* <__OVERLAY_GROUP_TABLE_START>: +#... + +.* <__OVERLAY_MULTIGROUP_TABLE_END>: +#... + +.* : +#... diff --git a/ld/testsuite/ld-riscv-elf/overlay-relax-02.csv b/ld/testsuite/ld-riscv-elf/overlay-relax-02.csv new file mode 100644 index 00000000000..172e005d0dc --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-relax-02.csv @@ -0,0 +1,3 @@ +apple,1 +banana,1 +cabbage,2 diff --git a/ld/testsuite/ld-riscv-elf/overlay-relax-02.d b/ld/testsuite/ld-riscv-elf/overlay-relax-02.d new file mode 100644 index 00000000000..eb823593ea3 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-relax-02.d @@ -0,0 +1,19 @@ +#source: overlay-relax.s +#as: -march=rv32ic -mabi=ilp32 +#ld: -T overlay.ld --grouping-file [riscv_get_testdir]/overlay-relax-02.csv -m[riscv_choose_ilp32_emul] -relax -gc-sections +#objdump: -d + +.*:[ ]+file format .* + +#... + +Disassembly of section \.ovlgrps: + +.* <__OVERLAY_GROUP_TABLE_START>: +#... + +.* <__OVERLAY_MULTIGROUP_TABLE_END>: +#... + +.* : +#... diff --git a/ld/testsuite/ld-riscv-elf/overlay-relax-multigroup.csv b/ld/testsuite/ld-riscv-elf/overlay-relax-multigroup.csv new file mode 100644 index 00000000000..d3d498d57bc --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-relax-multigroup.csv @@ -0,0 +1,3 @@ +apple,2,3,4 +banana,3,4,5 +cabbage,5,6,7 diff --git a/ld/testsuite/ld-riscv-elf/overlay-relax-multigroup.d b/ld/testsuite/ld-riscv-elf/overlay-relax-multigroup.d new file mode 100644 index 00000000000..cd1aa75bb51 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-relax-multigroup.d @@ -0,0 +1,19 @@ +#source: overlay-relax.s +#as: -march=rv32ic -mabi=ilp32 +#ld: -T overlay.ld --grouping-file [riscv_get_testdir]/overlay-relax-multigroup.csv -m[riscv_choose_ilp32_emul] -relax -gc-sections +#objdump: -d + +.*:[ ]+file format .* + +#... + +Disassembly of section \.ovlgrps: + +.* <__OVERLAY_GROUP_TABLE_START>: +#... + +.* <__OVERLAY_MULTIGROUP_TABLE_END>: +#... + +.* : +#... diff --git a/ld/testsuite/ld-riscv-elf/overlay-relax.s b/ld/testsuite/ld-riscv-elf/overlay-relax.s new file mode 100644 index 00000000000..d84ba27d38b --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-relax.s @@ -0,0 +1,55 @@ + .section .ovlinput.apple,"ax",@progbits + .global apple + .type apple,@function +apple: + j 0f + j 0f + j 0f + j 0f + j 0f + j 0f + j 0f + j 0f +0: + ret + + .section .ovlinput.banana,"ax",@progbits + .global banana + .type banana,@function +banana: + j 0f + j 0f + j 0f + j 0f + j 0f + j 0f + j 0f + j 0f +0: + ret + + .section .ovlinput.cabbage,"ax",@progbits + .global cabbage + .type cabbage,@function +cabbage: + j 0f + j 0f + j 0f + j 0f + j 0f + j 0f + j 0f + j 0f +0: + ret + + .text + .global _start + .type _start,@function +_start: + lui x1, %ovltok_hi(apple) + addi x1, x1, %ovltok_lo(apple) + lui x1, %ovltok_hi(banana) + addi x1, x1, %ovltok_lo(banana) + lui x1, %ovltok_hi(cabbage) + addi x1, x1, %ovltok_lo(cabbage) diff --git a/ld/testsuite/ld-riscv-elf/overlay-symbol-not-in-ovlinput.d b/ld/testsuite/ld-riscv-elf/overlay-symbol-not-in-ovlinput.d new file mode 100644 index 00000000000..464a9730767 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-symbol-not-in-ovlinput.d @@ -0,0 +1,4 @@ +#source: overlay-symbol-not-in-ovlinput.s +#as: -march=rv32i -mabi=ilp32 +#ld: -T overlay.ld -m[riscv_choose_ilp32_emul] -relax -gc-sections +#error: .*A symbol in section.*\.text.*is referred to by an overlay relocation, but the section does not have a.*\.ovlinput\..*prefix\..* diff --git a/ld/testsuite/ld-riscv-elf/overlay-symbol-not-in-ovlinput.s b/ld/testsuite/ld-riscv-elf/overlay-symbol-not-in-ovlinput.s new file mode 100644 index 00000000000..495dda6334e --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-symbol-not-in-ovlinput.s @@ -0,0 +1,10 @@ + .global apple + .type apple,@function +apple: + ret + + .global _start + .type _start,@function +_start: + lui x1, %ovltok_hi(apple) + addi x1, x1, %ovltok_lo(apple) diff --git a/ld/testsuite/ld-riscv-elf/overlay-trivial.s b/ld/testsuite/ld-riscv-elf/overlay-trivial.s new file mode 100644 index 00000000000..c4d2e941bdb --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay-trivial.s @@ -0,0 +1,12 @@ + .section .ovlinput.apple,"ax",@progbits + .global apple + .type apple,@function +apple: + ret + + .text + .global _start + .type _start,@function +_start: + lui x1, %ovltok_hi(apple) + addi x1, x1, %ovltok_lo(apple) diff --git a/ld/testsuite/ld-riscv-elf/overlay.ld b/ld/testsuite/ld-riscv-elf/overlay.ld new file mode 100644 index 00000000000..eb3a6223b13 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/overlay.ld @@ -0,0 +1,17 @@ +ENTRY(_start) + + +MEMORY { + ovl : ORIGIN = 0x800000, LENGTH = 0x100000 +} + +SECTIONS { + .text : { + *(.text*) + } + .ovlgrps : { + OVERLAY_START_OF_OVERLAYS = .; + *(.ovlinput.*) + OVERLAY_END_OF_OVERLAYS = .; + } >ovl AT>ovl +} -- 2.25.1