The examples given so far have a major bug. The first 8 words in the memory map are reserved for the exception vectors. When an exception occurs the control is transferred to one these 8 locations. The exceptions and their exception vector addresses are show in the following table.
Table 1. Exception Vector Addresses
Exception | Address |
---|---|
Reset |
0x00 |
Undefined Instruction |
0x04 |
Software Interrupt (SWI) |
0x08 |
Prefetch Abort |
0x0C |
Data Abort |
0x10 |
Reserved, not used |
0x14 |
IRQ |
0x18 |
FIQ |
0x1C |
These locations are supposed to contain a branch that will transfer control the appropriate exception handler. In the examples we have seen so far, we haven’t inserted branch instructions at the exception vector addresses. We got away without issues since these exceptions did not occur. All the above programs can be fixed, by linking them with the following assembly code.
.section "vectors"
reset: b start
undef: b undef
swi: b swi
pabt: b pabt
dabt: b dabt
nop
irq: b irq
fiq: b fiq
Only the reset exception is vectored to a different address
start
. All other exceptions are
vectored to the same address. So if any exception other that reset
occurs, the processor will be spinning in the same location. The
exception can then be identified by looking at the value of
pc
through a debugger (the monitor
interface in our case).
To ensure that these instruction are placed at the exception vector addresses, the linker script should look something like below.
SECTIONS {
. = 0x00000000;
.text : {
* (vectors);
* (.text);
...
}
...
}
Notice how the vectors
section is
placed before all other code, ensuring that the vectors
is located at address starting from
0x0.