3

I'm trying to get address of main() function in this way:

int main(int argc, char *argv[])
{
   void *pMainAddress=(void *)&main;
   printf("Address of main() 0x%08X \n", pMainAddress);

When I build project using Release configuration, the result is:
Address of main() : 0x00401000

This is under debugger:

00401000  /$  68 00104000  PUSH GetMain.00401000    ;  Entry address
00401005  |.  68 50A14000  PUSH GetMain.0040A150    ;  ASCII "0x%p \n"
0040100A  |.  E8 8B000000  CALL GetMain.0040109A

But when compiling with /Zi option, or use Debug build, address is redirected:
Address of main() : 0x0041178A. This address is obtained by performing an unconditional jump, the actual address is 0x00412530

This is under debugger:

00412530  /> \55                      PUSH EBP
...
00412539  |.  C745 FC 8A174100        MOV [LOCAL.1],GetMain.0041178A  ;  Entry address
00412540  |.  8B45 FC                 MOV EAX,[LOCAL.1]
00412543  |.  50                      PUSH EAX                                                         
00412544  |.  68 5CEC4200             PUSH GetMain.0042EC5C           ;  ASCII "0x%p \n"

Why this hapenes ?
How to get the real address of main() function (0x00412530 in above example) if code is compiled in Debug build ?

Edit:
Why this happens ? is already answered here: strange level of indirection of a function call

Function below solve my second question, Here I wrote answer .

void *GetMainAddress(void)
{
    void *pMainAddress=(void*)&main;/* address in main() function */
    unsigned long calculateJump=0;
    unsigned char *ptrJump;   
    printf("Address of main() : 0x%08X\n",  pMainAddress);


    ptrJump=(unsigned char*)pMainAddress;/* get pointer to main address */
    if(*(unsigned char*)ptrJump == 0xE9)/* address point to jmp opcode ? */
    {
        calculateJump = ( *(unsigned long *)(ptrJump+1) ); /* get address after 0xe9 */
        pMainAddress =  ptrJump + calculateJump + 5; /* calculate real address */
        printf("Unconditional jump is performed\n");
        printf("Actual sddress of main() is: 0x%08X \n", pMainAddress);
    }
    else
    {
        printf("Unconditional jump is not performed\n");
    }
    return   pMainAddress;
}  
Community
  • 1
  • 1
boleto
  • 1,149
  • 1
  • 22
  • 32
  • possible duplicate of [strange level of indirection of a function call](http://stackoverflow.com/questions/7221855/strange-level-of-indirection-of-a-function-call) – Hans Passant Jul 11 '13 at 00:39
  • I think it is worth mentioning that in C++, unlike C, `main()` cannot be called recursively and cannot have its address taken. Be careful if mixing C and C++ code or compiler (although there are tons of other differences so mixing is no good anyway). –  Aug 07 '13 at 01:48
  • @VladLazarenko Lazarenko You're right, but in my case I do not call `main()`, only take the pointer to its address. When code is compiled with `/ZI`, `pMainAddress` is a pointer to a jump opcode, otherwise (*Release Build*) - it is the actual address of `main()` Also, I tested it before posting and it working in both language C and C++. – boleto Aug 07 '13 at 03:56

2 Answers2

3

Just omit the parentheses if you need to get a function address.

For example:

int main(){
    printf("main is at %p\n", main);
    return 0;
}
Acsor
  • 1,011
  • 2
  • 13
  • 26
  • 2
    Strictly speaking you shouldn't be using `%p` to print a function pointer. – Carl Norum Jul 10 '13 at 23:38
  • Why not? It doesn't seem it makes any difference between %p and %x. – Acsor Jul 10 '13 at 23:40
  • 4
    It's undefined behaviour. It almost certainly works on any reasonable machine, though. Relevant reading: http://stackoverflow.com/questions/2741683/how-to-format-a-function-pointer – Carl Norum Jul 10 '13 at 23:41
  • 1
    According to the C standard, function pointers do not have to be compatible with any object pointer type (including `void *`), so `void *pMainAddress=&main;` would be undefined behavior. POSIX.1, however, mandates that conversion of a function pointer to/from `void *` must work correctly. **Note, however**, that if you're trying to pass a function pointer to something like [`printf()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html), however, you **must** cast the pointer to `void *`. – This isn't my real name Jul 11 '13 at 00:29
  • 3
    The reason you should be using `%p` instead of `%x` when printing a pointer is that the `%p` conversion specifier is explicitly provided for the purpose of printing pointers, whereas `%x` is intended for the printing of `unsigned int` objects. On a 64-bit system there's every chance that a pointer will be twice as large as an `unsigned int` object, and this results in Undefined Behavior, because you'll be passing a 64-bit object to a variadic function that's only expecting 32 bits. (While UB really does mean "no guarantees", one likely result is that you'll only be printing half the pointer.) – This isn't my real name Jul 11 '13 at 00:35
  • @boleto, that's what I said. – Acsor Jul 11 '13 at 00:44
1

This is a solution how to get the actual address of main() function when Debug Information Format is set to /ZI in the project configuration on Visual Studio.
Here is my function :

void *GetMainAddress(void)
{
    void* pMainAddress = (void*)&main;
    unsigned long calculateJump = 0;
    unsigned char* ptrJump;

    ptrJump = (unsigned char*)pMainAddress;
    if(*(unsigned char*)ptrJump == 0xE9)
    {
        calculateJump = (*(unsigned long*)(ptrJump + 1));
        pMainAddress = (ptrJump + calculateJump + 5);
        printf("Unconditional jump is performed\n");
        printf("Address of main() : %#x \n", pMainAddress);
    }
    else
    {
        printf("Unconditional jump is not performed\n");
        printf("Address of main() : %#x \n", pMainAddress);     
    }
    return   pMainAddress;
}

To test, use Visual Studio to create Console Applications and choose either Debug or Release from the Solution Configurations.
Place the GetAddressOfMain() in your int main(), and build solution .

Function also works with 64-bit project configuration, but you need to use an appropriate format specifier to print the addresses correctly .

boleto
  • 1,149
  • 1
  • 22
  • 32