Linker script is the default one provided by Cube.
To do so, I created a simple program in C# to generate a bin file out of elf and compare it to the bin generated during pio build.
For STM32, ROM sits at address 0x800 0000, and RAM at 0x200 0000.
But the bin file also contains the data section at location 0x200 0000.
The linker file also states for the data section:
/* Initialized data sections goes into RAM, load LMA copy after code */
Therefore init values need to be stored in flash.
So I added the section and my total flash size equals 5748 bytes including padding (see Total size in screenshot).
Thus FLASH = .text + .data + .rodata (here; all other empty) and thus 344 + 0 + 0 = 344 which is the same as PlatformIO says.
For RAM, only the sections .data + .bss + .noinit are considered and that is in this case just .bss and 28 bytes.
For your example, FLASH = 4592 + 560 + 192 = 5344 which matches
If the linker file has section names which are not listed in this regular expression but still contribute to flash or RAM, they are not counted. The size-tool and the PIO core logic is not intelligent enough to figure out that certain sections do end up in RAM or Flash after all based on its address.
Notice that it also ignores the core-coupled-memory (CCM) RAM.
So your calculations might be more correct than PlatformIO ones’.