How can I tell Microchip's XC8 compiler that I am using a custom interrupt handler? It tries to place other code at address 4!
intentry

The solution is called intentry, and is the name of a compiler-generated section. The manual reads:


  intentry – contains the entry code for the interrupt service routine which is linked to the interrupt vector. This code saves the necessary registers and jumps to the main interrupt code in the case of mid-range devices; for enhanced mid-range devices this psect will contain the interrupt function body. This psect must be linked at the interrupt vector.


This does not sound very inviting, and it is not obvious that you can place your own code in that section. However, if you do, the linker is already set up to place it at the right address, and most importantly, it knows that it must not place other code there.

To use it, write your code like this:

; This is the main interrupt handler. It is placed at address 4.
PSECT intentry,class=CODE,delta=2,space=0
    movwf   isr_temp_w
    swapf   STATUS,w
    clrf    STATUS           ; Switch to bank 0
    movwf   isr_temp_status
    ...
    swapf   isr_temp_status,w
    movwf   STATUS
    swapf   isr_temp_w,f
    swapf   isr_temp_w,w
    retfie


Simple! The linker takes care of the rest. With or without the Backup reset condition flags option, the startup code now avoids the custom handler:

I'm not sure this is the right solution, nor that it is the only solution, but it is one solution.