Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2012-01

estimating function code size

9 messages · 8 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Gennadiy Poryev

Hi all,

In my project (win32) I need to estimate the number of machine code bytes of a certain function. The most straightforward option was to look for $c3 which is ret, and it worked on optimization levels O0 and O1. O2 and O3 seem to prefer $c2 $04 $00 (retn 4) instead. Then here comes win64, where the function end is marked by $c3 (ret) regardless of optimization level. And it turned out the opcode for mov eax,ebx also has $c3 in it. For now, I use O3 level and patterns $c2 $04 $00 and $5d c3 00 (pop rbp, ret) for win32 and win64 respectively, in hope that the function is always geting padded to (but not equal to) nearest $20 in size. This is far from deploying a full-fledged disassembler but is still not simple and elegant solution. I remember back in TP days there were methods for this, by using labels and addressing them with absolute keyword to obtain offset delta. I wonder if some similar trick can be used here, or if there are some built-in function to do just that? Thanks in advance.

// Gennadiy

Reply by email

Gennadiy Poryev
to Michael Schnell
Do you think it's granted that there is only one return in a function ? Maybe optimization or "exit" could create additional returns

Actually I do. Because I write this function :)
It uses quite a lot of loops and ifs, but no exits. And what I need is a reliable way to get its code size at runtime without manually inspecting it on every rebuild.

Reply by email

Žilvinas Ledas
to Gennadiy Poryev
Gennadiy Poryev wrote 5 lines
> Do you think it's granted that there is only one return in a function ? > Maybe optimization or "exit" could create additional returns Actually I do. Because I write this function :) It uses quite a lot of loops and ifs, but no exits. And what I need is a reliable way to get its code size at runtime without manually inspecting it on every rebuild.

I had similar problem a year and a half ago. I ended up looking for "ret" using disassembler.

Regarding one ret per function, I got this response from Jonas at that time:

Jonas Maebe wrote 12 lines
On 18 Jul 2010, at 13:14, Žilvinas Ledas wrote: > I want to use it this way: > 1) Gel all @unitname.function addresses. > 2) Use disassembler to find nearest next RET. > 3) Then I assume that I have start and end of the function in the binary file. > > It works at least for the concept-showing app with some functions and enabled optimizations when compiling. Do I have some conceptual flaw? Yes: there is no guarantee that a function will contain only one "ret" (it is that way currently for compiler-generated code, but that can change at any time). Jonas

Reply by email

Thomas Schatzl
to Žilvinas Ledas

Hi,

Žilvinas Ledas wrote 6 lines
On 2012-01-18 15:08, Gennadiy Poryev wrote: >> Do you think it's granted that there is only one return in a function ? >> Maybe optimization or "exit" could create additional returns > Actually I do. Because I write this function :) > It uses quite a lot of loops and ifs, but no exits. > And what I need is a reliable way to get its code size at runtime without manually inspecting it on every rebuild.

try this:

{$CODEALIGN PROC=1} // force code alignment on 1 byte boundaries
var
  size : ptruint;

procedure findmysize;
label

  StartFindMySize, EndFindMySize; // actually things should work with

local labels too
begin
asm
call StartFindMySize
StartFindMySize:
popq %rax
movq %rax, size

  end;
  writeln('calculating size');
  asm
    call EndFindMySize

EndFindMySize:
popq %rax
subq size, %rax
movq %rax, size

  end;

end;

procedure findmysize_dummy;
begin
end;
begin
  findmysize;
  writeln(ptruint(@findmysize_dummy) - ptruint(@findmysize), ' ', size);
end.

It shows two ways of doing this, with different disadvantages. The first type is using assembler and calculating the range of addresses between two labels. This has the disadvantages that it is platform dependent (shwoing x64 code here, I'm sure you could make it more "optimized"), and only calculates the distance between the two labels, i.e. without entry and exit code. It is also always off by 5 bytes (single "call + <address>").

The other way is relying on the dodgy assumption that nobody changes the order of functions in the object file or during loading or linking. This is usually the case. It may not be completely safe, i.e. only work on particular platforms etc., but usually it should be okay in the absence of compiler options like e.g. smartlinking.
Further that while it includes method entry and exit code, it may not be completely accurate due to the compiler aligning code

You may want to check the returned sizes by dumping the memory containing the code using a debugger and choose the one which is more suitable for you.

Thomas

Reply by email

Marco van de Voort
to Gennadiy Poryev: In my project (win32) I need to estimate the number of machine code bytes of a certain…

In our previous episode, Gennadiy Poryev said:

Show quoted text 8 lines
In my project (win32) I need to estimate the number of machine code bytes of a certain function. The most straightforward option was to look for $c3 which is ret, and it worked on optimization levels O0 and O1. O2 and O3 seem to prefer $c2 $04 $00 (retn 4) instead. Then here comes win64, where the function end is marked by $c3 (ret) regardless of optimization level. And it turned out the opcode for mov eax,ebx also has $c3 in it. For now, I use O3 level and patterns $c2 $04 $00 and $5d c3 00 (pop rbp, ret) for win32 and win64 respectively, in hope that the function is always geting padded to (but not equal to) nearest $20 in size. This is far from deploying a full-fledged disassembler but is still not simple and elegant solution. I remember back in TP days there were methods for this, by using labels and addressing them with absolute keyword to obtain offset delta. I wonder if some similar trick can be used here, or if there are some built-in function to do just that?

I can't think of a foolproof trick other then compiling to assembler with smartlink support, or moving the relevant function to a separate unit (and compile that to assembler and postparse it)

Smartlinking divides the code into sections for linking purposes, and this is visible in the assembler sourcecode (either by section pseudo commands, or by the fact it is split into multiple files)

It might also be possible to get such information from the lineinfo in the debug information.

Reply by email

waldo kitty
to Florian Klämpfl
Florian Klämpfl wrote 6 lines
Am 18.01.2012 13:54, schrieb Gennadiy Poryev: > Hi all, > > In my project (win32) I need to estimate the number of machine code bytes of a certain function. What about using the map file?

there's a map file? how is it created? i'm already using the "godwarf" or some such command line parameters... the line in question has already been written about and recommended numerous times... i just do not recall it from memory but this one part ;)

Reply by email

Tomas Hajny
to waldo kitty
waldo kitty wrote 16 lines
On 1/21/2012 18:07, Florian Klämpfl wrote: > Am 18.01.2012 13:54, schrieb Gennadiy Poryev: >> Hi all, >> >> In my project (win32) I need to estimate the number of machine code >> bytes of a certain function. > > What about using the map file? there's a map file? how is it created? i'm already using the "godwarf" or some such command line parameters... the line in question has already been written about and recommended numerous times... i just do not recall it from memory but this one part ;)

Have you tried running fpc without parameters (to see the complete list) or looking at our documentation? Anyway, the parameter for link generation is -Xm.

Interestingly, I just noticed that it doesn't work for OS/2 (it seems that I've never implemented the required support for that), but there is no reason why it shouldn't work and I'll fix it.

Tomas

Reply by email