aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormengqinggang <mengqinggang@loongson.cn>2023-07-24 10:08:26 +0100
committerNick Clifton <nickc@redhat.com>2023-07-24 10:08:26 +0100
commit460d3c77f09a5da67e6d1d105725203aba5bf49c (patch)
tree5418ff4b1969045011074a8cf9204b3d194801b7
parent6069b75eeef92193d0b8faab9e8f2eb2183dfce6 (diff)
downloadfsf-binutils-gdb-460d3c77f09a5da67e6d1d105725203aba5bf49c.zip
fsf-binutils-gdb-460d3c77f09a5da67e6d1d105725203aba5bf49c.tar.gz
fsf-binutils-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/ChangeLog12
-rw-r--r--bfd/elfnn-loongarch.c59
-rw-r--r--bfd/elfxx-loongarch.c160
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;
}