Go to main content

Oracle® Solaris 11.4 Linkers and Libraries Guide

Exit Print View

Updated: March 2019
 
 

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 is 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        sun4
     [2]  CA_SUNW_MACH      sun4

  Symbols:
   index    value     size  type bind oth ver shndx          name
     [1]  0x108d4      0x4  OBJT LOCL  D    0 .data          foo%sun4

 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]  0x108d8      0x4  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
sun4v
$ main
machine: sun4v

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 a dynamic executable is typically position-dependent. In addition, data references within a dynamic executable are bound at link-edit time. Within a dynamic 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 dynamic 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        sun4
     [2]  CA_SUNW_MACH      sun4

  Symbols:
   index    value     size  type bind oth ver shndx          name
     [1]  0x1111c     0x1c  FUNC LOCL  D    0 .text          bar%sun4

 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]  0x11138     0x1c  FUNC LOCL  D    0 .text          bar%sun4v

$ uname -m
sun4v
$ main
machine: sun4v