3

I am looking for a way to determine the size (in bytes) of a compiled function.

I did a little research, and on most compilers you can't use sizeof(functionName). I looked at the PE32 headers, and I could only find the address of the entry point listed in there.

When using GCC, I think you could use a linker script, and it seems the info is also contained in the ELF file headers.

However, these solutions only work on Unix. Is there any way to do this in windows? I'm using Visual Studio and was wondering if the linker is capable of such a thing.

Another way to do this would be machinecode analysis (tracking down jmps and ret opcodes; I don't know how reliable this would be), but this seems pretty hard to implement.

EDIT: Several people asked why I want to do this. I do not consider this part of the question, but I want to run some tests with running certain computation-intensive functions on another computer. Nothing more than experimenting, really. I considered it to be a more efficient solution than sending the code and re-compiling every time. (So, maybe the classification as a "XY problem" might be true).

I know that optimization prevents functions to be nice 'blocks' of code, but I think it's possible to avoid this (by using a function pointer or compiler directives: this is how I got the function to be included in the export table when I was trying to extract the function size from the PE data).

Community
  • 1
  • 1
Ruben
  • 524
  • 1
  • 6
  • 14
  • Maybe the Dumpbin utility might be useful? http://support.microsoft.com/kb/177429 . If you can't get the size directly then maybe find consecutive symbols and subtract their offsets. – Adam Mar 20 '14 at 07:03
  • There should be an option for the linker to produce an output map. Then as Adam suggested, you can subtract the offsets between function names to get a function size, but this will include padding used to align functions. Complicating matters is if you build in debug mode, a jump table is created and the function names are associated with entries in the jump table, so this would only work in released mode. Another issue could occur if the compiler optimization "inlined" functions. – rcgldr Mar 20 '14 at 07:07
  • 3
    What are you actually trying to do? Knowing the size of a function isn't generally very meaningful, so I suspect an XY question... – Mats Petersson Mar 20 '14 at 08:20
  • Can you elaborate why do you want to do this? – concept3d Mar 20 '14 at 08:26
  • 2
    This is not generally possible. A strong optimization goal, for both the compiler and the linker, is to make your functions *disappear*. The inlining optimization is implemented by any compiler, removing unused functions is a common linker optimization. You can get the lay of the land by asking the linker to produce a map file, /MAP linker option. It will be incomplete. – Hans Passant Mar 20 '14 at 08:51
  • @MonKeePoo: What you are trying to do (pushing functions from your local machine to a remote machine for execution) won't work, or only under *very* precise preconditions: Global variables, library versions, virtual address mapping, ... -- there is a reason why distributed computing frameworks are so complex, and also why there isn't some list of function sizes available from the toolchain. You're barking up the wrong tree, sorry. – DevSolar Mar 20 '14 at 09:47
  • This was exactly why I didn't include this in the original question. I know what I'm trying to do is not usual. I wanted to send only very simple functions (which, nonetheless, can perform very computationally intensive tasks) that didn't use library functions or global variables. Of course, this would make dynamic memory allocation hard, but there are some ways around this. I put *some* thought into the whole thing (and remember, I'm just trying things). It seems the idea could work on Linux (with ELF headers). – Ruben Mar 20 '14 at 19:58

1 Answers1

1

Use Grouped Sections, so the functions are in the order you want them, and then subtract the function addresses:

#include <stdio.h>
#include <windows.h>

#ifdef _MSC_VER
#define CODE_SEG(seg) __declspec(code_seg(seg))
#else
#define CODE_SEG(seg) __attribute__((section(seg)))
#endif

static CODE_SEG(".text$1") int sum_arr (int *arr, int qty)
{
  int sum = 0;
  int i;
  for (i = 0; i < qty; i++)
    sum += arr[i];
  return sum;
}

static CODE_SEG(".text$2") int multiply (int m1, int m2)
{
  return m1 * m2;
}

CODE_SEG(".text$3") int main( void )
{
  printf ("size of sum_arr(): %u\n",
      (unsigned)((UINT_PTR)&multiply - (UINT_PTR)&sum_arr));
  printf ("size of multiply(): %u\n",
      (unsigned)((UINT_PTR)&main - (UINT_PTR)&multiply));

  return 0;
}

From the Microsoft Portable Executable and Common Object File Format Specification:

Grouped Sections (Object Only)

The “$” character (dollar sign) has a special interpretation in section names in object files.

When determining the image section that will contain the contents of an object section, the linker discards the “$” and all characters that follow it. Thus, an object section named .text$X actually contributes to the .text section in the image.

However, the characters following the “$” determine the ordering of the contributions to the image section. All contributions with the same object-section name are allocated contiguously in the image, and the blocks of contributions are sorted in lexical order by object-section name. Therefore, everything in object files with section name .text$X ends up together, after the .text$W contributions and before the .text$Y contributions.

The section name in an image file never contains a “$” character.

Community
  • 1
  • 1
ssbssa
  • 1,261
  • 1
  • 13
  • 21