0

I need the location of a code section in the executable (begin and ebn address). I tried to use two dummy functions:

void begin_address(){}
void f(){
    ...
}
void end_address(){}

...

printf("Function length: %td\n", (intptr_t)end_address - (intptr_t)begin_address);

The problem is, that using -O4 optimization with gcc I got a negative length. It seems that this does not work with optimizations.

I compiled f to assembly, and tried the following:

__asm__(
"func_begin:"
"movq $10, %rax;"
"movq $20, %rbx;"
"addq %rbx, %rax;"
"func_end:"
);

extern unsigned char* func_begin;
extern unsigned char* func_end;

int main(){
    printf("Function begin and end address: %p\t%p\n", func_begin, func_end);
    printf("Function length: %td\n", (intptr_t)func_end - (intptr_t)func_begin);
}

The problem is that even without optimization I am getting some strange output:

Function begin and end address: 0x480000000ac0c748  0xf5158b48e5894855
Function length: -5974716185612615411

How can I get the location of a function in the executable? My second question is whether referring to this address as const char* is safe or not. I am interested in both 32 and 64 bit solutions if there is a difference.

robert
  • 3,539
  • 3
  • 35
  • 56
  • 2
    In the second example you want to use `&func_begin` (the address of func_begin) not `func_begin` (its value). – user253751 Dec 02 '15 at 09:51
  • I'm surprised you didn't get zero for the first method. gcc will optimize identical functions to share a definition (both symbols refer to the same address). Both the functions are empty, so should compile to just a `ret`. You should try it on http://gcc.godbolt.org/ to see what comes out of the compiler (with nice highlighting and formatting). – Peter Cordes Dec 02 '15 at 12:27

3 Answers3

1

If you want to see how many bytes a function occupy in a binary, you can use objdump to disassemble the binary to see the first ip and last ip of a function. Or you can print $ebp - $esp if you want to know how many space a function use on stack.

Marvin Wang
  • 197
  • 9
0

If a viable option for you, tell gcc to compile the needed parts with -O0 instead:

#include <stdio.h>
#include <stdint.h>

void __attribute__((optimize("O0"))) func_begin(){}
void __attribute__((optimize("O0"))) f(){
    return;
}
void __attribute__((optimize("O0"))) func_end(){}

int main()
{
    printf("Function begin and end address: %p\t%p\n", func_begin, func_end);
    printf("Function length: %td\n", (uintptr_t)func_end - (uintptr_t)func_begin);
}

I'm not sure whether __attribute__((optimize("O0"))) is needed for f().

ljrk
  • 751
  • 1
  • 5
  • 21
0

I don't know about GCC, but in the case of some Microsoft compilers, or some versions of Visual Studio, if you build in debug mode, it creates a jump table for function entries that then jump to the actual function. In release mode, it normally doesn't use the jump table.

I thought most linker's have a map output option what would at least show the offsets to functions.

You could use an asm instruction that you could search for:

        movel   $12345678,eax     ;search for this instruction

This worked with Microsoft C / C++ 4.1, VS2005, and VS2010 release builds:

#include <stdio.h>

void swap(char **a, char **b){
    char *temp = *a;
    *a = *b;
    *b = temp;
}

void sortLine(char *a[], int size){
    int i, j;
    for (i = 0; i < size; i++){
        for (j = i + 1; j < size; j++){
            if(memcmp(a[i], a[j], 80) > 0){
                swap(&a[i], &a[j]);
            }
        }
    }
}

int main(int argc, char **argv)
{
void (*pswap)(char **a, char **b) = swap;
void (*psortLine)(char *a[], int size) = sortLine;
char *pfun1 = (void *) pswap;
char *pfun2 = (void *) psortLine;

    printf("%p %p %x\n", pfun1, pfun2, pfun2-pfun1);

    return(0);
}
rcgldr
  • 27,407
  • 3
  • 36
  • 61