Hex-Rays' blog

Igor’s tip of the week #86: Function chunks – Hex Rays

Written by Igor Skochinsky | Apr 21, 2022

In IDA, function is a sequence of instructions grouped together. Usually it corresponds to a high-level function or subroutine:

  1. it can be called from other places in the program, usually using a dedicated processor instruction;
  2. it has an entry and one or more exits (instruction(s) which return to the caller);
  3. it can accept arguments (in registers or on the stack) and optionally return values;
  4. it can use local (stack) variables

However, IDA’s functions can group any arbitrary sequence of instructions, even those not matching the above criteria. The only hard requirement is that the function must start with a valid instruction.

Creating functions

IDA usually creates functions automatically, based on the call instructions or debug information, but they can also be created manually using the Create Function action (under Edit > Functions or from context menu), or P shortcut. This can be done only for instructions not already belonging to functions. By default IDA follows the cross-references and tries to determine the function boundaries automatically, but you can also select a range beforehand to force creation of a function, for example, if there are some invalid instructions or embedded data.

Function range

In the most common case, a function occupies a contiguous address range, from the entry to the last return instruction. This is the start and end address specified in function properties available via the Edit Function dialog (Alt–P).

Chunked functions

A single-range function is not the only option supported by IDA. In real-life programs, a function may be split into several disjoint ranges. For example, this may happen as a result of profile-guided optimization, which can put cold (rarely executed) basic blocks into a separate part of binary from hot (often executed) ones. In IDA, such functions are considered to consist of multiple chunks (each chunk being a single contiguous range of instructions). The chunk containing the function entry is known as entry chunk, while the others are called tail chunks or simply tails.

In disassembly view, the functions which have additional chunks have additional annotations near the function’s entry, listing the tail chunks which belong to  the function.

The tail chunks themselves are marked with “START OF FUNCTION CHUNK” and “END OF FUNCTION CHUNK” annotations, mentioning which function they belong to.  This is mostly useful in text view, as in the graph view they are displayed as part of the overall function graph.

Sometimes a tail chunk may be shared by multiple functions. In that case, one of them is designated tail owner and others are considered additional parents. Such chunk will appear in the function graph for every function it belongs to.

Managing chunks manually

Usually IDA handles chunked functions automatically, either detecting them during autoanalysis or by making use of other function range metadata (such as .pdata function descriptors in x64 PE files, or debug information). However, there may be situations where you need to add or remove chunks manually, for example to fix a false positive or handle an unusual compiler optimization.

To remove (detach) a tail chunk, position cursor inside it and invoke Edit > Functions > Remove function tail. If the tail has only one owner, it will be removed immediately and converted to standalone instructions (not belonging to any function). If it has multiple owners, IDA will offer you to choose from which function(s) it should be detached.

To add a range of instructions as a tail to a function, select the range and invoke Edit > Functions > Append function tail, then select a function to which it should be added. This can be done multiple times to attach a tail to several functions (whole tail must be selected again in such case).

More info:

IDA Help: Append Function Tail

IDA Help: Remove Function Tail