Search code examples
cmakecross-compilingavr-gcc

avr-gcc ELF different between CMake and command line


I'm having difficulties with a CMake project that builds an ELF executable with avr-gcc. My executable is supposed to run a custom bytecode file using a virtual machine my colleague and I have written, so I would expect it to be several kilobytes large. However, when I run my CMake script, I get a 321 byte ELF file, whereas from the terminal avr-gcc command I get a 20KB file.

I've done quite a bit of searching, and it seems CMake does separate compilation -- it builds the object files, and then links them. That seems to the the source of my problem.

But, of course, my actual code is a bit long. So here is a more minimal, complete and verifiable example :) .

Here is a file that I want to compile using avr-gcc.

// foo.c

#define sz 400

volatile unsigned int foo[sz] = { 0, 1, 2, 3, 4 };


int main() {
    volatile unsigned int bar = 0;
    for (volatile int i = 0; i < sz; ++i) {
        bar += foo[i];
    }
    for (volatile int i = 0; i < sz; ++i) {
        bar += foo[i];
    }
    for (volatile int i = 0; i < sz; ++i) {
        bar += foo[i];
    }
    return bar;
}

Then run this bash script:

#!/bin/bash
rm -rf build
mkdir -p build
cd build

# Single command compilation
avr-gcc ../foo.c -o foo_all_in_one.elf -std=c99 -mmcu=atmega328p -Wall -Wl,-s -Wl,--gc-sections

# Separate compilation
avr-gcc ../foo.c -c -o foo_separate.c.obj -std=c99 -mmcu=atmega328p -Wall
avr-gcc foo_separate.c.obj -o foo_separate.elf -Wall -Wl,-s -Wl,--gc-sections

ls -lh

Output:

total 12K
-rwxrwxr-x 1 anthonyd973 anthonyd973 1.7K May 26 09:35 foo_all_in_one.elf
-rw-rw-r-- 1 anthonyd973 anthonyd973 2.0K May 26 09:35 foo_separate.c.obj
-rwxrwxr-x 1 anthonyd973 anthonyd973  296 May 26 09:35 foo_separate.elf

All-in-one compilation yields 1.7KB elf file, whil separate compilation yields a 296B file. Why the difference?


Solution

  • AVR's linker must know which microcontroller you are programming for. I don't have enough technical knowledge to explain why, but I guess it has to do with segment placements or something like that. If you have a better explanation, feel free to give another answer to this question and I'll accept it.

    At any rate, if I add -mmcu=atmega328p to the linking command, everything works fine.

    #!/bin/bash
    rm -rf build
    mkdir -p build
    cd build
    
    # Single command compilation
    avr-gcc ../foo.c -o foo_all_in_one.elf -std=c99 -mmcu=atmega328p -Wall -Wl,-s -Wl,--gc-sections
    
    # Separate compilation
    avr-gcc ../foo.c -c -o foo_separate.c.obj -std=c99 -mmcu=atmega328p -Wall
    avr-gcc foo_separate.c.obj -o foo_separate.elf -mmcu=atmega328p -Wall -Wl,-s -Wl,--gc-sections
    
    ls -lh
    

    Output:

    total 12K
    -rwxrwxr-x 1 anthonyd973 anthonyd973 1.7K May 26 09:41 foo_all_in_one.elf
    -rw-rw-r-- 1 anthonyd973 anthonyd973 2.0K May 26 09:41 foo_separate.c.obj
    -rwxrwxr-x 1 anthonyd973 anthonyd973 1.7K May 26 09:41 foo_separate.elf