Different .hex sizes between environments

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

Hi,

 

  I've been hard at work on my mini-console-thing and I'm reaching the 8K limit on my  ATTiny85, so I've been tinkering with stuff.

 

After fiddling with the settings on my windows machine, I managed to get AS7 to compile my program down to 5428 bytes. Here's the compiler command from the autogenerated makefile for that:

 

$(QUOTE)C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\bin\avr-gcc.exe$(QUOTE)  -x c -funsigned-char -funsigned-bitfields -DDEBUG 
-I"C:\Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATtiny_DFP\1.3.147\include"  -Os -fno-inline-small-functions -fno-inline-functions
-ffunction-sections -fdata-sections -fpack-struct -fshort-enums -mshort-calls -g2 -Wall -mmcu=attiny85
-B "C:\Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATtiny_DFP\1.3.147\gcc\dev\attiny85" -c -std=gnu99 -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)"   -o "$@" "$<"

 

which ultimately generates this:

 

C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\bin\avr-gcc.exe"  -x c -funsigned-char -funsigned-bitfields -DDEBUG 
-I"C:\Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATtiny_DFP\1.3.147\include"  -Os -fno-inline-small-functions -fno-inline-functions -ffunction-sections
-fdata-sections -fpack-struct -fshort-enums -mshort-calls -g2 -Wall -mmcu=attiny85 -B "C:\Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATtiny_DFP\1.3.147\gcc\dev\attiny85"
-c -std=gnu99 -MD -MP -MF "mage.d" -MT"mage.d" -MT"mage.o"   -o "mage.o" ".././mage.c"

 

I copied the various -f switches into my makefile for my proper build environment on my Raspberry Pi, so it looks like this:

 

OBJECTS    = utils.o beep.o oled.o mage.o     # Add more objects for each .c file here
C_FLAGS    = -Wl,--relax -ffunction-sections -fdata-sections -fno-inline-small-functions -fpack-struct -fshort-enums -mshort-calls
...
COMPILE = avr-gcc -Wall -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE) $(C_FLAGS)
...
main.elf: $(OBJECTS)
$(COMPILE) -o main.elf $(OBJECTS)
main.hex: main.elf
rm -f main.hex
avr-objcopy -j .text -j .data -O ihex main.elf main.hex
avr-size --format=avr --mcu=$(DEVICE) main.elf

 

which compiles each .c file separately (if that makes any difference)

 

but that only compiles to 5684 bytes.

 

I learnt about avr-nm today, so I had a look at that and a few things stood out -

 

1. the RPi (larger) version included symbol names of functions I know I haven't used but are still being included, although these are quite small.

2. There's a difference in size between many of my functions: main() - 756 bytes vs 812 b and battle_mode() - 410 vs 430, which obviously all add up.

3. There are extra symbols generated by the RPi version that aren't in the AS7 one: __udivmodhi4 @ 40b

 

As ever, I'm out of my depth with C compilers when it comes to these sorts of tweaks. What am I missing?

This topic has a solution.
Last Edited: Tue. May 22, 2018 - 05:29 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MalphasWats wrote:
1. the RPi (larger) version included symbol names of functions I know I haven't used but are still being included, although these are quite small.
Sounds like you may well have remember -function-sections and -fdata-sections on the compile but the link it possibly missing -gc-sections (the thing that then actually invokes the "garbage collect")

MalphasWats wrote:
2. There's a difference in size between many of my functions: main() - 756 bytes vs 812 b and battle_mode() - 410 vs 430, which obviously all add up.
You probably need to study the lss files side by side (diff, meld, beyond compare, etc etc) to see what the actual opcode differences are
MalphasWats wrote:
3. There are extra symbols generated by the RPi version that aren't in the AS7 one: __udivmodhi4 @ 40b
Ah then that sounds like you may well have the -mmcu= on the compile commands but it's been ommitted (or is different) on the link command. If that happens then I think it makes a fall back assumption of "tiny". If it does that it doesn't think it has MUL so it will pull in software math functions from the libc.a

 

So maybe show the complete build output from the RPi invocation.

 

Also google "mfile avr" and use that - it'll be much simpler than building a Makefile from scratch and it doesn't have errors like missing links and so on.

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

clawson wrote:
it doesn't have errors like missing links and so on.

Yes, those missing links can be devilish.

Image result for missing link

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

Quote:

Sounds like you may well have remember -function-sections and -fdata-sections on the compile but the link it possibly missing -gc-sections (the thing that then actually invokes the "garbage collect")

Doh! That was it, added -gc-sections as a linker command and accounted for my own idiocy (comparing slightly different code versions) and it's now 2bytes out in one single function and I know I don't care why!

Thank you

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

PS I just downloaded Mfile to check but note that it dates from 2006 and so does not even include delights such as -gc-sections as I think they were later additions to GCC. So if you do use Mfile (probably still a good "sanity check" anyway) then you might want to combine that with an analysis of what something like AS7 is up to.

 

BTW as far as I know it should be able to use the AS7 Makefile "as is" anyway. Just get AS7 to build the project and either the project\Debug or project\Release directory should then contain the Makefile that was used - just carry that over to the RPi Linux machine and it should work as well there. Note that because all the sources are referenced as ..\name.c or whatever (because this file usually lives in "Debug" or "Release" sub directories you have to arrange for the same. So on Rpi crate a "something" sub-directory from where the sources are located and put that Makefile into there to use it. If you want to invoke "make" from the project directory itself then just use "make -f something\Makefile" to direct it to look in the sub directory.

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

Are you using the same GCC version on both PC's?

Test with:

 avr-gcc --version

-Os is the switch for optimizing for small size, but it does not always generate the smallest code size.

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
avr-objcopy -j .text -j .data -O ihex main.elf main.hex

BTW be very careful with this. There are two schools of thought on the objcopy. Those who prefer -j and those who prefer -R. Most common Makefiles these days (and I think AS7 is one) prefer the -R option. That way if you add a new flash section like .mydata or something it automatically gets included. When using -j's you would need to remember to:

avr-objcopy -j .text -j .data -j .mydata -O ihex main.elf main.hex

to ensure it gets included if you added any such section destined for the flash image.

 

PS just checked and Mfile also favours -R:

# Create final output files (.hex, .eep) from ELF output file.
%.hex: %.elf
	@echo
	@echo $(MSG_FLASH) $@
	$(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock $< $@

PPS oh and I note you don't seem to be doing anything about EEP? Presumably you don't plan to use/preload the EEPROM? If you do model your solution on this:

%.eep: %.elf
	@echo
	@echo $(MSG_EEPROM) $@
	-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
	--change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0

 

Last Edited: Tue. May 22, 2018 - 03:05 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Definitely lots to think about there, thank you!

I got my initial makefile from someone else's project on github and have been learning how they work by making small tweaks to it!

I do plan to use EEPROM for save game data, although I have also considered using it to store some of the lesser-used image data once I get really desperate for PROGMEM!

I'll go read about the difference between -j and -R now!

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

MalphasWats wrote:
I get really desperate for PROGMEM!
Unless it is C++ I hope you really mean __flash? PROGMEM is so "last decade"

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

clawson wrote:

MalphasWats wrote:
I get really desperate for PROGMEM!
Unless it is C++ I hope you really mean __flash? PROGMEM is so "last decade"

Is this another one of those things where someone just stuffed #define __flash PROGMEM in a random header file just to give someone something to do?

Actually, I bet it's from those newfangled chips that only pretend to have separate program/eeprom/SRAM memories but really it's just one big chunk of flash somethingorother?

I can't keep up!

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

Nope. __flash is an extension added to the core compiler so that most of pgmspace.h is no longer needed. All that messy pgm_read_XXX() stuff is no longer required. You just modify your data items to be "const __flash" then the compiler already knows to generate LPM access code so doesn't have to be helped along with the old pgm_readXXX stuff.

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

clawson wrote:
Nope. __flash is an extension added to the core compiler so that most of pgmspace.h is no longer needed. All that messy pgm_read_XXX() stuff is no longer required. You just modify your data items to be "const __flash" then the compiler already knows to generate LPM access code so doesn't have to be helped along with the old pgm_readXXX stuff.

 

Woah! I was totally looking for some way of doing something like that because I wanted a draw function that can draw out of program memory or sram without a whole load of extra parameters! Will investigate!

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

MalphasWats wrote:
out of program memory or sram
Ah then for that you want __memx in fact. _memx is like a "super pointer" that can have a flag bit to say whether the rest of the value is "flash" or "RAM" so you can write routines that behave the same whether the input is in RAM or flash. If you need to check whether a value is flash or RAM you follow the manual:

 

https://gcc.gnu.org/onlinedocs/g...

https://gcc.gnu.org/onlinedocs/g...

 

and use __builtin_avr_flash_segment() on a __memx pointer it will return -1 if it is RAM or some positive value for flash.__builtin_avr_flash_segment