Unfortunately it didn't help in my case. I noticed another hint when I looked at the final binaries using readelf. It seems when I compile with LTO the section to segment mapping is off. Instead of putting `heap_mem_area_not_ret` in `.bss`, it is put in its own segment. So the variable is there, just not where the rest of the program expects it to be. Could it be that I have to change something in the linker script to make it work with LTO? ``` Section to Segment mapping: Segment Sections... 00 .ARM.exidx 01 ER_IROM1 02 ER_IROM2 03 ER_IROM3 .ARM.exidx .copy.table .zero.table .data .bss ER_NZI 04 RET_DATA RET_HEAP 05 RET_DATA_UNINIT_TRNG_STATE 06 ``` ``` Section to Segment mapping: Segment Sections... 00 .ARM.exidx 01 ER_IROM1 02 ER_IROM2 03 ER_IROM3 .ARM.exidx .copy.table .zero.table .data heap_db_area heap_env_area heap_mem_area_not_ret heap_msg_area trng_state .bss 04 RET_DATA 05 ``` - Niklas On Fri, 27 Sept 2024 at 16:19, Richard Earnshaw (lists) < Richard.Earnshaw@xxxxxxx> wrote: > 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 > >