PSoC4 Boot Sequence (Part 4) – Linker trickery with __attribute_((constructor(101)))

Summary

In the previous articles I took you through the first part of the PSoC4 Boot Sequence, then I showed you how the exception vectors got into the flash, lastly I showed you the Start_C() function and how it initializes your program variables.  After that your main() should start, right?  But wait, when does the PSoC get initialized?  Is it magic?  This article answers that question and explains the evil linker trickery __attribute_((constructor(101)) that is used to call the “initialize_psoc()” function.

For many many reasons, one of my heroes is Brian Kernighan.  He just gets “it” and even better, he can explain “it” beautifully.  One of my favorite Kernighan quotes is “Everyone knows that debugging is twice as hard as writing a program in the first place. So if you’re as clever as you can be when you write it, how will you ever debug it?”  Our business is hard, really hard and there is absolutely no call for doing things  that make it harder.  Don’t be deluded, obfuscation is not elegance.

Start_c()

As discussed previously, the Reset() function just calls Start_C() whose role in life is to get the C program initialized (the previous article).  Then it calls the function “__libc_init_array” (line 346) and finally it calls main (line 347).  The first time I saw this I thought, wow that is simple.  Then I started wondering, how and when does PSoC become PSoC?  When I look around in the Cm0Start.c file I see a function called “initialize_psoc” (which I will talk about in the next article).  But, there does not appear to be a call to “initialize_psoc()”.  Did I miss it?  Is it even run?

Debugging to initialize_psoc()

To answer the question, “where is initialize_psoc()” called, I put a breakpoint at that function.  When I run the debugger, you can see that it stops at the right place, and you can see in the call stack that the function is called by the function “__libc_init_array()”.  This is the point where things started to get really difficult in my life.

initialize_psoc function

__libc_init_array()

What in the world is this “__libc_init_array()”.  If you look in “Cm0Start.c” on line 219 you will see this block of code.  That means it is somewhere in some library (and not in this file).

My first thought was that it had something to do with initializing variables, but I realized that we had already done that.  So, what does it do? And how in the world does it call “initialize_psoc()” and where does it come from?  I started the search by right clicking on it and having PSoC Creator take me to the definition.  But, no luck, for some reason we didn’t include the source code for that function.  So, what does the function do?

Well, start by running the debugger and placing a breakpoint at “__libc_init_array”.  When you do that, you can look at the assembly language.  This is the place that I ended up spending a bunch of time as I had never written ARM assembly, and in fact the last time that I wrote any material amount of assembly was at Georgia Tech 26 years ago.

As I often do, I started by reading a few books and a Cypress application note.  Then I spent a few days writing simple C, compiling it, and looking at the results.  Specifically

Finally I was ready to dig back into this crazy code.  This function has three sections:

  • 0x0620 –> 0x0x0630 is a loop that loads an array of function pointers, then makes the function call to each one (line 0x0636)
  • 0x063c is a call to a function called “_init” (which I don’t know what it does)
  • 0x0640 –> 0x0x0658 is a loop that loads an array of function pointers, then makes the call to each one (line 0x0654)

What all of this means is that there are two arrays of function pointers.  The first array starts a 0x06e4 and ends at 0x6e4 (in other words it is empty).  The second array starts at 0x06e4 and ends at 0x06ec which means there are two function pointers.

When I look at the memory location 0x06e4 –> 0x06ec you see that there are two address 0x0129 and 0x01bc. (look at the memory window in the picture below).  When I scroll the assembly window to location 0x01bc, look what I find, “initialize_psoc”.

PSoC4 Boot Sequence - initialize_psoc

After all of that, I did what I probably should have done originally.  I googled “__libc_init_array source”.  One of the first few google hits was a link to the source code from CodeSourcery.  And it is indeed what I said it was:

  • A loop (lines 32-34) with function pointer calls
  • A call to “_init” (line 36)
  • Another loop (lines 38-40) with function pointer calls

Now I need to figure out how the address of the function “initialize_psoc” got into the memory in the table.

__attribute_((constructor(101)))

In the function “_libc_init_array” (above) it iterates through all of the function pointers that are in the array that starts at “__init_array_start” and ends at “__init_array_end”.  If you look at the linker script you will see that it puts the address of every function that is in the section ending with “.init_array.*”  That is cool but how does “intialize_psoc” get in that section?

Well… if you look at the “initialize_psoc” function in Cm0Start.c you see a bunch of compiler garbly-gook.  It says if you are using the GNU compiler that you should add the attribute “constructor(101)” to the function.

But what does the “constructor” attribute do?  The answer to that can be found in the ARM Information Center.  Basically it says that it will call all functions with that attribute before main in the order of the attribute value (in this case 101).  The compiler achieves this objective by putting the function in the “.init_array” section.  Then the linker does its magic.

As I said earlier in this post I am really not a fan.  There is absolutely no reason why we should not have just called “initialize_psoc” right before we call “main”.   This would have greatly simplified this file as there must be a similar trick going on with IAR and MDK (but I am not going to go figure it out).  In addition hardcoding that 101 means that someone else might slam into it unexpectedly.

Oh well.  In the next article I will talk about what initialize_psoc actually does.

Article Description
PSoC4 Boot Sequence (Part 1) - Debugging to the Reset Vector An introduction to the PSoC4 Boot Sequence
PSoC4 Boot Sequence (Part 2) - Creating the Exception Table using the Linker Building the exception vector table
PSoC4 Boot Sequence (Part 3) - Preinitializing Variables before main() Initializing BSS and Data
PSoC4 Boot Sequence (Part 4) - Linker trickery with __attribute_((constructor(101))) Running initialize_psoc()
PSoC4 Boot Sequence (Part 5) - Initialize PSoC