This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH] gas: bad output of double pseudo instruction
- From: Bosco García <jbgg dot gnu at gmail dot com>
- To: binutils at sourceware dot org
- Date: Sat, 17 Aug 2019 03:38:58 +0200
- Subject: [PATCH] gas: bad output of double pseudo instruction
Some numbers are interpreted in bad way by function atof_general.
The next POC is shown:
$ cat << EOF | as -o test -- && objdump -s test
.data
.double .0000000000000000000001
.double 1e-22
EOF
The output is:
test: file format elf64-x86-64
Contents of section .data:
0000 00000000 00000000 e65e1710 20395e3b .........^.. 9^;
Where we note that the same number is interpreted different,
in this case the output of the first form is bad.
The reason of this bug is the function atof_general which assumes,
when the number of digits is calculated, that the ``left'' zeros are
deleted, but this is not the case for the zeros after decimal mark.
The next patch fix this problem by skipping all zeros at the ``left'' side,
when there is zero after decimal mark then they are skipped and an
appropiate decimal_exponent is calculated for the shift which is then
propertly added to the final variable decimal_exponent.
diff --git a/gas/atof-generic.c b/gas/atof-generic.c
index 40ee910c72..0e97dc387c 100644
--- a/gas/atof-generic.c
+++ b/gas/atof-generic.c
@@ -189,18 +189,40 @@ atof_generic (/* return pointer to just AFTER number we read. */
* come out inexact for some reason related to length of the digit
* string.
*/
+ /* The case number_of_digits_before_decimal = 0 is handled for
+ * deleting zeros after decimal. In this case the decimal mark and
+ * the first zero digits after decimal mark are skipped.
+ */
+ seen_significant_digit = 0;
+ long substract_decimal_exponent = 0;
if (c && IS_DECIMAL_MARK (c))
{
unsigned int zeros = 0; /* Length of current string of zeros */
+ if( number_of_digits_before_decimal==0 )
+ {
+ /* skip decimal mark */
+ first_digit++;
+ }
+
for (p++; (c = *p) && ISDIGIT (c); p++)
{
if (c == '0')
{
- zeros++;
+ if( number_of_digits_before_decimal == 0 && !seen_significant_digit )
+ {
+ /* skip '0' and */
+ first_digit++;
+ substract_decimal_exponent--;
+ }
+ else
+ {
+ zeros++;
+ }
}
else
{
+ seen_significant_digit=1;
number_of_digits_after_decimal += 1 + zeros;
zeros = 0;
}
@@ -287,6 +309,11 @@ atof_generic (/* return pointer to just AFTER number we read. */
}
}
+ /* substract_decimal_exponent != 0 when number_of_digits_before_decimal = 0
+ * and first digit after decimal is '0'
+ */
+ decimal_exponent += substract_decimal_exponent;
+
*address_of_string_pointer = p;
number_of_digits_available =