FreeRTOS Vector Table

I’m trying to understand the FreeRTOS port code for the Zynq7’s Cortex A9 processor and have some questions that I could not solve on my own or by googling them:

.extern FreeRTOS_IRQ_Handler
.extern FreeRTOS_SWI_Handler

.section .freertos_vectors
	B	  _boot
	B	  FreeRTOS_Undefined
	ldr   pc, _swi
	B	  FreeRTOS_PrefetchAbortHandler
	B	  FreeRTOS_DataAbortHandler
	NOP	  /* Placeholder for address exception vector*/
	LDR   PC, _irq
	B	  FreeRTOS_FIQHandler

_irq:   .word FreeRTOS_IRQ_Handler
_swi:   .word FreeRTOS_SWI_Handler

Why does the vector table use b (branch) for some entries and for others it loads an address into the PC directly? As far as I can tell, both code do the same, so why not use b for every entry? Has it something to do with storing the caller’s address to the link register?

The FreeRTOS_IRQ_Handler has this code in his first line:

	/* Return to the interrupted instruction. */
	SUB		lr, lr, #4

I don’t get what it does… Apparently the address in the link register is decremented by 4. What’s the effect of this code?


The difference might be because it is not known how far the jump to the FreeRTOS handers is, but I’m not sure.

Ref subtracting 4: The link register holds the return address. When you enter an exception or interrupt the LR holds the return address, and it holds the address of the assembly instruction that follows the instruction being executed when the interrupt was accepted. If the interrupt (actually exception) was entered because you executed something like an SVC/SWI instruction then it is correct to return to the address after that instruction. However if you entered the interrupt because of an asynchronous interrupt you want to return to the instruction that was being executed when the interrupt occurred, rather than the following instruction, so you subtract 4 bytes (the size of the instruction) from the return address to ensure you return to the correct place.

Thanks for your fast reply!

You say that the ldr instruction is preferred over the b instruction as it can reach code that is located further away in memory. But why bother to use the b instruction at all then? Why not always use the ldr method?

Best Regards,

Not actually sure I had that the right way around. LDR should be able to jump further because it’s loading a whole 32-bit address rather than encoding the address in the instruction. Which to use is probably not important if the address jumping to is defined in the same file. Sometimes instruction choice is important for the rtos if you want to ensure no register values change before they are saved.

b is smaller and faster than the ldr used here. The ldr instruction must fetch the 32-bit address as a separate operation, whereas the address is built into the b instruction.

To expand on jefftenney’s answer.

The b instruction just directly places the relative address (which must be close enough) in the instruction.

The ldr instruction instead includes the address of a memory location that holds the full address, so in addition to the ldr instruction in the vector table, there will be another 32 bit value stored in memory some place nearby.

so b, when it works, is smaller. but ldr works in all cases.