I want to get rid of empty space in a binary

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

Picoboot takes less than 100 bytes including the sample blink app, yet when I build it I get an 8KB binary with lots of empty space (initialized to zero). Is there a way to avoid all the empty space?
Here's the start of my code:

.text
.org 0x0000
    rjmp BootStart
BlinkLED:
    sbi DDRB, LEDPIN
Blink:
    sbi PINB, LEDPIN
    ldi ZH, 30
DelayLoop:
    ; 5.9M cycles =~ .74s @ 8Mhz
    rcall Delay3Cycle               ; 256 * 3 cycles
    sbiw ZL, 1
    brne DelayLoop
    rjmp Blink

.org (VIRTUAL_RESET_ORG)
VirtualReset:
    rjmp BlinkLED                   ; will be overwritten by programmer
BootStart:

Here's the build commands:

Quote:
avr-gcc -mmcu=attiny84 -nostdlib -x assembler-with-cpp -c picobootSerial.S -o picobootSerial.o
avr-gcc -mmcu=attiny84 -nostdlib -o picobootSerial.elf picobootSerial.o
avr-objcopy -j .text -j .data -O ihex picobootSerial.elf picobootSerial.hex

I have no special talents.  I am only passionately curious. - Albert Einstein

 

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

I think that you would need to put the code on either side of
the gap into separate sections and locate them with the linker.
If that does not work, you might try just editing the .hex file.

Moderation in all things. -- ancient proverb

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

Quote:

If that does not work, you might try just editing the .hex file.

The .hex file should have sparse records if there's a bit at 0 and a bit at 0xNNN but it's the conversion from .hex to .bin that would then pad. How else could it possibly make sure the stuff at 0xNNN is properly offset to that address? So surely it's inevitable that:
Quote:
I get an 8KB binary

?

EDIt: as a test I built:

#include 

__attribute__ ((section(".foo"))) void foo(void) {
    PORTB = 0xFF;
}


int main(void)
{
    while(1) {
        foo();
    }
}

and linked with:

avr-gcc.exe -o test.elf  test.o   -nostartfiles -Wl,-Map="test.map" -Wl,--start-group -Wl,-lm  -Wl,--end-group -mrelax -mmcu=atmega8 -Wl,-section-start=.foo=0x1F80 

It produced:

:04000000BFDFFECF91
:061F80008FEF88BB0895FD
:00000001FF

Which is one record at 0x0000 and one at 0x1F80 as I requested. So this file *is* sparse.

Of course if I convert it to binary:

C:\Documents and Settings\asl\My Documents\Atmel Studio\test\test\Debug>dir test
.bin
 Volume in drive C has no label.
 Volume Serial Number is E0DD-96FE

 Directory of C:\Documents and Settings\asl\My Documents\Atmel Studio\test\test\
Debug

20/02/2014  11:00             8,070 test.bin
               1 File(s)          8,070 bytes
               0 Dir(s)  15,687,471,104 bytes free

Then I do get a file that is getting on for 8K long and which does contain an awful lot of padding 0x00;s:

uid23021@lxl0060u:~/windows$ hexdump -C test.bin
00000000  bf df fe cf 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001f80  8f ef 88 bb 08 95                                 |......|
00001f86
================================================================================

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

clawson wrote:
Quote:

If that does not work, you might try just editing the .hex file.

The .hex file should have sparse records if there's a bit at 0 and a bit at 0xNNN but it's the conversion from .hex to .bin that would then pad. How else could it possibly make sure the stuff at 0xNNN is properly offset to that address? So surely it's inevitable that:
Quote:
I get an 8KB binary

?
OP never made a .bin file.
I expect the the 8KB refered either to the .elf or to the number of addresses in the .hex file.
.org does produce padding and that would go into the .o and .elf files.
'Tis nice to know that the section method works.

Moderation in all things. -- ancient proverb

Last Edited: Fri. Feb 21, 2014 - 12:14 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh I see what you mean. A lot of people don't understand .org in a linking assembler such as avr-as, it doesn't work like org in the Atmel assembler.

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

clawson wrote:
Oh I see what you mean. A lot of people don't understand .org in a linking assembler such as avr-as, it doesn't work like org in the Atmel assembler.

So I need to make a section name before the 2nd .org and use -Wl,-section-start= on the link line?

I have no special talents.  I am only passionately curious. - Albert Einstein

 

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

ralphd wrote:
I want to get rid of empty space in a binary
Make it a singularity. :roll: :) Sorry, couldn't control myself.

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

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

Yes, using a section is the way to place data at absolute addresses when using avr-ld. .org is just a "pad to relative offset" directive.

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

ralphd wrote:
So I need to make a section name before the 2nd .org and use -Wl,-section-start= on the link line?
You can dispense with the .org directives altogether:
.text
    rjmp BootStart
...
.section .virtualreset,"ax",@progbits
VirtualReset:
    rjmp BlinkLED                   ; will be overwritten by programmer
...

You'll need to compute the address for section .virtualreset in a similar fashion as you're currently doing via C macros in the .S and pass that to the link command, but in your makefile or another build script. Or simply hard code it.

It would be worth it to compute it though. As picoboot evolves its size may change, even if just by a word. Easier to let the makefile do the work.

In fact if code grows beyond the current size, you can actually save yourself a word. If the bootloader grows to the point where the rjmp to VirtualReset in BootStart is in page N-1, then you can dispense with that rjmp altogether, and move VirtualReset in its place. Manipulating sections will let you do that automatically:

.section .virtualreset,"ax",@progbits
VirtualReset:
    rjmp BlinkLED                   ; will be overwritten by programmer
.section .bootstart_a,"ax",@progbits
BootStart:
    sbis UART_Port-2, UART_Rx       ; Rx high = start bootloader
.section .bootstart_vr
    rjmp VirtualReset               ; jump to application code
.section .bootstart_b
    clr FCS

.section .commandloop
CommandLoop:
...
$ avr-size -A picobootSerial.o
picobootSerial.o  :
section        size   addr
.text            16      0
.data             0      0
.bss              0      0
virtualreset      2      0
bootstart_a       2      0
bootstart_vr      2      0
bootstart_b       2      0
commandloop      56      0
Total            80

If the total size of sections .bootstart_vr + .bootstart_b + command_loop is greater than the device page size, drop section .bootstart_vr and link section .virtualreset in its place. If it isn't, link in the normal order.

This approach can also identify problems like if section commandloop is too big to fit in a single page.

It also avoids the padding that comes with the use of .org

My makefile-fu isn't what it should be, but I could probably bang together a bash script that managed it.

"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

joeymorin wrote:

In fact if code grows beyond the current size, you can actually save yourself a word. If the bootloader grows to the point where the rjmp to VirtualReset in BootStart is in page N-1, then you can dispense with that rjmp altogether, and move VirtualReset in its place.

That is a neat idea, though I would have to make UART_Port fixed since the sbis instruction would have to be re-written as well. Either that or come up with a way for the bootloader to communicate it avrdude.

I have no special talents.  I am only passionately curious. - Albert Einstein

 

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

ralphd wrote:
That is a neat idea, though I would have to make UART_Port fixed since the sbis instruction would have to be re-written as well. Either that or come up with a way for the bootloader to communicate it avrdude.
You've got a write-only bootloader with FCS in 31 words plus VirtualReset. Probably the only reason for the code to grow would be with the addition of flash read. With that avrdude can simply read page N-1, change the inline rjmp to the app, and upload the page.

"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

clawson wrote:
Yes, using a section is the way to place data at absolute addresses when using avr-ld. .org is just a "pad to relative offset" directive.

Thanks. That got the .hex file down to 238 bytes from ~23KB.
I've got the address hard-coded in the Makefile until I figure out a way to determine the size of the device flash from within the makefile so I can calculate the address.

I have no special talents.  I am only passionately curious. - Albert Einstein

 

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

ralphd wrote:
clawson wrote:
Yes, using a section is the way to place data at absolute addresses when using avr-ld. .org is just a "pad to relative offset" directive.

Thanks. That got the .hex file down to 238 bytes from ~23KB.
I've got the address hard-coded in the Makefile until I figure out a way to determine the size of the device flash from within the makefile so I can calculate the address.
Use the avr-gcc preprocessor to generate an option file for the linker.
awk or grep can be used to filter out the clutter.

Moderation in all things. -- ancient proverb

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

skeeve wrote:
ralphd wrote:

I've got the address hard-coded in the Makefile until I figure out a way to determine the size of the device flash from within the makefile so I can calculate the address.
Use the avr-gcc preprocessor to generate an option file for the linker.
awk or grep can be used to filter out the clutter.

It took some brushing up on gnu make (I almost said screw it and was going to write a perl makefile), but I came up with something a lot simpler:

DEVICE = attiny84
# calculate bootloader address
ADDRESS:=$(shell echo $(DEVICE)|cut -c7| awk '{ print $$1 * 1024 -66 }')

CFLAGS = -mmcu=$(DEVICE)

picobootSerial.elf: picobootSerial.o
        $(CC) $(CFLAGS) -Wl,-section-start=.bootloader=$(ADDRESS) -o $@ $<

Which results in:

avr-gcc -mmcu=attiny84 -nostdlib -Wl,-section-start=.bootloader=8126 -o picobootSerial.elf picobootSerial.o

I already had to define DEVICE for the -mmcu flag, and I realized the 7th character of the AVR parts supported by picoboot is the flash size in KB. So I multiply that number by 1024, subtract the number of bytes from end of flash to the virtual reset vector (66) to get the section address.

I have no special talents.  I am only passionately curious. - Albert Einstein