4.6 Using Based Addressing for Functions

With Microsoft C/C++ you can declare functions as based, so you can specify the code segment the functions reside in. Grouping functions into segments allows you to use near functions safely and to improve performance when you swap overlays to disk.

You can declare a function with both the __near and __based keywords, or with both the __far and __based keywords, even though such declarations are illegal for data. This is because the meaning of the __near and __far keywords for functions differs slightly from their meaning for data. Near functions can reside anywhere in memory, but you can call them only from functions in the same code segment. Far functions can also reside anywhere in memory, and you can call them from functions in other code segments. Thus, you can use the __near and __far keywords to describe a function's calling convention and use a __based expression to specify its location in memory.

The segment in which functions reside is normally determined by the memory model of your program. In the tiny, small, and compact models, all functions are stored in a single code segment. In the medium, large, and huge models, functions are stored in multiple code segments; there is a separate segment for each source file.

Summary: Placing functions correctly can reduce swapping.

The location of functions in segments becomes important when tuning large programs that use overlays. By placing the functions that most frequently call one another within the same segment, you can reduce swapping. The location of functions is also important when using near functions in a program that has multiple segments. A function might try to call a near function that resides in another segment, causing a run-time error.

To prevent this problem, you can declare functions as based to ensure that they are stored in the same segment. For example,

// FILE 1 - compiled under large model

void __based(__segname(“MYSEG”)) farfunc() // far by default

{

nearfunc();

}

// FILE 2 - compiled under large model

void __near __based(__segname(“MYSEG”)) nearfunc()

{

// ...

}

If these two functions were not declared as based in the same segment, they
would be placed in separate segments because they're declared in separate files.
In that situation, this program would suffer a link-time or run-time error because farfunc cannot perform a near call to nearfunc when nearfunc is in another segment. However, since both functions are based in the MYSEG segment, the program links and executes correctly.

Functions can be based only on a segment constant; unlike data, they cannot be based on segment variables, nor can they be based on pointers, void, or the __self segment. The __near or __far keyword can appear before or after the based expression.

Based addressing for functions replaces the alloc_text pragma as a method of controlling the placement of functions. If both a based expression and an alloc_text pragma specify a segment for a function to be placed in, the based expression takes precedence.