Discussion:
Problems with Newlib built with Clang for Cortex-M
Jangseop Shin
2018-10-31 12:40:44 UTC
Permalink
Hello, I'm doing a project using RIOT-OS on Cortex-M.
I would like to instrument the code that are linked into the final binary
using LLVM. Since RIOT-OS uses newlib, I tried to compile newlib using
Clang.

I used the GNU ARM Embedded Toolchain (gcc-arm-none-eabi-7-2018-q2-update)
with 20180831 snapshot of newlib, clang-7.0.0, and RIOT-OS 2018.10 branch.

First there were a few compile errors.
(libgloss/arm/linux-syscalls0.S - GLOBAL => global on line 105
liggloss/libnosys/warning.h - define stub_warning as null
newlib/libc/machine/arm/strlen-thumb2-Os.S) - ldrb.w => ldrb (line 48)

(The fact that these are all quite old files gives me a feeling that newlib
is not really serious about supporting Clang??)

After I fixed the errors I could get the library file.
But when I tried to run the application on Cortex-M3 (Arduino-due board),
some of the app crash or produce incorrect results.
One of the bug I suspect is with newlib/libc/stdlib/dtoa.c file, since it
makes my system halt when I try to print floating point number.
(I looked up the internet and added -fno-strict-aliasing flag to cflags
with no luck.)
When I replaced that specific object file in the libc library with the
gcc-compiled one, the app does not crash. (However, it still produces
incorrect results)
Replacing libm with the gcc-compiled version corrected the results to some
extent, but the floating point numbers are randomly printed with wrong sign.

I would very much appreciate any help on this issue.

Regards,
Jangseop
Richard Earnshaw (lists)
2018-10-31 13:54:13 UTC
Permalink
Post by Jangseop Shin
Hello, I'm doing a project using RIOT-OS on Cortex-M.
I would like to instrument the code that are linked into the final binary
using LLVM. Since RIOT-OS uses newlib, I tried to compile newlib using
Clang.
I used the GNU ARM Embedded Toolchain (gcc-arm-none-eabi-7-2018-q2-update)
with 20180831 snapshot of newlib, clang-7.0.0, and RIOT-OS 2018.10 branch.
First there were a few compile errors.
(libgloss/arm/linux-syscalls0.S - GLOBAL => global on line 105
liggloss/libnosys/warning.h - define stub_warning as null
newlib/libc/machine/arm/strlen-thumb2-Os.S) - ldrb.w => ldrb (line 48)
(The fact that these are all quite old files gives me a feeling that newlib
is not really serious about supporting Clang??)
On the contrary, the problem is that appears that clang is just not
serious about correctly implementing the GNU assembler syntax.

.GLOBAL: directive keywords are case independent - .global .Global and
.GLOBAL should all work exactly the same (as would .gLobal, for that
matter).
stub_warning: is wrapped inside of HAVE_GNU_LD, why is that defined if
you're using clang? However, you don't really say what the error is, so
it's hard to really know what the problem is.
ldrb.w: this is a legal mnemonic, if clang doesn't accept it, then it
needs fixing.
Post by Jangseop Shin
After I fixed the errors I could get the library file.
But when I tried to run the application on Cortex-M3 (Arduino-due board),
some of the app crash or produce incorrect results.
One of the bug I suspect is with newlib/libc/stdlib/dtoa.c file, since it
makes my system halt when I try to print floating point number.
(I looked up the internet and added -fno-strict-aliasing flag to cflags
with no luck.)
When I replaced that specific object file in the libc library with the
gcc-compiled one, the app does not crash. (However, it still produces
incorrect results)
Replacing libm with the gcc-compiled version corrected the results to some
extent, but the floating point numbers are randomly printed with wrong sign.
I would very much appreciate any help on this issue.
These sound like your stack is not correctly aligned: a common symptom
of failing to do this is that calls to the printf family fail when
64-bit sized items (like double) are passed. The EABI requires 64-bit
alignment at all function boundaries (and 32-bit alignment at all other
times).

R.
Post by Jangseop Shin
Regards,
Jangseop
Keith Packard
2018-10-31 14:40:04 UTC
Permalink
Post by Richard Earnshaw (lists)
These sound like your stack is not correctly aligned: a common symptom
of failing to do this is that calls to the printf family fail when
64-bit sized items (like double) are passed. The EABI requires 64-bit
alignment at all function boundaries (and 32-bit alignment at all other
times).
I ran into this with one embedded platform that wasn't aligning the
initial thread stack on 64-bit boundaries. The compiler was carefully
counting pushes/pops for non-varargs functions, but varargs was
computing the rounding and because the initial stack point was
mis-aligned, everything "worked" except for 64-bit (double) values to
printf which got fetched from the wrong address.
--
-keith
Jangseop Shin
2018-11-02 13:12:09 UTC
Permalink
The problem was that Clang does not define __VFP_FP__ while
arm-none-eabi-gcc does. This caused endianness problem in the following
code. The comments in the code says that __VFP_FP__ is defined even with
soft-float, but Clang seems to define it only when VFP is actually used.

==== newlib/libc/include/machine/ieeefp.h ========

#if (defined(__arm__) || defined(__thumb__)) && !defined(__MAVERICK__)
/* ARM traditionally used big-endian words; and within those words the byte
ordering was big or little endian depending upon the target. Modern
floating-point formats are naturally ordered; in this case __VFP_FP__ will
be defined, even if soft-float. */
#ifdef __VFP_FP__
# ifdef __ARMEL__
# define __IEEE_LITTLE_ENDIAN
# else
# define __IEEE_BIG_ENDIAN
# endif
# if __ARM_FP & 0x8
# define __OBSOLETE_MATH_DEFAULT 0
# endif
#else
# define __IEEE_BIG_ENDIAN
# ifdef __ARMEL__
# define __IEEE_BYTES_LITTLE_ENDIAN
# endif
#endif
#endif

====================================
Post by Keith Packard
Post by Richard Earnshaw (lists)
These sound like your stack is not correctly aligned: a common symptom
of failing to do this is that calls to the printf family fail when
64-bit sized items (like double) are passed. The EABI requires 64-bit
alignment at all function boundaries (and 32-bit alignment at all other
times).
I ran into this with one embedded platform that wasn't aligning the
initial thread stack on 64-bit boundaries. The compiler was carefully
counting pushes/pops for non-varargs functions, but varargs was
computing the rounding and because the initial stack point was
mis-aligned, everything "worked" except for 64-bit (double) values to
printf which got fetched from the wrong address.
--
-keith
Richard Earnshaw (lists)
2018-11-02 13:44:43 UTC
Permalink
Post by Jangseop Shin
The problem was that Clang does not define __VFP_FP__ while
arm-none-eabi-gcc does. This caused endianness problem in the following
code. The comments in the code says that __VFP_FP__ is defined even with
soft-float, but Clang seems to define it only when VFP is actually used.
__VFP_FP__ defines the /format/ of the floating point numbers in use.
It does not indicate the presence or absence of VFP instructions. So
this is another clang bug.

R.
Post by Jangseop Shin
==== newlib/libc/include/machine/ieeefp.h ========
#if (defined(__arm__) || defined(__thumb__)) && !defined(__MAVERICK__)
/* ARM traditionally used big-endian words; and within those words the byte
ordering was big or little endian depending upon the target. Modern
floating-point formats are naturally ordered; in this case __VFP_FP__ will
be defined, even if soft-float. */
#ifdef __VFP_FP__
# ifdef __ARMEL__
# define __IEEE_LITTLE_ENDIAN
# else
# define __IEEE_BIG_ENDIAN
# endif
# if __ARM_FP & 0x8
# define __OBSOLETE_MATH_DEFAULT 0
# endif
#else
# define __IEEE_BIG_ENDIAN
# ifdef __ARMEL__
# define __IEEE_BYTES_LITTLE_ENDIAN
# endif
#endif
#endif
====================================
Post by Keith Packard
Post by Richard Earnshaw (lists)
These sound like your stack is not correctly aligned: a common symptom
of failing to do this is that calls to the printf family fail when
64-bit sized items (like double) are passed. The EABI requires 64-bit
alignment at all function boundaries (and 32-bit alignment at all other
times).
I ran into this with one embedded platform that wasn't aligning the
initial thread stack on 64-bit boundaries. The compiler was carefully
counting pushes/pops for non-varargs functions, but varargs was
computing the rounding and because the initial stack point was
mis-aligned, everything "worked" except for 64-bit (double) values to
printf which got fetched from the wrong address.
--
-keith
Jangseop Shin
2018-11-02 07:48:34 UTC
Permalink
On Wed, Oct 31, 2018 at 10:54 PM Richard Earnshaw (lists) <
Post by Jangseop Shin
Post by Jangseop Shin
Hello, I'm doing a project using RIOT-OS on Cortex-M.
I would like to instrument the code that are linked into the final binary
using LLVM. Since RIOT-OS uses newlib, I tried to compile newlib using
Clang.
I used the GNU ARM Embedded Toolchain
(gcc-arm-none-eabi-7-2018-q2-update)
Post by Jangseop Shin
with 20180831 snapshot of newlib, clang-7.0.0, and RIOT-OS 2018.10
branch.
Post by Jangseop Shin
First there were a few compile errors.
(libgloss/arm/linux-syscalls0.S - GLOBAL => global on line 105
liggloss/libnosys/warning.h - define stub_warning as null
newlib/libc/machine/arm/strlen-thumb2-Os.S) - ldrb.w => ldrb (line 48)
(The fact that these are all quite old files gives me a feeling that
newlib
Post by Jangseop Shin
is not really serious about supporting Clang??)
On the contrary, the problem is that appears that clang is just not
serious about correctly implementing the GNU assembler syntax.
.GLOBAL: directive keywords are case independent - .global .Global and
.GLOBAL should all work exactly the same (as would .gLobal, for that
matter).
stub_warning: is wrapped inside of HAVE_GNU_LD, why is that defined if
you're using clang? However, you don't really say what the error is, so
it's hard to really know what the problem is.
ldrb.w: this is a legal mnemonic, if clang doesn't accept it, then it
needs fixing.
Sorry if I sounded a bit rude. So about the compile errors:

- I filed a bug to Clang about GNU assembler syntax.

- The error message for HAVE_GNU_LD is this:

<inline asm>:1:8: error: unsupported directive '.stabs'
.stabs "_chown is not implemented and will always fail",30,0,0,0
^
<inline asm>:2:8: error: unsupported directive '.stabs'
.stabs "_chown",1,0,0,0
^
2 errors generated.

Clang assembler does not understand .stabs directive and they do not seem
to plan to support it (https://sourceforge.net/p/libjpeg-turbo/bugs/72/)

However, newlib/libgloss/libnosys/configure.in seem to define HAVE_GNU_LD
regardless of whether clang or gcc is used.

- ldrb r2, [r3], #1

Clang does not give error for ldrb.w r2, [r3, #1].
It is a little confusing because "A7.7.45 LDRB(immediate)" section of the
ARM7-m architecture manual shows that .W suffix is applied to T2 encoding
but not to T3 encoding.
However "A7.2 Standard assembler syntax fields" suggests that .W suffix is
used to force the assembler to select 32-bit encoding. So I guess Clang
shouldn't really regard it as an error. I'll ask the Clang guys for this
also.
Post by Jangseop Shin
Post by Jangseop Shin
After I fixed the errors I could get the library file.
But when I tried to run the application on Cortex-M3 (Arduino-due board),
some of the app crash or produce incorrect results.
One of the bug I suspect is with newlib/libc/stdlib/dtoa.c file, since
it
Post by Jangseop Shin
makes my system halt when I try to print floating point number.
(I looked up the internet and added -fno-strict-aliasing flag to cflags
with no luck.)
When I replaced that specific object file in the libc library with the
gcc-compiled one, the app does not crash. (However, it still produces
incorrect results)
Replacing libm with the gcc-compiled version corrected the results to
some
Post by Jangseop Shin
extent, but the floating point numbers are randomly printed with wrong
sign.
Post by Jangseop Shin
I would very much appreciate any help on this issue.
These sound like your stack is not correctly aligned: a common symptom
of failing to do this is that calls to the printf family fail when
64-bit sized items (like double) are passed. The EABI requires 64-bit
alignment at all function boundaries (and 32-bit alignment at all other
times).
I'll look more into this.
Post by Jangseop Shin
R.
Post by Jangseop Shin
Regards,
Jangseop
Loading...