[PATCH 1/3] RISC-V: Add support for vendor-specific relocations
Ethan Y. C. Liang
ycl669@andestech.com
Wed Nov 26 08:47:53 GMT 2025
More information about the Binutils mailing list
Wed Nov 26 08:47:53 GMT 2025
- Previous message (by thread): [PATCH 0/3] RISC-V: Vendor relocation framework and XAndesPerf extension
- Next message (by thread): [PATCH 2/3] RISC-V: Refactor branch relaxation state encoding for extensibility
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Support vendor-specific relocations in RISC-V ELF according to the specification [1], allowing relocations in the 192–255 range to be independently defined and used by multiple vendors. The patch is adapted from Alexey's patch [2]. Contributors: Ethan Y. C. Liang <ycl669@andestech.com> Yu-Qi Liu <yuqiliu@andestech.com> bfd/ChangeLog * bfd-in2.h: Add BFD_RELOC_RISCV_VENDOR. * libbfd.h: Likewise. * reloc.c: Likewise. * elfnn-riscv.c: Add support for creating and parsing vendor relocation pairs. * elfxx-riscv.c: Likewise. * elfxx-riscv.h: Likewise. binutils/ChangeLog * readelf.c: Add support for parsing vendor relocation pairs. gas/ChangeLog * config/tc-riscv.c: Add support for creating vendor relocation pairs. include/ChangeLog * elf/riscv.h: Add support for vendor enum, vendor id, and vendor string. [1] https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#nonstandard-relocations-aka-vendor-specific-relocations [2] https://sourceware.org/pipermail/binutils/2025-April/140484.html --- bfd/bfd-in2.h | 1 + bfd/elfnn-riscv.c | 104 +++++++++++++++++--- bfd/elfxx-riscv.c | 221 +++++++++++++++++++++++++++++++++++++++--- bfd/elfxx-riscv.h | 15 ++- bfd/libbfd.h | 1 + bfd/reloc.c | 2 + binutils/readelf.c | 22 ++++- gas/config/tc-riscv.c | 64 ++++++++++++ include/elf/riscv.h | 61 ++++++++++-- 9 files changed, 455 insertions(+), 36 deletions(-) diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 5e7c6ddf1ee..06e78a30a2b 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -5449,6 +5449,7 @@ enum bfd_reloc_code_real BFD_RELOC_RISCV_32_PCREL, BFD_RELOC_RISCV_SET_ULEB128, BFD_RELOC_RISCV_SUB_ULEB128, + BFD_RELOC_RISCV_VENDOR, /* Renesas RL78 Relocations. */ BFD_RELOC_RL78_NEG8, diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c index 09cf7076733..f9e2f3a7597 100644 --- a/bfd/elfnn-riscv.c +++ b/bfd/elfnn-riscv.c @@ -284,7 +284,28 @@ riscv_info_to_howto_rela (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst) { - cache_ptr->howto = riscv_elf_rtype_to_howto (abfd, ELFNN_R_TYPE (dst->r_info)); + static enum elf_riscv_vendor_id vendor_id = RISCV_VENDOR_ID_NONE; + unsigned int r_type = ELFNN_R_TYPE (dst->r_info); + + cache_ptr->howto + = riscv_elf_rtype_to_howto (abfd, ELFNN_R_TYPE (dst->r_info), vendor_id); + vendor_id = RISCV_VENDOR_ID_NONE; + + /* Record the vendor id for use by the next relocation. */ + if (r_type == R_RISCV_VENDOR) + { + const char *vendor_str = bfd_asymbol_name (*cache_ptr->sym_ptr_ptr); + vendor_id = riscv_vendor_str_to_id (vendor_str); + if (vendor_id == RISCV_VENDOR_ID_NONE) + { + _bfd_error_handler (_("error: %pB: vendor-specific (%s) " + "relocations are not supported"), + abfd, vendor_str); + bfd_set_error (bfd_error_bad_value); + return false; + } + } + return cache_ptr->howto != NULL; } @@ -906,7 +927,8 @@ riscv_elf_record_got_reference (bfd *abfd, struct bfd_link_info *info, static bool bad_static_reloc (bfd *abfd, unsigned r_type, struct elf_link_hash_entry *h) { - reloc_howto_type * r = riscv_elf_rtype_to_howto (abfd, r_type); + reloc_howto_type *r + = riscv_elf_rtype_to_howto (abfd, r_type, RISCV_VENDOR_ID_NONE); /* We propably can improve the information to tell users that they should be recompile the code with -fPIC or -fPIE, just like what @@ -1114,8 +1136,8 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, name = bfd_elf_sym_name (abfd, symtab_hdr, sym, NULL); } - reloc_howto_type *r_t = - riscv_elf_rtype_to_howto (abfd, r_type); + reloc_howto_type *r_t = riscv_elf_rtype_to_howto ( + abfd, r_type, RISCV_VENDOR_ID_NONE); _bfd_error_handler (_("%pB: relocation %s against absolute symbol `%s' can " "not be used when making a shared object"), @@ -1157,7 +1179,8 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, if (is_abs_symbol) break; - reloc_howto_type *r_t = riscv_elf_rtype_to_howto (abfd, r_type); + reloc_howto_type *r_t = riscv_elf_rtype_to_howto ( + abfd, r_type, RISCV_VENDOR_ID_NONE); _bfd_error_handler (_("%pB: relocation %s against non-absolute symbol `%s' can " "not be used in RVNN when making a shared object"), @@ -1194,7 +1217,8 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, } } - reloc_howto_type *r = riscv_elf_rtype_to_howto (abfd, r_type); + reloc_howto_type *r = riscv_elf_rtype_to_howto ( + abfd, r_type, RISCV_VENDOR_ID_NONE); if (RISCV_NEED_DYNAMIC_RELOC (r->pc_relative, info, h, sec)) { struct elf_dyn_relocs *p; @@ -1975,7 +1999,8 @@ perform_relocation (const reloc_howto_type *howto, bfd_vma value, asection *input_section, bfd *input_bfd, - bfd_byte *contents) + bfd_byte *contents, + enum elf_riscv_vendor_id vendor_id) { if (howto->pc_relative) value -= sec_addr (input_section) + rel->r_offset; @@ -1984,6 +2009,19 @@ perform_relocation (const reloc_howto_type *howto, if (ELFNN_R_TYPE (rel->r_info) != R_RISCV_SUB_ULEB128) value += rel->r_addend; + if (vendor_id != RISCV_VENDOR_ID_NONE) + { + bfd_reloc_status_type status = bfd_reloc_ok; + switch (vendor_id) + { + default: + return bfd_reloc_notsupported; + } + if (status != bfd_reloc_ok) + return status; + goto finish_relocation; + } + switch (ELFNN_R_TYPE (rel->r_info)) { case R_RISCV_HI20: @@ -2139,6 +2177,8 @@ perform_relocation (const reloc_howto_type *howto, return bfd_reloc_notsupported; } +finish_relocation: + bfd_vma word; if (riscv_is_insn_reloc (howto)) word = riscv_get_insn (howto->bitsize, contents + rel->r_offset); @@ -2361,7 +2401,7 @@ riscv_resolve_pcrel_lo_relocs (riscv_pcrel_relocs *p) } perform_relocation (r->howto, r->reloc, entry->value, r->input_section, - input_bfd, r->contents); + input_bfd, r->contents, RISCV_VENDOR_ID_NONE); /* The corresponding R_RISCV_GOT_PCREL_HI20 and R_RISCV_PCREL_HI20 are converted to R_RISCV_HI20, so try to convert R_RISCV_PCREL_LO12_I/S @@ -2436,6 +2476,7 @@ riscv_elf_relocate_section (bfd *output_bfd, bfd_vma *local_got_offsets = elf_local_got_offsets (input_bfd); bfd_vma uleb128_set_vma = 0; Elf_Internal_Rela *uleb128_set_rel = NULL; + Elf_Internal_Rela *vendor_rel = NULL; bool absolute; if (!riscv_init_pcrel_relocs (&pcrel_relocs)) @@ -2455,11 +2496,34 @@ riscv_elf_relocate_section (bfd *output_bfd, bool unresolved_reloc, is_ie = false, is_desc = false; bfd_vma pc = sec_addr (input_section) + rel->r_offset; int r_type = ELFNN_R_TYPE (rel->r_info), tls_type; - reloc_howto_type *howto = riscv_elf_rtype_to_howto (input_bfd, r_type); + reloc_howto_type *howto; const char *msg = NULL; bool resolved_to_zero; bool via_plt = false; bool relative_got = false; + enum elf_riscv_vendor_id vendor_id = RISCV_VENDOR_ID_NONE; + + if (vendor_rel != NULL) + { + r_symndx = ELFNN_R_SYM (vendor_rel->r_info); + sym = bfd_sym_from_r_symndx (&htab->elf.sym_cache, input_bfd, + r_symndx); + name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, NULL); + vendor_id = riscv_vendor_str_to_id (name); + if (vendor_id == RISCV_VENDOR_ID_NONE) + { + _bfd_error_handler + (_("error: %pB: vendor-specific (%s) relocations are " + "not supported"), + input_bfd, name); + bfd_set_error (bfd_error_bad_value); + return false; + } + name = NULL; + vendor_rel = NULL; + } + + howto = riscv_elf_rtype_to_howto (input_bfd, r_type, vendor_id); if (howto == NULL) continue; @@ -2769,6 +2833,14 @@ riscv_elf_relocate_section (bfd *output_bfd, && h != NULL && h->plt.offset != MINUS_ONE); + /* Expected vendor-specific relocation if previous + type was R_RISCV_VENDOR. */ + switch (vendor_id) + { + default: + break; + } + switch (r_type) { case R_RISCV_NONE: @@ -2796,6 +2868,10 @@ riscv_elf_relocate_section (bfd *output_bfd, /* These require no special handling beyond perform_relocation. */ break; + case R_RISCV_VENDOR: + vendor_rel = rel; + continue; + case R_RISCV_SET_ULEB128: if (uleb128_set_rel == NULL) { @@ -2943,8 +3019,8 @@ riscv_elf_relocate_section (bfd *output_bfd, &relocation, contents, howto); /* Update howto if relocation is changed. */ - howto = riscv_elf_rtype_to_howto (input_bfd, - ELFNN_R_TYPE (rel->r_info)); + howto = riscv_elf_rtype_to_howto ( + input_bfd, ELFNN_R_TYPE (rel->r_info), RISCV_VENDOR_ID_NONE); if (howto == NULL) r = bfd_reloc_notsupported; else if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc, @@ -3091,8 +3167,8 @@ riscv_elf_relocate_section (bfd *output_bfd, absolute = riscv_zero_pcrel_hi_reloc (rel, info, pc, &relocation, contents, howto); /* Update howto if relocation is changed. */ - howto = riscv_elf_rtype_to_howto (input_bfd, - ELFNN_R_TYPE (rel->r_info)); + howto = riscv_elf_rtype_to_howto ( + input_bfd, ELFNN_R_TYPE (rel->r_info), RISCV_VENDOR_ID_NONE); if (howto == NULL) r = bfd_reloc_notsupported; else if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc, @@ -3376,7 +3452,7 @@ riscv_elf_relocate_section (bfd *output_bfd, do_relocation: if (r == bfd_reloc_ok) r = perform_relocation (howto, rel, relocation, input_section, - input_bfd, contents); + input_bfd, contents, vendor_id); /* We should have already detected the error and set message before. If the error message isn't set since the linker runs out of memory diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c index 085d77923a0..1a391c51f2b 100644 --- a/bfd/elfxx-riscv.c +++ b/bfd/elfxx-riscv.c @@ -876,7 +876,56 @@ static const reloc_howto_type howto_table[] = false, /* partial_inplace */ 0, /* src_mask */ ENCODE_ITYPE_IMM (-1U), /* dst_mask */ - false) /* pcrel_offset */ + false), /* pcrel_offset */ + + EMPTY_HOWTO (66), EMPTY_HOWTO (67), EMPTY_HOWTO (68), EMPTY_HOWTO (69), + EMPTY_HOWTO (70), EMPTY_HOWTO (71), EMPTY_HOWTO (72), EMPTY_HOWTO (73), + EMPTY_HOWTO (74), EMPTY_HOWTO (75), EMPTY_HOWTO (76), EMPTY_HOWTO (77), + EMPTY_HOWTO (78), EMPTY_HOWTO (79), EMPTY_HOWTO (80), EMPTY_HOWTO (81), + EMPTY_HOWTO (82), EMPTY_HOWTO (83), EMPTY_HOWTO (84), EMPTY_HOWTO (85), + EMPTY_HOWTO (86), EMPTY_HOWTO (87), EMPTY_HOWTO (88), EMPTY_HOWTO (89), + EMPTY_HOWTO (90), EMPTY_HOWTO (91), EMPTY_HOWTO (92), EMPTY_HOWTO (93), + EMPTY_HOWTO (94), EMPTY_HOWTO (95), EMPTY_HOWTO (96), EMPTY_HOWTO (97), + EMPTY_HOWTO (98), EMPTY_HOWTO (99), EMPTY_HOWTO (100), EMPTY_HOWTO (101), + EMPTY_HOWTO (102), EMPTY_HOWTO (103), EMPTY_HOWTO (104), EMPTY_HOWTO (105), + EMPTY_HOWTO (106), EMPTY_HOWTO (107), EMPTY_HOWTO (108), EMPTY_HOWTO (109), + EMPTY_HOWTO (110), EMPTY_HOWTO (111), EMPTY_HOWTO (112), EMPTY_HOWTO (113), + EMPTY_HOWTO (114), EMPTY_HOWTO (115), EMPTY_HOWTO (116), EMPTY_HOWTO (117), + EMPTY_HOWTO (118), EMPTY_HOWTO (119), EMPTY_HOWTO (120), EMPTY_HOWTO (121), + EMPTY_HOWTO (122), EMPTY_HOWTO (123), EMPTY_HOWTO (124), EMPTY_HOWTO (125), + EMPTY_HOWTO (126), EMPTY_HOWTO (127), EMPTY_HOWTO (128), EMPTY_HOWTO (129), + EMPTY_HOWTO (130), EMPTY_HOWTO (131), EMPTY_HOWTO (132), EMPTY_HOWTO (133), + EMPTY_HOWTO (134), EMPTY_HOWTO (135), EMPTY_HOWTO (136), EMPTY_HOWTO (137), + EMPTY_HOWTO (138), EMPTY_HOWTO (139), EMPTY_HOWTO (140), EMPTY_HOWTO (141), + EMPTY_HOWTO (142), EMPTY_HOWTO (143), EMPTY_HOWTO (144), EMPTY_HOWTO (145), + EMPTY_HOWTO (146), EMPTY_HOWTO (147), EMPTY_HOWTO (148), EMPTY_HOWTO (149), + EMPTY_HOWTO (150), EMPTY_HOWTO (151), EMPTY_HOWTO (152), EMPTY_HOWTO (153), + EMPTY_HOWTO (154), EMPTY_HOWTO (155), EMPTY_HOWTO (156), EMPTY_HOWTO (157), + EMPTY_HOWTO (158), EMPTY_HOWTO (159), EMPTY_HOWTO (160), EMPTY_HOWTO (161), + EMPTY_HOWTO (162), EMPTY_HOWTO (163), EMPTY_HOWTO (164), EMPTY_HOWTO (165), + EMPTY_HOWTO (166), EMPTY_HOWTO (167), EMPTY_HOWTO (168), EMPTY_HOWTO (169), + EMPTY_HOWTO (170), EMPTY_HOWTO (171), EMPTY_HOWTO (172), EMPTY_HOWTO (173), + EMPTY_HOWTO (174), EMPTY_HOWTO (175), EMPTY_HOWTO (176), EMPTY_HOWTO (177), + EMPTY_HOWTO (178), EMPTY_HOWTO (179), EMPTY_HOWTO (180), EMPTY_HOWTO (181), + EMPTY_HOWTO (182), EMPTY_HOWTO (183), EMPTY_HOWTO (184), EMPTY_HOWTO (185), + EMPTY_HOWTO (186), EMPTY_HOWTO (187), EMPTY_HOWTO (188), EMPTY_HOWTO (189), + EMPTY_HOWTO (190), + + /* Paired with a vendor-specific relocation and must be placed immediately + before it. Its symbol indicates which vendor owns the relocation. */ + HOWTO (R_RISCV_VENDOR, /* type */ + 0, /* rightshift */ + 0, /* size */ + 0, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_RISCV_VENDOR", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false) /* pcrel_offset */ }; static const reloc_howto_type howto_table_internal[] = @@ -960,11 +1009,25 @@ static const reloc_howto_type howto_table_internal[] = false), /* pcrel_offset */ }; +static const reloc_howto_type *const howto_table_vendors[] = +{ + /* Register vendor howto tables here. The order must match the order of + strings in the vendor string table. */ + NULL +}; + +static const size_t howto_table_vendor_sizes[] = +{ + /* Register vendor howto table sizes here. The order must match the order of + strings in the vendor string table. */ + 0 +}; + /* A mapping from BFD reloc types to RISC-V ELF reloc types. */ struct elf_reloc_map { bfd_reloc_code_real_type bfd_val; - enum elf_riscv_reloc_type elf_val; + uint32_t elf_val; }; static const struct elf_reloc_map riscv_reloc_map[] = @@ -1020,8 +1083,40 @@ static const struct elf_reloc_map riscv_reloc_map[] = { BFD_RELOC_RISCV_32_PCREL, R_RISCV_32_PCREL }, { BFD_RELOC_RISCV_SET_ULEB128, R_RISCV_SET_ULEB128 }, { BFD_RELOC_RISCV_SUB_ULEB128, R_RISCV_SUB_ULEB128 }, + { BFD_RELOC_RISCV_VENDOR, R_RISCV_VENDOR }, +}; + +static const struct elf_reloc_map *const riscv_vendor_reloc_maps[] = +{ + /* Register vendor relocation maps here. The order must match the order of + strings in the vendor string table. */ + NULL +}; + +static const size_t riscv_vendor_reloc_map_sizes[] = +{ + /* Register vendor relocation map sizes here. The order must match the order + of strings in the vendor string table. */ + 0 }; +static const char *const *const riscv_vendor_ext_with_reloc_tables[] = +{ + /* Register vendor extension-with-relocation tables here. The order must + match the order of strings in the vendor string table. */ + NULL +}; + +static const size_t riscv_vendor_ext_with_reloc_table_sizes[] = +{ + /* Register vendor extension-with-relocation table sizes here. The order must + match the order of strings in the vendor string table. */ + 0 +}; + +static const char *const riscv_vendor_str_table[] = +RISCV_VENDOR_STR_TABLE_INITIALIZER; + struct riscv_profiles { const char *profile_name; @@ -1034,42 +1129,121 @@ reloc_howto_type * riscv_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code) { - unsigned int i; + unsigned int i, j; 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]; + for (i = 0; i < ARRAY_SIZE (riscv_vendor_reloc_maps); i++) + for (j = 0; j < riscv_vendor_reloc_map_sizes[i]; j++) + if (riscv_vendor_reloc_maps[i][j].bfd_val == code + && riscv_vendor_reloc_maps[i][j].elf_val > R_RISCV_VENDOR + && riscv_vendor_reloc_maps[i][j].elf_val + <= R_RISCV_VENDOR + howto_table_vendor_sizes[i]) + return &howto_table_vendors[i][( + int)(riscv_vendor_reloc_maps[i][j].elf_val - R_RISCV_VENDOR - 1)]; + bfd_set_error (bfd_error_bad_value); return NULL; } +/* Given a BFD reloc type, return a vendor string. */ + +const char * +riscv_reloc_type_to_vendor_str (bfd_reloc_code_real_type code) +{ + unsigned int i, j; + + for (i = 0; i < ARRAY_SIZE (riscv_reloc_map); i++) + if (riscv_reloc_map[i].bfd_val == code) + return NULL; + + for (i = 0; i < ARRAY_SIZE (riscv_vendor_reloc_maps); i++) + for (j = 0; j < riscv_vendor_reloc_map_sizes[i]; j++) + if (riscv_vendor_reloc_maps[i][j].bfd_val == code) + return riscv_vendor_str_table[i]; + + return NULL; +} + reloc_howto_type * riscv_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) { - unsigned int i; + unsigned int i, j; for (i = 0; i < ARRAY_SIZE (howto_table); i++) if (howto_table[i].name && strcasecmp (howto_table[i].name, r_name) == 0) return &howto_table[i]; + for (i = 0; i < ARRAY_SIZE (howto_table_vendors); i++) + for (j = 0; j < howto_table_vendor_sizes[i]; j++) + if (howto_table_vendors[i][j].name + && strcasecmp (howto_table_vendors[i][j].name, r_name) == 0) + return &howto_table_vendors[i][j]; + return NULL; } reloc_howto_type * -riscv_elf_rtype_to_howto (bfd *abfd, unsigned int r_type) +riscv_elf_rtype_to_howto (bfd *abfd, unsigned int r_type, + enum elf_riscv_vendor_id vendor_id) { - if (r_type < ARRAY_SIZE (howto_table)) - return &howto_table[r_type]; - else if (r_type < R_RISCV_max + ARRAY_SIZE (howto_table_internal)) - return &howto_table_internal[r_type - R_RISCV_max]; + if (vendor_id == RISCV_VENDOR_ID_NONE) + { + if (r_type >= R_RISCV_internal_first + && r_type < (R_RISCV_internal_first + + ARRAY_SIZE (howto_table_internal))) + return &howto_table_internal[r_type - R_RISCV_internal_first]; + else if (r_type < ARRAY_SIZE (howto_table)) + return &howto_table[r_type]; + } else { - (*_bfd_error_handler) (_("%pB: unsupported relocation type %#x"), - abfd, r_type); - bfd_set_error (bfd_error_bad_value); - return NULL; + if (vendor_id > RISCV_VENDOR_ID_NONE + && vendor_id < RISCV_VENDOR_ID_COUNT + && r_type > R_RISCV_VENDOR + && r_type <= R_RISCV_VENDOR + howto_table_vendor_sizes[vendor_id]) + return &howto_table_vendors[vendor_id][r_type - R_RISCV_VENDOR - 1]; } + + if (vendor_id == RISCV_VENDOR_ID_NONE) + (*_bfd_error_handler) (_("%pB: unsupported relocation type %#x"), abfd, + r_type); + else + (*_bfd_error_handler) ( + _("%pB: unsupported relocation type %#x for vendor id %d"), abfd, + r_type, (int)vendor_id); + + bfd_set_error (bfd_error_bad_value); + return NULL; +} + +/* Given a vendor id, return a vendor string. */ + +const char * +riscv_vendor_id_to_str (enum elf_riscv_vendor_id vendor_id) +{ + if (vendor_id <= RISCV_VENDOR_ID_NONE + || vendor_id >= RISCV_VENDOR_ID_COUNT) + return NULL; + + return riscv_vendor_str_table[vendor_id]; +} + +/* Given a vendor string, return a vendor id. */ + +enum elf_riscv_vendor_id +riscv_vendor_str_to_id (const char *vendor_str) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE (riscv_vendor_str_table); i++) + if (riscv_vendor_str_table[i] && vendor_str + && strcmp (riscv_vendor_str_table[i], vendor_str) == 0) + return i; + + return RISCV_VENDOR_ID_NONE; } /* Special_function of RISCV_ADD and RISCV_SUB relocations. */ @@ -2790,6 +2964,27 @@ riscv_subset_supports (riscv_parse_subset_t *rps, return riscv_lookup_subset (rps->subset_list, feature, &subset); } +/* Return true if any extension of the given vendor that uses relocation is + supported in the subset list. */ + +bool +riscv_subset_supports_vendor_ext_with_reloc (riscv_parse_subset_t *rps, + enum elf_riscv_vendor_id vendor_id) +{ + if (vendor_id <= RISCV_VENDOR_ID_NONE + || vendor_id >= RISCV_VENDOR_ID_COUNT) + return false; + + unsigned int i; + + for (i = 0; i < riscv_vendor_ext_with_reloc_table_sizes[vendor_id]; i++) + if (riscv_subset_supports ( + rps, riscv_vendor_ext_with_reloc_tables[vendor_id][i])) + return true; + + return false; +} + /* Each instuction is belonged to an instruction class INSN_CLASS_*. Call riscv_subset_supports to make sure if the instuction is valid. */ diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h index fbbefb5ac18..41631ad4465 100644 --- a/bfd/elfxx-riscv.h +++ b/bfd/elfxx-riscv.h @@ -33,6 +33,8 @@ typedef enum PLT_ZICFILP_UNLABELED = 0x1 /* Landing pad unlabeled plts. */ } riscv_plt_type; +enum elf_riscv_vendor_id; + struct riscv_elf_params { /* Whether to relax code sequences to GP-relative addressing. */ @@ -52,8 +54,16 @@ riscv_reloc_name_lookup (bfd *, const char *); extern reloc_howto_type * riscv_reloc_type_lookup (bfd *, bfd_reloc_code_real_type); +extern const char * +riscv_reloc_type_to_vendor_str (bfd_reloc_code_real_type); + extern reloc_howto_type * -riscv_elf_rtype_to_howto (bfd *, unsigned int r_type); +riscv_elf_rtype_to_howto (bfd *, unsigned int r_type, + enum elf_riscv_vendor_id); + +extern const char * riscv_vendor_id_to_str (enum elf_riscv_vendor_id); +extern enum elf_riscv_vendor_id riscv_vendor_str_to_id (const char *); + /* The information of architecture attribute. */ struct riscv_subset_t @@ -124,6 +134,9 @@ riscv_update_subset_norvc (riscv_parse_subset_t *); extern bool riscv_subset_supports (riscv_parse_subset_t *, const char *); +extern bool +riscv_subset_supports_vendor_ext_with_reloc (riscv_parse_subset_t *, + enum elf_riscv_vendor_id); extern bool riscv_multi_subset_supports (riscv_parse_subset_t *, enum riscv_insn_class); diff --git a/bfd/libbfd.h b/bfd/libbfd.h index f2485d99078..9da65b4ec9d 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -2464,6 +2464,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_RISCV_32_PCREL", "BFD_RELOC_RISCV_SET_ULEB128", "BFD_RELOC_RISCV_SUB_ULEB128", + "BFD_RELOC_RISCV_VENDOR", "BFD_RELOC_RL78_NEG8", "BFD_RELOC_RL78_NEG16", "BFD_RELOC_RL78_NEG24", diff --git a/bfd/reloc.c b/bfd/reloc.c index c9d53bb9e11..0ef5e550403 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -5036,6 +5036,8 @@ ENUMX BFD_RELOC_RISCV_SET_ULEB128 ENUMX BFD_RELOC_RISCV_SUB_ULEB128 +ENUMX + BFD_RELOC_RISCV_VENDOR ENUMDOC RISC-V relocations. diff --git a/binutils/readelf.c b/binutils/readelf.c index fd9722c8afc..6217aded055 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -2216,6 +2216,7 @@ dump_relocations (Filedata * filedata, size_t i; Elf_Internal_Rela * rels; bool res = true; + const char *riscv_vendor_str = NULL; if (rel_type == reltype_unknown) rel_type = guess_is_rela (filedata->file_header.e_machine) ? reltype_rela : reltype_rel; @@ -2444,7 +2445,15 @@ dump_relocations (Filedata * filedata, break; case EM_RISCV: - rtype = elf_riscv_reloc_type (type); + if (riscv_vendor_str) + { + /* Use special function for vendor-specific relocations. */ + rtype = elf_riscv_vendor_reloc_type (riscv_vendor_str, type); + free ((void *)riscv_vendor_str); + riscv_vendor_str = NULL; + } + else + rtype = elf_riscv_reloc_type (type); break; case EM_ALPHA: @@ -2798,6 +2807,11 @@ dump_relocations (Filedata * filedata, } else { + /* Record RISC-V vendor string for use by the next + relocation. */ + if (filedata->file_header.e_machine == EM_RISCV + && rtype && strcmp (rtype, "R_RISCV_VENDOR") == 0) + riscv_vendor_str = strdup (strtab + psym->st_name); if (dump_reloc) { print_symbol_name (22, strtab + psym->st_name); @@ -2887,6 +2901,12 @@ dump_relocations (Filedata * filedata, } } + if (riscv_vendor_str) + { + free ((void *)riscv_vendor_str); + riscv_vendor_str = NULL; + } + free (rels); return res; diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c index df60c206b82..1893e4ce11d 100644 --- a/gas/config/tc-riscv.c +++ b/gas/config/tc-riscv.c @@ -196,6 +196,9 @@ static bool start_assemble = false; static bool probing_insn_operands; +/* Used for vendor symbol relocation. */ +segT vendor_section; + /* Set the default_isa_spec. Return 0 if the spec isn't supported. Otherwise, return 1. */ @@ -1963,6 +1966,25 @@ riscv_apply_const_reloc (bfd_reloc_code_real_type reloc_type, bfd_vma value) } } +/* Add a vendor symbol relocation before any vendor-specific relocation. */ + +static void +add_vendor_symbol_relocation (fragS *frag, long where, long size, + const char *vendor_str) +{ + if (!vendor_str) + return; + + symbolS *sym; + + /* Find the vendor symbol created in md_assemble (). */ + sym = symbol_find (vendor_str); + if (!sym) + abort (); + + fix_new (frag, where, size, sym, 0, false, BFD_RELOC_RISCV_VENDOR); +} + /* Output an instruction. IP is the instruction information. ADDRESS_EXPR is an operand of the instruction to be used with RELOC_TYPE. */ @@ -2004,6 +2026,10 @@ append_insn (struct riscv_cl_insn *ip, expressionS *address_expr, as_bad (_("internal: unsupported RISC-V relocation number %d"), reloc_type); + add_vendor_symbol_relocation ( + frag_now, frag_more (0) - frag_now->fr_literal, insn_length (ip), + riscv_reloc_type_to_vendor_str (reloc_type)); + ip->fixp = fix_new_exp (ip->frag, ip->where, bfd_get_reloc_size (howto), address_expr, false, reloc_type); @@ -4407,6 +4433,34 @@ md_assemble (char *str) { start_assemble = true; + /* Check if any vendor extension with relocation is supported; if so, a + corresponding vendor symbol must be created. */ + unsigned int i; + + for (i = 0; i < RISCV_VENDOR_ID_COUNT; i++) + { + if (riscv_subset_supports_vendor_ext_with_reloc (&riscv_rps_as, i)) + { + symbolS *sym; + + /* Create a vendor section to hold the vendor symbol. */ + if (!vendor_section) + { + segT saved_now_seg = now_seg; + subsegT saved_now_subseg = now_subseg; + vendor_section = subseg_new (".vendor", 0); + subseg_set (saved_now_seg, saved_now_subseg); + } + + /* Create a corresponding vendor symbol and mark it as used in + reloc to ensure it is not removed later. */ + sym = symbol_new (riscv_vendor_id_to_str (i), vendor_section, + &zero_address_frag, 0); + symbol_table_insert (sym); + symbol_mark_used_in_reloc (sym); + } + } + riscv_set_abi_by_arch (); if (!riscv_set_default_priv_spec (NULL)) return; @@ -5000,6 +5054,9 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg) case BFD_RELOC_RISCV_ALIGN: break; + case BFD_RELOC_RISCV_VENDOR: + break; + default: /* We ignore generic BFD relocations we don't know about. */ if (bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type) != NULL) @@ -5442,6 +5499,10 @@ md_convert_frag_branch (fragS *fragp) /* Just keep the RVC branch. */ reloc = RELAX_BRANCH_UNCOND (fragp->fr_subtype) ? BFD_RELOC_RISCV_RVC_JUMP : BFD_RELOC_RISCV_RVC_BRANCH; + /* Maybe it is a vendor-specific relocation in the future. */ + add_vendor_symbol_relocation ( + fragp, buf - (bfd_byte *)fragp->fr_literal, 2, + riscv_reloc_type_to_vendor_str (reloc)); fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal, 2, &exp, false, reloc); buf += 2; @@ -5475,6 +5536,9 @@ md_convert_frag_branch (fragS *fragp) case 4: reloc = RELAX_BRANCH_UNCOND (fragp->fr_subtype) ? BFD_RELOC_RISCV_JMP : BFD_RELOC_12_PCREL; + /* Maybe it is a vendor-specific relocation in the future. */ + add_vendor_symbol_relocation (fragp, buf - (bfd_byte *)fragp->fr_literal, + 4, riscv_reloc_type_to_vendor_str (reloc)); fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal, 4, &exp, false, reloc); buf += 4; diff --git a/include/elf/riscv.h b/include/elf/riscv.h index 2ea1ae82eb6..8ce9fc98c43 100644 --- a/include/elf/riscv.h +++ b/include/elf/riscv.h @@ -95,15 +95,62 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type) RELOC_NUMBER (R_RISCV_TLSDESC_LOAD_LO12, 63) RELOC_NUMBER (R_RISCV_TLSDESC_ADD_LO12, 64) RELOC_NUMBER (R_RISCV_TLSDESC_CALL, 65) -END_RELOC_NUMBERS (R_RISCV_max) + EMPTY_RELOC (R_RISCV_internal_first) + RELOC_NUMBER (R_RISCV_VENDOR, 191) +END_RELOC_NUMBERS () /* Internal relocations used exclusively by the relaxation pass. */ -#define R_RISCV_DELETE (R_RISCV_max) -#define R_RISCV_RVC_LUI (R_RISCV_max + 1) -#define R_RISCV_GPREL_I (R_RISCV_max + 2) -#define R_RISCV_GPREL_S (R_RISCV_max + 3) -#define R_RISCV_TPREL_I (R_RISCV_max + 4) -#define R_RISCV_TPREL_S (R_RISCV_max + 5) +#define R_RISCV_DELETE (R_RISCV_internal_first) +#define R_RISCV_RVC_LUI (R_RISCV_internal_first + 1) +#define R_RISCV_GPREL_I (R_RISCV_internal_first + 2) +#define R_RISCV_GPREL_S (R_RISCV_internal_first + 3) +#define R_RISCV_TPREL_I (R_RISCV_internal_first + 4) +#define R_RISCV_TPREL_S (R_RISCV_internal_first + 5) + +enum elf_riscv_vendor_id +{ + RISCV_VENDOR_ID_NONE = -1, + /* Register vendor id here. The order must match the order of strings in the + vendor string table. */ + RISCV_VENDOR_ID_COUNT +}; + +#define RISCV_VENDOR_STR_TABLE_INITIALIZER \ +{ \ + /* Register vendor strings (defined as macros) here. Remember to \ + append a space to each string to avoid symbol conflicts. */ \ + NULL \ +} + +/* Used for readelf. */ +#ifdef RELOC_MACROS_GEN_FUNC +static const char *const elf_riscv_vendor_str_table[] = +RISCV_VENDOR_STR_TABLE_INITIALIZER; + +static const char *(*elf_riscv_vendor_reloc_type_funcs[]) (unsigned long) = +{ + /* Register vendor-defined functions (given a relocation number, return a + relocation name string) here. The order must match the order of strings + in the vendor string table. */ + NULL +}; + +/* Given a vendor string and a relocation number, return a relocation name + string. */ +static const char * +elf_riscv_vendor_reloc_type (const char *vendor_str, unsigned long rtype) +{ + unsigned int i; + + /* Choose a vendor-defined function according to the vendor string. */ + for (i = 0; i < ARRAY_SIZE (elf_riscv_vendor_str_table); i++) + if (elf_riscv_vendor_str_table[i] && vendor_str + && strcmp (elf_riscv_vendor_str_table[i], vendor_str) == 0) + return elf_riscv_vendor_reloc_type_funcs[i](rtype); + + return NULL; +} +#endif /* Processor specific flags for the ELF header e_flags field. */ -- 2.49.0
- Previous message (by thread): [PATCH 0/3] RISC-V: Vendor relocation framework and XAndesPerf extension
- Next message (by thread): [PATCH 2/3] RISC-V: Refactor branch relaxation state encoding for extensibility
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
More information about the Binutils mailing list