Aha! I’ve managed to setup interrupt vectors table manually, like this:
// NOTE: this must be the first function in the source!
export fn _vectors() void {
    asm volatile ("jmp main");
    asm volatile ("jmp 0");
    asm volatile ("jmp 0");
    asm volatile ("jmp stub");
    asm volatile ("jmp stub");
    asm volatile ("jmp stub");
    asm volatile ("jmp stub");
    asm volatile ("jmp stub");
    asm volatile ("jmp stub");
    asm volatile ("jmp stub");
    asm volatile ("jmp stub");
    asm volatile ("jmp stub");
    asm volatile ("jmp stub");
    asm volatile ("jmp __vector_13");
    asm volatile ("jmp stub");
    asm volatile ("jmp stub");
    asm volatile ("jmp stub");
    asm volatile ("jmp stub");
    asm volatile ("jmp stub");
    asm volatile ("jmp stub");
    asm volatile ("jmp stub");
    asm volatile ("jmp stub");
    asm volatile ("jmp stub");
    asm volatile ("jmp stub");
    asm volatile ("jmp stub");
    asm volatile ("jmp stub");
} 
....
export fn __vector_13() callconv(.Signal) void {
    flipLed();
    avr.tcnt1.* = one_second;
}
I used intblink.zig from here as my starting point. Original version just does not work because of the absence of that jump table.
And now the LED is cheerfully blinking, hooray!