2

I'm developing an OS kernel as a hobby and I already have a library that replaces the standard library in both hosted and freestanding environments. Naturally it provides the entry point that does the necessary set up and calls main().

In hosted environment it seems that it doesn't matter if the signatures of the main() declaration and in the actual main() definition doesn't exactly match. However, once I add the -ffreestanding compilation flag, the linker can no longer resolve such reference. See the minimal example below:

start.cpp

int main(int argc, char *argv[], char *envp[]);

extern "C" void _start()
{
    main(0, nullptr, nullptr);
}

main.cpp

int main()
{
    return 0;
}

Command line:

clang++-6.0 -nostdlib -ffreestanding start.cpp main.cpp

It seems that this behavior is specific to Clang since GCC 7.3.0 compiles this example successfully.

My question is how the above example is allowed and working in general and whether the issue I'm experiencing is a Clang bug.


Update 1:

Turned out that the solution to this is to add __attribute__((weak)) to the declaration of main(). However, it would be nice if someone could explain in more detail how does this usually work with main().

Update 2:

Apparently marking main() as a weak symbol makes it possible to link without main() at all which is obviously not how it normally works (given all the other "undefined reference to main" questions on SO). So if main() is not usually a weak symbol how does it really work?

Update 3:

Turns out that a weak symbol is not a solution at all, because when used with -ffreestanding it only hides the fact that the int main(int argc, char *argv[], char *envp[]) is never resolved and the actual int main() is not called from _start() at all. In hosted environment, however it's still called as usual. This seems more and more like a Clang bug.

r3mus n0x
  • 5,954
  • 1
  • 13
  • 34
  • Potential duplicate: https://stackoverflow.com/questions/1990932/two-main-functions-in-c-c – alter_igel Oct 15 '18 at 18:52
  • 1
    @Rabbid76, I don't see how is this a duplicate of the "Two main functions" question and I don't see an answer to my question there either, please clarify. – r3mus n0x Oct 15 '18 at 18:58
  • This is not a duplicate of a linked question, I do not see any connection at all. – SergeyA Oct 15 '18 at 19:00
  • I feel it is CLang issue which doesn't understand the special nature of `main()` in freestanding environment - or, may be, it is by design, that in freestanding env main is not special. – SergeyA Oct 15 '18 at 19:02
  • @SergeyA, so I found the solution to this by adding `__attribute__((weak))` which is only vaguely mentioned in the 3rd answer to the "duplicate" question. – r3mus n0x Oct 15 '18 at 19:08
  • I don't believe the language allows two mains. The `main` symbol is distinguished among symbols and there are some rules about the way it is handled. I think making it a weak symbol with a different signature is playing with fire. I think the proper way to do what you want is to use preprocessor definitions. Regarding your question *"... if main() is not usually a weak symbol how does it really work?"*, see [Is a main() required for a C program?](https://stackoverflow.com/q/4113731/608639) and maybe [Avoiding the main (entry point) in a C program](https://stackoverflow.com/q/3379190/608639). – jww Oct 16 '18 at 01:31
  • Possible duplicate of [What should main() return in C and C++?](https://stackoverflow.com/questions/204476/what-should-main-return-in-c-and-c) – eyllanesc Oct 16 '18 at 04:00
  • @alterigel, this is not a duplicate of "two main functions" because I have only one definition of main. – r3mus n0x Oct 16 '18 at 04:44
  • @jww, obviously using a weak symbol is not a proper solution here. But I don't think that preprocessor would help in this situation either. I'm trying to do what the standard library usually does: declare a main with a most complete signature possible an then the user code can define it with simpler signature. How can a preprocessor directive help the library to "guess" what signature the user will use in his program? – r3mus n0x Oct 16 '18 at 04:49
  • You are changing the parameters of your question: *"How can a preprocessor directive help the library to "guess" what signature the user will use in his program?"*. Why would you care what an arbitrary user is doing when you are building your custom kernel freestanding or not? – jww Oct 16 '18 at 04:52
  • @jww, as I mentioned, I have a library that I use in both hosted and freestanding environments. I suppose I could use preprocessor to "change" the main's signature when building for the kernel, but this is more like a workaround. All I'm trying to do is to make it work the way it does with standard library and my main question is whether it is intended not to work with `-ffreestanding` or is it a compiler bug. – r3mus n0x Oct 16 '18 at 04:58
  • 1
    @eyllanesc, not really a duplicate of "What should main() return" because in my case the difference is the arguments, not the return type. Also I don't see an answer to this particular case there, please explain if you do. – r3mus n0x Oct 16 '18 at 05:01
  • @jww, I don't particularity understand your suggestion about `first_main` and `second_main`, but I don't have two main functions. I only have a declaration in one file and the definition in the other. – r3mus n0x Oct 16 '18 at 10:08
  • @r3musn0x - I gotta admit I'm fairly confused. I don't really get the point of declaring `main` as weak unless it is intended to be overridden on occasion (implying two implementations). I should probably just step out now. – jww Oct 16 '18 at 10:49
  • Very late addition, but I suspect the issue is that `main` is compiled with C++ name mangling (something like `_Z4mainv` for example). Therefore, an `extern "C"` should hopefully fix it. – ayke Apr 25 '22 at 14:31

0 Answers0