Re: [PATCH/QUESTION] newlib: fenv: AArch64 Cygwin linking fixes

"Richard Earnshaw (lists)" <[email protected]>
Newsgroups gmane.comp.lib.newlib,gmane.os.cygwin.patches
Message-ID <[email protected]>
On 16/06/2025 12:31, Radek Barton wrote:
> Hello.
> 
> This is more a question than patch submission: Without the attached changes, the Cygwin cannot be linked for AArch64 failing on:
> ```
> ld: cannot export _fe_nomask_env: symbol not defined
> ld: cannot export fedisableexcept: symbol not defined
> ld: cannot export fegetexcept: symbol not defined
> ld: cannot export fegetprec: symbol not defined
> ld: cannot export fesetprec: symbol not defined
> ```
> Can anybody share some insights why are those changes needed and whether there is a better way how to overcome this issue?
> 
> Note that the `feenableexcept`, `fedisableexcept`, `fegetexcept` implementations are similarly defined in `newlib/libc/machine/mips/machine/fenv-fp.h` for MIPS architecture as well.
> 
> Thank you,
> 
> Radek
> 

Ugh, this is a real rat's nest of code...

I may be on completely the wrong track, but I think the clue is in the comment:

 +/* We currently provide no external definitions of the functions below. */

So it is expected that these functions have no definition in a file, but will be inlined into the calling code when needed.  This is why they are provided in fenv.h.  fenv-fp.h seems to be the internal header that is used for code that will create the non-inlined versions; the header file fenv-fp.h isn't exported from the library though (it's only used while building it), so anything defined there will never be inlined into user code.

I suspect that the underlying issue is that coff libraries rely on explicitly exporting symbols, while ELF libraries do that implicitly (unless something is explicitly marked hidden).

What I don't fully understand is what role __BSD_VISIBLE might have here.  If that's not defined (which I'd think is possible in CYGWIN), then I can't see how your changes would resolve this.

I'm guessing (somewhat) that libm/.../fenv.c should perhaps define __BSD_VISIBLE before including fenv.h to force the inline functions to become visible. 

The other alternative might be to remove the list of functions scoped by the ifdef from libm/machine/aarch64/fenv.c so that the functions that file exports matches the comment I mentioned above.

Perhaps you could try this patch instead of yours and let me know if it resolves the issue:

diff --git a/newlib/libm/machine/aarch64/fenv.c b/newlib/libm/machine/aarch64/fenv.c
index 3ffe23441..fb6a67dcc 100644
--- a/newlib/libm/machine/aarch64/fenv.c
+++ b/newlib/libm/machine/aarch64/fenv.c
@@ -27,6 +27,9 @@
  * $FreeBSD$
  */
 
+/* Enable all fenv-related functions.  */
+#define __BSD_VISIBLE
+
 #define        __fenv_static
 #include <fenv.h>
 #include <machine/fenv-fp.h>



R.
> ---
> From 17fd8e16061ab199d111b303a44c042ea43c4018 Mon Sep 17 00:00:00 2001
> From: Radek Barton <[email protected]>
> Date: Mon, 9 Jun 2025 08:55:18 +0200
> Subject: [PATCH/QUESTION] newlib: fenv: AArch64 Cygwin linking fixes
> 
> ---
>  newlib/libc/machine/aarch64/machine/fenv-fp.h | 64 +++++++++++++++++++
>  newlib/libc/machine/aarch64/sys/fenv.h        | 40 ------------
>  newlib/libm/machine/aarch64/fenv.c            |  7 ++
>  winsup/cygwin/fenv.c                          | 10 +++
>  4 files changed, 81 insertions(+), 40 deletions(-)
> 
> diff --git a/newlib/libc/machine/aarch64/machine/fenv-fp.h b/newlib/libc/machine/aarch64/machine/fenv-fp.h
> index d8ec3fc76..e42e2d873 100644
> --- a/newlib/libc/machine/aarch64/machine/fenv-fp.h
> +++ b/newlib/libc/machine/aarch64/machine/fenv-fp.h
> @@ -154,3 +154,67 @@ feupdateenv(const fenv_t *__envp)
>  	return (0);
>  }
>  
> +#if __BSD_VISIBLE
> +
> +/* We currently provide no external definitions of the functions below. */
> +
> +__fenv_static inline int
> +feenableexcept(int __mask)
> +{
> +	fenv_t __old_r, __new_r;
> +
> +	__mrs_fpcr(__old_r);
> +	__new_r = __old_r | ((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
> +	__msr_fpcr(__new_r);
> +	return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
> +}
> +
> +__fenv_static inline int
> +fedisableexcept(int __mask)
> +{
> +	fenv_t __old_r, __new_r;
> +
> +	__mrs_fpcr(__old_r);
> +	__new_r = __old_r & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
> +	__msr_fpcr(__new_r);
> +	return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
> +}
> +
> +__fenv_static inline int
> +fegetexcept(void)
> +{
> +	fenv_t __r;
> +
> +	__mrs_fpcr(__r);
> +	return ((__r & _ENABLE_MASK) >> _FPUSW_SHIFT);
> +}
> +
> +#endif /* __BSD_VISIBLE */
> +
> +#if defined(__CYGWIN__)
> +
> +/*  Returns the currently selected precision, represented by one of the
> +   values of the defined precision macros.  */
> +__fenv_static inline int
> +fegetprec (void)
> +{
> +  return 0;
> +}
> +
> +/* http://www.open-std.org/jtc1/sc22//WG14/www/docs/n752.htm:
> +
> +   The fesetprec function establishes the precision represented by its
> +   argument prec.  If the argument does not match a precision macro, the
> +   precision is not changed.
> +
> +   The fesetprec function returns a nonzero value if and only if the
> +   argument matches a precision macro (that is, if and only if the requested
> +   precision can be established). */
> +__fenv_static inline int
> +fesetprec (int prec)
> +{
> +  /* Indicate success.  */
> +  return 1;
> +}
> +
> +#endif /* __CYGWIN__ */
> diff --git a/newlib/libc/machine/aarch64/sys/fenv.h b/newlib/libc/machine/aarch64/sys/fenv.h
> index 6b0879269..1cfbeaaf4 100644
> --- a/newlib/libc/machine/aarch64/sys/fenv.h
> +++ b/newlib/libc/machine/aarch64/sys/fenv.h
> @@ -77,44 +77,4 @@ extern const fenv_t	*_fe_dfl_env;
>  #define	__mrs_fpsr(__r)	__asm __volatile("mrs %0, fpsr" : "=r" (__r))
>  #define	__msr_fpsr(__r)	__asm __volatile("msr fpsr, %0" : : "r" (__r))
>  
> -
> -#if __BSD_VISIBLE
> -
> -/* We currently provide no external definitions of the functions below. */
> -
> -static inline int
> -feenableexcept(int __mask)
> -{
> -	fenv_t __old_r, __new_r;
> -
> -	__mrs_fpcr(__old_r);
> -	__new_r = __old_r | ((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
> -	__msr_fpcr(__new_r);
> -	return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
> -}
> -
> -static inline int
> -fedisableexcept(int __mask)
> -{
> -	fenv_t __old_r, __new_r;
> -
> -	__mrs_fpcr(__old_r);
> -	__new_r = __old_r & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
> -	__msr_fpcr(__new_r);
> -	return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
> -}
> -
> -static inline int
> -fegetexcept(void)
> -{
> -	fenv_t __r;
> -
> -	__mrs_fpcr(__r);
> -	return ((__r & _ENABLE_MASK) >> _FPUSW_SHIFT);
> -}
> -
> -#endif /* __BSD_VISIBLE */
> -
> -
> -
>  #endif	/* !_FENV_H_ */
> diff --git a/newlib/libm/machine/aarch64/fenv.c b/newlib/libm/machine/aarch64/fenv.c
> index 3ffe23441..86f8cd5aa 100644
> --- a/newlib/libm/machine/aarch64/fenv.c
> +++ b/newlib/libm/machine/aarch64/fenv.c
> @@ -55,3 +55,10 @@ extern inline int feupdateenv(const fenv_t *__envp);
>  extern inline int feenableexcept(int __mask);
>  extern inline int fedisableexcept(int __mask);
>  extern inline int fegetexcept(void);
> +
> +#if defined(__CYGWIN__)
> +
> +extern inline int fegetprec(void);
> +extern inline int fesetprec(int prec);
> +
> +#endif /* CYGWIN */
> diff --git a/winsup/cygwin/fenv.c b/winsup/cygwin/fenv.c
> index 80f7cc52c..1558f76c2 100644
> --- a/winsup/cygwin/fenv.c
> +++ b/winsup/cygwin/fenv.c
> @@ -3,3 +3,13 @@
>     being called from mainCRTStartup in crt0.o. */
>  void _feinitialise (void)
>  {}
> +
> +#if defined(__aarch64__)
> +
> +#include <fenv.h>
> +#include <stddef.h>
> +
> +/* _fe_nomask_env is exported by cygwin.din but not used at all for AArch64. */
> +const fenv_t *_fe_nomask_env = NULL;
> +
> +#endif /* __aarch64__ */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.