incompatible with avr-gcc7.1

Bug #1703250 reported by Henning on 2017-07-09
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
Flashlight Firmware Repository
Undecided
Unassigned

Bug Description

Hello,
it seems like building fails on avr-gcc 7.1, it happens in an Arch VM and in Windows. Log:

[antergos-avr@antergos-avr hello_world]$ make
  CC STAR_smaller.o
avr-gcc -Wall -g -Os -mmcu=attiny13 -o STAR_smaller.o -c STAR_smaller.c
  LD STAR_smaller.elf
avr-gcc -Wall -g -Os -mmcu=attiny13 -o STAR_smaller.elf STAR_smaller.o
STAR_smaller.o: In function `main':
/home/antergos-avr/flashlight-firmware/hello_world/STAR_smaller.c:(.text.startup+0x10): undefined reference to `ADC_on'
STAR_smaller.o: In function `__vector_8':
/home/antergos-avr/flashlight-firmware/hello_world/STAR_smaller.c:213: undefined reference to `read_mode_idx'
/home/antergos-avr/flashlight-firmware/hello_world/STAR_smaller.c:213: undefined reference to `next_mode'
/home/antergos-avr/flashlight-firmware/hello_world/STAR_smaller.c:213: undefined reference to `WDT_on'
/home/antergos-avr/flashlight-firmware/hello_world/STAR_smaller.c:215: undefined reference to `WDT_off'
collect2: error: ld returned 1 exit status
make: *** [Makefile:15: STAR_smaller.elf] Error 1

C:\Coding\toykeeper\hello_world>make
  CC STAR_smaller.o
avr-gcc -Wall -g -Os -mmcu=attiny13 -o STAR_smaller.o -c STAR_smaller.c
  LD STAR_smaller.elf
avr-gcc -Wall -g -Os -mmcu=attiny13 -o STAR_smaller.elf STAR_smaller.o
STAR_smaller.o: In function `main':
C:\Coding\toykeeper\hello_world/STAR_smaller.c:248: undefined reference to `ADC_on'
C:\Coding\toykeeper\hello_world/STAR_smaller.c:295: undefined reference to `read_mode_idx'
C:\Coding\toykeeper\hello_world/STAR_smaller.c:300: undefined reference to `next_mode'
C:\Coding\toykeeper\hello_world/STAR_smaller.c:307: undefined reference to `WDT_on'
C:\Coding\toykeeper\hello_world/STAR_smaller.c:332: undefined reference to `WDT_off'
collect2.exe: error: ld returned 1 exit status
make: *** [Makefile:15: STAR_smaller.elf] Error 1

C:\Coding\toykeeper\hello_world>

log for make -d: https://pastebin.com/F3WVAQLg

Selene ToyKeeper (toykeeper) wrote :

So, gcc 7.1 doesn't support the "inline" keyword by default? What happens if you add -std=gnu99 to the compile options?

The latest available in Debian (even in unstable) is gcc-avr 1:4.9.2+Atmel3.5.4-1. I'm not sure what all changed between gcc 4 and gcc 7, but some platforms failed by merely switching from 4 to 5. I expect to see a wide variety of problems for pretty much any project which uses gcc.

For this project, it looks like the inline functions may need to be declared as external, to trick the linker into not trying to resolve them. If -std=gnu99 doesn't work, what happens if you change those to "extern inline" instead of just "inline"?

Changed in flashlight-firmware:
status: New → Incomplete
Henning (wuelpi) wrote :

Adding -std=gnu99 to the CFLAGS does nothing, while using extern inline to the functions, that are throwing the errors, works. -std=gnu89 works with just inline, but adds 4 byte. Sizes differ by a surprising amount, just in case you are interested:

extern inline and -std=gnu89 OR extern inline and -fgnu89-inline
   text data bss dec hex filename
      0 940 0 940 3ac STAR_smaller.hex

extern inline (same with -std=gnu99 and without)
   text data bss dec hex filename
      0 952 0 952 3b8 STAR_smaller.hex

-std=gnu89
   text data bss dec hex filename
      0 956 0 956 3bc STAR_smaller.hex

precompiled
   text data bss dec hex filename
      0 972 0 972 3cc precompiled.hex

Selene ToyKeeper (toykeeper) wrote :

Interesting. Thanks! I don't have easy access to avr-gcc-7 yet, but this should be very helpful when that's more widely used. I'll also have to do some testing to find the smallest compile options during the next updates.

I'm not sure there will be a single set of options which works best with all recent versions of gcc though... For example, here's what I'm getting with biscotti on gcc-4.9.2:

-std=gnu99 and no externs: 1022 bytes

-std=gnu89 and no externs: 1066 bytes

-std=gnu99 and extern inline: 1058 bytes

-std=gnu89 and extern inline: 1030 bytes

With -std=gnu11, I get the same results as gnu99.

Since only one of these fits under the 1024-byte limit, it might need to use different build options for different versions of gcc, and possibly replace some built-in keywords with version-specific #defines. The changes required to make it compile with gcc-7.1 have a side effect of breaking the gcc-4.9.2 build.

Changed in flashlight-firmware:
status: Incomplete → Confirmed
Henning (wuelpi) wrote :

I was interested how everything behaves and got avr-gcc 5.4 to work on OpenSuse Tumbleweed (my main Distro) so here are tests with 5.4 and biscotti:

OpenSuse Tumbleweed GCC 5.4

no extern
-std=gnu11 1020 bytes
-std=gnu99 1020 bytes
-std=gnu89 1082 bytes
-std=gnu11 -fgnu11-inline 1082 bytes
-std=gnu99 -fgnu99-inline 1082 bytes
-std=gnu89 -fgnu89-inline 1082 bytes
extern inline
-std=gnu11 1078 bytes
-std=gnu99 1078 bytes
-std=gnu89 1024 bytes
-std=gnu11 -fgnu89-inline 1024 bytes
-std=gnu99 -fgnu89-inline 1024 bytes
-std=gnu89 -fgnu89-inline 1024 bytes

And as I have the VM up and running, here are the 7.1 results on arch:
no extern
-std=gnu11 fails
-std=gnu99 fails
-std=gnu89 1082 bytes
-std=gnu89 -fgnu11-inline 1082 bytes
-std=gnu89 -fgnu99-inline 1082 bytes
-std=gnu89 -fgnu89-inline 1082 bytes
extern inline
-std=gnu11 1078 bytes
-std=gnu99 1078 bytes
-std=gnu89 1026 bytes
-std=gnu11 -fgnu89-inline 1026 bytes
-std=gnu99 -fgnu89-inline 1026 bytes
-std=gnu89 -fgnu89-inline 1026 bytes

Both times avr-libc 2.0

I'll see how easy it is to update GCC to 6 and 7 on TW (it is a different repo and has problems) and will add results in case it works.

Henning (wuelpi) wrote :

I found a way to downgrade on arch, this is the most hassle free at the moment. The results are to no surprise the same for 5.3 on Arch and 5.4 on TW. For GCC 6.3 it was exactly the same as 7.1 but without failing:

no extern
-std=gnu11 1022 bytes
-std=gnu99 1022 bytes
-std=gnu89 1082 bytes
-std=gnu11 -fgnu89-inline 1082 bytes
-std=gnu99 -fgnu89-inline 1082 bytes
-std=gnu89 -fgnu89-inline 1082 bytes
extern inline
-std=gnu11 1078 bytes
-std=gnu99 1078 bytes
-std=gnu89 1026 bytes
-std=gnu11 -fgnu89-inline 1026 bytes
-std=gnu99 -fgnu89-inline 1026 bytes
-std=gnu89 -fgnu89-inline 1026 bytes

-Winline shows lots of functions not being inlined without -fgnu89-inline: https://pastebin.com/sxRDnQS6 due to GCC thinking it would let the code size grow. I would assume this is the biggest cuprit. Maybe I try to experiment with __attribute__((always_inline)), a short try failed though.

Small correction for my last posting, I mixed up the build options, it's -fgnu89-inline every time and the standard changes.

Henning (wuelpi) wrote :

I have looked up the changes that C99 brought to the inline keyword and changed the functions that threw an error to static inline and this results in no code size regression.

GCC 7
static inline
-std=gnu11 1022 bytes
-std=gnu99 1022 bytes
-std=gnu89 1026 bytes
-std=gnu11 -fgnu89-inline 1026 bytes
-std=gnu99 -fgnu89-inline 1026 bytes
-std=gnu89 -fgnu89-inline 1026 bytes

GCC 5
static inline
-std=gnu11 1020 bytes
-std=gnu99 1020 bytes
-std=gnu89 1024 bytes
-std=gnu11 -fgnu89-inline 1024 bytes
-std=gnu99 -fgnu89-inline 1024 bytes
-std=gnu89 -fgnu89-inline 1024 bytes

Has static inline regressions on your GCC 4.9?

I believe all the cases that blew up the code size by a larger margin (40+ byte) came from the compiler not inlining the functions. -Winline seems to be a good addition to the build scripts to spot this kind of stuff, in my opinion.

I'll try to figure out why GCC 5 uses one instruction less in versions 4.9, 6 and 7 and if it's a bug in GCC 5 that produces smaller, but incorrect code or if it's a code size regression in 6 and 7.

Same with GCC 8
"extern inline" hack solves the issue, Anduril had been successfully compiled on MacOs High Sierra with gcc and avr-gcc installed with Brew without specifying the versions etc (all default)

Leo (leo-died-again) wrote :

Same with GCC 9.1. Replacing externing the inline fixes this for GCC 9.1 at least for the hello_world example.

Dan Nelson (dnelson1901) wrote :

I'm using avr-gcc 9.1 and worked around the issue with the -fgnu89-inline flag. That way no code needs to be changed.

To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers