HEX file size difference between GCC and MDK

Asked by JiachengWang

with the same source code, when using GCC, the compiled HEX file is 188K. when using MDK, the compiled final HEX file is about 50K. what is the reason they are so difference? any idea to reduce the HEX file size with GCC? thanks a lot

Question information

Language:
English Edit question
Status:
Solved
For:
GNU Arm Embedded Toolchain Edit question
Assignee:
No assignee Edit question
Solved by:
Thomas Preud'homme
Solved:
Last query:
Last reply:
Revision history for this message
Thomas Preud'homme (thomas-preudhomme) said :
#1

Hi Jiacheng,

Are you measuring the size of .text and .data sections or the whole binary? If looking into whole binary that might be because of the symbols and these can be stripped using arm-none-eabi-strip. How are you compiling and linking? Are you using our newlib-nano library?

Best regards.

Revision history for this message
JiachengWang (jiacheng123-wang) said :
#2

With newlib-nano, the HEX file size is reduced to 119K. however, the problem can not run, maybe some error in my compiling and linking.

Revision history for this message
Thomas Preud'homme (thomas-preudhomme) said :
#3

Hi Jiacheng,

Can you give us the command lines you use to compile and link with Newlib nano?

Best regards.

Revision history for this message
JiachengWang (jiacheng123-wang) said :
#4

Thanks a lot for your help. the make file is like:

# Linker flags
LDFLAGS += -Xlinker -Map=$(LISTING_DIRECTORY)/$(OUTPUT_FILENAME).map
LDFLAGS += -mthumb -mabi=aapcs -L ./ -T$(LINKER_SCRIPT)
LDFLAGS += -mcpu=cortex-m0
# let linker to dump unused sections
LDFLAGS += -Wl,--gc-sections
# use newlib in nano version
LDFLAGS += --specs=nano.specs -lc -lnosys

# Compiler flags
CFLAGS += -mcpu=$(CPU) -mthumb -mabi=aapcs -D$(DEVICE) -D$(BOARD) -D$(TARGET_CHIP) --std=gnu99
CFLAGS += -Wall #-Werror
CFLAGS += -mfloat-abi=soft

# keep every function in separate section. This will allow linker to dump unused functions
CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing
CFLAGS += -flto -fno-builtin

BTW, I'm using Nordic chip, it is cortex M0 based. the compiled program can not run on the chip and "printf" function can not work.

Revision history for this message
JiachengWang (jiacheng123-wang) said :
#5

With some more work, printf is working now. The main function is simple like:

int main(void)
{
  simple_uart_config(RTS_PIN_NUMBER, TX_PIN_NUMBER, CTS_PIN_NUMBER, RX_PIN_NUMBER, HWFC);

 printf("\r\n i = %d**************************", 60);
 printf("\r\n j = %x................................", 60);
 printf("\r\n");
}

By MDK, the compiler option is:
-c --cpu Cortex-M0 -D__MICROLIB --li -g -O0 --apcs=interwork --split_sections -I..\include --c99
-I C:\Keil_v5\ARM\RV31\INC

And the final complied HEX file size is 6K

By GCC, the complier lines are:
"C:/Program Files (x86)/GNU Tools ARM Embedded/4.9 2014q4/bin/arm-none-eabi-gcc" -mcpu=cortex-m0 -mthumb -mabi=aapcs -DNRF51 -DBOARD_PCA10001 -DNRF51822_QFAA_CA --std=gnu99 -Wall -Werror -mfloat-abi=soft -DDEBUG -g3 -O0 -I"../include" -I"../include/gcc" -M ../main.c -MF "_build/main.d" -MT _build/main.o

"C:/Program Files (x86)/GNU Tools ARM Embedded/4.9 2014q4/bin/arm-none-eabi-gcc" -mcpu=cortex-m0 -mthumb -mabi=aapcs -DNRF51 -DBOARD_PCA10001 -DNRF51822_QFAA_CA --std=gnu99 -Wall -Werror -mfloat-abi=soft -DDEBUG -g3 -O0 -I"../include" -I"../include/gcc" -c -o _build/main.o ../main.c

"C:/Program Files (x86)/GNU Tools ARM Embedded/4.9 2014q4/bin/arm-none-eabi-gcc" -mcpu=cortex-m0 -mthumb -mabi=aapcs -DNRF51 -DBOARD_PCA10001 -DNRF51822_QFAA_CA --std=gnu99 -Wall -Werror -mfloat-abi=soft -DDEBUG -g3 -O0 -I"../include" -I"../include/gcc" -M ../source/simple_uart.c -MF "_build/simple_uart.d" -MT _build/simple_uart.o

"C:/Program Files (x86)/GNU Tools ARM Embedded/4.9 2014q4/bin/arm-none-eabi-gcc" -mcpu=cortex-m0 -mthumb -mabi=aapcs -DNRF51 -DBOARD_PCA10001 -DNRF51822_QFAA_CA --std=gnu99 -Wall -Werror -mfloat-abi=soft -DDEBUG -g3 -O0 -I"../include" -I"../include/gcc" -c -o _build/simple_uart.o ../source/simple_uart.c

"C:/Program Files (x86)/GNU Tools ARM Embedded/4.9 2014q4/bin/arm-none-eabi-gcc" -mcpu=cortex-m0 -mthumb -mabi=aapcs -DNRF51 -DBOARD_PCA10001 -DNRF51822_QFAA_CA --std=gnu99 -Wall -Werror -mfloat-abi=soft -DDEBUG -g3 -O0 -I"../include" -I"../include/gcc" -M ../source/system_nrf51.c -MF "_build/system_nrf51.d" -MT _build/system_nrf51.o

"C:/Program Files (x86)/GNU Tools ARM Embedded/4.9 2014q4/bin/arm-none-eabi-gcc" -mcpu=cortex-m0 -mthumb -mabi=aapcs -DNRF51 -DBOARD_PCA10001 -DNRF51822_QFAA_CA --std=gnu99 -Wall -Werror -mfloat-abi=soft -DDEBUG -g3 -O0 -I"../include" -I"../include/gcc" -c -o _build/system_nrf51.o ../source/system_nrf51.c

"C:/Program Files (x86)/GNU Tools ARM Embedded/4.9 2014q4/bin/arm-none-eabi-gcc" -x assembler-with-cpp -DDEBUG -g3 -O0 -I"../include" -I"../include/gcc" -c -o _build/gcc_startup_nrf51.o gcc_startup_nrf51.s

"C:/Program Files (x86)/GNU Tools ARM Embedded/4.9 2014q4/bin/arm-none-eabi-gcc" -L"C:/Program Files (x86)/GNU Tools ARM Embedded/4.9 2014q4/arm-none-eabi/lib/armv6-m" -L"C:/Program Files (x86)/GNU Tools ARM Embedded/4.9 2014q4/lib/gcc/arm-none-eabi/4.9.3/armv6-m" -Xlinker -Map=_build/uart_example_gcc_xxaa.map -mcpu=cortex-m0 -mthumb -mabi=aapcs -L ./ -Tgcc_nrf51_blank_xxaa.ld --specs=nano.specs -lc -lnosys _build/main.o _build/simple_uart.o _build/system_nrf51.o _build/gcc_startup_nrf51.o -o _build/uart_example_gcc_xxaa.out

"C:/Program Files (x86)/GNU Tools ARM Embedded/4.9 2014q4/bin/arm-none-eabi-objcopy" -O binary _build/uart_example_gcc_xxaa.out _build/uart_example_gcc_xxaa.bin

"C:/Program Files (x86)/GNU Tools ARM Embedded/4.9 2014q4/bin/arm-none-eabi-objcopy" -O ihex _build/uart_example_gcc_xxaa.out _build/uart_example_gcc_xxaa.hex

The compiled HEX file size is 23K. (wihtout link new-lib nano, the compiled HEX file will be 108K, and printf also can work)

Revision history for this message
Thomas Preud'homme (thomas-preudhomme) said :
#6

Hi Jiacheng,

Are you satisfied with the size now? If not, you could look at the size of each function and compare the MDK to the GNU toolchain.

On another matter I noticed that you link -lnosys and -lc manually. This should be done automatically by the linker by just using --specs=nosys.specs. You should also not need to specify -maapcs as this is the default. Finally, the -L should not be necessary to find the toolchain library so the linking command should be:

"C:/Program Files (x86)/GNU Tools ARM Embedded/4.9 2014q4/bin/arm-none-eabi-gcc" -Xlinker -Map=_build/uart_example_gcc_xxaa.map -mcpu=cortex-m0 -mthumb -L ./ -Tgcc_nrf51_blank_xxaa.ld --specs=nano.specs --specs=nosys.specs _build/main.o _build/simple_uart.o _build/system_nrf51.o _build/gcc_startup_nrf51.o -o _build/uart_example_gcc_xxaa.out

Best regards.

Revision history for this message
JiachengWang (jiacheng123-wang) said :
#7

Hi Thomas,

Thanks a loy for your help.

With some more experiment, I guess the final HEX file size difference between MDK and GCC is the linking. In MDK, if a function in the source code is never called, it will not be linked into the final HEX file. But in GCC, all the functions in the source code will be linked into final HEX file. I can remove the un-called functions from my source code, but I can not control the functions in LIB. In my real project case, When I use MDK, it produces a 42K HEX file, but with GCC it produces a 99K HEX file(do my best to reduce the source code). The previous "printf" function just is a simple example to show the HEX file size difference between MKD and GCC (6K vs. 23K).

Is there any linking options to reomve the un-called LIB functions from the final HEX file?

Thanks again,

Jiacheng

Revision history for this message
Best Thomas Preud'homme (thomas-preudhomme) said :
#8

Hi Jiacheng,

Unfortunately I'm only aware of --gc-sections. The problem is that it is not generally safe to remove unused function as it would change distance between functions in the same section. This is problematic because some there might exist some pc-relative access (like function call). I'm not sure exactly what is the MDK doing.

As to your own code, you can compile with -ffunction-sections which will put each function in its own section and would thus allow --gc-sections to do its job. I encourage you to read the entry about this option in GCC's manual before using it.

Best regards.

Revision history for this message
JiachengWang (jiacheng123-wang) said :
#9

Thanks Thomas Preud'homme, that solved my question.

Revision history for this message
JiachengWang (jiacheng123-wang) said :
#10

with --gc-sections, there will be only 2-3K size reduce, and the HEX file can not run in the chip. Thanks a lot for your help, I'll read some GCC's manual to try more.