Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Versions of ld available

Target platformld versionNotes
Native Intel RHEL52.17Doesn't support -l:filename
Native Intel RHEL62.20 
ARM RTEMS 4.112.23+ 
ARM XIlinx Linux GNU EABI2.23+ 
ARM Xilinx EABI2.23+ 

We need the syntax -l:filename in order to support if we find shared libraries using -L and want to use arbitrary file names for shared libraries, at least for RTEMS, see belowthem. I list the Intel linkers here in case someone wants to try, for example, a quick test of new linker script techniques without setting up the cross-compilation environment.

Summary of command-line ld options

If given to a compiler driver instead of directly to ld some of these options need to be prefaced with "-Wl,". However a series of options can be given following a single preface, e.g., "-Wl,-soname=foo,--hash-style=gnu,-zcombreloc".

Base options

(instead of -l) 
OptionNeeds -Wl,Notes
-shared To make a shared object.
-fpic or -fPIC Shared objects for ARM must use position-independent code. This is actually a compiler option, ld will check to make sure you've used it.
-e (optional) or --entry Specifies the entry point (use 0 if there is none).
-soname(tick)
--as-needed(tick)
Make sure SO names are used in needed lists.
-zcombreloc(tick)Combine relocation entries into one or two tables and sort them by the index of the symbol referred to. This allows symbol lookups to be cached by the dynamic linker for efficiency.
--zmax-page-size=4096(tick)This is the page size used in the Run Time Support Region, the part of memory into which shared objects are loaded.
--hash-style=gnu(tick)Provides more efficient symbol lookup.
-l:libname 

Refer to a shared library libname that's to be found using the search path established using -L options.

-L dirname Add dirname to the search path for ld, which uses the path for two purposes: to find libraries named using -l: and to find linker scripts named in include statements in other linker scripts (and named using -T).
-T scriptname(tick)Use scriptname as the main linker script.
--no-undefined(tick)Makes it an error if the resulting shared object has undefined references remaining after ld has finished making it. It allows needed objects to contain undefined references but presumably these too have been constructed using --no-undefined.

 

File names, sonames and the needed list

A shared library has both a file name and a so-called SO (shared object) name, or soname. The two need not be related as the soname can be set using the ld option -soname. The soname is contained in the dynamic string table at an offset given by the DT_SONAME entry in the dynamic section. Other entries of type DT_NEEDED, which also contain offsets into the dynamic string table, specify the needed list for the shared library. These are the shared libraries that must also be loaded for the shared library to work. Standard convention allows the needed list to contain both file names and sonames but we'll use only sonames.

File name conventions

...

File names need not begin with "lib"; we use -l:

...

or just name the shared object file as input. We use the following extensions for the different kinds of shared objects:

  • .svt for symbol-value tables.
  • .exe for tasks.
  • .drv for device drivers.
  • .so for everything else).

Soname and needed list conventions

  1. Every shared object must have a soname.
  2. Sonames must be legal C identifiers.
  3. Sonames must be no longer than 128 characters long.Needed lists contain no file names, only sonames.
  4. The needed list for an shared object must contain an entry for every other shared object it references directlya reference to each other object on which it depends.
  5. A shared object must have no undefined references left after linking with ld.
  6. The following sonames are reserved:
    1. "RTEMS___" for the shared object containing RTEMS, newlib and other run-time support.
    2. "SYS" for the shared object containing the System Name Table.
    3. "APP" for the shared object containing the Application Name Table.

...

In order to have a shared object satisfy the requirements listed above we need to use -soname when building every shared object. Then whether you include the object as an input or search for it using -L and -l:, ld will put the soname on the needed list. Referencing an object that lacks an embedded soname will result in the file name of the object being put on the needed list which is not what we want, and that will cause the lookup with Svt_Translate() to fail.

All the direct dependencies of the shared object being built should be searched or included as inputs, and undefined references should cause the build to fail (--no-undefined). For efficiency we should use Normally one would name only the objects to which the one being built makes symbolic references, as ld by default puts every object so named on the needed list. However, you can't always depend on symbolic references to tell which objects are needed. For example, suppose object A uses the /dev/foo device whose driver is installed by object B. Then A needs B even though A never makes symbolic references to B. If it weren't for situations like that you could just use the --as-needed which will put only those sonames on the list whose objects actually satisfy references in the object being built; the default is to list every object named as an input or using -l:.option on the ld command line and just mention all the other objects that the new object might need; the option ensures that only objects which satisfy symbolic references go on the needed list. Instead you'll have to use --no-as-needed in front of objects that you know will be needed and --as-needed in front of those that might be needed. For example:

arm-rtemsx.yy-ld -shared -o a.so -soname A ... a.o --no-as-needed b.so --as-needed c.so d.so ...

Dynamic symbol table

  1. Every shared object must have a GNU-style hash table (--hash-style=gnu). System V hash tables will be ignored.
  2. Symbols beginning with "lnk_" are used for data and functions to be made known to the dynamic linker. Currently in use are:
    1. "lnk_preferences" labels object preference data, passed to lnk_prelude().
    2. "lnk_prelude" labels a function to be called by the dynamic linker just after the functions pointed to by the .init_array have been run.

...

The ARM cross-compilers use .init_array to hold pointers to compiler-generated functions that run constructors for statically allocated C++ objects. Therefore .init_array is processed before calling lnk_prelude(). However, lnk_prelude() can't itself be called using the .init_array mechanism because it takes arguments, it returns a status value and there's no way to control the ordering of entries in .init_array.

RTEMS shared object

The shared object containing RTEMS, newlib and other run-time support is unique in that it has to be loaded at a fixed location, the start of the RTS Region. The loading is done by U-Boot which looks at the physical addresses of the loadable segments in order to determine where to put them. In order to set the physical addresses properly the linker script for the RTEMS object assigns all output to a region of memory, defined using the MEMORY directive, whose origin is at the required location. This has the side effect of giving the lowest loadable segment in the shared object a non-zero starting virtual address which has to be taken into account when using symbols defined by the object. All other shared objects are created with virtual addresses starting at zero.File names need not begin with "lib"; we use -l: instead of plain -l (or just name the shared object file as input).