From 4f7cc14110d67a180f5408a91ac53a91f88f776e Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Thu, 12 Dec 2019 09:29:45 +1030 Subject: [PATCH 1/1] gas signed overflow fixes * config/tc-aarch64.c (get_aarch64_insn): Avoid signed overflow. * config/tc-metag.c (parse_dalu): Likewise. * config/tc-tic4x.c (md_pcrel_from): Likewise. * config/tc-tic6x.c (tic6x_output_unwinding): Likewise. * config/tc-csky.c (parse_fexp): Use an unsigned char temp buffer. Don't use register keyword. Avoid signed overflow and remove now unneccesary char masks. Formatting. * config/tc-ia64.c (operand_match): Don't use shifts to sign extend. * config/tc-mep.c (mep_apply_fix): Likewise. * config/tc-pru.c (md_apply_fix): Likewise. * config/tc-riscv.c (load_const): Likewise. * config/tc-nios2.c (md_apply_fix): Likewise. Don't potentially truncate fixup before right shift. Tidy BFD_RELOC_NIOS2_HIADJ16 calculation. --- gas/ChangeLog | 17 ++++++++++++ gas/config/tc-aarch64.c | 3 ++- gas/config/tc-csky.c | 59 +++++++++++++++++++++-------------------- gas/config/tc-ia64.c | 10 +++---- gas/config/tc-mep.c | 2 +- gas/config/tc-metag.c | 4 +-- gas/config/tc-nios2.c | 8 +++--- gas/config/tc-pru.c | 9 ++++--- gas/config/tc-riscv.c | 4 +-- gas/config/tc-tic4x.c | 2 +- gas/config/tc-tic6x.c | 2 +- 11 files changed, 68 insertions(+), 52 deletions(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index d8c5a17b3d..a65b7d37a2 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,20 @@ +2019-12-12 Alan Modra + + * config/tc-aarch64.c (get_aarch64_insn): Avoid signed overflow. + * config/tc-metag.c (parse_dalu): Likewise. + * config/tc-tic4x.c (md_pcrel_from): Likewise. + * config/tc-tic6x.c (tic6x_output_unwinding): Likewise. + * config/tc-csky.c (parse_fexp): Use an unsigned char temp buffer. + Don't use register keyword. Avoid signed overflow and remove now + unneccesary char masks. Formatting. + * config/tc-ia64.c (operand_match): Don't use shifts to sign extend. + * config/tc-mep.c (mep_apply_fix): Likewise. + * config/tc-pru.c (md_apply_fix): Likewise. + * config/tc-riscv.c (load_const): Likewise. + * config/tc-nios2.c (md_apply_fix): Likewise. Don't potentially + truncate fixup before right shift. Tidy BFD_RELOC_NIOS2_HIADJ16 + calculation. + 2019-12-12 Alan Modra * config/obj-evax.c (crc32, encode_32, encode_16, decode_16): diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c index cd4601682b..8879451440 100644 --- a/gas/config/tc-aarch64.c +++ b/gas/config/tc-aarch64.c @@ -5024,7 +5024,8 @@ get_aarch64_insn (char *buf) { unsigned char *where = (unsigned char *) buf; uint32_t result; - result = (where[0] | (where[1] << 8) | (where[2] << 16) | (where[3] << 24)); + result = ((where[0] | (where[1] << 8) | (where[2] << 16) + | ((uint32_t) where[3] << 24))); return result; } diff --git a/gas/config/tc-csky.c b/gas/config/tc-csky.c index 970c72afaf..6fa6ee5dd6 100644 --- a/gas/config/tc-csky.c +++ b/gas/config/tc-csky.c @@ -1777,8 +1777,8 @@ static char * parse_fexp (char *s, expressionS *e, unsigned char isdouble, uint64_t *dbnum) { int length; /* Number of chars in an object. */ - register char const *err = NULL; /* Error from scanning float literal. */ - char temp[8]; + const char *err = NULL; /* Error from scanning float literal. */ + unsigned char temp[8]; /* input_line_pointer->1st char of a flonum (we hope!). */ input_line_pointer = s; @@ -1788,9 +1788,9 @@ parse_fexp (char *s, expressionS *e, unsigned char isdouble, uint64_t *dbnum) input_line_pointer += 2; if (isdouble) - err = md_atof ('d', temp, &length); + err = md_atof ('d', (char *) temp, &length); else - err = md_atof ('f', temp, &length); + err = md_atof ('f', (char *) temp, &length); know (length <= 8); know (err != NULL || length > 0); @@ -1818,41 +1818,42 @@ parse_fexp (char *s, expressionS *e, unsigned char isdouble, uint64_t *dbnum) { uint32_t fnum; if (target_big_endian) - fnum = (((temp[0] << 24) & 0xffffffff) - | ((temp[1] << 16) & 0xffffff) - | ((temp[2] << 8) & 0xffff) - | (temp[3] & 0xff)); + fnum = (((uint32_t) temp[0] << 24) + | (temp[1] << 16) + | (temp[2] << 8) + | temp[3]); else - fnum = (((temp[3] << 24) & 0xffffffff) - | ((temp[2] << 16) & 0xffffff) - | ((temp[1] << 8) & 0xffff) - | (temp[0] & 0xff)); - e->X_add_number = fnum; } + fnum = (((uint32_t) temp[3] << 24) + | (temp[2] << 16) + | (temp[1] << 8) + | temp[0]); + e->X_add_number = fnum; + } else { if (target_big_endian) { - *dbnum = (((temp[0] << 24) & 0xffffffff) - | ((temp[1] << 16) & 0xffffff) - | ((temp[2] << 8) & 0xffff) - | (temp[3] & 0xff)); + *dbnum = (((uint32_t) temp[0] << 24) + | (temp[1] << 16) + | (temp[2] << 8) + | temp[3]); *dbnum <<= 32; - *dbnum |= (((temp[4] << 24) & 0xffffffff) - | ((temp[5] << 16) & 0xffffff) - | ((temp[6] << 8) & 0xffff) - | (temp[7] & 0xff)); + *dbnum |= (((uint32_t) temp[4] << 24) + | (temp[5] << 16) + | (temp[6] << 8) + | temp[7]); } else { - *dbnum = (((temp[7] << 24) & 0xffffffff) - | ((temp[6] << 16) & 0xffffff) - | ((temp[5] << 8) & 0xffff) - | (temp[4] & 0xff)); + *dbnum = (((uint32_t) temp[7] << 24) + | (temp[6] << 16) + | (temp[5] << 8) + | temp[4]); *dbnum <<= 32; - *dbnum |= (((temp[3] << 24) & 0xffffffff) - | ((temp[2] << 16) & 0xffffff) - | ((temp[1] << 8) & 0xffff) - | (temp[0] & 0xff)); + *dbnum |= (((uint32_t) temp[3] << 24) + | (temp[2] << 16) + | (temp[1] << 8) + | temp[0]); } } return input_line_pointer; diff --git a/gas/config/tc-ia64.c b/gas/config/tc-ia64.c index 0c618e811e..5eb024e92b 100644 --- a/gas/config/tc-ia64.c +++ b/gas/config/tc-ia64.c @@ -5839,9 +5839,8 @@ operand_match (const struct ia64_opcode *idesc, int res_index, expressionS *e) /* Sign-extend 32-bit unsigned numbers, so that the following range checks will work. */ val = e->X_add_number; - if (((val & (~(bfd_vma) 0 << 32)) == 0) - && ((val & ((bfd_vma) 1 << 31)) != 0)) - val = ((val << 32) >> 32); + if ((val & (~(bfd_vma) 0 << 32)) == 0) + val = (val ^ ((bfd_vma) 1 << 31)) - ((bfd_vma) 1 << 31); /* Check for 0x100000000. This is valid because 0x100000000-1 is the same as ((uint32_t) -1). */ @@ -5879,9 +5878,8 @@ operand_match (const struct ia64_opcode *idesc, int res_index, expressionS *e) /* Sign-extend 32-bit unsigned numbers, so that the following range checks will work. */ val = e->X_add_number; - if (((val & (~(bfd_vma) 0 << 32)) == 0) - && ((val & ((bfd_vma) 1 << 31)) != 0)) - val = ((val << 32) >> 32); + if ((val & (~(bfd_vma) 0 << 32)) == 0) + val = (val ^ ((bfd_vma) 1 << 31)) - ((bfd_vma) 1 << 31); } else val = e->X_add_number; diff --git a/gas/config/tc-mep.c b/gas/config/tc-mep.c index c0d48e8354..18e96c8046 100644 --- a/gas/config/tc-mep.c +++ b/gas/config/tc-mep.c @@ -1790,7 +1790,7 @@ mep_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) switch (fixP->fx_cgen.opinfo) { case BFD_RELOC_MEP_LOW16: - *valP = ((long)(*valP & 0xffff)) << 16 >> 16; + *valP = ((*valP & 0xffff) ^ 0x8000) - 0x8000; break; case BFD_RELOC_MEP_HI16U: *valP >>= 16; diff --git a/gas/config/tc-metag.c b/gas/config/tc-metag.c index c7bb36d5b9..d056e9adf7 100644 --- a/gas/config/tc-metag.c +++ b/gas/config/tc-metag.c @@ -5340,7 +5340,7 @@ parse_dalu (const char *line, metag_insn *insn, /* Only MOV instructions have a DSP register as a destination. Set the MOV DSPe.r opcode. The simple OR'ing is OK because the usual MOV opcode is 0x00. */ - insn->bits = (0x91 << 24); + insn->bits = 0x91u << 24; du_shift = 0; l1_shift = 2; regs_shift[0] = 19; @@ -5455,7 +5455,7 @@ parse_dalu (const char *line, metag_insn *insn, du_shift = 0; l1_shift = 2; regs_shift[1] = 14; - insn->bits = (0x92 << 24); /* Set opcode. */ + insn->bits = 0x92u << 24; /* Set opcode. */ } } } diff --git a/gas/config/tc-nios2.c b/gas/config/tc-nios2.c index ec572a61ce..f1a02001f8 100644 --- a/gas/config/tc-nios2.c +++ b/gas/config/tc-nios2.c @@ -1384,7 +1384,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) nios2_diagnose_overflow (fixup, howto, fixP, value); /* Apply the right shift. */ - fixup = ((signed)fixup) >> howto->rightshift; + fixup = (offsetT) fixup >> howto->rightshift; /* Truncate the fixup to right size. */ switch (fixP->fx_r_type) @@ -1396,13 +1396,11 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) fixup = fixup & 0xFFFF; break; case BFD_RELOC_NIOS2_HIADJ16: - fixup = ((((fixup >> 16) & 0xFFFF) + ((fixup >> 15) & 0x01)) - & 0xFFFF); + fixup = ((fixup + 0x8000) >> 16) & 0xFFFF; break; default: { - int n = sizeof (fixup) * 8 - howto->bitsize; - fixup = (fixup << n) >> n; + fixup &= ((valueT) 1 << howto->bitsize) - 1; break; } } diff --git a/gas/config/tc-pru.c b/gas/config/tc-pru.c index 2e2058c1de..6de9f3ce48 100644 --- a/gas/config/tc-pru.c +++ b/gas/config/tc-pru.c @@ -642,7 +642,6 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) { unsigned char *where; valueT value = *valP; - long n; /* Assert that the fixup is one we can handle. */ gas_assert (fixP != NULL && valP != NULL @@ -801,11 +800,13 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) pru_diagnose_overflow (fixup, howto, fixP, insn); /* Apply the right shift. */ - fixup = ((offsetT)fixup) >> howto->rightshift; + fixup = (offsetT) fixup >> howto->rightshift; /* Truncate the fixup to right size. */ - n = sizeof (fixup) * 8 - howto->bitsize; - fixup = (fixup << n) >> n; + if (howto->bitsize == 0) + fixup = 0; + else + fixup &= ((valueT) 2 << (howto->bitsize - 1)) - 1; /* Fix up the instruction. Non-contiguous bitfields need special handling. */ diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c index 055d80c344..7ec1028b28 100644 --- a/gas/config/tc-riscv.c +++ b/gas/config/tc-riscv.c @@ -1043,9 +1043,9 @@ static void load_const (int reg, expressionS *ep) { int shift = RISCV_IMM_BITS; - bfd_vma upper_imm; + bfd_vma upper_imm, sign = (bfd_vma) 1 << (RISCV_IMM_BITS - 1); expressionS upper = *ep, lower = *ep; - lower.X_add_number = (int32_t) ep->X_add_number << (32-shift) >> (32-shift); + lower.X_add_number = ((ep->X_add_number & (sign + sign - 1)) ^ sign) - sign; upper.X_add_number -= lower.X_add_number; if (ep->X_op != O_constant) diff --git a/gas/config/tc-tic4x.c b/gas/config/tc-tic4x.c index b5588b9c46..bbbd696e43 100644 --- a/gas/config/tc-tic4x.c +++ b/gas/config/tc-tic4x.c @@ -2937,7 +2937,7 @@ md_pcrel_from (fixS *fixP) unsigned int op; buf = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where; - op = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + op = ((unsigned) buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; return ((fixP->fx_where + fixP->fx_frag->fr_address) >> 2) + tic4x_pc_offset (op); diff --git a/gas/config/tc-tic6x.c b/gas/config/tc-tic6x.c index cd12c82dce..6260ecb983 100644 --- a/gas/config/tc-tic6x.c +++ b/gas/config/tc-tic6x.c @@ -5060,7 +5060,7 @@ tic6x_output_unwinding (bfd_boolean need_extab) if (unwind->personality_index == -1) { tmp = md_chars_to_number (unwind->frag_start + 4, 4); - tmp |= ((unwind->data_bytes - 8) >> 2) << 24; + tmp |= (valueT) ((unwind->data_bytes - 8) >> 2) << 24; md_number_to_chars (unwind->frag_start + 4, tmp, 4); } else if (unwind->personality_index == 1 || unwind->personality_index == 2) -- 2.34.1