Mapfiles

Mapfiles provide a large degree of control over the operation of the link-editor, and the resulting output object:

Note: The link-editor used without a mapfile will always produce a valid ELF output file. The mapfile option provides the user with a great deal of flexibility and control over the output object, some of which has the potential to produce an invalid or unusable object. The user is expected to have knowledge of the rules and conventions that govern the ELF format.

The -M command line option is used to specify the mapfile to be used. Multiple mapfiles can be used in a single link operation. When more than one mapfile is specified, the link-editor processes each one in the order given, as if they represented a single logical mapfile. This occurs before any input objects are processed.

The system provides sample mapfiles for solving common problems in the /usr/lib/ld directory.

Mapfile Structure and Syntax

Mapfile directives can span more than one line, and can have any amount of white space, including new lines. For all syntax discussions, the following notations apply.
Syntax Notations
Mapfile Version
The first non-comment, non-empty, line in a mapfile is expected to be a mapfile version declaration. This declaration establishes the version of the mapfile language used by the remainder of the file. The mapfile language documented in this manual is version 2:
$mapfile_version 2

A mapfile that does not begin with a version declaration is assumed to be written in the original mapfile language defined for System V Release 4 Unix (SVR4) by AT&T. The link-editor retains the ability to process such mapfiles. Their syntax is documented in Appendix ZZZ - AT&T System V Release 4 Mapping Syntax.

Conditional Input
Lines within a mapfile can be conditionalized so that they only apply to a specific ELFCLASS (32 or 64-bit) or machine type:
$if expr
...
[$elif expr]
...
[$else]
...
$endif

Each of the directives ($if, $elif, $else, and $endif) appear alone on a line. The logical expressions in $if and subsequent $elif lines are evaluated in order until an expression that evaluates to True is found. Text following a line with a False value is discarded. The text following a successful directive line is treated normally. "Text" here refers to any material, that is not part of the conditional structure. Once a successful $if or $elif has been found, and its text processed, succeeding $elif and $else lines, together with their text, are discarded. If all the expressions are zero, and there is a $else, the text following the $else is treated normally.

The scope of an $if directive cannot extend across multiple mapfiles. A $if directive must be terminated by a matching $endif within the mapfile that uses it, or the link-editor will issue an error.

The link-editor maintains an internal table of names that can be used in the logical expressions evaluated by $if and $elif. At startup, this table is initialized with each of the following names that apply to the output object being created:

NameMeaning
_ELF3232-bit object
_ELF6464-bit object
_sparcSparc machine (32 or 64-bit)
_x86x86 machine (32 or 64-bit)
trueAlways defined

The names are case sensitive, and must be used exactly as shown. For example, true is defined, but TRUE is not. Any of these names can be used by themselves as a logical expression. For example:

$if _ELF64
...
$endif
will evaluate to true, and allow the link-editor to process the enclosed text, when the output object is 64-bit. Although numeric values are not allowed in these logical expressions, a special exception is made for the value '1' which evaluates to true, and '0' for false.

More complex logical expressions can be written, using the following operators:

OperatorMeaning
&&Logical AND
||Logical OR
(expr)Sub-expression
!Negate boolean value of following expression
Expressions are evaluated from left to right. Sub-expressions are evaluated before enclosing expressions.

For example, the lines in the following construct will be evaluated when building 64-bit objects for X86 platforms:

$if _ELF64 && _x86
...
$endif
The $add directive can be used to add a new name to the link-editor's table of known names. Using the above example, it might be convenient to define the name amd64 to stand for 64-bit x86 objects, in order to simplify $if directives:
$if _ELF64 && _x86
$add amd64
$endif
We can use this to simplify our previous example:
$if amd64
...
$endif
The $clear directive is the reverse of the $add directive. It is used to remove names from the internal table:
$clear amd64

The effect of the $add directive persists beyond the end of the mapfile that uses it, and is visible to any subsequent mapfile that is processed by the link-editor in the same link operation. If this is not desired, use $clear at the end of the mapfile containing the $add to remove it.

Finally, the $error directive causes the link-editor to print all remaining text on the line as a fatal error, and halt the link operation. This can be used to ensure that a programmer porting an object to a new machine type will not be able to silently build an incorrect object that is missing a necessary mapfile definition:

$if _sparc
...
$elif _x86
...
$else
$error unknown machine type
$endif

C language programmers will recognize that the syntax used for mapfile conditional input resembles that of the C preprocessor macro language (cpp). This similarity is intentional. However, mapfile conditional input directives are by design considerably less powerful than those provided by cpp. They provide only the most basic facilities required to support linking operations in a cross platform environment.

Among the significant differences between the two languages:

Those requiring more sophisticated macro processing should consider using an external macro processor, such as m4(1).
Mapfile Directives
Mapfile directives exist to specify many aspects of the output object. These directives share a common syntax, using name value pairs for attributes, and { ... } constructs to represent hierarchy and grouping. The directives accepted by the link-editor are:
DirectivePurpose
CAPABILITY Hardware and software capabilities
DEPEND_VERSIONS Specify allowed versions from sharable object dependencies
HDR_NOALLOC ELF header and program headers are not allocable
LOAD_SEGMENTCreate new loadable segment, or modify an existing one
NOTE_SEGMENTCreate note segment, or modify an existing one
NULL_SEGMENTCreate null segment, or modify an existing one
PHDR_ADD_NULL Add Null Program Header Entries
SEGMENT_ORDERSpecify the order of segments in the output object and program header array.
STACKProcess Stack Attributes
SYMBOL_SCOPESet symbol attributes and scope within the unnamed global version
SYMBOL_VERSIONSet symbol attributes and scope within an explicitly named version
The syntax of mapfile directives is based on the following generic forms:

The simplest form is a directive name without a value:

directive;
The next form is a directive name with a value, or a whitespace separated list of values:
directive = value...;

In addition to the '=' operator shown, the '+=' and '-=' forms of assignment are allowed. The '=' operator sets the given directive to the given value, or value list. The '+=' operator can be used to specify that the value on the right hand side is to be added to the current value, and the '-=' operator is used to remove values.

More complex directives manipulate items that take multiple attributes enclosed within {...} brackets to group the attributes together as a unit:

directive [name] {
        attribute [= value];
        ...
} [name...];

There can be a name before the opening '{', which is used to name the result of the given statement. Similarly, one or more optional names may follow the closing '}', prior to the terminating ';'. These names are used to express that the named item being defined has relationship with other named items.

Note that the format for attributes within a grouping use the same syntax described for simple directives with a value above, with a '=', '+=', or '-=' assignment operator, followed by a value, or whitespace sepated list of values, terminated with a semicolon (';').

A directive may have sub-attributes that in turn have sub-attributes. In such cases, the sub-attributes are also grouped within nested { ... } brackets to reflect this hierarchy:

directive [name] {
        attribute {
                subattribute [= value];
                ...
        };
                ...
} [name...];

The mapfile syntax grammar puts no limit on the depth to which such nesting is allowed. It depends solely on the requirements of the directive.

The specific syntax for each supported mapfile directive is shown in the sections that follow.

CAPABILITY Directive

The hardware and software capabilities of a relocatable object are typically recorded within an object at compile time. The link-editor combines the capabilities of any input relocatable objects to create a final capabilities section for the output file. Capabilities can be defined within a mapfile, to augment, or completely replace, the capabilities that are supplied from input relocatable objects:
CAPABILITY {
        HW = hwcap_flags;
        HW += hwcap_flags;
        HW -= hwcap_flags;

        SF = sfcap_flags;
        SF += sfcap_flags;
        SF -= sfcap_flags;

        HW_1 = value;
        HW_1 += value;
        HW_1 -= value;

        HW_2 = value;
        HW_2 += value;
        HW_2 -= value;

        SF_1 = value;
        SF_1 += value;
        SF_1 -= value;
};	
For each capability, the link-editor maintains a current value (value), and a set of values to be excluded (exclude). Prior to processing mapfiles, both values are 0. When processing a CAPABILITY mapfile directive: Input objects are processed after mapfiles have been read. Capability values specified by the input objects are merged with those from the mapfiles, unless the '=' operator was used, in which case that capability is ignored when encountered in an input object. Hence, the '=' operator overrides the input objects, whereas the '+=' operator can be used to augment them.

Prior to wring the resulting capability value to the output object, the link-editor subtracts any capability values specified with the '-=' operator.

Within an ELF object, hardware and software capabilities are represented as bit assignments within one or more bitmasks found in the capabilities section of the object. The HW and SF mapfile attributes provide a more abstract view of this implementation, accepting a space separated list of symbolic capability names that the link-editor maps internally to the appropriate mask and bit. The numbered attributes (HW_1, etc) exist in order to allow direct numeric access to the underlying capability bitmasks. They can be used to specify capability bits that have not been officially defined. When possible, the HW and SF attributes should be used.

HW
Hardware capabilities are specified as a space separated list of symbolic capability names. For SPARC platforms, hardware capabilities are defined as AV_ values in <sys/auxv_SPARC.h>. For x86 platforms, hardware capabilities are defined as AV_ values in <sys/auxv_386.h>. Mapfiles use the same names, without the AV_ prefix. For example, the x86 AV_SSE hardware capability is called SSE within a mapfile. This list can contain any of the capability names defined for the CA_SUNW_HW_ capability masks.
SF
Software capabilities are specified as a space separated list of symbolic capability names. Software capabilities are defined as SF1_SUNW_ values in <sys/elf.h>. Mapfiles use the same names, without the SF1_SUNW_ prefix. For example, the SF1_SUNW_ADDR32 software capability is called ADDR32 in a mapfile. This list can contain any of the capability names defined for the CA_SUNW_SF_1 capability mask.
HW_1, HW_2
The HW_1 and HW_2 attributes allow the the CA_SUNW_HW_1 and CA_SUNW_HW_2 capability masks to be specified directly as numeric values, or as the symbolic hardware capability names that correspond to that mask.
SF_1
The SF_1 attribute allows the the CA_SUNW_SF_1 capability mask to be specified directly as a numeric value, or as symbolic software capability names that correspond to that mask.

DEPEND_VERSIONS Directive

When linking against a sharable object, the the symbols from all versions exported by the object are normally available for use by the link-editor. The DEPEND_VERSION directive is used to limit access to specified versions only. Restricting version access can be used to ensure that a given output object does not use newer features that might not be available on an older version of the system. A DEPEND_VERSIONS directive has the following syntax:
DEPEND_VERSIONS objname {
        ALLOW = version_name;
        REQUIRE = version_name;
        ...
}

objname is the name of the sharable object, as specified on the command line. In the common case where the object is specified via the -l command line option, this will be the specified name with a 'lib' prefix. For instance, libc is commonly referenced as '-lc' on the command line, and is therefore specified as 'libc.so' in a DEPEND_VERSIONS directive.

ALLOW
The ALLOW attribute specifies that the specified version, and versions it inherits, are available to the link-editor for resolving symbols in the output object. The link-editor will add a requirement for the highest version used in the inheritance chain containing this version to the output object requirements.
REQUIRE
REQUIRE adds the specified version to the output object requirements, whether or not the version is actually required to satisfy the link operation.

HDR_NOALLOC Directive

Every ELF object has an ELF header at offset 0 in the file. Executables and sharable objects also contain Program Headers, which are accessed via the ELF header. The link-editor normally arranges for these items to be included as part of the first loadable segment. The information contained in these headers is therefore visible within the mapped image, and is typically used by the runtime linker. The HDR_NOALLOC directive can be specified to prevent this:
HDR_NOALLOC;
When HDR_NOALLOC is specified, the ELF header and Program Header array still appear at the start of the resulting output object file, but are not contained in a loadable segment, and virtual address calculations for the image start at the first section of the first segment rather than at the base of the ELF header.

PHDR_ADD_NULL Directive

The PHDR_ADD_NULL directive causes the link-editor to add a specified number of additional program header entries of type PT_NULL at the end of the program header array. Extra PT_NULL entries can be used by post-processing utilities.
PHDR_ADD_NULL = value;
value must be a positive integer value, and gives the number of extra PT_NULL entries to create. All fields of the resulting program header entries will be set to 0.

LOAD_SEGMENT, NOTE_SEGMENT, and NULL_SEGMENT Directives

A segment is a contiguous portion of the output object that contains sections. The mapfile segment directives allow the specification of three different segment types:
LOAD_SEGMENT
Specifies a loadable segment containing code or data to be mapped into the address space of a process at runtime. The link-editor creates a PT_LOAD program header entry for each allocable segment, which is used by the runtime linker to locate and map the segment.

NOTE_SEGMENT
A NOTE_SEGMENT holds NOTE sections. The link-editor creates a PT_NOTE program header entry that references it. Note segments are not allocable.

NULL_SEGMENT
A null segment holds non-allocable sections that included in the output object, but which are not available to the object at runtime. Common examples of such sections are the .symtab symbol table, and the various sections produced for the benefit of debuggers. No program header is created for a null segment.
Segment directives are used to create new segments in the output file, or to change the attribute values of an existing segment. An existing segment is one that was previous defined, or one of the built-in segments discussed in Predefined Segments. Each new segment is added to the object after the last such segment of its type, loadable segments first, then note segments, and finally null segments. Any program headers associated with these segments are placed in the program header array in the same relative order as the segments themselves. This default placement can be altered by setting an explicit address (in the case of a loadable segment), or via the SEGMENT_ORDER directive.

If segment_name is a pre-existing segment, then the attributes specified modify it. Otherwise, a new segment is created and the specified attributes are applied to it. The link-editor fills in default values for attributes not explicitly supplied.

Note: When selecting a segment name, bear in mind that future versions of the link-editor may add new predefined segments. If the name used in your segment directive matches this new name, it will alter the meaning of your mapfile, from creating a new segment to modifying an existing one. The best way to prevent this situation is to avoid generic names for segments, and give all of your segment names a unique prefix, such as a company/project identifier, or even the name of the program (e.g. hello_world_data_segment).

All three segment directives share a common set of core attributes. Substituting one of (LOAD_SEGMENT, NOTE_SEGMENT, NULL_SEGMENT) for directive in the following, the syntax for this shared core is:

directive segment_name {

        ASSIGN_SECTION [assign_name];
        ASSIGN_SECTION [assign_name] {
                FILE_BASENAME = file_basename;
                FILE_OBJNAME = objname;
                FILE_PATH = file_path;
                FLAGS = section_flags;
                IS_NAME = section_name;
                TYPE = section_type;
        };

        DISABLE;

        IS_ORDER = assign_name ...;
        IS_ORDER += assign_name ...;

        OS_ORDER = section_name ...;
        OS_ORDER += section_name ...;
};

The LOAD_SEGMENT directive accepts an additional set of attributes specific to loadable segments. The syntax for these additional attributes is:

LOAD_SEGMENT segment_name {
        ALIGN = value;

        FLAGS  = segment_flags;
        FLAGS += segment_flags;
        FLAGS -= segment_flags;

        MAX_SIZE = value;

	NOHDR;

        PADDR = value;
        ROUND = value;

        SIZE_SYMBOL = symbol_name ...;
        SIZE_SYMBOL += symbol_name ...;

        VADDR = value;
};

Any of the segment directives can be specified as an empty directive. When an empty segment directive creates a new segment, default values are established for all of its attributes:

LOAD_SEGMENT segment_name;

NOTE_SEGMENT segment_name;

NULL_SEGMENT segment_name;

All of the attributes accepted by one or more of the segment directives are described below.

ALIGN (LOAD_SEGMENT only)
The ALIGN attribute is used to specify the alignment for a loadable segment. The value specified is set in the p_align field of the program header corresponding to the segment. Segment alignment is used in calculating the virtual address of the beginning of the segment.

The alignment specified must be a power of 2. By default, the link-editor sets the alignment of a segment to the built-in default. This default differs from one CPU to another and might even be different between software revisions.

The ALIGN attribute is mutually exclusive to the PADDR and VADDR attributes, and cannot be used with them together. When PADDR or VADDR is specified, the p_align field of the corresponding program header will be set to the default value.

ASSIGN_SECTION
ASSIGN_SECTION specifies a combination of section attributes, such as section name, type, and flags, that collectively qualify a section for assignment to a given segment. Each such set of attributes is called an entrance criteria. A section matches when its attributes match those of an entrance criteria exactly. An ASSIGN_SECTION that does not specify any attributes matches any section it is compared to.

Multiple ASSIGN_SECTION attributes are allowed for a given segment. Each ASSIGN_SECTION attribute is independent of the others. A section will be assigned to a segment if it satisfies any one of the ASSIGN_SECTION attributes. The link-editor will not assign sections to a segment unless it has at least one ASSIGN_SECTION attribute.

The link-editor uses an internal list of entrance criteria to assign sections to segments. Each ASSIGN_SECTION declaration encountered in the mapfile is placed on this list, in the order encountered. The entrance criteria for the built-in segments discussed in Predefined Segments are placed on this list immediately following the final mapfile defined entry.

The entrance criteria can be given an optional name (assign_name). This name can be used in conjunction with the IS_ORDER attribute to specify the order in which input sections are placed in the output section.

To place an input section, the link-editor starts at the head of the entrance criteria list, and compares the attributes of the section to each entrance criteria in turn. The section is assigned to the segment associated with the first entrance criteria that matches the section attributes exactly. If there is no match, the section is placed at the end of the file, as is generally the case for all non-allocable sections.

ASSIGN_SECTION accepts the following:

FILE_BASENAME, FILE_OBJNAME, FILE_PATH
These attribute allows the selection of sections based on the path (FILE_PATH), basename (FILE_BASENAME), or object name (FILE_OBJNAME) of the file they come from.

File paths are specified using the standard Unix slash delimited convention. The final path segment is the basename of the path, also known simply as the filename. In the case of an archive, the basename can be augmented with the name of the archive member, using the form archive_name(component_name) . For example, /lib/libc.a(printf.o) specifies the object printf.o, found in an archive named /lib/libc.a.

FILE_BASENAME and FILE_OBJNAME are equivalent when applied to a non-archive, and compare the given name to the basename of the file. When applied to an archive, FILE_BASENAME still examines the basename of the file (the archive name), while FILE_OBJNAME examines the name of the object contained within the archive.

Each ASSIGN_SECTION maintains a list of all FILE_BASENAME, FILE_PATH, and FILE_OBJNAME values. A file match occurs if any one of these definitions match an input file.

IS_NAME
Input section name

TYPE
Specifies an ELF section_type, which can be any of the SHT_ constants defined in , with the SHT_ prefix removed. (e.g. PROGBITS, SYMTAB, NOBITS, etc).

FLAGS
The FLAGS attribute uses section_flags to specify section attributes as a space separated list of one or more of the following values, which correspond to the SHF_ values defined in <sys/elf.h>:
Flag ValueMeaning
ALLOCSection is allocable
WRITESection is writable
EXECUTESection is executable
AMD64_LARGESection can be larger than 2GB
If an individual flag is preceded by an exclamation mark (!), that attribute must explicitly not be present. For example,
ALLOC !WRITE
specifies that a section must be allocable, and not writable. Flags not explicitly in a section_flags list are ignored. In the above example, only the value of ALLOC and WRITE are examined when matching a section against the specified flags. The other section flags can have any value.

DISABLE
The DISABLE attribute causes the link-editor to ignore the segment that carries it. No sections will be assigned to a disabled segment. The section is automatically re-enabled if it is referenced by a following segment directive. Hence, an empty reference suffices to re-enable a disabled section:
segment segment_name;
FLAGS (LOAD_SEGMENT only)
The FLAGS attribute specifies segment permissions as a space separated list of permissions. By default, user defined segments receive READ, WRITE, and EXECUTE permissions. The default flags for the predefined segments are supplied by the link-editor, and in some cases may be platform-dependent.

There are three forms allowed:

FLAGS  = segment_flags;
FLAGS += segment_flags;
FLAGS -= segment_flags;
The simple '=' assignment operator replaces the current flags with the new set, the '+=' form adds the new flags to the existing set, and the '-=' form removes the specified flags from the existing set.
IS_ORDER
The link-editor normally places output sections into the segment in the order they are encountered. Similarly, the input sections that make up the output section are placed in the order they are encountered. The IS_ORDER attribute can be used to alter this default placement of input sections. IS_ORDER specifies a space separated list of entrance criteria names (assign_name). Sections matched by one of these entrance criteria are placed at the head of the output section, sorted in the order given by IS_ORDER. Sections matched by entrance criteria not found in the IS_ORDER list are placed following the sorted sections, in the order they are encountered.

When the '=' form of assignment is used, the previous value of IS_ORDER for the given segment is discarded, and replaced with the new list. The '+=' form of IS_ORDER concatenates the new list to the end of the existing list.

The IS_ORDER attribute is of particular interest when used in conjunction with the -xF option to the compilers. When a file is compiled with the -xF option, each function in that file is placed in a separate section with the same attributes as the .text section. These sections are called .text%function_name.

For example, a file containing three functions, main(), foo() and bar(), when compiled with the -xF option, yields a relocatable object file with text for the three functions being placed in sections called .text%main, .text%foo, and .text%bar. When the link-editor places these sections into the output, the '%' and anything following it are removed. Hence, all three of these functions will be placed in the .text output section. The IS_ORDER attribute can be used to force them to be placed in a specific order within the .text output section relative to each other.

Consider the following user-defined mapfile.

$mapfile_version 2
LOAD_SEGMENT text {
	ASSIGN_SECTION text_bar  { IS_NAME = .text%bar };
	ASSIGN_SECTION text_main { IS_NAME = .text%main };
	ASSIGN_SECTION text_foo  { IS_NAME = .text%foo };
	IS_ORDER = text_foo text_bar text_main;
};
No matter the order in which these three functions are found in the source code, or encountered by the link-editor, their order in the output object text segment will be foo, bar, main.
MAX_SIZE (LOAD_SEGMENT only)
By default, the link-editor will allow a segment to grow to the size required by its contents. The MAX_SIZE attribute can be used to specify a maximum size for the segment. If MAX_SIZE is set, the link-editor will generate an error if the segment grows beyond the specified size.
NOHDR (LOAD_SEGMENT only)
If a segment with the NOHDR attribute set becomes the first loadable segment in the output object, the ELF and program headers will not be included within the segment.

The NOHDR attribute differs from the top level HDR_NOALLOC directive in that it is a per-segment value, and only has an effect if the segment becomes the first loadable segment. This feature exists primarily to provide feature parity with the older mapfiles. See Appendix ZZZ - AT&T System V Mapping Syntax for more details.

The HDR_NOALLOC directive is recommended in preference to the segment NOHDR attribute.

ROUND (LOAD_SEGMENT only)
The ROUND attribute is used to specify that the size of the segment should be rounded up to the given value. The rounding value specified must be a power of 2. By default, the link-editor sets the rounding factor of a segment to 1, meaning that the segment size is not rounded up.
SIZE_SYMBOL (LOAD_SEGMENT only)
The SIZE_SYMBOL attribute defines a space separated list of section size symbol names to be created by the link-editor. A size symbol is a global-absolute symbol that represents the size, in bytes, of the segment. These symbols can be referenced in your object files. In order to access the symbol within your code, you should ensure that symbol_name is a legal C language identifier.

The '=' form of assignment can be used to establish an initial value. It can only be used once per link-editor session. The '+=' form of SIZE_SYMBOL concatenates the new list to the end of the existing list, and can be used as many times as desired.

OS_ORDER
The link-editor normally places output sections into the segment in the order they are encountered. The OS_ORDER attribute can be used to alter this default placement of output sections. OS_ORDER specifies a space separated list of output section names (section_name). The listed sections are placed at the head of the segment, sorted in the order given by OS_ORDER. Sections not listed in OS_ORDER are placed following the sorted sections, in the order they are encountered.

When the '=' form of assignment is used, the previous value of OS_ORDER for the given segment is discarded, and replaced with the new list. The '+=' form of OS_ORDER concatenates the new list to the end of the existing list.

PADDR (LOAD_SEGMENT only)
The PADDR attribute is used to specify an explicit physical address for the segment. The value specified is set in the p_paddr field of the program header corresponding to the segment. By default, the link-editor sets the physical address of segments to 0, as this field has no meaning in userland objects.
VADDR (LOAD_SEGMENT only)
The VADDR attribute is used to specify an explicit virtual address for the segment. The value specified is set in the p_vaddr field of the program header corresponding to the segment. By default, the link-editor assigns virtual addresses to segments as the output file is created.

SEGMENT_ORDER Directive

The SEGMENT_ORDER directive is used to specify a non-default ordering for segments in the output object.

SEGMENT_ORDER accepts a space separated list of segment names:

SEGMENT_ORDER = segment_name ...;
SEGMENT_ORDER += segment_name ...;

When the '=' form of assignment is used, the previous segment order list is discarded, and replaced with the new list. The '+=' form of assignment concatenates the new list to the end of the existing list.

By default, the link-editor orders segments as follows:

  1. Loadable segments with explicit addresses set via the VADDR attribute of the LOAD_SEGMENT directive, sorted by address

  2. Segments ordered via the SEGMENT_ORDER directives come next, in the specified order.

  3. Loadable segments without explicit addresses, not found in the SEGMENT_ORDER list.

  4. Note segments without explicit addresses, not found in the SEGMENT_ORDER list.

  5. Null segments without explicit addresses, not found in the SEGMENT_ORDER list.

Note: ELF has some implicit conventions that must be followed by a well formed object: Mapfiles can be used to create objects that violate these requirements. This should be avoided, as the result of running such an object is undefined.
Unless the HDR_NOALLOC directive is specified, the link-editor enforces the requirement that the first segment must be a loadable segment, and not a note or null segment. As HDR_NOALLOC cannot be used for non-kernel executables, it is of little practical use for most objects.

STACK Directive

The STACK directive specifies attributes of the process stack. It can only be used when linking a dynamic executable object.
STACK {
        FLAGS  = segment_flags;
        FLAGS += segment_flags;
        FLAGS -= segment_flags;
};
The FLAGS attribute specifies segment permissions as a space separated list of permissions.

There are three forms allowed. The simple '=' assignment operator replaces the current flags with the new set, the '+=' form adds the new flags to the existing set, and the '-=' form removes the specified flags from the existing set.

The default stack permissions are defined by the platform ABI, and vary between platforms. The value for the target platform can be specified using the segment flag name 'STACK'.

On some platforms, the ABI mandated default permissions include EXECUTE. It is rarely if ever needed and is generally considered to be a potential security risk. Removing EXECUTE permission from the stack is a recommended practice:

STACK {
        FLAGS -= EXECUTE;
};

The STACK directive is reflected in the output ELF object as a PT_SUNWSTACK program header entry.

SYMBOL_SCOPE and SYMBOL_VERSION Directives

The SYMBOL_SCOPE and SYMBOL_VERSION directives are used to specify the scope and attributes of global symbols. SYMBOL_SCOPE operates within the context of the unnamed base symbol version, while SYMBOL_VERSION is used to gather symbols into explicitly named global versions. The SYMBOL_VERSION directive allows the creation of stable interfaces that support object evolution in a backward compatible manner.

The syntax for SYMBOL_VERSION is:

SYMBOL_VERSION version_name {
	symbol_scope:

	*;
	symbol_name;
	symbol_name {
		AUXILIARY = soname;
		FILTER = soname;
		FLAGS = symbol_flags;
		SIZE = value;
		TYPE = symbol_type
		VALUE = value;
	};
} [inherited_version_name...];

SYMBOL_SCOPE is identical, except that it does not accept version names:

SYMBOL_SCOPE {
        ...
};
In a SYMBOL_VERSION directive, version_name provides a label for this set of symbol definitions. It identifies a version definition within the output object. One or more inherited versions (inherited_version_name) can be specified, separated by whitespace, in which case the newly defined version inherits from the versions named. See Chapter 5, "Application Binary Interfaces and Versioning."

symbol_scope defines the scope of symbols in a SYMBOL_SCOPE or SYMBOL_VERSION mapfile directive. By default, symbols are assumed to have global scope. This can be modified by specifying a symbol_scope followed by a colon (:). These lines determine the symbol scope for all symbols that follow, until changed by a subsequent scope declaration. The possible scope values and their meanings are given in the following table:

ScopeMeaning
default / global Global symbols of this scope are visible to all external objects. References to such symbols from within the object are bound at runtime, thus allowing interposition to take place. This visibility scope provides a default, that can be demoted, or eliminated by other symbol visibility techniques. This scope definition has the same affect as a symbol with STV_DEFAULT visibility. See Table 7-20.
hidden / local Global symbols of this scope are reduced to symbols with a local binding. Symbols of this scope are not visible to other external objects. This scope definition has the same affect as a symbol with STV_HIDDEN visibility. See Table 7-20.
protected / symbolic Global symbols of this scope are visible to all external objects. References to these symbols from within the object are bound at link-edit, thus preventing runtime interposition. This visibility scope can be demoted, or eliminated by other symbol visibility techniques. This scope definition has the same affect as a symbol with STV_PROTECTED visibility. See Table 7-20.
exported Global symbols of this scope are visible to all external objects. References to such symbols from within the object are bound at runtime, thus allowing interposition to take place. This symbol visibility can not be demoted, or eliminated by any other symbol visibility technique. This scope definition has the same affect as a symbol with STV_EXPORTED visibility. See Table 7-20.
singleton Global symbols of this scope are visible to all external objects. References to such symbols from within the object are bound at runtime, and ensure that only one instance of the symbol is bound to from all references within a process. This symbol visibility can not be demoted, or eliminated by any other symbol visibility technique. This scope definition has the same affect as a symbol with STV_SINGLETON visibility. See Table 7-20.
eliminate Global symbols of this scope are hidden. Their symbol table entries are eliminated. This scope definition has the same affect as a symbol with STV_ELIMINATE visibility. See Table 7-20. Note that local symbols can also be eliminated by using the link-editor -z redlocsym option.
A symbol_name is the name of a symbol. This name can result in a symbol definition, or a symbol reference, depending on any qualifying attributes. In the simplest form, without any qualifying attributes, a symbol reference is created. This reference is exactly the same as would be generated using the -u option discussed in "Defining Additional Symbols with the -u option" on page 50. Typically, if the symbol name is followed by any qualifying attributes, then a symbol definition is generated using the associated attributes.

When a local scope is defined, the symbol name can be defined as the special auto-reduction directive "*". Symbols that have no explicitly defined visibility are demoted to a local binding within the dynamic object being generated. Explicit visibility definitions originate from mapfile definitions, or visibility definitions that are encapsulated within relocatable objects. Similarly, when an eliminate scope is defined, the symbol name can be defined as the special auto-elimination directive "*". Symbols that have no explicitly defined visibility are eliminated from the dynamic object being generated.

A symbol_name can be listed by itself in order to simply assign it to a version and/or specify its scope. Optional symbol attributes can be specified within {} brackets. Valid attributes are described below.

AUXILIARY
Indicates that this symbol is an auxiliary filter on the shared object name (soname). See "Generating Auxiliary Filters" on page 132.
FILTER
The symbol is a standard filter on a sharable object with the given . Indicates that this symbol is a filter on the shared object name (soname). See "Generating Standard Filters" on page 129. Filter symbols do not require any backing implementation to be provided from an input relocatable object. Therefore, use this directive together with defining the symbol's type, to create an absolute symbol table entry.
FLAGS
symbol_flags specify symbol attributes as a space separated list of one or more of the following values:
FlagMeaning
DIRECT Indicates that this symbol should be directly bound to. When used with a symbol definition, this flag results in any reference from within the object being built to be directly bound to the definition. When used with a symbol reference, this flag results in a direct binding to the dependency that provides the definition. See Appendix D, "Direct Bindings." This flag can also be used with the PARENT flag to establish a direct binding to any parent at runtime.
DYNSORT Indicates that this symbol should be included in a sort section. See "Symbol Sort Sections" on page 270. The symbol type must be STT_FUNC, STT_OBJECT, STT_COMMON, or STT_TLS.
EXTERN Indicates the symbol is defined externally to the object being created.

This flag is typically defined to label callback routines. Undefined symbols that would be flagged with the -z defs option are suppressed with this flag.

This flag is only meaningful when generating a symbol reference. Should a definition for this symbol occur within the objects combined at link-edit, then the flag is silently ignored.

INTERPOSE Indicates that this symbol acts an interposer. This flag can only be used when generating a dynamic executable. This flag provides for finer control of defining interposing symbols than is possible by using the -z interpose option.
NODIRECT Indicates that this symbol should not be directly bound to. This state applies to references from within the object being created and from external references. See Appendix D, "Direct Bindings." This flag can also be used with the PARENT flag to prevent a direct binding to any parent at runtime.
NODYNSORT Indicates that this symbol should not be included in a sort section. See "Symbol Sort Sections" on page 270.
PARENT Indicates the symbol is defined in the parent of the object being created. A parent is an object that references this object at runtime as an explicit dependency. A parent can also reference this object at runtime using dlopen(3C). This flag is typically defined to label callback routines. This flag can be used with the DIRECT or NODIRECT flags to establish individual direct, or no-direct references to the parent. Undefined symbols that would be flagged with the -z defs option are suppressed with this flag.

This flag is only meaningful when generating a symbol reference. Should a definition for this symbol occur within the objects combined at link-edit, then the flag is silently ignored.

SIZE
Sets the size attribute. This attribute results in the creation of a symbol definition.
TYPE
The symbol type attribute. This attribute can be either COMMON, DATA, or FUNCTION. The COMMON attribute results in a tentative symbol definition. The data and function attributes result in a section symbol definition or an absolute symbol definition. See "Symbol Table Section" on page 261.

A data attribute results in the creation of an OBJT symbol. A data attribute that is accompanied with a size, but no value creates a section symbol by associating the symbol with an ELF section. This section is filled with zeros. A function attribute results in the creation of an FUNC symbol.

A function attribute that is accompanied with a size, but no value creates a section symbol by associating the symbol with an ELF section. This section is assigned a void function, generated by the link-editor, with the signature:

void (*)(void)

A data or function attribute that is accompanied with a value results in the appropriate symbol type together with an absolute, ABS, section index.

The creation of a section data symbol is useful for the creation of filters. External references to a section data symbol of a filter from an executable result in the appropriate copy relocation being generated. See "Copy Relocations" on page 146.

VALUE
Indicates the value attribute. This attribute results in the creation of a symbol definition.

Predefined Segments

The link-editor provides a predefined set of output segment descriptors and entrance criteria. These definitions satisfy the needs of most linking scenarios, and comply with the ELF layout rules and conventions expected by the system.

The text, data, and extra segments are of primary interest, while the others serve more specialized purposes, as described below.

text

The text segment defines a readonly executable loadable segment that accepts allocable, non-writable sections. This includes executable code, readonly data needed by the program, and readonly data produced by the link-editor for use by the runtime linker such as the dynamic symbol table.

The text segment is the first segment in the process, so the link-editor will place the ELF header, and the program header array into it. This can be prevented using the HDR_NOALLOC mapfile directive.

data

The data segment defines a writable loadable segment. It is used for writable data needed by the program, and for writable data used by the runtime linker, such as the Global Offset Table (GOT), and the PLT on architectures such as sparc that require the PLT sections to be writable.

extra

The extra segment captures all sections not assigned elsewhere, directed there by the final entrance criteria record. Common examples are the full symbol table (.symtab), and the various sections produced for the benefit of debuggers. This is a null segment, and has no corresponding program header table entry.

note

The note segment captures all sections of type SHT_NOTE. The link-editor provides a PT_NOTE program header entry to reference it.

lrodata and ldata

The amd64 ABI defines small, medium, and large compilation models. The ABI requires sections for the medium and large models to set the SHF_AMD64_LARGE section flag. An input section lacking the SHF_AMD64_LARGE must be placed in an output segment that does not exceed 2GB in size. The lrodata and ldata predefined segments are present for amd64 output objects only, and are used to handle sections with the SHF_AMD64_LARGE flag set. lrodata receives readonly sections, and ldata receives the others.

bss

ELF allows for any segment to contain NOBITS sections. The link-editor places such sections at the end of the segment they are assigned to. This is implemented via the program header entry p_filesz and p_memsz fields, which must follow the rule:
p_memsz >= p_filesz
If p_memsz is greater than p_filesz, the extra bytes are NOBITS. The first p_filesz bytes come from the object file, and any remaining bytes up to p_memsz are zeroed by the system prior to use.

The default assignment rules send readonly NOBITS sections to the text segment, and writable NOBITS sections to the data segment. The link-editor defines the bss segment as an alternative segment that can accept writable NOBITS sections. This segment is disabled by default, and must be explicitly enabled to be used.

Since writable NOBITS sections are easily handled as part of the data segment, the benefit of having a separate bss segment may not be immediately obvious. By convention, the process dynamic memory heap starts at the end of the final segment, which must be writable. This is usually the data segment, but if bss is enabled, it becomes the final segment. When building a dynamic executable, enabling the bss segment with an appropriate alignment can be used to enable large page assignment of the heap. For example, the following enables the bss segment and sets an alignment of 4MB:

LOAD_SEGMENT bss {
        ALIGN=0x400000;
};
Note: Users are cautioned that an alignment specification may be machine-specific, and may lose its benefit on different hardware platforms. A more flexible means of requesting the most optimal underlying page size may evolve in future releases.

Examples: Section to Segment Assignment

The following are examples of user-defined mapfiles. The numbers on the left are included in the example for tutorial purposes. Only the information to the right of the numbers actually appears in the mapfile.

Example 1

1    $mapfile_version 2
2    LOAD_SEGMENT elephant {
3            ASSIGN_SECTION {
4                    IS_NAME=.data;
5                    FILE_PATH=peanuts.o;
6            };
7            ASSIGN_SECTION {
8                    IS_NAME=.data;
9                    FILE_OBJNAME=popcorn.o;
10           };
11   };
12
13   LOAD_SEGMENT monkey {
14           VADDR=0x80000000;
15           MAX_SIZE=0x4000;
16           ASSIGN_SECTION {
17                   TYPE=progbits;
18                   FLAGS=ALLOC EXECUTE;
19           };
20           ASSIGN_SECTION {
21                   IS_NAME=.data
22           };
23   };
24
25   LOAD_SEGMENT donkey {
26           FLAGS=READ EXECUTE;
27           ALIGN=0x1000;
28           ASSIGN_SECTION {
29                   IS_NAME=.data;
30           };
31   };
32
33   LOAD_SEGMENT text {
34           VADDR=0x80008000
35   };
Four separate segments are manipulated in this example. Every mapfile starts with a mapfile version declaration as shown on line 1. Segment elephant (lines 2-11) receives all of the data sections from the files peanuts.o or popcorn.o. Note that popcorn .o can come from an archive (in which case the archive file can have any name), or it can come from any file with a basename of popcorn.o. In contrast, peanuts.o can only come from a file with exactly that name. For example, if /var/tmp/peanuts.o was supplied to the link-edit, it does not match peanuts.o.

Segment monkey (lines 13-23) has a virtual address of 0x80000000, and a maximum length of 0x4000. This segment receives all sections that are both PROGBITS and allocable-executable, as well as all sections not already in the segment elephant with the name .data. The .data sections entering the monkey segment need not be PROGBITS or allocable-executable, because they match the entrance criteria on line 20 rather than the one on line 16. This illustrates that an "and" relationship exists between the sub-attributes within a ASSIGN_SECTION attribute, while an "or" relationship exists between the different ASSIGN_SECTION attributes for a single segment.

The donkey segment (lines 25-31) is given non-default permission flags and alignment, and will accept all sections named .data. However, this segment will never be assigned any sections, and as a result, segment donkey will never appear in the output object. The reason for this is that the link-editor examines entrance criteria in the order they appear in the mapfile. In this mapfile, segment elephant accepts some .data sections, and segment takes any that are left, leaving none for donkey.

Lines 33-35 set the virtual address of the text segment to 0x80008000. The text segment is one of the standard predefined segments, as described in Predefined Segments, so this statement modifies the existing segment rather than creating a new one.

Example 2

The following mapfile example manipulates the predefined text and data segments, header options and section within segment ordering.
1    $mapfile_version 2
2    HDR_NOALLOC;
3
4    LOAD_SEGMENT text {
5            VADDR=0xf0004000;
6            FLAGS=READ EXECUTE;
7            OS_ORDER=.text .rodata;
9            ASSIGN_SECTION {
10                   TYPE=PROGBITS;
11                   FLAGS=ALLOC !WRITE;
12           };
13   };
14
15   LOAD_SEGMENT data {
16           FLAGS=READ WRITE EXECUTE;
17           ALIGN=0x1000;
18           ROUND=0x1000;
19   };
As always, the first line declares the mapfile language version used by the mapfile. The HDR_NOALLOC directive (line 2) specifies that the resulting object should not include the ELF header or program header array within the first allocable segment in the object, which is the predefined text segment.

The segment directive on lines 4-13 set a virtual address and permission flags for the text segment. It also specifies that sections named .text sections should be placed at the head of the segment, followed by any sections named .rodata, and that all other sections will follow these. Finally, allocable, non-writable PROGBITS sections are assigned to it.

The segment directive on lines 15-19 specifies that the data segment must be aligned on a boundary of 0x1000. This has the effect of aligning the first section within the segment at the same alignment. The length of the segment is to be rounded up to a multiple of the same value as the alignment. The segment permissions are set to read, write, and execute.

Link-Editor Internals: Section and Segment Processing

The internal process used by the link-editor to assign sections to output segments is described here. This information is not necessary in order to use mapfiles. It is primarily of interest to those interested in linker internals, and for those who want a deep understanding of how segment mapfile directives are interpreted and executed by the link-editor.

Section To Segment Assignment

The process of assigning input sections to output segments involves the following data structures:
Input Sections
Input sections are read from relocatable objects input to the link editor. Some are examined and processed by the link-editor, while others are simply passed to the output without examination of their contents (e.g. PROGBITS).

Output Sections
Output sections are sections that are written to the output object. Some are formed from the concatenation of sections passed through from the input objects. Others, such as symbol tables and relocation sections are generated by the link-editor itself, often incorporating information read from the input objects.

When the link-editor passes an an input section through to become an output section, it usually retains its original name. However, the link-editor can modify the name in certain circumstances. For instance, the link-editor translates input section names of the form name%XXX, dropping the '%' character and any characters following it from the output section name.

Segment Descriptors
The link-editor maintains a list of known segments. It initially contains the predefined segments, described in Predefined Segments. When a LOAD_SEGMENT, NOTE_SEGMENT, or NULL_SEGMENT mapfile directive is used to create a new segment, an additional segment descriptor for it is added to this list. The new segment goes at the end of the list following other segments of hte same type, unless explicitly ordered by setting a virtual address for it (LOAD_SEGMENT), or by using the SEGMENT_ORDER directive.

When creating the output object, the link-editor only creates program headers for the segments that receive a section. Empty segments are quietly ignored. Hence, user specified segment definitions have the power to completely replace the use of the predefined segments definitions, despite the fact that there is no explicit facility for removing a segment definition from the link-editor list.

Entrance Criteria
The set of section attributes required in order to place that section in a given segment is called an entrance criteria for the segment. A given segment can have an arbitrary number of entrance criteria.

The link-editor maintains an internal list of all defined entrance criteria. This list is used to place sections into segments, as described below. Each mapfile inserts the entrance criteria created by the ASSIGN_SECTION attribute to the LOAD_SEGMENT, NOTE_SEGMENT, or NULL_SEGMENT mapfile directive at the head of this list, in the order they are encountered in the mapfile. The entrance criteria for the built-in segments discussed in Predefined Segments are placed at the bottom of this list. Therefore, mapfile defined entrance criteria take precedence over the built in rules, and mapfiles at the end of the command line take precedence over those found at the beginning.

For each section written to the output object, the link-editor performs the following steps to place it in an output segment:

  1. The attributes of the section are compared to each record in the internal entrance criteria list, starting at the head of the list and considering each entrance criteria in turn. A match occurs when every attribute in the entrance criteria matches exactly, and the segment associated with the entrance criteria is not disabled. The search stops with the first entrance criteria that matches, and the section is directed to the associated segment.

    If no Entrance Criteria match is found, the section is placed at the end of the output file after all other segments. No program header entry is created for this information. Most non-allocable sections (debug sections, etc) end up in this area.

  2. When the section falls into a segment, the link-editor checks the list of existing output sections in that segment as follows.

    If the section attribute values match those of an existing output section exactly, the section is placed at the end of the list of sections associated with that output section.

    If no matching output section is found, a new output section is created with the attributes of the section being placed, and the section is placed within it. This new output section is positioned within the segment following any other output sections with the same section type, or at the end of the segment if there are none.

    Note: If the input section has a user-defined section type value between SHT_LOUSER and SHT_HIUSER, it is treated as a PROGBITS section. No method exists for naming this section type value in the mapfile, but these sections can be redirected using the other attribute value specifications (section flags, section name) in the entrance criteria.

Mapfile Directives for Predefined Segments and Entrance Criteria

The link-editor provides a predefined set of output segment descriptors and entrance criteria, as described in Predefined Segments. The link-editor already knows about these sections, so mapfile directives are not required to create them. However, we show mapfile directives that could be used to produce them here for illustrative purposes, and as an example of a relatively complex mapfile specification. Mapfile segment directives can be used to modify or augment these built in definitions.

Normally, section to segment assignments are done within a single segment directive. However, the predefined sections have more complex requirements, requiring their entrance criteria to be processed in a different order than the segments are laid out in memory. In order to achieve this, we use two passes, the first to define all the segments in the desired order, and the second to establish entrance criteria in an order that will achieve the desired results. It is rare for a user mapfile to require this strategy.

        # Predefined segments and entrance criteria for the Solaris link-editor
        $mapfile_version 2

        # The lrodata and ldata segments only apply to amd64 objects.
        # Establish amd64 as a convenient token for conditional input
        $if _ELF64 && _x86
        $add amd64
        $endif

        # Pass 1: Define the segments and their attributes, but
        # defer the entrance criteria details to the 2nd pass.
        LOAD_SEGMENT text {
                FLAGS = READ EXECUTE;
        };
        LOAD_SEGMENT data {
                FLAGS = READ WRITE EXECUTE;
        };
        LOAD_SEGMENT bss {
                DISABLE;
                FLAGS=DATA;
        };
        $if amd64
                LOAD_SEGMENT lrodata {
                        FLAGS = READ
                };
                LOAD_SEGMENT ldata {
                        FLAGS = READ WRITE;
                };
        $endif
        NOTE_SEGMENT note;
        NULL_SEGMENT extra;

        # Pass 2: Define ASSIGN_SECTION attributes for the segments defined
	# above, in the order we require the link-editor to evaluate them.

        # All SHT_NOTE sections go to the note segment
        NOTE_SEGMENT note {
                ASSIGN_SECTION {
                        TYPE = NOTE;
                };
        };
        $if amd64
                # Medium/large model amd64 readonly sections to lrodata
                LOAD_SEGMENT lrodata {
                        ASSIGN_SECTION {
                                FLAGS = ALLOC AMD64_LARGE;
                        };
                };
        $endif

        # text receives all readonly allocable sections
        LOAD_SEGMENT text {
                ASSIGN_SECTION {
                        FLAGS = ALLOC !WRITE;
                };
        };

        # If bss is enabled, it takes the writable NOBITS sections
        # that would otherwise end up in ldata or data.
        LOAD_SEGMENT bss {
                DISABLE;
                ASSIGN_SECTION {
                        FLAGS = ALLOC WRITE;
                        TYPE = NOBITS;
                };
        };

        $if amd64
                # Medium/large model amd64 writable sections to ldata
                LOAD_SEGMENT ldata {
                        ASSIGN_SECTION {
                                FLAGS = ALLOC WRITE AMD64_LARGE;
                        };
                        ASSIGN_SECTION {
                                TYPE = NOBITS;
                                FLAGS = AMD64_LARGE
                        };
                };
        $endif

        # Any writable allocable sections not taken above go to data
        LOAD_SEGMENT data {
                ASSIGN_SECTION {
                        FLAGS = ALLOC WRITE;
                };
        };

        # Any section that makes it to this point ends up at the
        # end of the object file in the extra segment. This accounts
        # for the bulk of non-allocable sections.
        NULL_SEGMENT extra {
                ASSIGN_SECTION;
        };