How do I get the size of my program at runtime?
Just to warn you, I minimally tested this, but it seems to work.
In the Due's linker script there are these relevant lines, containing the named rom section.
MEMORY
{
    rom (rx)    : ORIGIN = 0x00080000, LENGTH = 0x00080000 /* Flash, 512K */

Below you'll see:
SECTIONS
{
    .text :
    {
        . = ALIGN(4);
        _sfixed = .;

_sfixed is a symbol they've created to mark the current location, which happens to be the start of the rom section in this case, 0x00080000.  At the bettom of the brace matching the one following .text, you'll see:
} &gt; rom

showing that section goes into ROM, which is why . at the beginning of the .text section refers to the rom section start address.
If you look near the last thing placed in rom, you'll see:
    . = ALIGN(4);
    _etext = .;

So, they've set another symbol there, the one of interest, _etext, the address of which should be the byte of ROM not used, or so I thought the first time through this; turns out it isn't.  I gather you have no use for start of ROM symbol, since it's a static value and at the beginning, so I'll ignore that, but if you cared to make use of it it could be done the same way as follows for _etext.
These symbols don't have any type, but you can make them whatever you want.  If you want to perform arithmetic on a pointer that results, it makes sense to use a char type, so:
extern &quot;C&quot; unsigned char _etext;

I thought this was the end of the story, could just take the address of this symbol, but there is more to it.  Following the regular code is this section:
    .relocate : AT (_etext)
    {
        . = ALIGN(4);
        _srelocate = .;
        *(.ramfunc .ramfunc.*);
        *(.data .data.*);
        . = ALIGN(4);
        _erelocate = .;
    } &gt; ram

They're placing code for the banzai (reset) function (and perhaps other things), which goes into ram ultimately, at this location in ROM.  So, presumably in the start code this is copied from the end of the normal program code into some place in ram.
So, there are two more symbols of interest here, _srelocate and _erelocate.  Declarations for them:
extern &quot;C&quot; unsigned char _srelocate;
extern &quot;C&quot; unsigned char _erelocate;

These symbols resolve to addresses in RAM, so they can't be used directly, but can have their addresses subtracted to get the size of the image in ROM that gets relocated to RAM, leading to:
const unsigned char *rom_end = &amp;_etext + (&amp;_erelocate - &amp;_srelocate); 
Serial.print(&quot;The end of used ROM is : 0x&quot;);
Serial.println((uintptr_t)rom_end, HEX);

When I compile and run a simple test like this and check the serial monitor connection, I see output like:
The end of used ROM is : 0x82FF8

If look at the .bin file produced by the compiler:
$ wc --bytes  build/arduino.sam.arduino_due_x_dbg/efixed.ino.bin 
12280 build/arduino.sam.arduino_due_x_dbg/efixed.ino.bin

And 0x82FF8 - 0x80000 == 12280.
When I hex dump flash around this address I can see what looks like it padding out the flash sector with 0x00 bytes before the next unprogrammed flash sector shows as 0xFF.  So you would need to round this up yourself, and if you want be somewhat safer, maybe add some margin.
I don't know how common that configuration in the linker script is.  It's likely that most linker scripts place a symbol there, if they've had some forethought.  But I wouldn't necessarily expect it have the same name.  It's possible they modify it to add more stuff after that symbol.  But for now, for the Due, that would seem to work fine.  It is a bit messy though.