AVR Bootloader write: How to write a bootloader page address and execute SPM instruction in C code
Here's a way to do it in GCC using asm().  The rest of the bootloader was in C except for enabling and disabling interrupts.

while (NVM_STATUS &amp; NVM_NVMBUSY_bm) ;
NVM_CMD = NVM_CMD_LOAD_FLASH_BUFFER_gc;

// load bytes into page buffer
p = flash_RAM_buffer;

for(ix = 0; ix &lt; 512; ix+=2) {
    asm("ld r0, %a0+":: "z" (p) : "r0");
    asm("ld r1, Z"::: "r1");    // load R0:R1 from flash_RAM_buffer
    asm("movw r30, %0":: "w" (ix) : "r30","r31");   // load Z with ix;
    asm("spm"::);               // not change protected
    asm("clr r1"::);
    p += 2;
    }

asm("ldi r30, 0" ::: "r30");        // low byte of flash address (ignored)
asm("mov r31, %0" :: "r" (curr_flash_address.uval8.ML) : "r31");
asm("out __RAMPZ__, %0" :: "r" (curr_flash_address.uval8.MH));

NVM_CMD = NVM_CMD_ERASE_WRITE_APP_PAGE_gc;
asm("cli"::);
CPU_CCP = CCP_SPM_gc;    // set change control register to enable
asm("spm"::);
asm("clr r1"::: "r1");
asm("sei"::);


curr_flash_address is a union that allows accessing it as 32, 16 or 8 bit variable.