News for hackers. Stuff that matters.
Re:What happens before main() is executed in C and why is it... by doomjunky on Friday May 04, 2018 @06:03PM (#16998770)
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("%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.
Re:What happens before main() is executed in C and why is it... by brandmeyer on Friday May 04, 2018 @08:22PM (#16999497)
> 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.

Re:What happens before main() is executed in C and why is it... by saagarjha on Friday May 04, 2018 @07:10PM (#16999172)
Here's what works on my Mac, compiled with clang -m32.

  #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.
Re:What happens before main() is executed in C and why is it... by doomjunky on Saturday May 05, 2018 @12:38AM (#17000356)
On Windows this dependes on the calling convention. The calling convention determines whether function arguments are passed: In order or in reverse order. Who takes care of cleaning the stack: caller or callee? And even if the arguments are passed by stack or CPU registers.

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.

[1]: https://msdn.microsoft.com/en-us/library/984x0h58.aspx

[2]: https://msdn.microsoft.com/en-us/library/46t77ak2.aspx

Re:What happens before main() is executed in C and why is it... by saagarjha on Saturday May 05, 2018 @07:53PM (#17004528)
> Passing arguments via CPU registers has a huge preformance benefit, but also some drawbacks.

Like what?

Re:What happens before main() is executed in C and why is it... by pjmlp on Saturday May 05, 2018 @08:36PM (#17004681)
On architectures like x86, the set of registers is limited and some are special, so there is some contention going on.
Re:What happens before main() is executed in C and why is it... by kbumsik on Friday May 04, 2018 @07:57PM (#16999379)
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... by saagarjha on Friday May 04, 2018 @08:04PM (#16999415)
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... by nitrogen on Saturday May 05, 2018 @01:10PM (#17002657)
Something surprising about C is that an empty argument list doesn't mean "no arguments", it means "unspecified arguments".

https://stackoverflow.com/questions/693788/is-it-better-to-u...

Though that is unlikely to be related to the arguments passed to main.

Re:What happens before main() is executed in C and why is it... by nineteen999 on Sunday May 06, 2018 @06:48PM (#17009073)
The C standard says arguments to main() should be defined as:

  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.

Re:What happens before main() is executed in C and why is it... by JdeBP on Tuesday May 08, 2018 @06:21PM (#17025818)
It actually has a whole other half to the sentence, following the semi-colon.

* http://jdebp.eu./FGA/legality-of-void-main.html

Re:What happens before main() is executed in C and why is it... by nineteen999 on Tuesday May 15, 2018 @02:47AM (#17072112)
I took a detour at the footnote reference, and never came back. Interesting to note, thank you.
Re:What happens before main() is executed in C and why is it... by kbumsik on Friday May 04, 2018 @07:28PM (#16999261)
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... by ronsor on Friday May 04, 2018 @06:29PM (#16998929)
totally unportable and undefined behavior
Re:What happens before main() is executed in C and why is it... by dfox on Friday May 04, 2018 @06:35PM (#16998979)
I have strong feeling that while this obviously works on i386 linux (and probably any unix for that matter) if it works on even amd64 it's just a pure coincidence.
Re:What happens before main() is executed in C and why is it... by colejohnson66 on Saturday May 05, 2018 @09:47AM (#17001765)
It shouldn’t work on amd64 because the x64 calling convention puts the arguments in the registers first