Menu

#635 Unused functions are not removed

None
open
nobody
None
8
2023-09-01
2019-07-22
No

Static nor global unused functions get removed from final executable, thus increasing memory footprint. Moreover, unused static functions are not highlighted by the compiler as warnings (compilation stage should be enough as the function is only valid within a compilation unit).

SDCC : stm8 3.9.0 #11195 (Linux)

Using the following minimalistic example:

static void unused(void);

_Noreturn int main(void)
{
    for (;;);
}

static void unused(void)
{
    main();
}

and

sdcc main.c --out-fmt-elf --all-callee-saves --opt-code-size -o main.elf

stm8-size (downloaded from the stm8 binutils-gdb project and built from source) returns;

stm8-size main.elf 
   text    data     bss     dec     hex filename
     43       0       0      43      2b main.elf

If unused() is removed, ELF size is reduced:

stm8-size main.elf 
   text    data     bss     dec     hex filename
     40       0       0      40      28 main.elf

The very same results are obtained if unused() is defined as a public function.

Even if not a big difference on this example, this issue becomes critical when using third-party APIs where many functions are left unused, specially under constrained devices such as STM8S103F3, which is limited to 8 KiB flash memory.

These optimizations should be platform-independent, but I have not tested any other ports so far. Is this issue STM8 or SDCC-specific?

Related

Feature Requests: #624

Discussion

  • Philipp Klaus Krause

    Ticket moved from /p/sdcc/bugs/2925/

    Can't be converted:

    • _category: Build
     
  • Philipp Klaus Krause

    Not a bug, just a missing feature.
    Currently SDCC supports not including unused funtions in binaries only the old style way via libraries.

    Philipp

     
  • Xavier Del Campo

    I wrote a tool which looks for unused functions by looking up the assembly files generated by sdcc and removes them in order to perform dead code elimination: https://github.com/XaviDCR92/sdccrm
    I still must check whether these modified .asm files can be safely compiled and linked, but I think it would be a good idea to integrate this tool into sdcc. So far it is only meant for the stm8 port, but it shouldn't be too complicated to port to other platforms.

     
  • Xavier Del Campo

    sdccrm now effectively removes unused functions, both global and private, so output files can be assembled via sdasstm8 and linked as usual.
    Todo:

    • Assembly files generated using the --debug switch are not supported yet. I need some guidelines about how to do this.
    • Unused static variables are not being removed yet.
      It would be interesting to integrate sdccrm into sdcc application suite (or just implement these implementations from the compiler / linker side). @spth, could you please review it? See https://github.com/XaviDCR92/sdccrm for further reference.
     
  • Xavier Del Campo

    @arenhnman helped me out a lot with this so we finally got:

    • Link-time dead code elimination, so both static and global unused functions get removed.
    • Total compatibility with other tools from the stm8-binutils-gdb package, such as stm8-size, stm8-objdump or stm8-readelf.

    Two forks have been created for these experimental versions of SDCC and stm8-binutils-gdb:
    https://github.com/XaviDCR92/sdcc-gas
    https://github.com/XaviDCR92/stm8-binutils-gdb
    Feel free to experiment and report any issues you might encounter. Everything is on a preliminary state, so expect bugs and/or unexpected behaviour.

    There are still some minor changes that need to be done on SDCC though:

    • Implement --data-sections so unused symbols on .data or .bss get removed too.
    • Ensure previous compatibility with the SDCC toolchain.
    • Create linker scripts for each STM8 part so valid memory use % is returned when using stm8-ld's --print-memory-usage.
     
    • Philipp Klaus Krause

      I'll have a look next week.
      Does this fork require gas? Does it still work with asxxxx?

       
  • Xavier Del Campo

    Unused code elimination must be performed by the linker and sdld does not have such feature, so this fork depends on this forked version of stm8-binutils-gdb. In any case, IMHO compatibility with the GNU toolchain is a must-have for a compiler.
    I wrote a small working example which uses these two forks to demonstrate these new capabilities: https://github.com/XaviDCR92/stm8-dce-example
    Beware these modifications have not been tested under other targets yet, so they should be reviewed before introducing them into the main tree.

    SDCC fork with GNU as support:
    https://github.com/XaviDCR92/sdcc-gas

    stm8-binutils-gdb fork with bugfixes and --gc-sections:
    https://github.com/XaviDCR92/stm8-binutils-gdb

     

    Last edit: Xavier Del Campo 2019-10-30
    • Philipp Klaus Krause

      Unused code elimination must be performed by the linker and sdld does not have such feature, so this fork depends on this forked version of stm8-binutils-gdb.

      For the feature, yes. But what if I don't use --gas? Will it still work as before (i.e. without any elimination of unused functions).

       
  • Xavier Del Campo

    A flag called options.gasOutput was added so any exceptions that must be done for GAS output (most of them are located on SDCCglue.c) are avoided on other assemblers.
    OTOH, there are some places where the tprintf family of functions, that allow printing different strings depending on the selected assembler, are not being used as much as they should. I have done some fixes here and there, but that should be reviewed extensively.

     
  • Konstantin Kim

    Konstantin Kim - 2020-03-05
     
  • BOBAH

    BOBAH - 2022-01-28

    just for information / state of progress https://sourceforge.net/p/sdcc/bugs/3303/#13df

     

Log in to post a comment.

Monday.com Logo