I'm trying to implement on HCS08 a technique that I use on ColdFire and Kinetis, but I'm hitting a snag with the linker - I need a way to avoid dead stripping of unreferenced constants when the exact object names are not known in advance.
To give a little background, the mechanism I'm implementing is an auto-start list. I have projects with numerous peripheral drivers (typically sensors) and each has an init function that checks for the presence of the associated device and registers callbacks with the main application as needed.
I have an AUTO_START() macro that's called from each driver and creates a struct with a function pointer, priority, and any other required settings, and stores it as a const in a special section. This lets me add and remove peripheral support from multiple projects without changing any of the application code or having to add includes - the main application simply reads through the list in memory and calls each init function in turn.
Creating and placing the const struct is no problem with CW10.6, but the HCS08 linker doesn't seem to have any way to avoid automatic dead stripping short of disabling smart linking entirely, which is a really bad idea with the ANSI C libraries.
On Kinetis KEEP (*(.auto_start)) is sufficient to retain everything in that section. With the ColdFire linker I use REF_INCLUDE {.auto_start}. I don't see any way to do that sort of wildcard with the HCS08 linker. All it provides is the ENTRIES list, and exact names are needed for each object to be retained. The AUTO_START() macro creates each entry with a unique name using token pasting and having to enter each name into ENTRIES would entirely defeat the purpose.
ENTRIES, INIT, and VECTOR seem to be the only starting points for the linker's transitive closure. None of those do me any good. Placing a const at a specified address using @address avoids dead stripping, but that doesn't do me any good when I'm trying to automatically construct a list with more than one item. The @"section" specifier does not prevent dead stripping.
Any ideas?
Scott
HI Erich,
I've used the ROM Library concept before. I've got a USB CDC bootloader I wrote that way for the JM60. That's not quite what I'm going for here, since the modules aren't pre-compiled libraries. In the case of my Kinetis and Coldfire implementations, they're not even using the same platform. Add 'bluetooth.c' to the project and the Bluetooth module is compiled in and automatically initializes at startup and registers any callbacks it needs, whether it's on a JM128 or a K22F.
It's just a mechanism for source code level modularity. It's certainly not a critical feature, particularly when I'm moving away from HCS08 entirely, but it seemed so tantalizingly close that I couldn't resist trying to make it work the way it does on the other platforms.
I could just write a script that scans all of the source files for the AUTO_START macro and constructs a list of function calls to dump into an auto_start.c, but that seems like cheating.
If there's no clever way around the linker issue, I think I'll move on to other things.
Thanks,
Scott
Hi Jennie,
Anything further to add on this, or is it just not going to work? And can you tell me if the HCS08 tools are still being developed?
Thanks,
Scott
Hi Scott,
I think the 'ROM Library' concept is what you are looking for. Search for 'ROM_LIB' in the linker manual (e.g. CW MCU v10.6.4\MCU\Help\PDF\MCU_Build_Tools_Uilities.pdf).
The HCS08 tools in CodeWarrior are still maintained (Maintenance mode), but not developed further.
I hope this helps,
Erich
Hi,
In hcs08, we put the global symbol to ENTRIES section to avoid optimization.
try in prm file, add:
ENTRIES
AUTO_START
END
can it work for you?
if not, can you please feedback with your demo code, I will check the issue directly with it. thanks!
Have a great day,
Jennie Zhang
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi Jennie,
The problem is that the object names (or even the number of objects) can not be known in advance, and ENTRIES does not appear to support anything except individual literal object names.
Here's the relevant header code:
typedef struct {
void (*func)(void);
unsigned char priority;
unsigned char unused[3];
} auto_start_t;
#define AUTO_START(x, y) const auto_start_t _auto_start_func_##x @ "AUTO_START" = {x, y}
And its use in one of the peripheral drivers:
void BMP085_Init(void);
AUTO_START(BMP085_Init, 4);
The desired result is this:
MODULE: -- bmp085_c.obj --
- PROCEDURES:
BMP085_Init 8854 5D 93 2 .text
- VARIABLES:
_auto_start_func_BMP085_Init F840 6 6 0 AUTO_START
For this example I added the _auto_start_func explicitly in the linker ENTRIES section:
ENTRIES
_auto_start_func_BMP085_Init
END
As you can see, if I add the entry manually it works and _auto_start_func_BMP085_Init is added to a list in section AUTO_START. The main application reads each entry in AUTO_START and executes the functions.
The problem is that I can find no way to accomplish this without explicitly adding each init function to the ENTRIES list, and having to do that entirely defeats the purpose of the mechanism. I need either an equivalent to the KEEP (*(.auto_start)) or REF_INCLUDE {.auto_start} commands that will work with the HCS08, a way to selectively disable smart linking, or a way to include a dummy function or other item that references the _auto_start function that will not itself be dead stripped.
Scott
Hi,
If you specify a file name in the ENTRIES block, the linker considers the corresponding file as part of the application. see below snapshot from help manual.
Hope this helps!
Have a great day,
Jennie Zhang
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Yes, but that doesn't actually accomplish what I need to do. The file names aren't known in advance, either. Your method would also eliminate dead stripping of unused functions in what might be a large driver with more functions than the application needs.
For the Kinetis and Coldfire products that I use this technique with, I can add peripheral drivers by simply adding a .c file to the project. If I want to exclude support for certain peripherals in a particular build, I can do that in a makefile or through the build configuration in Eclipse. Without this ability, I have to edit the application and add conditional compilation blocks.
If the compiler supported the __COUNTER__ define I might at least be able to use that to construct a list of function pointers in memory using the @<address> syntax, but the HCS08 compiler doesn't seem to have an equivalent.
I could also implement a workaround as a custom build step with an external script, but last I checked, custom build steps are completely broken in CW10.6 and there's been no word of a fix.
Scott