On 27/09/2024 14:32, Niklas Dusenlund wrote: > Hi! > > I'm compiling for a cortex-m0 with a very small memory, so I would like to > use LTO to minimize my program size. > > I compile all the source files of an SDK to object files. Then I create an > archive with gcc-ar. Finally I link everything together with gcc. > Everything except this global variable works as expected both with and > without LTO. I fail to understand why the variable is removed when I enable > LTO. > > As you can see in the output maps below, the size in the correct version is > 0x80c, whereas it is 0 in the bad output. > > When I look at the object files and archives with gcc-nm they look the same > with and without -flto. > > I guess this is a "hack" to define the size of a heap. But if there is > another way to achieve the same result I'm all open for it. This memory > area is referenced by code that is burned into a ROM at manufacturing time. > So it is used, but of course GCC doesn't see that. > > The variable is defined like this: > > ``` > uint32_t rwip_heap_non_ret[RWIP_CALC_HEAP_LEN(RWIP_HEAP_NON_RET_SIZE_JT)] > __attribute__((section("heap_mem_area_not_ret"))); When the LTO pass is run, any variable not explicitly referenced in your source code will be discarded (LTO doesn't look at the linker script), so you need to tell the compiler not to discard it (this doesn't generally happen without LTO because the compiler is unable to tell if a variable will be referenced by another component in your program, but with LTO we can see ALL the code). So try uint32_t rwip_heap_non_ret[RWIP_CALC_HEAP_LEN(RWIP_HEAP_NON_RET_SIZE_JT)] __attribute__((used,section("heap_mem_area_not_ret"))); The extra 'used' attribute tells the compiler that this value is used, even if it can't tell where that happens. A simple testcase demonstrates this: int __attribute__((used)) x; int y; int main() { return 0;} If I build this without LTO (gcc test.c -O3 -o test.exe) I get definitions of x and y in my executable, but if I enable LTO (gcc -flto test.c -O3 -o test.lto.exe) I only get a definition of x. nm test.exe ... 0000000000004018 B x 0000000000004014 B y nm test.lto.exe ... 0000000000004014 B x R. > ``` > > It is referenced like this in the linker script: > ``` > ER_NZI (NOLOAD) : > { > . = ALIGN(4); > __heap_mem_area_not_ret_start__ = .; > *jump_table.o(heap_mem_area_not_ret) /* not retained HEAP */ > __heap_mem_area_not_ret_end__ = .; > } > LR_IROM3 > ``` > > > From the memory map it looks like this when it is correct: > > ``` > ER_NZI 0x07fc754c 0x80c > 0x07fc754c . = ALIGN (0x4) > 0x07fc754c > __heap_mem_area_not_ret_start__ = . > *jump_table.o(heap_mem_area_not_ret) > heap_mem_area_not_ret > 0x07fc754c 0x80c > /var/folders/9n/c7ggvkrn03ld13___37y6lcw0000gn/T/rustcqiFzCU/libda14531_sdk.a(2077e224400bc0d4-jump_table.o) > 0x07fc754c rwip_heap_non_ret > 0x07fc7d58 > __heap_mem_area_not_ret_end__ = . > ``` > > and this when it is incorrect: > > ``` > ER_NZI 0x07fc800c 0x0 > 0x07fc800c . = ALIGN (0x4) > 0x07fc800c > __heap_mem_area_not_ret_start__ = . > *jump_table.o(heap_mem_area_not_ret) > 0x07fc800c > __heap_mem_area_not_ret_end__ = . > ``` > > Ouput of gcc-nm: > > ``` > 00000000 D rwip_heap_db_ret > 00000000 D rwip_heap_env_ret > 00000000 D rwip_heap_msg_ret > 00000000 D rwip_heap_non_ret > ``` > > - Niklas