NetBSD Problem Report #58789
From www@netbsd.org Tue Oct 29 18:24:24 2024
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits)
client-signature RSA-PSS (2048 bits))
(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
by mollari.NetBSD.org (Postfix) with ESMTPS id 20CE21A9238
for <gnats-bugs@gnats.NetBSD.org>; Tue, 29 Oct 2024 18:24:24 +0000 (UTC)
Message-Id: <20241029182422.CE37F1A923B@mollari.NetBSD.org>
Date: Tue, 29 Oct 2024 18:24:22 +0000 (UTC)
From: campbell+netbsd@mumble.net
Reply-To: campbell+netbsd@mumble.net
To: gnats-bugs@NetBSD.org
Subject: aarch64 long double arithmetic is haunted
X-Send-Pr-Version: www-1.0
>Number: 58789
>Category: port-arm
>Synopsis: aarch64 long double arithmetic is haunted
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: port-arm-maintainer
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Tue Oct 29 18:25:01 +0000 2024
>Last-Modified: Tue Oct 29 18:55:01 +0000 2024
>Originator: Taylor R Campbell
>Release: current
>Organization:
The Haunted NetBSD Rintlation
>Environment:
>Description:
Since the resolution to PR lib/57021 (libc __trunctfdf2 conflicts with libgcc on aarch64), we have, on aarch64:
- compiler-rt softfloat128 long double arithmetic linked into libc.so
- libgcc softfloat128 long double arithmetic defined in libgcc_s.so
- executables linked against both by default
The long double arithmetic symbols in question are symbols like __addtf3 and __subtf3.
The two implementations, from compiler-rt and libgcc, are not quite compatible. For example, compiler-rt softfloat128 long double arithmetic has no concept of floating-point rounding mode, while gcc softfloat128 long double arithmetic respects the rounding mode set in the FPCR (floating-point control register).
I suspect this is why long double functions such as rintl exhibit haunted behaviour like the example below.
>How-To-Repeat:
$ cat rintl1.c
#include <fenv.h>
#include <math.h>
#include <unistd.h>
int
main(void)
{
volatile long double x = 0x2.00000000000008p+52L;
volatile long double y, z;
volatile int c;
y = rintl(x);
fesetround(FE_UPWARD);
z = rintl(x);
c = x ? 0 : 1;
write(STDOUT_FILENO, __UNVOLATILE(&y), sizeof(y));
write(STDOUT_FILENO, __UNVOLATILE(&z), sizeof(z));
return c;
}
$ cat rintl2.c
#include <fenv.h>
#include <math.h>
#include <unistd.h>
int
main(void)
{
volatile long double x = 0x2.00000000000008p+52L;
volatile long double y, z;
volatile int c;
y = rintl(x);
fesetround(FE_UPWARD);
z = rintl(x);
c = 1 ? 0 : 1;
write(STDOUT_FILENO, __UNVOLATILE(&y), sizeof(y));
write(STDOUT_FILENO, __UNVOLATILE(&z), sizeof(z));
return c;
}
$ diff -u rintl1.c rintl2.c
--- rintl1.c 2024-10-29 12:48:29.000000000 +0000
+++ rintl2.c 2024-10-29 12:48:09.000000000 +0000
@@ -12,7 +12,7 @@
y = rintl(x);
fesetround(FE_UPWARD);
z = rintl(x);
- c = x ? 0 : 1;
+ c = 1 ? 0 : 1;
write(STDOUT_FILENO, __UNVOLATILE(&y), sizeof(y));
write(STDOUT_FILENO, __UNVOLATILE(&z), sizeof(z));
return c;
$ make rintl1 rintl2 LDLIBS=-lm DBG=-g\ -O2\ -Wall\ -Werror
cc -g -O2 -Wall -Werror -o rintl1 rintl1.c -lm
cc -g -O2 -Wall -Werror -o rintl2 rintl2.c -lm
$ ./rintl1 | hexdump -C
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 34 40 |..............4@|
00000010 00 00 00 00 00 00 00 08 00 00 00 00 00 00 34 40 |..............4@|
00000020
$ ./rintl2 | hexdump -C
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 34 40 |..............4@|
*
00000020
>Fix:
Yes, please!
>Audit-Trail:
From: Taylor R Campbell <riastradh@NetBSD.org>
To: gnats-bugs@NetBSD.org, netbsd-bugs@NetBSD.org
Cc:
Subject: Re: port-arm/58789: aarch64 long double arithmetic is haunted
Date: Tue, 29 Oct 2024 18:52:50 +0000
It seems the reason why the rintl1/rintl2 examples I gave get linked
against libgcc_s is that libm pulls it in, via --as-needed -lgcc_s:
$ grep -B2 libgcc_s libm.so.0.map
As-needed library included to satisfy reference by file (symbol)
libgcc_s.so.1 libm_pic.a(s_tanl.pico) (__getf2@@GCC_3.0)
...
(In netbsd-10, it's for __getf2 in csqrtl.pico. __getf2 is the
one-argument `tetra-float' (128-bit long double) greater-or-equal
comparison function.)
It is unclear to me why libm wants __getf2 out of libgcc_s, but not,
say, __addtf3 (two-argument `tetra-float' add function), which is also
defined in both libgcc_s and in libc.
$ nm -gD --undefined-only libm.so.0 | grep -e __addtf3 -e __getf2
U __addtf3
U __getf2
$ readelf -a libm.so.0 | grep -e __addtf3 -e __getf2
000000060368 012300000402 R_AARCH64_JUMP_SL 0000000000000000 __addtf3@GCC_=
3.0 + 0
0000000605f8 01ea00000402 R_AARCH64_JUMP_SL 0000000000000000 __getf2@GCC_3=
.0 + 0
291: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __addtf3@GCC_3.0=
(2)
490: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __getf2@GCC_3.0 =
(2)
1210: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __addtf3@GCC_3.0
1409: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __getf2@GCC_3.0
Need a wizard to decipher this ancient elven lore...
(Contact us)
$NetBSD: query-full-pr,v 1.47 2022/09/11 19:34:41 kim Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2024
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.