Hello,
I am examining the generated assembly of my toy program for msp430 and I think I might be do something incorrectly. Regardless, I would like to fix this.
Here is a portion of the listing using objdump -d <my_executable>. I will annotate the call addresses with the symbol name:
0000813e <PreMainInner>:
813e: b0 12 d6 81 call #33238 ;#0x81d6 systemInit000
8142: b0 12 42 82 call #33346 ;#0x8242 stdlib_macrosDatInit000
8146: b0 12 e0 81 call #33248 ;#0x81e0 unknown_msp430DatInit000
814a: b0 12 46 82 call #33350 ;#0x8246 unknown_iomacrosDatInit000
814e: b0 12 e4 81 call #33252 ;#0x81e4 unknown_msp430f5510DatInit000
8152: b0 12 3e 82 call #33342 ;#0x823e unknown_ringDatInit000
8156: b0 12 40 82 call #33344 ;#0x8240 stdlib_macrosInit000
815a: b0 12 de 81 call #33246 ;#0x81de unknown_msp430Init000
815e: b0 12 44 82 call #33348 ;#0x8244 unknown_iomacrosInit000
8162: b0 12 e2 81 call #33250 ;#0x81e2 unknown_msp430f5510Init000
8166: b0 12 3c 82 call #33340 ;#0x823c unknown_ringInit000
816a: 30 41 ret
The first one moves a zero into the symbol nimvm_IAxmsqnME4Jmed24hOgrFQ. Not sure what that is exactly. It is never referenced again in the executable as far as I can tell.
The others do nothing except return.That is an awful lot of wasted bytes. Except for the stdlib_... symbols, the others are the names of the nim files I've included in the compilation.
Am I doing something wrong to generate these extra routines? I plan to get this in a public repo but I would like to iron out the major kinks first. I would have imagined that the dead code elimination would have removed those routines.
Here is my makefile:
MCU=msp430f5510
SUPPORT_FILES=gcc/include/
GDB=gcc/bin/msp430-elf-gdb
GDB_CONSOLE=gcc/bin/gdb_agent_console
MSP430_DAT=gcc/msp430.dat
HEADERS=msp430.nim msp430f5510.nim iomacros.nim
CODEFILES=blink.nim ring.nim
NIMFLAGS=-d:release --os:standalone --opt:size --gc:none --deadCodeElim:on -d:StandaloneHeapSize=0
# avr is the closest cpu for the moment
NIMFLAGS+=--cpu:avr
# running one C compiler lets its errors show
NIMFLAGS+=--parallelBuild:1 --verbosity:2
#location of include files
NIMFLAGS+=--passC:"-mmcu=$(MCU) -I=$(SUPPORT_FILES) -L=$(SUPPORT_FILES)"
NIMFLAGS+=--passL:"-mmcu=$(MCU) -I=$(SUPPORT_FILES) -L=$(SUPPORT_FILES)"
%: %.nim panicoverride.nim
nim c $(NIMFLAGS) $<
blink: $(HEADERS) $(CODEFILES)
all: blink
listing: blink
gcc/bin/msp430-elf-objdump -d blink > asm.lst && gcc/bin/msp430-elf-objdump -x blink >> asm.lst
debugserver:
$(GDB_CONSOLE) $(MSP430_DAT) &> ./gdb_agent_console.log &
debug:
$(GDB) blink -ex "target remote :55000"
.PHONY: debug debugserver
This blog post of Mr Felsing may help you to get minimal total executable size:
Thanks for the response. I have read that and partially implemented it where it made sense for my use case. I'm think this is a different problem however.
I have already removed everything that isn't referenced, which is the main point of the article. The functions that are being called are referenced by the call so the linker can't remove them. It's just that the call is pointless.
In the generated C the functions are marked as N_NOINLINE. I think that if they weren't, maybe the compiler would remove the call, but can't test that until lunch. Either way, removing calls that do nothing is a problem I expected Nim to be able to do.
Another way to remove the call would be to have the setup calls be macros that expand to nothing if the call were unnecessary.
So marking them as inline and then recompiling didn't work. With the way the compiler currently works the extra bytes wasted seems unavoidable.
I think maybe it ends up not being a big deal because larger programs will have modules that likely need initialization of some kind.
Can anyone tell me what kinds of initialization those functions can perform? I'll do some experiments as well.
The functions that are being called are referenced by the call so the linker can't remove them
see issue #6134