Since I hit the ROM limitation, I decided to move as much as possible of it's code and constant data to the FLASH.
One way to do this is to add an attribute to each large constant array I found in the code:
__attribute__((section(".irom.text"))) __attribute__((aligned(4)))
But this was not enough, and so I decided to be a smart-ass and and blindly move everything into the irom.text section.
I did this by modifying the linker script (eagle.app.v6.common.ld), moving these lines:
*(.rodata)
*(.rodata.*)
from .rodata to .irom0.text.
After flashing the device, the boot loader started resetting wildly.
So, I tried to test this approach with a basic blink code which causes the ESP to hang right after the bootloader finishes.
Maybe someone has an idea of why it was bad to put everything into irom? Maybe if the reason is specific pieces of code that can not run from FLASH, I can exclude them, while the rest of the code will run from the FLASH.