I am checking some terrible C source code; I haven't got any idea about how to maintain it or cooperate with it. But I found a very fundamental problem. It does NOT have a startup.asm; it has a startup.c using the powerful C extension "#pragma". So, the C runtime environment is setup by "#pragma section", "#pragma intvect", "#pragma asm". I quite worry about such a startup.c; so I contacted the FAE of our local distributor. The FAE is an experienced good engineer, but he told me that, this is not their standard way to setup C runtime environment; they definitely provided the startup.s from Day 1.
What will be the side-effect, when the C runtime environment is setup by the C extension "#pragma"?
Yes, the Cortex really are special.
No __irq keywords for interrupt handlers.
A fixed address for storage of information of the stack, so that the processor can initialize an initial stack on its own.
C is well qualified for low-level tasks.
One thing to care about when having strict C code to initialize a processor is that this init() function don't have access to the full C RTL until it has called a init function available with the C RTL - the call we normally see either directly before our main() is called, or the last call in a normal assembler startup file in case the C RTL init function performs the call to main().
Same thing with zeroing memory and assign of initialized data.
But having the init code in C or assembler is really irrelevant to this specific thread. In this case, we are talking about assembler initialization - but assembler instructions in a C file instead of in a separate assembler file.
This is bad modularization. And potentially, there may be part of the initialization in assembler and part in C, and lots of assumptions about compiler-specific requirements.
When talking about an all-C initialization for a Cortex processor, it would normally be the compiler vendor who supplies a complete system with the required helper functionality in the CRTL, and with a sample startup.c file containing the "normal" initialization steps.
'Yes, the Cortex really are special.'
like what?
"In this case, we are talking about assembler initialization - but assembler instructions in a C file instead of in a separate assembler file."
I am not sure if that (inclusion of assembler instructions in a C file) makes a big difference. end of the day, they produce the same result.
I do see a benefit to create a separate assembler file for those assembler instructions if you have tons of them -> essentially create a .asm start-up file.
but if the amount of assembler instructions is small, it probably makes more sense to include them in a .c file.
my point is that it is hard to make an absolute statement about whether it is right (or wrong) to embed assembler instructions in a .c file. it depends on many other factors.
Both of these are major risks to you / your project / your company - I'm not sure which is worse!
To me, the worst case is, people here think that: what John Linq did well is due to those things are simple; And what John Linq failed to do it well, is due to John Linq's fault.
Hope this worst case would not happen. I guess I have to be more positive. Since I don't have choices, and I am being paid to handle this.
Hi Mike,
. As long as the environment is set up properly, it doesn't matter if it's a .s or a .c file.
May I assume that, you have seen several cases, where the C runtime environment is set up properly by "#pragma asm"?
"like what?"
Already covered in previous posts.
"To me, the worst case is, people here think that: ...
Since I don't have choices,"
then no point in worrying about things you have no power to influence.
"but if the amount of assembler instructions is small, it probably makes more sense to include them in a .c file."
That very much depends on used compiler.
Some compilers will remove support for source-level debugging if mixing assembler and C.
Some compilers will merge the compiler-generated assembler instructions with the inlined assembler instructions and then run everything through the optimizer, potentially resulting in an object file containing other instruction sequences than the programmer did write.
So in the general case, C and assembler shouldn't be mixed in the same file. Having assembler in a C file in the first place is outside of the C standard, so any such use should not be considered unless the specific compiler have specific documentation saying both how to do it and clearly documenting limitations or potential problems.
A compiler vendor normally ships sample startup files since there are a number of needs that must be fulfilled to make the C RTL work as expected and make the processor reach main() in a way fulfilling the requirements from the C standard. Not using the compiler-supplied startup file (with optional additions for supporting extra hardware) means that a developer have to take his chances about his own startup code being enough to fulfill all initialization requirements. Compiler vendors often do not write a document listing these requirements for the simple reason that they consider it enough to just ship a startup file.
I avoid to mention the actual platform, because it is a Fujitsu F2MC-16LX MCU. Sorry for that.
Hi Per,
Recently I am quite frustrated. But many thanks for your help, explaining and illustrating.
Also thanks to all the helps/hints, which I got from this Keil discussion forum.
Base on the reading about C51, I suspect that: the [startup.c + other C-files] project creates two C runtime environment setup procedules, one is the startup.c itself, another is the other C-files partially invoke the C runtime library of the Toolchain.
No, I haven't seen it. But I can easily imagine it. Although I do agree that this is an unconventional way of writing startup code. It does raise suspicion.
I am not sure if that (inclusion of assembler instructions in a C file) makes a big difference. end of the day, they produce the same result.<i/>
This is a very generic statement; it can be asserted about programming in C vs. assembly or even almost any other programming language. The bit stream (might) yield the same result, but as mentioned the intricacies of start-up are very different and impose a different discipline. Also, generally speaking inline assembly greatly reduces the freedom of the compiler to apply all soft of optimizations. Will you then get the same result? I don't think so.
Things can get really nasty when one bypasses the default initialization of the C library, and that creates problems with some hardware start-up timing, because of some rare "living on the edge" condition that suddenly becomes relevant...
If you believe it can be set up properly; then it must be true.
The problem is: I can not trust the mentioned third party as I trust you.
Maybe the mentioned third party is trustable, but it doesn't mean that my colleagues would use the startup.c correctly.
Don't you have access to an assembler startup file for the used compiler?
If we ignore potential timing issues, a comparison of that startup file with the code you have should be able to tell if the current code does try to recreate all steps performed by the compiler-supplied startup file.
Next step - if they do mix actual C code during their startup sequence - is to figure out if the calling conventions are correct, and stack etc are already correctly configured before first C function is used.
Next step is to check when the C RTL gets initialized, and if any C RTL functions might have been called before this has happened. Lack of source code for the C RTL means that it will be impossible to know the full set of requirements that needs to be fulfilled for each individual C RTL function.
"The problem is: I can not trust the mentioned third party as I trust you."
the last part of what you wrote is scary.
"Maybe the mentioned third party is trustable, but it doesn't mean that my colleagues would use the startup.c correctly."
sounds like you have trouble trusting your colleagues' capabilities. if that's the case, no amount of help over the internet will get you there.
because it is a Fujitsu F2MC-16LX MCU. Sorry for that.
Yes, you should be sorry for that. For two reasons:
1) You're holding this discussion in entirely the wrong place 2) You're working on an outdated architecture. IIRC, Fuji (rightfully) stopped making new versions of that years ago.
As to the problem in point, I think you should just stop worrying about it. If you really don't believe in that startup code getting the job done properly, compile it to asm and look at what you get. If you're still not convinced, replace the .c file by the generated .asm file and forget about the fact it was ever .C in the first place.
And yes, I have seen a project using exactly that kind of setup on exactly that architecture, and it's working just fine on millions of devices in the field.
I don't know who is Mike Kleshov. But I have read his posts for more than one or two years. My impression on his posts is, "straightforward", "correct", "helpful". My impression on his expertise is, "somehow Mike knows compilers/compiler behaviors very well." Although I don't think Mike is a compiler developer.
Since my colleagues and myself don't know much about compilers/compiler behaviors, C runtime environment setup procedures etc; and I don't know anything about the mentioned third party; it is reasonable to me to believe what Mike told me.