Live data from Hacker News

What happens before main() is executed in C and why is it important?

mymicrocontroller.com

71–80 of 104 posts

Re: What happens before main() is executed in C and why is it important?

#71

To me one curious thing about the main() function without arguments is, these arguments are still pushed onto the stack. You can find them by dereferencing a pointer of another stack variable and playing around with the offset. // 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(…

In embedded system, many manufacturer’s default startup code does not even implement argc/argv. In that case this won’t work, or you need to implement your own startup code.

Re: What happens before main() is executed in C and why is it important?

#73

Is it strange that C++ is able to do this but C itself cannot? Sometimes I hear the argument that "C is lower level" and their is the idiom that "C++ is C but better" (not that I believe these are true)

It's somewhat misleading when they say the C++ code runs before main. What's going on is after the same initialization steps the first code of your program is executed.

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.

Re: What happens before main() is executed in C and why is it important?

#74

Earlier quoted context omitted.

Low latency IO and computational performance isn't always needed.

If it's not, you can drop the cost. There are AVR like 8051s that you can get for 10 cents.

I can't find any 8051 less than 30 cents and I digikey sells attinys for 17 cents.

Re: What happens before main() is executed in C and why is it important?

#75

Is it strange that C++ is able to do this but C itself cannot? Sometimes I hear the argument that "C is lower level" and their is the idiom that "C++ is C but better" (not that I believe these are true)

It is certainly possible to do this with C by editing a startup code. In embedded system, a source code of startup is provided and exposed by manufacturer's SDK so it is quite straightforward to do this.

Besides that, I can't see much difference between doing something before main() and just putting some code on the very top of main().

Re: What happens before main() is executed in C and why is it important?

#76

To me one curious thing about the main() function without arguments is, these arguments are still pushed onto the stack. You can find them by dereferencing a pointer of another stack variable and playing around with the offset. // 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(…

Here's what works on my Mac, compiled with clang -m32. #include 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.

I don't know much about AMD64 but if the arguments are passed to registers then how it is possible to retrieve argc/argv later, as other functions likely to touch registers?

Re: What happens before main() is executed in C and why is it important?

#77
Why not just looking at the source code?

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...

Re: What happens before main() is executed in C and why is it important?

#78
post #76

Earlier quoted context omitted.

Here's what works on my Mac, compiled with clang -m32. #include 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.

I don't know much about AMD64 but if the arguments are passed to registers then how it is possible to retrieve argc/argv later, as other functions likely to touch registers?

They're pushed on to the stack if another function will touch them.

Re: What happens before main() is executed in C and why is it important?

#79

Earlier quoted context omitted.

If it's not, you can drop the cost. There are AVR like 8051s that you can get for 10 cents.

I can't find any 8051 less than 30 cents and I digikey sells attinys for 17 cents.

I haven't confirmed what you've said yet, but it makes sense since 8051/8052 MCUs are generally used for their compatibility with legacy code.

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.

Re: What happens before main() is executed in C and why is it important?

#80

To me one curious thing about the main() function without arguments is, these arguments are still pushed onto the stack. You can find them by dereferencing a pointer of another stack variable and playing around with the offset. // 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(…

> Exclaimer: I don't know how this behaves in an embedded environment.

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.

Post reply on HN