Code download issue

Our code ran fine when deploying in RAM (i.e Run Kernel Task…). When we decided to deploy the code to the flash disk (i.e. FIRST download), it downloaded fine but after rebooting the robot, the console spits out tons of:

  • Loading StartupDlls: FRC_UserProgram
    Relocation value does not fit in 24 bits.
    Relocation value does not fit in 24 bits.

    Relocation value does not fit in 24 bits.
    Relocation value does not fit in 24 bits.
    …FRC_UserProgram failed to load.
    task 0x230ad70 (t2) deleted: errno=0 (0) status=0 (0)

It failed to load our code and the driver station is showing no code. Does anybody know what “Relocation value does not fit in 24 bits.” mean? It sounded like it is complaining the program is big or something. 24-bit is 16MB so it is inconceivable that cRIO is running out of memory. It must mean something else but I don’t know what. Any pointers? It’s very painful not to be able to deploy the code to the flash disk and have to keep downloading to RAM. BTW, in case you asked, we have all the latest updates (Workbench update 4.3 dated 2/17/2010, cRIO image v20 with Labview update 2.1, DS update 1.1).

Thanks.

A search for that string yields a helpful thread.

I read the thread and tried doing the -mlongcall. That works although I am still curious why 24-bit is not enough for the relocation value. 24-bit is 16MB. My program is certainly nowhere close to 16MB. BTW, the thread also suggested that it was an update mismatch issue. I spent 2 hours uninstalling everything, reinstalling WindRiver and LabView, then applying only the latest update to it. And the problem still exists. So it wasn’t an update mismatch unless the latest update is broken.
Thanks for the tips.

Your program is not a self-sufficient entity – it calls many library functions.
Those library functions may be loaded into memory more than ±16M away from the call to them.

BTW, the thread also suggested that it was an update mismatch issue. I spent 2 hours uninstalling everything, reinstalling WindRiver and LabView, then applying only the latest update to it. And the problem still exists. So it wasn’t an update mismatch unless the latest update is broken.
Thanks for the tips.

When I wrote that 24-bit relocation problems seemed to be a clear indication of install/update errors, it was after following dozens of threads that ended up supporting that conclusion. YMMV.

Yes, the 24-bit thing is a side effect of the memory architecture of the PPC processor in the cRIO. It turns out that the goal of the PPC was to execute almost all calls in 1 clock cycle. The fast local branch call executes in one cycle. But, in order to do that, the chip designers had to limit the distance of the branch. Hence, the fast local branch instruction is not 32-bit capable which is the reason for the -mlong-calls option in the C++ compiler. The -mlong-calls uses a 32-bit branch instruction that is relative to the contents of a special-purpose register on the PPC. The 32-bit capable call takes additional instruction execution time that isn’t required for the fast local branch instruction. This is not a big deal for FIRST, but it does cause problems for some mission-critical uses of non-64 bit PPC processors.

The PPC is actually a very odd duck in that it uses the IBM RISC System-6000 instruction set, Motorola 88K cache & MMU and the limitations on memory that Apple had back 20 years ago when those companies got together (called the Apple-IBM-Motorola (AIM) alliance) to create the PowerPC. In the early 90’s, having more than 16 MBs of RAM was unthinkable due to cost. So, they made some design decisions that made sense at the time but have come back to haunt us many years later.

The “Run as kernel task” option in Workbench loads your code into a special Wind Debug Agent (WDB) pool of memory located just above the O/S in low memory. However, then you deploy the code to the cRIO, your application can be loaded into high memory at the discretion of the loader (it uses a best-fit memory model). Therefore, when you run from Workbench, things will work fine. But, when you deploy the code, you’re too far away for the fast local branch instruction of the PPC processor. So as George pointed out, use the -mlong-calls option to the compiler and you should be fine.

HTH,

Mike

Thanks for the info. It makes sense now. So this is similar to the Intel x86 processor with respect to short and long jumps. And the problem is not within our code but between our code and the OS code that the distance could be beyond 16MB? It is still strange that I am imagining between our code and the OS/library code, it should only have CALLs instead of BRANCH instructions but then I am not familiar with PPC. Untill CALLs can also have 24-bit limitations. I am surprise that not more people hit this. We must be the lucky ones that the loader decided to load a lot higher than other people.

Thanks again for the explanation.

There’s 64M RAM in the cRio, making that likely.

It is still strange that I am imagining between our code and the OS/library code, it should only have CALLs instead of BRANCH instructions but then I am not familiar with PPC.

PPC doesn’t have a CALL instruction, only branches.
Function calls are implemented by a special branch instruction that saves the address of the next instruction in an internal register before branching. Without -mlongcall, the offset of the branch target must fit in the 24-bit offset field of the 32-bit branch opcode – as a signed value.

I am surprise that not more people hit this. We must be the lucky ones that the loader decided to load a lot higher than other people.

No, plenty of people stumbled over it. Empirically, it seemed (and still does) that everyone who was bitten by it had failed to apply all updates to Workbench and/or LabView.

Yes, you’ve got the right basic idea. It’s simply an issue of the distance between your code and the O/S or libraries that you’re calling. Because VxWorks 6.x uses a best-fit memory allocation scheme, the size of your code will be compared to the free memory regions (in a VxWorks console shell, issue “memShow(1)” to see the gory details) and your code will be placed in the memory area where it fits with the least amount of memory fragmentation. So, if your code was smaller in size, this problem may not have surfaced for quite some time (like the finals in Atlanta ;-).

Good luck,

Mike A.