Exceptional Code

A strange thing happened on the way to my last blog post - I was interrupted. Interrupts are pretty common when working with embedded systems, but this was something that I’d never seen before. This was an interrupt for my own good, supposedly.

A Programmer Walks Into A Bar - OUCH!

While I was doing research for my DMA post, I tried to move all of the Flash memory in my processor into a peripheral to calculate the Flash checksum. I’m using an ARM processor which locates a bunch of information so that it starts at address 0: the start address, initial stack pointer, and interrupt vector tables.

When I ran it, my program didn’t iterate through Flash: it generated an exception (a high priority interrupt generated by the processor to indicate that something really bad happened) very soon after it started.

The code looked like this:

#define START_OF_FLASH 0x00000000U /* Start address of the code FLASH */
#define FLASH_SIZE 262144

uint32_t* flashPointer;
uint32_t i;

flashPointer = (uint32_t*) START_OF_FLASH;
for (i = 0U; i < FLASH_SIZE; i++) {
   CRC->DR = *flashPointer++;
}

Pretty straightforward stuff, just iterate from location 0, through to the top of Flash, moving 32-bit chunks into the CRC peripheral’s data register. But, instead, the program immediately threw an IBUSERR exception.

I’m using a recent version of the GCC C compiler and I use it with all warnings turned on. There were no errors or warnings being reported.

I figured that there must be some sort of memory protection happening around location 0. I wasn’t surprised since this is code space, and the memory protection unit might mark this area as execute only. I checked the documentation but, no, that isn’t correct.

This processor has a built in bootloader and, depending on the voltage on a pin at boot time, will either put your code or the bootloader at location 0. Perhaps reading location 0 is illegal because location 0 doesn’t actually exist, it’s just a figment of the architecture. Checking around I discovered that - no - that theory wasn’t correct either.

I must go deeper so look what we get when C generates the assembly code:

08001a9c: movs r3, #0
08001a9e: ldr r3, [r3, #0]
08001aa0: udf #255 ; 0xff

The first instruction shows that we will be using general purpose register 3 as a pointer to our source data. Register 3 is initialized to 0. This would be the code generated from the command:

flashPointer = (uint32_t*) START_OF_FLASH;

The second instruction loads into register 3, the data pointed at by register 3 plus a displacement of 0. I stepped through that instruction and register 3 did get loaded with the data stored at location 0.

I would expect that the next instruction would store the content of register 3 into the CRC peripheral, but instead we have:

udf #255 ; 0xff

I didn’t recognize this instruction, and when I stepped through it, my program immediately jumped to the interrupt handler. What is UDF? I had to search the internet for this one: UDF is the permanently undefined instruction instruction. It intentionally generates an undefined instruction exception.

But Why?

One of the things that C does for you, when your program begins, is it zeros out all of your RAM memory. If you have a pointer that doesn’t get set to a reasonable value, it will probably have the value 0. What C is doing is protecting us from using an uninitialized pointer.

When the compiler analyzed the code, it saw that the pointer had been set to 0. Even though 0 is a reasonable value for our code, it is unlikely to be correct because reading location 0 is not that common.

So putting in the code to halt my program isn’t a bad choice, but the compiler should have generated a message, warning that I was dereferencing a null pointer.

On The Other Hand

Using my black belt google-fu, I found that there is a compiler command line option that turns off the generation of the UDF command:

-fno-delete-null-pointer-checks

So we can get around the issue, but a better idea would be to have a warning generated when the UDF instruction is inserted.

This would be a really annoying, hard to find bug for most people. Elecia remembered an article that describes the exception handler system on ARM Cortex-M processors and has code to walk through the registers to tell you what happened. I’ll have to use this in my next project.


This post is part of a series. Please see the other posts here.


Music to program by - King Sunny Ade, Juju Music

The German Shorthaired Pointer. Get it? Pointer? Get it? &nbsp;I'll see myself out.By Bonnie van den Born, http://www.bonfoto.nl - Transferred from nl.wikipedia to Commons., CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=1745399

The German Shorthaired Pointer. Get it? Pointer? Get it?  I'll see myself out.

By Bonnie van den Born, http://www.bonfoto.nl - Transferred from nl.wikipedia to Commons., CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=1745399