What happens before main() is executed in C and why is it important?
mymicrocontroller.com
mymicrocontroller.com
Most will put this type of code in '.S' startup assembly files, which often also contain information like the memory addresses for hardware interrupts to use, and linker scripts for telling the compiler about the memory available on the chip.
For example, ST's 'CubeF0' package has some example projects for their simpler ARM chips:
http://www.st.com/en/embedded-software/stm32cubef0.html
I think that it is good practice with microcontrollers to tell GCC not to include generic startup logic in order to ensure that you are doing the right thing for your particular chip, by using flags such as --specs=nosys.specs, and even -nostdlib with -lgcc and -lc only if necessary.
My biggest complaint though is that he expresses GPIO cycle time and interrupt latency in cycles, rather than normalized on real time.
Particularly when comparing a STM32F0 to an AVR, the perf looks almost even, until you realize that the STM32F0 is clocked 2.5x faster.
I've been working on an agricultural spray controller that uses some silab part only because there is already assembly code written for it. The company that sells the controller doesn't want to spend the time rewriting it in C and moving to arm or pic.
There's your problem. Digikey is only really meant for low volume.
It's simply that they want to push people to their propietary IDEs (to increase vendor lock in). STM used to provide an okayish libc implementation but then decided to bury it inside CUBE (MX).
If your design becomes complicated enough sure go ahead and change the startup code. But that's quite a small portion of all uses and for those we should have AVR like ease of use.
Edit: spelling
Deviating with a war story now, I once modified some startup code so it self-detected its boot location and initialized the ram data according to this location shift. It was fun, but debugging code you relocated is a pain because you need to somehow relocate the symbols as well.
I also wanted to maintain full functionality even at shifted location in case the self-copy process somehow failed. Never did fail, at least to my knowledge.
Basically I only let children of one class be statically initialized (and enforced this with a tool that goes through the generated binary and type information). These 'subsystem' classes then gets callbacks after all of the static initializers have run which allows them to find the other subsystems they depend on, and then that dependency graph is walked to initialize the full system (the dependency graph has to be a DAG or the system faults). Combined with a code review rule that static initializations only happen in one compilation unit in an anonymous namespace, and nothing else can happen there, means that no one can really touch other subsystems before they've all been initialized, and therefore the order doesn't matter.
I was really happy with how it turned out, despite being completely off the wall compared to how C++ normally works.
embedded systems software in one phrase. :-D
This is such a notorious problem, it even has a name: Static Initialisation Order Fiasco (see: https://isocpp.org/wiki/faq/ctors#static-init-order)
The symmetrical Static Destruction Order Fiasco is also a very fun problem to deal with. The solution proposed for SIOF in the C++ FAQ does nothing to help you deal with this one, though.
Is atexit the post-main hook to which you were referring, or is that just the posix hook into a larger class of post-main hooks?
I attached an example of Arduino Zero varients [1] (it is directly from Atmel's SDK.) It is quite straightforward to see what happends before main(). In embedded system, you can even change it easily if you want.
In this example, the stack pointer is updated at very first point after powering up the device [2]. And the undersocre-prefixed variables are defined in its linker script. [3]
[1]: https://github.com/arduino/ArduinoCore-samd/blob/master/boot...
[2]: https://github.com/arduino/ArduinoCore-samd/blob/master/boot...
[3]: https://github.com/arduino/ArduinoCore-samd/blob/master/boot...
It seems like the rust answer of making it difficult to share mutable state is a solid answer—you explicitly manage concurrent state, rather than implicitly allowing sharing. In addition rust has some interesting run-once constraints you can add to closures that work well with global initialization. I’ll admit I haven’t seen enough rust to see it work well in action, but the pieces are there.
Creating threads in pre-main code is generally a code smell, rather than running pre-main code.
// Just tested with mingw-gcc on Win8.1
// Maybe you need to play around with the offset, +28
int main() {
int i; // Another stack variable
printf("%d\n", (long long)&i + 28); // &argv
printf("%d\n", *((void**)((long long)&i + 28))); // argv
printf("%s\n", ((char**)*((void**)((long long)&i + 28)))[0]); // argv[0]
return 0;
}
Exclaimer: I don't know how this behaves in an embedded environment. #include <stdio.h>
int main() {
int i; // Another stack variable
printf("%s\n", **(char ***)(&i + 8)); // argv[0]
return 0;
}
Of course, this won't work at all on x86_64 because arguments are passed on registers instead of the stack.In Visual Studio you can control this behavoir with the __cdecl, __clrcall, __stdcall, __fastcall, __thiscall, __vectorcall [1] calling convention function prefixes, but this also depends on the optimization options [2] of the compiler.
Passing arguments via CPU registers has a huge preformance benefit, but also some drawbacks.
Like what?
The handful of times I've written startup code for an embedded micro, I've always passed zero arguments to the program's "command line", not even its own program name.
Ie, from the perspective of _start, declare the application's entry point as int main(int argc, char argv), call it with main(0, NULL), and ignore the return value.
ARM passes the first several arguments in registers anyway, so your UB trick wouldn't reveal anything interesting.
https://stackoverflow.com/questions/693788/is-it-better-to-u...
Though that is unlikely to be related to the arguments passed to main.
int main(void)
or int main(int argc, char *argv[])
(or equivalent, eg. int can be replaced by a typedef name
defined as int, or the type of argv can be written as
char ** argv).
From http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf, Section 5.1.2.2.1: Program startup)EDIT: apologies for the atrocious formatting, but it wasn't clear to me how to put two asterisks in a sequence here on HN without preformatted text.
I had a lot of curiosity about how JTAG works and how I can build my own debugger for general targets, but is seems documentation for this is thin. I should look over openocd to see how those guys are doing stuff.
[1] https://community.cypress.com/community/psoc-6/blog/2017/05/...
Sometimes strange bugs manifest due to misalignments between configs at early boot stages and what the later code needs, so you want to be able to review and change those stages.
What he writes is an introduction to bare metal programs for somebody who has worked under an operating system before.
In both cases a lot of code is run before main(). But very different code. In bare metal you more likely need to care what it does. In the operating system case the developers of the OS more likely have done more for you than you will ever need to know about.
https://www.youtube.com/watch?v=yWCMy5EiNkQ https://people.freebsd.org/~brooks/talks/eurobsdcon2016-hell...
I would add that in some (most?) environments, the code that gets executed before main() is easily accessible: it sits in files within the project (written in assembly most of the time).
I've used this as a trick to automatically run unit tests, though, not for any real work.
I link using gcc and -nostdlib plus a very simple start.S:
.globl _start
_start:
call main
movl $1,%eax
xorl %ebx,%ebx
int $0x80
fasm 1.asm;gcc -nostdlib start.S 1.o lib1.a;a.out"lib1.a" contains only the functions needed by a.out instead of, e.g., every function in libc.a
I use ar -M < 1.mri to script changes to lib1.a
(Did I forget about crt0.o?)
movl $1,%eax
int $0x80"main" has been renamed to "xyz".
format ELF
section '.text' executable
public xyz
extrn _exit
extrn write
xyz:
mov eax,len00
push eax
push char00
mov eax,1
push eax
call write
call _exit
section '.data' writeable
char00 db "21 symbols", 0xA
len00 = $ - char00There have historically been some big security holes when parsing XML that it is a security code smell now if you are working with it (especially in lower level languages like C or C++).
C and C++ have different syntax for what that code is, but it's pure semantics as far as the computer is concerned and C++ gives you zero extra power.
Besides that, I can't see much difference between doing something before main() and just putting some code on the very top of main().
var loadTheme: Bool = { Style.loadTheme(); return true; }()
Nit: that’s not the best wording. if the executable is being executed by something like `exec` then these are just “arguments”; the command line (i.e. a shell) isn’t involved. Do embedded systems support something like `exec`?
Seriously-- why is the font greyed out? What possible purpose does this serve?
p{color:#999;line-height:1.4;margin-bottom:.75em}
so paragraph tags, sadly, have the ugly grey font color by default
> * Command line arguments are received. This may not be relevant in embedded systems as in embedded systems we don’t usually call main() with arguments
> * The stack pointer is configured. This is necessary because the program needs to know where to start from. Note that some microcontrollers may require a start.c or cstart file that has the initialization code (whether this file is manually created or auto generated).
> Now that we know what happens before main(), we might wonder if there’s a way we can control what happens before main, or if there is a way we can write our own version of what happens before main(). In C, the answer is largely no. Whatever happens before main() is largely dependent on your architecture and compiler. However this is in fact possible in C++.
> One way you can do this in C++ is by declaring a global class object. Since global variables are initialized before main(), the constructor of the class you have initialized as global will run before main(). You can therefore place the code you want to run before main() in such a constructor.
Certainly looks like it is.
* What happens before main()
* What can you do to make code run before main()
It suggests only the avenue of C++ global constructors to make code run before main() (as others have noted, __attribute__((constructor)) is basically the same thing for C). But there are other ways to make code run before main, such as by use of linker scripts and assembly files to put code in _start that eventually calls main() (note that it's this latter way by which all of the things they mention are done).
It's an absolutely terrible idea, but I've seen engineers be so afraid of asm files that they'd try something like this.
Normally, the 2 places you can't avoid assembly are (1) the startup code (because you're doing things like disabling interrrupts and setting the stack pointer) and (2) interrupt service routines - usually there is a little bit of magic on the front and back ends (for example on an older ARM7 chip, the CPU didn't automatically push / save any registers onto the stack, you had to do it yourself if you needed that).
With the Cortex-M, the CPU design and its microcode took care of all that, so all of the messy assembly stuff went away. Now, as someone who started writing 6502 ASM as a kid, I kind of miss it, but as someone who has to build lots of systems and ship products on deadlines, I like the change.