Linker and Libraries Guide

Creating a Family of Symbol Capabilities Data Items

Multiple instances of initialized data, where each instance is specific to a system, can be provided within the same object. However, providing such data through functional interfaces if often simpler, and is recommended. See Creating a Family of Symbol Capabilities Functions. Special care is required to provide multiple instances of initialized data within an executable.

The following example initializes a data item foo within foo.c, to point to a machine name string. This file can be compiled for various machines, and each instance is identified with a machine capability. A reference to this data item is made from bar() from the file bar.c. A shared object foobar.so.1 is then created by combining bar() with two capabilities instances of foo.


$ cat foo.c
char *foo = MACHINE;
$ cat bar.c
#include	<stdio.h>

extern char *foo = MACHINE;

void bar()
{
        (void) printf("machine: %s\n", foo);
}

$ elfdump -H foobar.so.1

Capabilities Section:  .SUNW_cap

 Symbol Capabilities:
     index  tag               value
       [1]  CA_SUNW_ID       sun4u
       [2]  CA_SUNW_MACH     sun4u

  Symbols:
     index    value      size      type bind oth ver shndx          name
       [1]  0x000108d4 0x00000004  OBJT LOCL  D    0 .data          foo%sun4u

 Symbol Capabilities:
     index  tag               value
       [4]  CA_SUNW_ID       sun4v
       [5]  CA_SUNW_MACH     sun4v

  Symbols:
     index    value      size      type bind oth ver shndx          name
       [2]  0x000108d8 0x00000004  OBJT LOCL  D    0 .data          foo%sun4v

An application can reference bar(), and the runtime linker binds to the instance of foo that is associated with the underlying system.


$ uname -m
sun4u
$ main
machine: sun4u

The proper operation of this code depends on the code having been compiled to be position-independent, as is normally the case for code in sharable objects. See Position-Independent Code. Position-independent data references are indirect references, which allow the runtime linker to locate the required reference and update elements of the data segment. This relocation update of the data segment preserves the text segment as read-only.

However, the code within an executable is typically position-dependent. In addition, data references within an executable are bound at link-edit time. Within an executable, a symbol capabilities data reference must remain unresolved through a global data item, so that the runtime linker can select from the symbol capabilities family. If the reference from bar() in the previous example bar.c is compiled as position-dependent code, then the text segment of the executable must be relocated at runtime. By default, this condition results in a fatal link-time error.


$ cc -o main main.c bar.c foo.o foo.1.o foo.2.o ...
warning: Text relocation remains                referenced
    against symbol                  offset      in file
foo                                 0x0         bar.o
foo                                 0x8         bar.o

One approach to solve this error condition is to compile bar.c as position-independent. Note however, that all references to any symbol capabilities data items from within the executable must be compiled position-independent for this technique to work.

Although data can be accessed using the symbol capabilities mechanism, making data items a part of the public interface to an object can be problematic. An alternative, and more flexible model, is to encapsulate each data item within a symbol capabilities function. This function provides the sole means of access to the data. Hiding data behind a symbol capabilities function has the important benefit of allowing the data to be defined static and kept private. The previous example can be coded to use symbol capabilities functions.


$ cat foobar.c
cat bar.c
#include	<stdio.h>

static char *foo = MACHINE;

void bar()
{
        (void) printf("machine: %s\n", foo);
}
$ elfdump -H main

Capabilities Section:  .SUNW_cap

 Symbol Capabilities:
     index  tag               value
       [1]  CA_SUNW_ID       sun4u
       [2]  CA_SUNW_MACH     sun4u

  Symbols:
     index    value      size      type bind oth ver shndx          name
       [1]  0x0001111c 0x0000001c  FUNC LOCL  D    0 .text          bar%sun4u

 Symbol Capabilities:
     index  tag               value
       [4]  CA_SUNW_ID       sun4v
       [5]  CA_SUNW_MACH     sun4v

  Symbols:
     index    value      size      type bind oth ver shndx          name
       [2]  0x00011138 0x0000001c  FUNC LOCL  D    0 .text          bar%sun4v

$ uname -m
sun4u
$ main
machine: sun4u