Whither fabs() ?

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm using the avr toolchain 3.5.4_468 from ATMel.

 

fabs() is nowhere to be found.

 

I've tried building with and without -lm and I get

undefined reference to `fabs'

at link time.

 

I mean, I can use a #define to make it (x<0)?-x:x, but this is supposed to just work, right?

This topic has a solution.

Last Edited: Tue. Jan 3, 2017 - 04:08 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Include the h file with fabs in it? (math.h? stdlib.h?) Use the newest toolchain? Use a commercial compiler that is ansi c89 compliant?

 

Imagecraft compiler user

Last Edited: Sat. Oct 8, 2016 - 04:00 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am indeed including math.h. It says

 

/**
    The fabs() function computes the absolute value of a floating-point
    number \a __x.
 */
extern double fabs(double __x) __ATTR_CONST__;
#define fabsf   fabs            /**< The alias for fabs().      */

 

Unless the toolchain doesn't come from here, I'm using the latest.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Which micro are you building for? In other words which version of the 17 versions of libm.a is it linking with?

 

EDIT: actually I just picked one at random (avr5) and found:

C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\avr5>avr-nm libm.a | findstr "fabs"

C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\avr5>avr-nm libm.a | findstr "sin"
asin.o:
00000000 T asin
         U __fp_sinus
fp_sinus.o:
00000000 T __fp_sinus
isinf.o:
00000000 T isinf
sinh.o:
00000000 T sinh
sin.o:
         U __fp_sinus
00000000 T sin

So, yes, something like sin() is there but you are right, it looks like fasb() is missing - curious.

Last Edited: Sat. Oct 8, 2016 - 10:02 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I built a test program in Studio 6.2, and it builds cleanly.  But I can't get it to invoke fabs().

 

#include <avr/io.h>
#include <math.h>

volatile float x;
volatile float y;
volatile float z;

int main(void)
{
	y = 4.567;
	z = fabs(x*y);
	PORTB = floor(z);
    while (1) 
    {
    }
}
	z = fabs(x*y);
 122:	60 91 00 02 	lds	r22, 0x0200
 126:	70 91 01 02 	lds	r23, 0x0201
 12a:	80 91 02 02 	lds	r24, 0x0202
 12e:	90 91 03 02 	lds	r25, 0x0203
 132:	20 91 08 02 	lds	r18, 0x0208
 136:	30 91 09 02 	lds	r19, 0x0209
 13a:	40 91 0a 02 	lds	r20, 0x020A
 13e:	50 91 0b 02 	lds	r21, 0x020B
 142:	bf d0       	rcall	.+382    	; 0x2c2 <__mulsf3>
 144:	dc 01       	movw	r26, r24
 146:	cb 01       	movw	r24, r22
 148:	bf 77       	andi	r27, 0x7F	; 127
 14a:	80 93 04 02 	sts	0x0204, r24
 14e:	90 93 05 02 	sts	0x0205, r25
 152:	a0 93 06 02 	sts	0x0206, r26
 156:	b0 93 07 02 	sts	0x0207, r27
	PORTB = floor(z);
 15a:	60 91 04 02 	lds	r22, 0x0204
 15e:	70 91 05 02 	lds	r23, 0x0205
 162:	80 91 06 02 	lds	r24, 0x0206
 166:	90 91 07 02 	lds	r25, 0x0207
 16a:	2f d0       	rcall	.+94     	; 0x1ca <floor>
 16c:	02 d0       	rcall	.+4      	; 0x172 <__fixunssfsi>
 16e:	65 b9       	out	0x05, r22	; 5
 170:	ff cf       	rjmp	.-2      	; 0x170 <main+0x66>

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I believe the "andi" instruction removes the sign bit - the equivalent to fabs().

To answer someone else's question, -mmcu=atmega328pb. Which is the same set of libraries as atmega328p.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I figured it out.

 

I was using -ffreestanding, which allows me to declare main() as void, but also disappears all of the compiler's built-ins, which include fabs().

 

The correct workaround is

 

#define fabs(n) __builtin_fabs(n)

 

As documented: https://gcc.gnu.org/onlinedocs/g... (look under the -fno-builtin section).

 

Doing that instead of declaring a replacement static inline function saves quite a few bytes, it turns out.

Last Edited: Tue. Jan 3, 2017 - 04:05 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why on earth are you using -ffreestanding ? Offtopic here, but with that switch you are removing any knowledge about library functions from the compiler — both about correct prototypes and inner working of these functions.

 

For example, it will no more optimize strlen ("foo") to 3, etc.

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I thought that was recommended.

 

From what I can tell, the only immediate negative from not using it is that insists that main() returns int, but that's largely moot because my main() doesn't return.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That's no issue.  If the compiler detects that main never returns, e.g. due to an endless loop, it won't generate no return statement anyway.  Hence there is no issue with the final "return 0;".

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@nsayer, have a look at attribute OS_main:

https://gcc.gnu.org/onlinedocs/gcc/AVR-Function-Attributes.html

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If GCC specific extensions are no issue, you might also have a look at attribute((noreturn)) and __builtin_unreachable().

avrfreaks does not support Opera. Profile inactive.