diff options
author | mengqinggang <mengqinggang@loongson.cn> | 2023-07-24 10:08:26 +0100 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2023-07-24 10:08:26 +0100 |
commit | 460d3c77f09a5da67e6d1d105725203aba5bf49c (patch) | |
tree | 5418ff4b1969045011074a8cf9204b3d194801b7 | |
parent | 6069b75eeef92193d0b8faab9e8f2eb2183dfce6 (diff) | |
download | gdb-460d3c77f09a5da67e6d1d105725203aba5bf49c.zip gdb-460d3c77f09a5da67e6d1d105725203aba5bf49c.tar.gz gdb-460d3c77f09a5da67e6d1d105725203aba5bf49c.tar.bz2 |
LoongArch: Fix immediate overflow check bug
* elfnn-loongarch.c (RELOCATE_CALC_PC32_HI20): Redefined.
(RELOCATE_CALC_PC64_HI32): Redefined.
* elfxx-loongarch.c (reloc_bits_pcrel20_s2): Delete.
(reloc_bits_b16): Delete.
(reloc_bits_b21): Delete.
(reloc_bits_b26): Delete.
(reloc_sign_bits): New.
-rw-r--r-- | bfd/ChangeLog | 12 | ||||
-rw-r--r-- | bfd/elfnn-loongarch.c | 59 | ||||
-rw-r--r-- | bfd/elfxx-loongarch.c | 160 |
3 files changed, 93 insertions, 138 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 2352f4f..723c8c2 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,15 @@ +2023-07-24 Nick Clifton <nickc@redhat.com> + + Import from mainline: + * elfnn-loongarch.c (RELOCATE_CALC_PC32_HI20): Redefined. + (RELOCATE_CALC_PC64_HI32): Redefined. + + * elfxx-loongarch.c (reloc_bits_pcrel20_s2): Delete. + (reloc_bits_b16): Delete. + (reloc_bits_b21): Delete. + (reloc_bits_b26): Delete. + (reloc_sign_bits): New. + 2023-07-03 Nick Clifton <nickc@redhat.com> * version.m4: Update version number to 2.40.90. diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c index d3d8419..e9c408b 100644 --- a/bfd/elfnn-loongarch.c +++ b/bfd/elfnn-loongarch.c @@ -2284,26 +2284,65 @@ loongarch_reloc_is_fatal (struct bfd_link_info *info, return fatal; } +/* If lo12 immediate > 0x7ff, because sign-extend caused by addi.d/ld.d, + hi20 immediate need to add 0x1. + For example: pc 0x120000000, symbol 0x120000812 + lo12 immediate is 0x812, 0x120000812 & 0xfff = 0x812 + hi20 immediate is 1, because lo12 imm > 0x7ff, symbol need to add 0x1000 + (((0x120000812 + 0x1000) & ~0xfff) - (0x120000000 & ~0xfff)) >> 12 = 0x1 + + At run: + pcalau12i $t0, hi20 (0x1) + $t0 = 0x120000000 + (0x1 << 12) = 0x120001000 + addi.d $t0, $t0, lo12 (0x812) + $t0 = 0x120001000 + 0xfffffffffffff812 (-(0x1000 - 0x812) = -0x7ee) + = 0x120001000 - 0x7ee (0x1000 - 0x7ee = 0x812) + = 0x120000812 + Without hi20 add 0x1000, the result 0x120000000 - 0x7ee = 0x11ffff812 is + error. + 0x1000 + sign-extend-to64(0x8xx) = 0x8xx. */ #define RELOCATE_CALC_PC32_HI20(relocation, pc) \ ({ \ bfd_vma __lo = (relocation) & ((bfd_vma)0xfff); \ - pc = pc & (~(bfd_vma)0xfff); \ + relocation = (relocation & ~(bfd_vma)0xfff) \ + - (pc & ~(bfd_vma)0xfff); \ if (__lo > 0x7ff) \ - { \ relocation += 0x1000; \ - } \ - relocation &= ~(bfd_vma)0xfff; \ - relocation -= pc; \ }) +/* For example: pc is 0x11000010000100, symbol is 0x1812348ffff812 + offset = (0x1812348ffff812 & ~0xfff) - (0x11000010000100 & ~0xfff) + = 0x712347ffff000 + lo12: 0x1812348ffff812 & 0xfff = 0x812 + hi20: 0x7ffff + 0x1(lo12 > 0x7ff) = 0x80000 + lo20: 0x71234 - 0x1(lo12 > 0x7ff) + 0x1(hi20 > 0x7ffff) + hi12: 0x0 + + pcalau12i $t1, hi20 (0x80000) + $t1 = 0x11000010000100 + sign-extend(0x80000 << 12) + = 0x11000010000100 + 0xffffffff80000000 + = 0x10ffff90000000 + addi.d $t0, $zero, lo12 (0x812) + $t0 = 0xfffffffffffff812 (if lo12 > 0x7ff, because sign-extend, + lo20 need to sub 0x1) + lu32i.d $t0, lo12 (0x71234) + $t0 = {0x71234, 0xfffff812} + = 0x71234fffff812 + lu52i.d $t0, hi12 (0x0) + $t0 = {0x0, 0x71234fffff812} + = 0x71234fffff812 + add.d $t1, $t1, $t0 + $t1 = 0x10ffff90000000 + 0x71234fffff812 + = 0x1812348ffff812. */ #define RELOCATE_CALC_PC64_HI32(relocation, pc) \ ({ \ - bfd_vma __lo = (relocation) & ((bfd_vma)0xfff); \ + bfd_vma __lo = (relocation & (bfd_vma)0xfff); \ + relocation = (relocation & ~(bfd_vma)0xfff) \ + - (pc & ~(bfd_vma)0xfff); \ if (__lo > 0x7ff) \ - { \ - relocation -= 0x100000000; \ - } \ - relocation -= (pc & ~(bfd_vma)0xffffffff); \ + relocation += (0x1000 - 0x100000000); \ + if (relocation & 0x80000000) \ + relocation += 0x100000000; \ }) static int diff --git a/bfd/elfxx-loongarch.c b/bfd/elfxx-loongarch.c index da440d5..2d29905 100644 --- a/bfd/elfxx-loongarch.c +++ b/bfd/elfxx-loongarch.c @@ -54,13 +54,7 @@ typedef struct loongarch_reloc_howto_type_struct static bool reloc_bits (bfd *abfd, reloc_howto_type *howto, bfd_vma *val); static bool -reloc_bits_pcrel20_s2 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val); -static bool -reloc_bits_b16 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val); -static bool -reloc_bits_b21 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val); -static bool -reloc_bits_b26 (bfd *abfd, reloc_howto_type *howto, bfd_vma *val); +reloc_sign_bits (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val); static bfd_reloc_status_type loongarch_elf_add_sub_reloc (bfd *, arelent *, asymbol *, void *, @@ -457,7 +451,7 @@ static loongarch_reloc_howto_type loongarch_howto_table[] = 0x3fffc00, /* dst_mask */ false, /* pcrel_offset */ BFD_RELOC_LARCH_SOP_POP_32_S_10_16_S2, /* bfd_reloc_code_real_type */ - reloc_bits_b16, /* adjust_reloc_bits */ + reloc_sign_bits, /* adjust_reloc_bits */ NULL), /* larch_reloc_type_name */ LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_5_20, /* type (43). */ @@ -493,7 +487,7 @@ static loongarch_reloc_howto_type loongarch_howto_table[] = false, /* pcrel_offset */ BFD_RELOC_LARCH_SOP_POP_32_S_0_5_10_16_S2, /* bfd_reloc_code_real_type */ - reloc_bits_b21, /* adjust_reloc_bits */ + reloc_sign_bits, /* adjust_reloc_bits */ NULL), /* larch_reloc_type_name */ LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_0_10_10_16_S2, /* type (45). */ @@ -511,7 +505,7 @@ static loongarch_reloc_howto_type loongarch_howto_table[] = false, /* pcrel_offset */ BFD_RELOC_LARCH_SOP_POP_32_S_0_10_10_16_S2, /* bfd_reloc_code_real_type */ - reloc_bits_b26, /* adjust_reloc_bits */ + reloc_sign_bits, /* adjust_reloc_bits */ NULL), /* larch_reloc_type_name */ LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_U, /* type (46). */ @@ -766,7 +760,7 @@ static loongarch_reloc_howto_type loongarch_howto_table[] = 0x3fffc00, /* dst_mask. */ false, /* pcrel_offset. */ BFD_RELOC_LARCH_B16, /* bfd_reloc_code_real_type. */ - reloc_bits_b16, /* adjust_reloc_bits. */ + reloc_sign_bits, /* adjust_reloc_bits. */ "b16"), /* larch_reloc_type_name. */ LOONGARCH_HOWTO (R_LARCH_B21, /* type (65). */ @@ -783,7 +777,7 @@ static loongarch_reloc_howto_type loongarch_howto_table[] = 0x3fffc1f, /* dst_mask. */ false, /* pcrel_offset. */ BFD_RELOC_LARCH_B21, /* bfd_reloc_code_real_type. */ - reloc_bits_b21, /* adjust_reloc_bits. */ + reloc_sign_bits, /* adjust_reloc_bits. */ "b21"), /* larch_reloc_type_name. */ LOONGARCH_HOWTO (R_LARCH_B26, /* type (66). */ @@ -800,7 +794,7 @@ static loongarch_reloc_howto_type loongarch_howto_table[] = 0x03ffffff, /* dst_mask. */ false, /* pcrel_offset. */ BFD_RELOC_LARCH_B26, /* bfd_reloc_code_real_type. */ - reloc_bits_b26, /* adjust_reloc_bits. */ + reloc_sign_bits, /* adjust_reloc_bits. */ "b26"), /* larch_reloc_type_name. */ LOONGARCH_HOWTO (R_LARCH_ABS_HI20, /* type (67). */ @@ -1436,7 +1430,7 @@ static loongarch_reloc_howto_type loongarch_howto_table[] = 0x1ffffe0, /* dst_mask. */ false, /* pcrel_offset. */ BFD_RELOC_LARCH_PCREL20_S2, /* bfd_reloc_code_real_type. */ - reloc_bits_pcrel20_s2, /* adjust_reloc_bits. */ + reloc_sign_bits, /* adjust_reloc_bits. */ NULL), /* larch_reloc_type_name. */ /* Canonical Frame Address. */ @@ -1677,12 +1671,14 @@ reloc_bits (bfd *abfd ATTRIBUTE_UNUSED, } static bool -reloc_bits_pcrel20_s2 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val) +reloc_sign_bits (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val) { + if (howto->complain_on_overflow != complain_overflow_signed) + return false; + bfd_signed_vma val = (bfd_signed_vma)(*fix_val); - bfd_signed_vma mask = ((bfd_signed_vma)0x1 << howto->bitsize) - 1; - /* Check rightshift. */ + /* Check alignment. FIXME: if rightshift is not alingment. */ if (howto->rightshift && (val & ((((bfd_signed_vma) 1) << howto->rightshift) - 1))) { @@ -1692,8 +1688,12 @@ reloc_bits_pcrel20_s2 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val) return false; } - val = val >> howto->rightshift; + bfd_signed_vma mask = ((bfd_signed_vma)0x1 << (howto->bitsize + + howto->rightshift - 1)) - 1; + /* Positive number: high part is all 0; + Negative number: if high part is not all 0, high part must be all 1. + high part: from sign bit to highest bit. */ if ((val & ~mask) && ((val & ~mask) != ~mask)) { (*_bfd_error_handler) (_("%pB: relocation %s overflow 0x%lx"), @@ -1702,123 +1702,27 @@ reloc_bits_pcrel20_s2 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val) return false; } - /* Perform insn bits field. */ - val = val & mask; - val <<= howto->bitpos; - - *fix_val = (bfd_vma)val; - - return true; -} - - -/* Adjust val to perform insn - R_LARCH_SOP_POP_32_S_10_16_S2 - R_LARCH_B16. */ -static bool -reloc_bits_b16 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val) -{ - bfd_signed_vma val = *fix_val; - bfd_signed_vma mask = ((bfd_signed_vma)0x1 << howto->bitsize) - 1; - - if (howto->complain_on_overflow != complain_overflow_signed) - return false; - - /* Judge whether 4 bytes align. */ - if (val & ((0x1UL << howto->rightshift) - 1)) - return false; - - val = val >> howto->rightshift; - - if ((val & ~mask) && ((val & ~mask) != ~mask)) - { - (*_bfd_error_handler) (_("%pB: relocation %s overflow 0x%lx"), - abfd, howto->name, (long) val); - bfd_set_error (bfd_error_bad_value); - return false; - } - - /* Perform insn bits field. */ - val = val & mask; - val <<= howto->bitpos; - - *fix_val = val; - - return true; -} - -/* Reloc type : - R_LARCH_SOP_POP_32_S_0_5_10_16_S2 - R_LARCH_B21. */ -static bool -reloc_bits_b21 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val) -{ - bfd_signed_vma val = *fix_val; - bfd_signed_vma mask = ((bfd_signed_vma)0x1 << howto->bitsize) - 1; - - if (howto->complain_on_overflow != complain_overflow_signed) - return false; - - /* Judge whether 4 bytes align. */ - if (val & ((0x1UL << howto->rightshift) - 1)) - return false; - val = val >> howto->rightshift; - - if ((val & ~mask) && ((val & ~mask) != ~mask)) - { - (*_bfd_error_handler) (_("%pB: relocation %s overflow 0x%lx"), - abfd, howto->name, (long) val); - bfd_set_error (bfd_error_bad_value); - return false; - } - - /* Perform insn bits field. */ + /* can delete? */ + mask = ((bfd_signed_vma)0x1 << howto->bitsize) - 1; val = val & mask; - /* Perform insn bits field. 15:0<<10, 20:16>>16. */ - val = ((val & 0xffff) << 10) | ((val >> 16) & 0x1f); - - *fix_val = val; - - return true; -} - -/* Reloc type: - R_LARCH_SOP_POP_32_S_0_10_10_16_S2 - R_LARCH_B26. */ -static bool -reloc_bits_b26 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val) -{ - bfd_signed_vma val = *fix_val; - bfd_signed_vma mask = ((bfd_signed_vma)0x1 << howto->bitsize) - 1; - - if (howto->complain_on_overflow != complain_overflow_signed) - return false; - - /* Judge whether 4 bytes align. */ - if (val & ((0x1UL << howto->rightshift) - 1)) - return false; - - val = val >> howto->rightshift; - - if ((val & ~mask) && ((val & ~mask) != ~mask)) + switch (howto->type) { - (*_bfd_error_handler) (_("%pB: relocation %s overflow 0x%lx"), - abfd, howto->name, (long) val); - bfd_set_error (bfd_error_bad_value); - return false; + case R_LARCH_SOP_POP_32_S_0_10_10_16_S2: + case R_LARCH_B26: + /* Perform insn bits field. 25:16>>16, 15:0<<10. */ + val = ((val & 0xffff) << 10) | ((val >> 16) & 0x3ff); + break; + case R_LARCH_B21: + val = ((val & 0xffff) << 10) | ((val >> 16) & 0x1f); + break; + default: + val <<= howto->bitpos; + break; } - - /* Perform insn bits field. */ - val = val & mask; - - /* Perform insn bits field. 25:16>>16, 15:0<<10. */ - val = ((val & 0xffff) << 10) | ((val >> 16) & 0x3ff); - *fix_val = val; - return true; } |