Skip to content

Commit 3eab96f

Browse files
committed
RISC-V: Separate invalid/internal only ELF relocs
After ratification of the RISC-V psABI specification (version 1.0), it is getting enhanced and improved. This commit performs following changes. 1. Reject unknown ELF relocation types when fed into a tool Before this commit, it accepted unknown (but small) relocation types and relocation types only for internal uses (linker relaxation). More worryingly, some internal only relocation types conflict with global relocation types in the latest psABI draft [1]. [1] <riscv-non-isa/riscv-elf-psabi-doc@d49e480> If (a) psABI changes conflict with internal only relocation types and/or (b) an object (possibly malicious or just from the future) with unknown relocation type is encountered while linking (by ld) or relocating by other tools, it can cause a severe failure (with unpredictable erroneous results). This commit now rejects small unknown relocation types and internal only ones when an ELF file with such relocation types is fed into a tool. 2. Move internal only ELF relocation types after all regular ones Currently, we have six internal only relocation types but only R_RISCV_DELETE is distinguished from the regular one (others were defined in between regular relocation types). This design caused the conflict with regular relocation types *and* made fixing the number of such internal relocation a non-trivial task. This commit moves all internal only relocation types (not only R_RISCV_DELETE) after R_RISCV_max and creates separate howto relocation table for range (R_RISCV_DELETE + 1..R_RISCV_internal_max). All internal only relocations are defined relative to R_RISCV_max and will not conflict with regular ones (if psABI started to use large numbers, internal relocations are automatically adjusted). 3. Prevent internal only ELF relocation types from emitting It prevents emitting internal only relocations when the --emit-relocs option is specified when linking (instead, replaces such internal only relocations to R_RISCV_NONE). bfd/ChangeLog: * elfnn-riscv.c (R_RISCV_DELETE): Move to elf_riscv_reloc_type. (riscv_info_to_howto_rela, bad_static_reloc): Reflect riscv_elf_rtype_to_howto changes. (riscv_elf_check_relocs): Likewise. Also reject unknown relocs are found. Reuse howto variable. (riscv_elf_relocate_section): Reflect riscv_elf_rtype_to_howto changesL but also look up for internal relocs only when necessary. Delete internal only relocation after the relocation. * elfxx-riscv.c (HOWTO_ISEMPTY): New macro to query whether the howto entry is empty. (howto_table): Reserve all howto entries defined by the latest RISC-V psABI specification except no actual EMPTY_HOWTO defs at the end of the list. Move internal only relocs to... (howto_table_internal): ...here. (riscv_elf_rtype_to_howto): Add ability to look up internal only relocation types only when necessary. * elfxx-riscv.h (riscv_elf_rtype_to_howto): Reflect above. include/ChangeLog: * elf/riscv.h (enum elf_riscv_reloc_type): Comment all reserved relocation types as defined by the latest RISC-V psABI spec. Move all internal relocation types after R_RISCV_max, first being R_RISCV_DELETE. Add R_RISCV_internal_max. Add safety guard for all relocation types on C11 and later.
1 parent 6f85247 commit 3eab96f

File tree

4 files changed

+183
-99
lines changed

4 files changed

+183
-99
lines changed

bfd/elfnn-riscv.c

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,6 @@
130130
} \
131131
while (0)
132132

133-
/* Internal relocations used exclusively by the relaxation pass. */
134-
#define R_RISCV_DELETE (R_RISCV_max + 1)
135-
136133
#define ARCH_SIZE NN
137134

138135
#define MINUS_ONE ((bfd_vma)0 - 1)
@@ -267,7 +264,8 @@ riscv_info_to_howto_rela (bfd *abfd,
267264
arelent *cache_ptr,
268265
Elf_Internal_Rela *dst)
269266
{
270-
cache_ptr->howto = riscv_elf_rtype_to_howto (abfd, ELFNN_R_TYPE (dst->r_info));
267+
cache_ptr->howto =
268+
riscv_elf_rtype_to_howto (abfd, ELFNN_R_TYPE (dst->r_info), false);
271269
return cache_ptr->howto != NULL;
272270
}
273271

@@ -714,7 +712,7 @@ riscv_elf_record_got_reference (bfd *abfd, struct bfd_link_info *info,
714712
static bool
715713
bad_static_reloc (bfd *abfd, unsigned r_type, struct elf_link_hash_entry *h)
716714
{
717-
reloc_howto_type * r = riscv_elf_rtype_to_howto (abfd, r_type);
715+
reloc_howto_type * r = riscv_elf_rtype_to_howto (abfd, r_type, false);
718716

719717
/* We propably can improve the information to tell users that they
720718
should be recompile the code with -fPIC or -fPIE, just like what
@@ -756,11 +754,17 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
756754
{
757755
unsigned int r_type;
758756
unsigned int r_symndx;
757+
reloc_howto_type *howto;
759758
struct elf_link_hash_entry *h;
760759
bool is_abs_symbol = false;
761760

762761
r_symndx = ELFNN_R_SYM (rel->r_info);
763762
r_type = ELFNN_R_TYPE (rel->r_info);
763+
howto = riscv_elf_rtype_to_howto (abfd, r_type, false);
764+
765+
/* Reject unknown relocs. */
766+
if (!howto)
767+
return false;
764768

765769
if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
766770
{
@@ -916,12 +920,10 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
916920
name = bfd_elf_sym_name (abfd, symtab_hdr, sym, NULL);
917921
}
918922

919-
reloc_howto_type *r_t =
920-
riscv_elf_rtype_to_howto (abfd, r_type);
921923
_bfd_error_handler
922924
(_("%pB: relocation %s against absolute symbol `%s' can "
923925
"not be used when making a shared object"),
924-
abfd, r_t ? r_t->name : _("<unknown>"), name);
926+
abfd, howto ? howto->name : _("<unknown>"), name);
925927
bfd_set_error (bfd_error_bad_value);
926928
return false;
927929
}
@@ -959,11 +961,10 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
959961
if (is_abs_symbol)
960962
break;
961963

962-
reloc_howto_type *r_t = riscv_elf_rtype_to_howto (abfd, r_type);
963964
_bfd_error_handler
964965
(_("%pB: relocation %s against non-absolute symbol `%s' can "
965966
"not be used in RVNN when making a shared object"),
966-
abfd, r_t ? r_t->name : _("<unknown>"),
967+
abfd, howto ? howto->name : _("<unknown>"),
967968
h != NULL ? h->root.root.string : "a local symbol");
968969
bfd_set_error (bfd_error_bad_value);
969970
return false;
@@ -996,8 +997,7 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
996997
}
997998
}
998999

999-
reloc_howto_type *r = riscv_elf_rtype_to_howto (abfd, r_type);
1000-
if (RISCV_NEED_DYNAMIC_RELOC (r->pc_relative, info, h, sec))
1000+
if (RISCV_NEED_DYNAMIC_RELOC (howto->pc_relative, info, h, sec))
10011001
{
10021002
struct elf_dyn_relocs *p;
10031003
struct elf_dyn_relocs **head;
@@ -1058,7 +1058,7 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
10581058
}
10591059

10601060
p->count += 1;
1061-
p->pc_count += r == NULL ? 0 : r->pc_relative;
1061+
p->pc_count += howto == NULL ? 0 : howto->pc_relative;
10621062
}
10631063

10641064
break;
@@ -2182,7 +2182,8 @@ riscv_elf_relocate_section (bfd *output_bfd,
21822182
bool unresolved_reloc, is_ie = false;
21832183
bfd_vma pc = sec_addr (input_section) + rel->r_offset;
21842184
int r_type = ELFNN_R_TYPE (rel->r_info), tls_type;
2185-
reloc_howto_type *howto = riscv_elf_rtype_to_howto (input_bfd, r_type);
2185+
reloc_howto_type *howto =
2186+
riscv_elf_rtype_to_howto (input_bfd, r_type, true);
21862187
const char *msg = NULL;
21872188
bool resolved_to_zero;
21882189

@@ -2615,7 +2616,8 @@ riscv_elf_relocate_section (bfd *output_bfd,
26152616
howto);
26162617
/* Update howto if relocation is changed. */
26172618
howto = riscv_elf_rtype_to_howto (input_bfd,
2618-
ELFNN_R_TYPE (rel->r_info));
2619+
ELFNN_R_TYPE (rel->r_info),
2620+
false);
26192621
if (howto == NULL)
26202622
r = bfd_reloc_notsupported;
26212623
else if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc,
@@ -2766,7 +2768,8 @@ riscv_elf_relocate_section (bfd *output_bfd,
27662768
contents, howto);
27672769
/* Update howto if relocation is changed. */
27682770
howto = riscv_elf_rtype_to_howto (input_bfd,
2769-
ELFNN_R_TYPE (rel->r_info));
2771+
ELFNN_R_TYPE (rel->r_info),
2772+
false);
27702773
if (howto == NULL)
27712774
r = bfd_reloc_notsupported;
27722775
else if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc,
@@ -3008,6 +3011,11 @@ riscv_elf_relocate_section (bfd *output_bfd,
30083011
r = perform_relocation (howto, rel, relocation, input_section,
30093012
input_bfd, contents);
30103013

3014+
/* Delete internal only relocations
3015+
(overwrite with R_RISCV_NONE). */
3016+
if (r_type >= R_RISCV_max)
3017+
rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE);
3018+
30113019
/* We should have already detected the error and set message before.
30123020
If the error message isn't set since the linker runs out of memory
30133021
or we don't set it before, then we should set the default message

bfd/elfxx-riscv.c

Lines changed: 126 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ static bfd_reloc_status_type riscv_elf_add_sub_reloc
4141
static bfd_reloc_status_type riscv_elf_ignore_reloc
4242
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
4343

44+
/* Check whether the given howto entry is empty (unknown). */
45+
46+
#define HOWTO_ISEMPTY(howto) (!((howto).name))
47+
4448
/* The relocation table used for SHT_RELA sections. */
4549

4650
static reloc_howto_type howto_table[] =
@@ -602,8 +606,8 @@ static reloc_howto_type howto_table[] =
602606
false), /* pcrel_offset */
603607

604608
/* 41 and 42 are reserved. */
605-
EMPTY_HOWTO (0),
606-
EMPTY_HOWTO (0),
609+
EMPTY_HOWTO (41),
610+
EMPTY_HOWTO (42),
607611

608612
/* Indicates an alignment statement. The addend field encodes how many
609613
bytes of NOPs follow the statement. The desired alignment is the
@@ -652,80 +656,20 @@ static reloc_howto_type howto_table[] =
652656
ENCODE_CJTYPE_IMM (-1U), /* dst_mask */
653657
true), /* pcrel_offset */
654658

655-
/* High 6 bits of 18-bit absolute address. */
656-
HOWTO (R_RISCV_RVC_LUI, /* type */
657-
0, /* rightshift */
658-
2, /* size */
659-
16, /* bitsize */
660-
false, /* pc_relative */
661-
0, /* bitpos */
662-
complain_overflow_dont, /* complain_on_overflow */
663-
bfd_elf_generic_reloc, /* special_function */
664-
"R_RISCV_RVC_LUI", /* name */
665-
false, /* partial_inplace */
666-
0, /* src_mask */
667-
ENCODE_CITYPE_IMM (-1U), /* dst_mask */
668-
false), /* pcrel_offset */
659+
/* 46 is reserved. */
660+
EMPTY_HOWTO (46),
669661

670-
/* GP-relative load. */
671-
HOWTO (R_RISCV_GPREL_I, /* type */
672-
0, /* rightshift */
673-
4, /* size */
674-
32, /* bitsize */
675-
false, /* pc_relative */
676-
0, /* bitpos */
677-
complain_overflow_dont, /* complain_on_overflow */
678-
bfd_elf_generic_reloc, /* special_function */
679-
"R_RISCV_GPREL_I", /* name */
680-
false, /* partial_inplace */
681-
0, /* src_mask */
682-
ENCODE_ITYPE_IMM (-1U), /* dst_mask */
683-
false), /* pcrel_offset */
662+
/* Reserved for R_RISCV_GPREL_LO12_I. */
663+
EMPTY_HOWTO (47),
684664

685-
/* GP-relative store. */
686-
HOWTO (R_RISCV_GPREL_S, /* type */
687-
0, /* rightshift */
688-
4, /* size */
689-
32, /* bitsize */
690-
false, /* pc_relative */
691-
0, /* bitpos */
692-
complain_overflow_dont, /* complain_on_overflow */
693-
bfd_elf_generic_reloc, /* special_function */
694-
"R_RISCV_GPREL_S", /* name */
695-
false, /* partial_inplace */
696-
0, /* src_mask */
697-
ENCODE_STYPE_IMM (-1U), /* dst_mask */
698-
false), /* pcrel_offset */
665+
/* Reserved for R_RISCV_GPREL_LO12_S. */
666+
EMPTY_HOWTO (48),
699667

700-
/* TP-relative TLS LE load. */
701-
HOWTO (R_RISCV_TPREL_I, /* type */
702-
0, /* rightshift */
703-
4, /* size */
704-
32, /* bitsize */
705-
false, /* pc_relative */
706-
0, /* bitpos */
707-
complain_overflow_signed, /* complain_on_overflow */
708-
bfd_elf_generic_reloc, /* special_function */
709-
"R_RISCV_TPREL_I", /* name */
710-
false, /* partial_inplace */
711-
0, /* src_mask */
712-
ENCODE_ITYPE_IMM (-1U), /* dst_mask */
713-
false), /* pcrel_offset */
668+
/* Reserved for R_RISCV_GPREL_HI20. */
669+
EMPTY_HOWTO (49),
714670

715-
/* TP-relative TLS LE store. */
716-
HOWTO (R_RISCV_TPREL_S, /* type */
717-
0, /* rightshift */
718-
4, /* size */
719-
32, /* bitsize */
720-
false, /* pc_relative */
721-
0, /* bitpos */
722-
complain_overflow_signed, /* complain_on_overflow */
723-
bfd_elf_generic_reloc, /* special_function */
724-
"R_RISCV_TPREL_S", /* name */
725-
false, /* partial_inplace */
726-
0, /* src_mask */
727-
ENCODE_STYPE_IMM (-1U), /* dst_mask */
728-
false), /* pcrel_offset */
671+
/* 50 is reserved. */
672+
EMPTY_HOWTO (50),
729673

730674
/* The paired relocation may be relaxed. */
731675
HOWTO (R_RISCV_RELAX, /* type */
@@ -879,6 +823,101 @@ static reloc_howto_type howto_table[] =
879823
0, /* src_mask */
880824
0, /* dst_mask */
881825
false), /* pcrel_offset */
826+
827+
/* Reserved for R_RISCV_TLSDESC_HI20. */
828+
/* EMPTY_HOWTO (62), */
829+
830+
/* Reserved for R_RISCV_TLSDESC_LOAD_LO12. */
831+
/* EMPTY_HOWTO (63), */
832+
833+
/* Reserved for R_RISCV_TLSDESC_ADD_LO12. */
834+
/* EMPTY_HOWTO (64), */
835+
836+
/* Reserved for R_RISCV_TLSDESC_CALL. */
837+
/* EMPTY_HOWTO (65), */
838+
};
839+
840+
/* The relocation table used for SHT_RELA sections for internal use.
841+
Those relocations must be removed before we finish linking. */
842+
843+
static reloc_howto_type howto_table_internal[] =
844+
{
845+
/* R_RISCV_DELETE is omitted since this is special. */
846+
847+
/* High 6 bits of 18-bit absolute address. */
848+
HOWTO (R_RISCV_RVC_LUI, /* type */
849+
0, /* rightshift */
850+
2, /* size */
851+
16, /* bitsize */
852+
false, /* pc_relative */
853+
0, /* bitpos */
854+
complain_overflow_dont, /* complain_on_overflow */
855+
bfd_elf_generic_reloc, /* special_function */
856+
"R_RISCV_RVC_LUI", /* name */
857+
false, /* partial_inplace */
858+
0, /* src_mask */
859+
ENCODE_CITYPE_IMM (-1U), /* dst_mask */
860+
false), /* pcrel_offset */
861+
862+
/* GP-relative load. */
863+
HOWTO (R_RISCV_GPREL_I, /* type */
864+
0, /* rightshift */
865+
4, /* size */
866+
32, /* bitsize */
867+
false, /* pc_relative */
868+
0, /* bitpos */
869+
complain_overflow_dont, /* complain_on_overflow */
870+
bfd_elf_generic_reloc, /* special_function */
871+
"R_RISCV_GPREL_I", /* name */
872+
false, /* partial_inplace */
873+
0, /* src_mask */
874+
ENCODE_ITYPE_IMM (-1U), /* dst_mask */
875+
false), /* pcrel_offset */
876+
877+
/* GP-relative store. */
878+
HOWTO (R_RISCV_GPREL_S, /* type */
879+
0, /* rightshift */
880+
4, /* size */
881+
32, /* bitsize */
882+
false, /* pc_relative */
883+
0, /* bitpos */
884+
complain_overflow_dont, /* complain_on_overflow */
885+
bfd_elf_generic_reloc, /* special_function */
886+
"R_RISCV_GPREL_S", /* name */
887+
false, /* partial_inplace */
888+
0, /* src_mask */
889+
ENCODE_STYPE_IMM (-1U), /* dst_mask */
890+
false), /* pcrel_offset */
891+
892+
/* TP-relative TLS LE load. */
893+
HOWTO (R_RISCV_TPREL_I, /* type */
894+
0, /* rightshift */
895+
4, /* size */
896+
32, /* bitsize */
897+
false, /* pc_relative */
898+
0, /* bitpos */
899+
complain_overflow_signed, /* complain_on_overflow */
900+
bfd_elf_generic_reloc, /* special_function */
901+
"R_RISCV_TPREL_I", /* name */
902+
false, /* partial_inplace */
903+
0, /* src_mask */
904+
ENCODE_ITYPE_IMM (-1U), /* dst_mask */
905+
false), /* pcrel_offset */
906+
907+
/* TP-relative TLS LE store. */
908+
HOWTO (R_RISCV_TPREL_S, /* type */
909+
0, /* rightshift */
910+
4, /* size */
911+
32, /* bitsize */
912+
false, /* pc_relative */
913+
0, /* bitpos */
914+
complain_overflow_signed, /* complain_on_overflow */
915+
bfd_elf_generic_reloc, /* special_function */
916+
"R_RISCV_TPREL_S", /* name */
917+
false, /* partial_inplace */
918+
0, /* src_mask */
919+
ENCODE_STYPE_IMM (-1U), /* dst_mask */
920+
false), /* pcrel_offset */
882921
};
883922

884923
/* A mapping from BFD reloc types to RISC-V ELF reloc types. */
@@ -973,16 +1012,27 @@ riscv_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
9731012
}
9741013

9751014
reloc_howto_type *
976-
riscv_elf_rtype_to_howto (bfd *abfd, unsigned int r_type)
1015+
riscv_elf_rtype_to_howto (bfd *abfd, unsigned int r_type,
1016+
bool lookup_internal)
9771017
{
978-
if (r_type >= ARRAY_SIZE (howto_table))
1018+
reloc_howto_type *ret = NULL;
1019+
if (r_type < ARRAY_SIZE (howto_table))
1020+
{
1021+
ret = &howto_table[r_type];
1022+
if (HOWTO_ISEMPTY (*ret))
1023+
ret = NULL;
1024+
}
1025+
else if (lookup_internal
1026+
&& r_type > R_RISCV_DELETE
1027+
&& r_type < R_RISCV_internal_max)
1028+
ret = &howto_table_internal[r_type - (R_RISCV_DELETE + 1)];
1029+
if (!ret)
9791030
{
9801031
(*_bfd_error_handler) (_("%pB: unsupported relocation type %#x"),
9811032
abfd, r_type);
9821033
bfd_set_error (bfd_error_bad_value);
983-
return NULL;
9841034
}
985-
return &howto_table[r_type];
1035+
return ret;
9861036
}
9871037

9881038
/* Special_function of RISCV_ADD and RISCV_SUB relocations. */

bfd/elfxx-riscv.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ extern reloc_howto_type *
4545
riscv_reloc_type_lookup (bfd *, bfd_reloc_code_real_type);
4646

4747
extern reloc_howto_type *
48-
riscv_elf_rtype_to_howto (bfd *, unsigned int r_type);
48+
riscv_elf_rtype_to_howto (bfd *, unsigned int r_type,
49+
bool lookup_internal);
4950

5051
/* The information of architecture attribute. */
5152
struct riscv_subset_t

0 commit comments

Comments
 (0)