diff options
Diffstat (limited to 'results/classifier/105/other/1821444')
| -rw-r--r-- | results/classifier/105/other/1821444 | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/results/classifier/105/other/1821444 b/results/classifier/105/other/1821444 new file mode 100644 index 000000000..1e2facc93 --- /dev/null +++ b/results/classifier/105/other/1821444 @@ -0,0 +1,166 @@ +other: 0.240 +mistranslation: 0.117 +graphic: 0.106 +device: 0.081 +KVM: 0.080 +instruction: 0.067 +network: 0.063 +semantic: 0.062 +vnc: 0.061 +assembly: 0.049 +boot: 0.047 +socket: 0.027 + +qemu-ppc (user) incorrectly translates float32 arithmetics + +I'm using qemu-3.1.0 (Gentoo). + +When I was running regression test suite via qemu-ppc for GHC I noticed a few uint32_t<->float32 failures I did not expect to encounter. + +Here is an example + +$ cat a.c +#include <stdio.h> +#include <stdint.h> + +int main() { + volatile uint32_t i = 1; + printf("0x1 = %e\n", *(volatile float*)&i); +} + +$ powerpc-unknown-linux-gnu-gcc -O2 a.c -Wall -o a -fno-strict-aliasing -fno-stack-protector -static && ./a +0x1 = 2.802597e-45 + +$ scp a timberdoodle.ppc64.dev.gentoo.org:~/ +a 100% 826KB 102.0KB/s 00:08 + +$ ssh timberdoodle.ppc64.dev.gentoo.org ./a +0x1 = 1.401298e-45 +$ qemu-ppc ./a +0x1 = 2.802597e-45 + +Looks like off-by-one bit somewhere. I'm not sure if it's FPU instruction or some internals of printf() that are emulated incorrectly. + + + +My native system is x86_64-pc-linux-gnu with a few binfmt_misc handlers wired. +Checking other targets I have locally I get the following: + +affected targets: +- powerpc +- powerpc64 +- powerpc64le +unaffected targets: +- arm +- arm64 +- hppa +- sparc +probably unaffected: +- alpha (maybe it's ok as alpha is not quite an IEEE754 platform) + +Raw log: + +$ for gcc in /usr/bin/*-gcc; do rm -f a; $gcc -O2 a.c -Wall -o a -fno-strict-aliasing -fno-stack-protector 2>/dev/null && ./a 2>/dev/null && echo -n "$gcc: " && file a; done | sort + +0x1 = 1.401298e-45 : /usr/bin/aarch64-unknown-linux-gnu-gcc: a: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, not stripped +0x1 = 1.401298e-45 : /usr/bin/aarch64_be-unknown-linux-gnu-gcc: a: ELF 64-bit MSB pie executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64_be.so.1, for GNU/Linux 3.7.0, not stripped +0x1 = 1.401298e-45 : /usr/bin/afl-gcc: a: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, with debug_info, not stripped +0x1 = 1.401298e-45 : /usr/bin/armv6j-unknown-linux-gnueabihf-gcc: a: ELF 32-bit LSB pie executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, not stripped +0x1 = 1.401298e-45 : /usr/bin/armv7a-unknown-linux-gnueabihf-gcc: a: ELF 32-bit LSB pie executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, not stripped +0x1 = 1.401298e-45 : /usr/bin/hppa-unknown-linux-gnu-gcc: a: ELF 32-bit MSB pie executable, PA-RISC, 1.1 version 1 (GNU/Linux), dynamically linked, interpreter /lib/ld.so.1, for GNU/Linux 3.2.0, with debug_info, not stripped +0x1 = 1.401298e-45 : /usr/bin/hppa2.0-unknown-linux-gnu-gcc: a: ELF 32-bit MSB pie executable, PA-RISC, 1.1 version 1 (GNU/Linux), dynamically linked, interpreter /lib/ld.so.1, for GNU/Linux 3.2.0, with debug_info, not stripped +0x1 = 1.401298e-45 : /usr/bin/m68k-unknown-linux-gnu-gcc: a: ELF 32-bit MSB pie executable, Motorola m68k, 68020, version 1 (SYSV), dynamically linked, interpreter /lib/ld.so.1, for GNU/Linux 3.2.0, not stripped +0x1 = 1.401298e-45 : /usr/bin/mips64-unknown-linux-gnuabin64-gcc: a: ELF 64-bit MSB pie executable, MIPS, MIPS-III version 1 (SYSV), dynamically linked, interpreter /lib64/ld.so.1, for GNU/Linux 3.2.0, not stripped +0x1 = 1.401298e-45 : /usr/bin/riscv64-unknown-linux-gnu-gcc: a: ELF 64-bit LSB pie executable, UCB RISC-V, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-riscv64-lp64d.so.1, for GNU/Linux 4.15.0, not stripped +0x1 = 1.401298e-45 : /usr/bin/s390x-unknown-linux-gnu-gcc: a: ELF 64-bit MSB pie executable, IBM S/390, version 1 (SYSV), dynamically linked, interpreter /lib/ld64.so.1, for GNU/Linux 3.2.0, not stripped +0x1 = 1.401298e-45 : /usr/bin/sparc-unknown-linux-gnu-gcc: a: ELF 32-bit MSB pie executable, SPARC32PLUS, V8+ Required, total store ordering, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, not stripped +0x1 = 1.401298e-45 : /usr/bin/x86_64-HEAD-linux-gnu-gcc: a: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, not stripped +0x1 = 1.401298e-45 : /usr/bin/x86_64-UNREG-linux-gnu-gcc: a: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, not stripped +0x1 = 1.401298e-45 : /usr/bin/x86_64-pc-linux-gnu-gcc: a: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, with debug_info, not stripped + +0x1 = 2.652494e-315 : /usr/bin/alpha-unknown-linux-gnu-gcc: a: ELF 64-bit LSB pie executable, Alpha (unofficial), version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, not stripped + +0x1 = 2.802597e-45 : /usr/bin/powerpc-unknown-linux-gnu-gcc: a: ELF 32-bit MSB pie executable, PowerPC or cisco 4500, version 1 (SYSV), dynamically linked, interpreter /lib/ld.so.1, for GNU/Linux 3.2.0, not stripped +0x1 = 2.802597e-45 : /usr/bin/powerpc64-unknown-linux-gnu-gcc: a: ELF 64-bit MSB pie executable, 64-bit PowerPC or cisco 7500, version 1 (SYSV), dynamically linked, interpreter /lib64/ld64.so.1, for GNU/Linux 3.2.0, not stripped +0x1 = 2.802597e-45 : /usr/bin/powerpc64le-unknown-linux-gnu-gcc: a: ELF 64-bit LSB pie executable, 64-bit PowerPC or cisco 7500, version 1 (SYSV), dynamically linked, interpreter /lib64/ld64.so.2, for GNU/Linux 3.10.0, not stripped + +Shorter example without relying on printf() implementation. Looks like uint32_t<->float<->double transitions are enough. + +$ cat a.c +#include <stdio.h> +#include <stdint.h> + +int main() { + volatile uint32_t i = 1; + volatile float f; + volatile double d; + *(volatile uint32_t*)&f = i; + d = f; f = d; // double conversion + i = *(volatile uint32_t*)&f; + printf("0x1 = %x\n", i); +} + +$ powerpc-unknown-linux-gnu-gcc -O2 a.c -Wall -o a -fno-strict-aliasing -fno-stack-protector -static && qemu-ppc ./a +0x1 = 2 + +A bit more investigation: + +It looks like the bug happens in float->double conversion direction. + +$ cat a.c +#include <stdio.h> +#include <stdint.h> + +int main() { + volatile uint32_t i = 1; + volatile float f; + volatile double d; + *(volatile uint32_t*)&f = i; + d = f; + printf("d = %#llx (expect 0x36a0000000000000)\n", *(volatile uint64_t*)&d); +} + +$ powerpc-unknown-linux-gnu-gcc -O2 a.c -Wall -o a -fno-strict-aliasing -fno-stack-protector -static && qemu-ppc ./a +d = 0x36b0000000080000 (expect 0x36a0000000000000) + +10000400 <main>: +10000404: 39 20 00 01 li r9,1 +... +10000434: 91 21 00 10 stw r9,16(r1) +... +1000043c: c0 01 00 10 lfs f0,16(r1) +10000440: d8 01 00 08 stfd f0,8(r1) +... +10000448: 80 a1 00 08 lwz r5,8(r1) +1000044c: 80 c1 00 0c lwz r6,12(r1) +... +10000454: 48 02 01 ad bl 10020600 <___printf_chk> + +This is just lfs/stfd conversion. qemu does translates that pair if instructions into: +$ ppc-linux-user/qemu-ppc -d in_asm,out_asm,op,op_opt /tmp/b/a +... +IN: main +... +0x1000043c: c0010010 lfs f0, 0x10(r1) +0x10000440: d8010008 stfd f0, 8(r1) +... +OP: + ---- 1000043c + movi_i32 tmp1,$0x10 + add_i32 tmp0,r1,tmp1 + qemu_ld_i32 tmp1,tmp0,beul,2 + call todouble,$0x5,$1,tmp2,tmp1 + st_i64 tmp2,env,$0x9198 + +'todouble' must be a 'uint64_t helper_todouble(uint32_t arg=0x1)' from: + https://github.com/qemu/qemu/blob/master/target/ppc/fpu_helper.c#L55 + +Attaching the patch and sending for review as: + https://lists.gnu.org/archive/html/qemu-devel/2019-03/msg06562.html + +Alternatively 'uint64_t helper_todouble(uint32_t)' could be implemented via + include/fpu/softfloat.h:float64 float32_to_float64(float32, float_status *status); + + +fix committed with c0e6616b6685ffdb4c5e091bc152e46e14703dd1 and released with 4.2.0 + |