diff -rupN binutils.orig/bfd/elfnn-riscv.c binutils-2.41/bfd/elfnn-riscv.c --- binutils.orig/bfd/elfnn-riscv.c 2024-01-02 17:35:07.412218130 +0000 +++ binutils-2.41/bfd/elfnn-riscv.c 2024-01-02 17:36:52.274311071 +0000 @@ -1737,7 +1737,10 @@ perform_relocation (const reloc_howto_ty { if (howto->pc_relative) value -= sec_addr (input_section) + rel->r_offset; - value += rel->r_addend; + + /* PR31179, ignore the non-zero addend of R_RISCV_SUB_ULEB128. */ + if (ELFNN_R_TYPE (rel->r_info) != R_RISCV_SUB_ULEB128) + value += rel->r_addend; switch (ELFNN_R_TYPE (rel->r_info)) { @@ -1818,10 +1821,7 @@ perform_relocation (const reloc_howto_ty value = ENCODE_CITYPE_LUI_IMM (RISCV_CONST_HIGH_PART (value)); break; - /* SUB_ULEB128 must be applied after SET_ULEB128, so we only write the - value back for SUB_ULEB128 should be enough. */ - case R_RISCV_SET_ULEB128: - break; + /* R_RISCV_SET_ULEB128 won't go into here. */ case R_RISCV_SUB_ULEB128: { unsigned int len = 0; @@ -2514,7 +2514,7 @@ riscv_elf_relocate_section (bfd *output_ else { msg = ("Mismatched R_RISCV_SET_ULEB128, it must be paired with" - "and applied before R_RISCV_SUB_ULEB128"); + " and applied before R_RISCV_SUB_ULEB128"); r = bfd_reloc_dangerous; } break; @@ -2523,14 +2523,40 @@ riscv_elf_relocate_section (bfd *output_ if (uleb128_set_rel != NULL && uleb128_set_rel->r_offset == rel->r_offset) { - relocation = uleb128_set_vma - relocation; + relocation = uleb128_set_vma - relocation + + uleb128_set_rel->r_addend; uleb128_set_vma = 0; uleb128_set_rel = NULL; + + /* PR31179, the addend of SUB_ULEB128 should be zero if using + .uleb128, but we make it non-zero by accident in assembler, + so just ignore it in perform_relocation, and make assembler + continue doing the right thing. Don't reset the addend of + SUB_ULEB128 to zero here since it will break the --emit-reloc, + even though the non-zero addend is unexpected. + + We encourage people to rebuild their stuff to get the + non-zero addend of SUB_ULEB128, but that might need some + times, so report warnings to inform people need to rebuild + if --check-uleb128 is enabled. However, since the failed + .reloc cases for ADD/SET/SUB/ULEB128 are rarely to use, it + may acceptable that stop supproting them until people rebuld + their stuff, maybe half-year or one year later. I believe + this might be the least harmful option that we should go. + + Or maybe we should teach people that don't write the + .reloc R_RISCV_SUB* with non-zero constant, and report + warnings/errors in assembler. */ + if (htab->params->check_uleb128 + && rel->r_addend != 0) + _bfd_error_handler (_("%pB: warning: R_RISCV_SUB_ULEB128 with" + " non-zero addend, please rebuild by" + " Fedora 40 binutils or up"), input_bfd); } else { msg = ("Mismatched R_RISCV_SUB_ULEB128, it must be paired with" - "and applied after R_RISCV_SET_ULEB128"); + " and applied after R_RISCV_SET_ULEB128"); r = bfd_reloc_dangerous; } break; @@ -5123,7 +5149,13 @@ _bfd_riscv_relax_section (bfd *abfd, ase if (h != NULL && h->type == STT_GNU_IFUNC) continue; + /* Maybe we should check UNDEFWEAK_NO_DYNAMIC_RELOC here? But that + will break the undefweak relaxation testcases, so just make sure + we won't do relaxations for linker_def symbols in short-term. */ if (h->root.type == bfd_link_hash_undefweak + /* The linker_def symbol like __ehdr_start that may be undefweak + for now, but will be guaranteed to be defined later. */ + && !h->root.linker_def && (relax_func == _bfd_riscv_relax_lui || relax_func == _bfd_riscv_relax_pc)) { diff -rupN binutils.orig/bfd/elfxx-riscv.h binutils-2.41/bfd/elfxx-riscv.h --- binutils.orig/bfd/elfxx-riscv.h 2024-01-02 17:35:07.412218130 +0000 +++ binutils-2.41/bfd/elfxx-riscv.h 2024-01-02 17:35:24.252233056 +0000 @@ -31,6 +31,8 @@ struct riscv_elf_params { /* Whether to relax code sequences to GP-relative addressing. */ bool relax_gp; + /* Whether to check if SUB_ULEB128 relocation has non-zero addend. */ + bool check_uleb128; }; extern void riscv_elf32_set_options (struct bfd_link_info *, diff -rupN binutils.orig/ld/NEWS binutils-2.41/ld/NEWS --- binutils.orig/ld/NEWS 2024-01-02 17:35:08.012218662 +0000 +++ binutils-2.41/ld/NEWS 2024-01-02 17:35:56.139261318 +0000 @@ -1,5 +1,10 @@ -*- text -*- +* On RISC-V, add ld target option --[no-]check-uleb128. Should rebuild the + objects by binutils 2.42 and up if enabling the option and get warnings, + since the non-zero addend of SUB_ULEB128 shouldn't be generated from .uleb128 + directives. + * Added --warn-execstack-objects to warn about executable stacks only when an input object file requests one. Also added --error-execstack and --error-rxw-segments options to convert warnings about executable stacks and diff -rupN binutils.orig/ld/emultempl/riscvelf.em binutils-2.41/ld/emultempl/riscvelf.em --- binutils.orig/ld/emultempl/riscvelf.em 2024-01-02 17:35:07.699218385 +0000 +++ binutils-2.41/ld/emultempl/riscvelf.em 2024-01-02 17:35:24.252233056 +0000 @@ -25,7 +25,8 @@ fragment <<EOF #include "elf/riscv.h" #include "elfxx-riscv.h" -static struct riscv_elf_params params = { .relax_gp = 1 }; +static struct riscv_elf_params params = { .relax_gp = 1, + .check_uleb128 = 0}; EOF # Define some shell vars to insert bits of code into the standard elf @@ -35,17 +36,23 @@ enum risccv_opt { OPTION_RELAX_GP = 321, OPTION_NO_RELAX_GP, + OPTION_CHECK_ULEB128, + OPTION_NO_CHECK_ULEB128, }; ' PARSE_AND_LIST_LONGOPTS=${PARSE_AND_LIST_LONGOPTS}' { "relax-gp", no_argument, NULL, OPTION_RELAX_GP }, { "no-relax-gp", no_argument, NULL, OPTION_NO_RELAX_GP }, + { "check-uleb128", no_argument, NULL, OPTION_CHECK_ULEB128 }, + { "no-check-uleb128", no_argument, NULL, OPTION_NO_CHECK_ULEB128 }, ' PARSE_AND_LIST_OPTIONS=${PARSE_AND_LIST_OPTIONS}' fprintf (file, _(" --relax-gp Perform GP relaxation\n")); fprintf (file, _(" --no-relax-gp Don'\''t perform GP relaxation\n")); + fprintf (file, _(" --check-uleb128 Check if SUB_ULEB128 has non-zero addend\n")); + fprintf (file, _(" --no-check-uleb128 Don'\''t check if SUB_ULEB128 has non-zero addend\n")); ' PARSE_AND_LIST_ARGS_CASES=${PARSE_AND_LIST_ARGS_CASES}' @@ -56,6 +63,14 @@ PARSE_AND_LIST_ARGS_CASES=${PARSE_AND_LI case OPTION_NO_RELAX_GP: params.relax_gp = 0; break; + + case OPTION_CHECK_ULEB128: + params.check_uleb128 = 1; + break; + + case OPTION_NO_CHECK_ULEB128: + params.check_uleb128 = 0; + break; ' fragment <<EOF diff -rupN binutils.orig/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp binutils-2.41/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp --- binutils.orig/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp 2024-01-02 17:35:07.942218600 +0000 +++ binutils-2.41/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp 2024-01-02 17:35:24.252233056 +0000 @@ -173,6 +173,8 @@ if [istarget "riscv*-*-*"] { run_dump_test "attr-phdr" run_dump_test "relax-max-align-gp" run_dump_test "uleb128" + run_dump_test "pr31179" + run_dump_test "pr31179-r" run_ld_link_tests [list \ [list "Weak reference 32" "-T weakref.ld -m[riscv_choose_ilp32_emul]" "" \ "-march=rv32i -mabi=ilp32" {weakref32.s} \ diff -rupN binutils.orig/ld/testsuite/ld-riscv-elf/pr31179-r.d binutils-2.41/ld/testsuite/ld-riscv-elf/pr31179-r.d --- binutils.orig/ld/testsuite/ld-riscv-elf/pr31179-r.d 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.41/ld/testsuite/ld-riscv-elf/pr31179-r.d 2024-01-02 17:35:24.252233056 +0000 @@ -0,0 +1,10 @@ +#source: pr31179.s +#as: +#readelf: -Wr + +Relocation section '.rela.text' at .* +[ ]+Offset[ ]+Info[ ]+Type[ ]+.* +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_SET_ULEB128[ ]+[0-9a-f]+[ ]+bar \+ 1 +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_SUB_ULEB128[ ]+[0-9a-f]+[ ]+foo \+ 0 +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_SET_ULEB128[ ]+[0-9a-f]+[ ]+bar \+ 1 +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_SUB_ULEB128[ ]+[0-9a-f]+[ ]+foo \+ 1 diff -rupN binutils.orig/ld/testsuite/ld-riscv-elf/pr31179.d binutils-2.41/ld/testsuite/ld-riscv-elf/pr31179.d --- binutils.orig/ld/testsuite/ld-riscv-elf/pr31179.d 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.41/ld/testsuite/ld-riscv-elf/pr31179.d 2024-01-02 17:35:24.252233056 +0000 @@ -0,0 +1,11 @@ +#source: pr31179.s +#as: +#ld: --check-uleb128 +#objdump: -sj .text +#warning: .*R_RISCV_SUB_ULEB128 with non-zero addend, please rebuild by Fedora 40 binutils or up + +.*:[ ]+file format .* + +Contents of section .text: + +[ ]+[0-9a-f]+[ ]+00000303[ ]+.* diff -rupN binutils.orig/ld/testsuite/ld-riscv-elf/pr31179.s binutils-2.41/ld/testsuite/ld-riscv-elf/pr31179.s --- binutils.orig/ld/testsuite/ld-riscv-elf/pr31179.s 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.41/ld/testsuite/ld-riscv-elf/pr31179.s 2024-01-02 17:35:24.252233056 +0000 @@ -0,0 +1,13 @@ +.globl _start +_start: + +foo: +.2byte 0 +bar: + +.uleb128 bar - foo + 1 + +reloc: +.reloc reloc, R_RISCV_SET_ULEB128, bar + 1 +.reloc reloc, R_RISCV_SUB_ULEB128, foo + 1 +.byte 0x0 --- binutils.orig/gas/config/tc-riscv.c 2024-01-03 13:08:16.588286420 +0000 +++ binutils-2.41/gas/config/tc-riscv.c 2024-01-03 13:08:32.749297812 +0000 @@ -4949,6 +4949,7 @@ riscv_insert_uleb128_fixes (bfd *abfd AT fix_new_exp (fragP, fragP->fr_fix, 0, exp_dup, 0, BFD_RELOC_RISCV_SET_ULEB128); exp_dup->X_add_symbol = exp->X_op_symbol; + exp_dup->X_add_number = 0; /* Set addend of SUB_ULEB128 to zero. */ fix_new_exp (fragP, fragP->fr_fix, 0, exp_dup, 0, BFD_RELOC_RISCV_SUB_ULEB128); }