aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2020-06-24 10:24:32 +0930
committerAlan Modra <amodra@gmail.com>2020-06-24 10:48:15 +0930
commitf8b1e5f6fcdb27c7ea520643880a208578d42d0e (patch)
tree429b4a7bb209434c48541f9744761370ba3de3de
parentd5722d3be21d05f8735da36bfa3d03f8bad06079 (diff)
downloadgdb-f8b1e5f6fcdb27c7ea520643880a208578d42d0e.zip
gdb-f8b1e5f6fcdb27c7ea520643880a208578d42d0e.tar.gz
gdb-f8b1e5f6fcdb27c7ea520643880a208578d42d0e.tar.bz2
ubsan: alpha-vms: shift exponent 536874240 is too large
C_OPR_ASH is supposed to be an arithmetic shift. By the look of it, this operator implemented logical shifts since the original binutils support was added. This patch corrects that and avoids some nonsense ubsan complaints. I chose to implement infinite precision shifts rather than masking shift counts to the word size as the spec I had is silent on what is supposed to happen with overlarge shift counts. * vms-alpha.c (_bfd_vms_slurp_etir <ETIR__C_OPR_ASH>): Implement shifts without undefined behaviour.
-rw-r--r--bfd/ChangeLog5
-rw-r--r--bfd/vms-alpha.c29
2 files changed, 30 insertions, 4 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 5d1075e..9c202b2 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,8 @@
+2020-06-24 Alan Modra <amodra@gmail.com>
+
+ * vms-alpha.c (_bfd_vms_slurp_etir <ETIR__C_OPR_ASH>): Implement
+ shifts without undefined behaviour.
+
2020-06-23 H.J. Lu <hongjiu.lu@intel.com>
* elf-bfd.h (elf_link_hash_table): Add dt_pltgot_required and
diff --git a/bfd/vms-alpha.c b/bfd/vms-alpha.c
index e31a9e4..5bf32d6 100644
--- a/bfd/vms-alpha.c
+++ b/bfd/vms-alpha.c
@@ -34,6 +34,7 @@
*/
#include "sysdep.h"
+#include <limits.h>
#include "bfd.h"
#include "bfdlink.h"
#include "libbfd.h"
@@ -71,6 +72,9 @@
#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
/* The r_type field in a reloc is one of the following values. */
#define ALPHA_R_IGNORE 0
@@ -2520,10 +2524,27 @@ _bfd_vms_slurp_etir (bfd *abfd, struct bfd_link_info *info)
_bfd_vms_etir_name (cmd));
return FALSE;
}
- if ((int)op2 < 0) /* Shift right. */
- op1 >>= -(int)op2;
- else /* Shift left. */
- op1 <<= (int)op2;
+ if ((bfd_signed_vma) op2 < 0)
+ {
+ /* Shift right. */
+ bfd_vma sign;
+ op2 = -op2;
+ if (op2 >= CHAR_BIT * sizeof (op1))
+ op2 = CHAR_BIT * sizeof (op1) - 1;
+ /* op1 = (bfd_signed_vma) op1 >> op2; */
+ sign = op1 & ((bfd_vma) 1 << (CHAR_BIT * sizeof (op1) - 1));
+ op1 >>= op2;
+ sign >>= op2;
+ op1 = (op1 ^ sign) - sign;
+ }
+ else
+ {
+ /* Shift left. */
+ if (op2 >= CHAR_BIT * sizeof (op1))
+ op1 = 0;
+ else
+ op1 <<= op2;
+ }
if (!_bfd_vms_push (abfd, op1, RELC_NONE)) /* FIXME: sym. */
return FALSE;
break;