1

I'm working on MS C++ compiler, and have done the next program:

#include <stdio.h>

void main(void)
{
    void(*ptr)(void) = &main;
}

I wanted to make a pointer on main() method/function, but has got the next error:

error C2440: 'initializing' : cannot convert from 'int (__cdecl *)(void)' to 'void (__cdecl *)(void)'
This conversion requires a reinterpret_cast, a C-style cast or function-style cast

I wonder:

  • how can I get the pointer of function/method main()
  • why by default in output is info about int __decl..., but I have exactly wrote void on main() , not int?
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • 14
    In C++, `main` ***must*** return `int`. And since a C++ program cannot invoke `main` (it's forbidden), I don't see how useful a pointer to it would be (if that's even allowed) – R. Martinho Fernandes Mar 17 '12 at 01:50
  • 1
    Maybe main by default with return integer with the exit code. So have you tried `int(*ptr)(void)`? – Reci Mar 17 '12 at 01:51
  • @r-martinho-fernandes in MS C++ compiler I can define main() as: void main(void) and no error –  Mar 17 '12 at 01:51
  • 2
    @R.MartinhoFernandes: slightly wrong, it must have return type `int`, it doesnt have to actually return something. – smerlin Mar 17 '12 at 01:53
  • 2
    @smerlin: It does always return something. If control falls off the end without encountering a `return` statement, the Standard decrees that it will then return `0`. – Ben Voigt Mar 17 '12 at 01:54
  • 3
    @user1131997: Correct, but [`void main()` is a Microsoft specific extension to the language according to the MSDN docs](http://msdn.microsoft.com/en-us/library/6wd819wh.aspx). It may not work in other C++ compilers. **Write in standard C++ and avoid compiler-specific extensions unless they are absolutely necessary.** – In silico Mar 17 '12 at 01:57
  • @crend-king yeah! thanks! I have made: int main(void) { int(*ptr)(void) = &main; } And got success! In debug mode, I can see pointer to method _main. Intersting, that if in debug try &main, there are some symbols, which I don't know from what have come –  Mar 17 '12 at 01:58
  • 5
    @user1131997: That doesn't change the fact that you shouldn't be doing this at all. Calling main is *illegal* in C++. Even if it just so happens to work, you *should not do it!* – Nicol Bolas Mar 17 '12 at 02:01
  • @nicol-bolas if I try to change the address of current main() method in current running program, what will I catch? –  Mar 17 '12 at 02:06
  • 2
    @user1131997: You can't change the address of a function. I mean, you *can* through a series of casts, but you won't be coding in C++ anymore. The C++ standard sets up a series of rules that you have to follow. If you follow them, you get predictable, well-defined, consistent, cross-platform behavior. What you're trying to do is break those rules. At which point, the behavior you get will not be predictable, well-defined, or consistent (let alone cross-platform). – Nicol Bolas Mar 17 '12 at 02:10
  • 1
    @user1131997: What are you trying to accomplish? If you're just playing around, what are you trying to learn or understand? – Omnifarious Mar 17 '12 at 02:55
  • @Omnifarious trying to change the address of method main() despiting on language standart features –  Mar 17 '12 at 03:21
  • 1
    @user1131997: Why do you want to change the address of the method `main()`? What do you want to accomplish by doing that? – Omnifarious Mar 17 '12 at 03:26
  • @Omnifarious the question was exaclty about "how do it?", not "why" –  Mar 17 '12 at 03:35
  • 2
    @user1131997: Well, the answer is "It can't be done within your program. It is absolutely and completely impossible.". Seriously, it is. You can cause main to appear at a different address, but you have to recompile and relink your program to do it. Its address cannot be changed while your program is running. There may be some platforms on which this is possible, but not very many, and most of them don't have what you might reasonably call an OS. On Windows (and Linux) it is not possible. So, why do you want to do it? That might be possible. – Omnifarious Mar 17 '12 at 03:39
  • @user1131997: I'll put it a different way. Changing the address of `main` in your program would be like changing the value of the number 3 to be something else. It's a constant that's set by the linker at link time. – Omnifarious Mar 17 '12 at 08:53
  • @IntermediateHacker: Whether they're wrong or not, it's generally not a good idea to modify code snippets that appear in people's *questions*. Doing so can hide a problem that needs to be referenced by the answers and fixed by the asker. I rolled back your edit; feel free to leave a comment providing the same advice. – Cody Gray - on strike Mar 17 '12 at 10:35
  • @user1131997: You cannot "change address" of function. Function is a sequence of machine code commands within executable. While executable provides several named entry points for some functions (in dynamic library), for majority of executable there is no concept of "function". Once program is compiled, it is soup of CPU commands. So to change the address of function, you'll have to modify entire executable, find all places where somebody calls routine you want to replace, and insert different address. This is reverse-engineering, and normally program can't change itself while it is running. – SigTerm Mar 17 '12 at 10:51
  • @user1131997: "the question was exaclty about "how do it?", not "why"" If you you asked how to nail your foot to the ceiling with railroad spike, a reasonable person would ask why would you want to do that. Your question about changing address of main isn't very different - there's no reason to ever attempt to do that. – SigTerm Mar 17 '12 at 10:56

2 Answers2

4

Here’s how to obtain a pointer to the main function:

#define DECLARE_UNUSED( name ) (void) name;  struct name

int main()
{
    int(*ptr)() = &main;
    DECLARE_UNUSED( ptr );    // Prevents using `ptr`.
    // Don't use `ptr` here. In particular, don't call.
}

Note that

  • main must have result type int.

  • calling main (e.g. via that pointer) incurs Undefined Behavior.

  • It is not necessary to return anything from main; the default return value is 0.

As you can see main is a very special function.

Those rules do not (in general) apply to other functions.

Also note that Visual C++ is wrong in not diagnosing void result type.

Finally, note that writing non-standard void is one character more to type than standard int, i.e., it is just a very, very dumb thing to do. ;-)

PS: Visual C++ is probably mumbling things about int main because it (probably) translates void main to int main internally, and probably it does that to make things link with a non-intelligent linker while actively supporting void main so that e.g. Microsoft’s own non-standard examples in their documentation will compile. That’s my theory #1 anyway, since you ask. But it is, of course, pure guesswork, and it may be that even those who coded that up have no clear idea of why (theory #2).

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
2

Well, if you really want to change the entry point of an executable, find the Optional Header by following the steps here, offset 16 bytes and change the 4 bytes. You can find the PE specification here. In order to change the executable file itself while running, you will need some assembly trick, or emit another executable, run a batch and kill the running process.

Community
  • 1
  • 1
Reci
  • 4,099
  • 3
  • 37
  • 42