summaryrefslogtreecommitdiffstats
path: root/user/exe/loader.rst
blob: be2e78eda753065c4ab014dcd7b416d6f3415665 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
.. SPDX-License-Identifier: CC-BY-SA-4.0

.. Copyright (C) 2019 Chris Johns <chrisj@rtems.org>

.. index:: Dynamic Loader

Dynamic Loader
==============
.. index:: Dynamic Loader
.. index:: Run-time Loader
.. index:: RTL
.. index:: Libdl

RTEMS supports dynamically loading of executable code and data in the form of
object files into a running system where the run-time loaded code can be
executed and data accessed

This section describes RTEMS loader, preparing and loading executable code into
a running system, the supported architectures and any limitation that may exist
with an architecture.

The RTEMS operating system contains a link editor that runs on the target. The
link editor supports loading Extendable Linker Format (ELF) relocatable
executable object files locating the code and data in the target's address space
as it is loaded. An executable object file's external references to function
identifiers and data object identifiers are resolved and any external symbols
can be made available in the global symbol table. The executing performance of
dynamically loaded code is similar to the same code statically linked into an
executable. This is a core requirement of the RTEMS link editor.

.. _fig-dl-libdl:

.. figure:: ../../images/user/libdl.png
   :width: 95%
   :alt: Run Time Loader (libdl)
   :figclass: align-center

   Run Time Loader (libdl)

The RTEMS operating system's dynamic loader is not the same as the dynamic
shared library support Unix or Windows have. Those operating systems use dynamic
loading to share code between processes and this is an important feature in
their design. RTEMS is a single address space operating system and that means
there is no ability to share code at run-time. As a result code is loaded in a
similar manner to static linking removing the need for any overheads sharing
code may have.

To load an executable object file it must be resident on a target and accessible
by RTEMS's file system. The executable object file can be a single file or a
collection in a library stored using the Unix standard archive format. The RTEMS
loader supports the extended GNU format for long file names in archives.

The RTEMS developers do not see dynamically loading of code as a real-time
activity. A system should not respond to real-time external events by loading
code. The loading of code should happen before a system is considered available
and the activity the system is experiencing is low and stable.

.. index: base image

The statically linked executable that is loaded and run after reset is called
the *base image*. The *base image* contains your base application that is used
to dynamically load code, a global symbol table, the parts of the RTEMS
operating system code used in the base image as well as functions and data from
the tool suite libraries and packages you are using. Only the software
referenced is used to create the base image. The parts of the libraries not
referenced are not part of the executable or present in the global symbol table.

Application software can locate a symbol by name and call the address or
reference the data at that address. A function identifier located by a symbol
does not have it's signatures checked, it is the responsibility of the caller to
make sure the function is called with the correct arguments. It is the same for
data objects, there is no type checking. Symbol versioning is not supported and
supporting it does not make sense within the RTEMS operating system. An RTEMS
target system is closed to normal users and software needs to be built from the
same tool set and header files used to the build the base image.

An executable object file's text or code has to be built for the target's
architecture it is loaded on and it must be built with the same ABI flags the
base image is built with. See :ref:`MachineFlagsandABI`.

System Design
-------------

The use of dynamic loading in a project is a system design decision. Some
systems will have strict requirements where loading code into a live system is
not allowed while other projects will benefit from the system level flexibility
dynamically loading code provides.

Code loaded at run time needs to be resident or accessible to the target via
RTEMS's file system. Targets that have suitable media or a network interface to
NFS servers to hold the executable object and library files are best suited.

Dynamically loading code uses more memory than statically linking the same code
into the base image. The link editor maintains symbol tables where each symbol
is a string, an address, and some additional data. The executable object files
resident in memory each have data to manage them, the memory they use, and any
dependencies they might have. The link editor is designed to minimize the memory
overheads however only statically linked executables have no memory overhead.

The link editor relocates the code and data into RAM fixing it to the load
address as it is loaded. A target needs to have suitably configured memory
available for the executable object file to reside in. The memory must be able
to support read, write and executable type access. Fine control of the memory
and it's modes can be supported using a customer allocator. Examples are systems
that have a custom memory map, specialized memory for the execution of code or a
requirement for read-only executable sections.

The load address of an executable object file is determined by the load order
and the allocator used. The default allocator for the link editor is the system
heap which means the location a specific executable object file is loaded at
depends on the memory allocated before it is loaded and when in the load order
it is loaded. A statically linked executable's address map is fixed and this is
considered important in some systems. A dynamically loaded system can be loaded
in a repeatable manner if the load order is the same and the initialization
sequence of the system is controlled. A custom allocator may also help.

Management of dynamically loadable object files and libraries adds to the
configuration management of the hosts in a project. The loadable files need to
be released and tracked in a suitable configuration management process just like
the base image is. Executable object files and libraries are specific to a
version of RTEMS and cannot be mixed or moved and this needs to be carefully
managed. Currently there are no checks an executable object file matches the
version of the base image it is being loaded on. These extra configuration
controlled items add to the overheads of a project and need to be considered.

Dynamically loadable systems have a number of features that benefit some systems
and products. Systems can be built on a base of trusted or *golden* modules. A
number of projects using a common base of hardware can make use of proven
modules reducing the testing and qualification overhead for each new release. A
tested base image with libraries for common and available boards provides a
simple and fast way for new users to trial and use RTEMS.

A project can use dynamic loading during development, shipping statically linked
executables in production. Hardware used by a development team can have more
memory, extra media for disk drives, or a network interface.

Loader Interface
----------------
.. index:: Loader Interface
.. index:: Loading object files
.. index:: dlfcn.h

Run-time executable object file loading and management is via the standard's
based calls provided by the header file ``<dlfcn.h>``. The details of the calls
follow.

.. _dlopen:
.. index:: dlopen

``void* dlopen(const char* path, int mode);``
  The ``dlopen()`` function makes the symbols (function identifiers and data
  object identifiers) in the executable object file specified by `file`
  available to the calling program.

  The executable object files eligible for this operation are in the ELF
  format.

  The link loader may load embedded dependencies in executable object files. In
  such cases, a ``dlopen()`` operation may load those dependencies in addition
  to the executable object file specified by `file`.

  A successful ``dlopen()`` returns a `handle` which the caller may use on
  subsequent calls to ``dlsym()``, ``dlinfo()`` and ``dlclose()``.

  The value of the `handle` should not be interpreted in any way by the caller.

  Subsequent calls to ``dlopen()`` for the same executable object file increases
  the references to it.

  The `file` argument is used to construct a pathname to the executable object
  file or archive library of executable object files. If the `file` argument
  contains a colon (``:``) the name of the executable object file in the library
  follows and this file name may optionally end with ``@`` followed by a number
  which is the absolute offset in the library file where the executable object
  file starts. If an executable object file is not detected at the offset the
  archive library's file table is searched.

  If `file` is a null pointer, ``dlopen()`` returns a global symbol table
  handle. This `handle` provides access to the global symbols from an ordered
  set of executable object files consisting of the original base image file, the
  set of executable object files loaded using ``dlopen()`` operations with the
  ``RTLD_GLOBAL`` flag, and any dependencies loaded. As the latter sets of
  executable object files can change during execution, the set of symbols made
  available by this `handle` can also change dynamically.

  Only a single copy of an executable object file is brought into the address
  space, even if ``dlopen()`` is invoked multiple times in reference to the
  executable object file, and even if different pathnames are used to reference
  the executable object file.

  Unresolved external symbols do not cause an error to be returned allowing the
  loading of jointly dependent executable object files.

  If ``dlopen()`` fails, it returns a null pointer, and sets an error condition
  which may be interrogated with ``dlerror()``.

  The `mode` parameter describes how ``dlopen()`` operates upon `file` with
  respect to the processing of relocations and the scope of visibility of the
  symbols provided within `file`. When an executable object file is brought into
  the address space, it may contain references to symbols whose addresses are
  not known until the executable object file is loaded.

  If a loaded executable object file and any dependent executable object files
  loaded with it contain any initialiser functions, they are called in the order
  loaded before ``dlopen()`` returns.

  The modes ``RTLD_LAZY`` and ``RTLD_NOW`` do not effect the type of relocation
  performed, it is same for both modes. All relocations of an executable object
  file and any dependent executable object files loaded with it are completed
  before the ``dlopen()`` call returns. The execution performance of the code
  loaded can be considered deterministic once ``dlopen()`` has returned.

  Any executable object file loaded by ``dlopen()`` can reference global symbols
  in the base image, any executable object files loaded included in the same
  ``dlopen()`` invocation, and any executable object files that were loaded in
  any ``dlopen()`` invocation and which specified the ``RTLD_GLOBAL`` flag. To
  determine the scope of visibility for the symbols loaded with a ``dlopen()``
  invocation, the `mode` parameter should be a bitwise-inclusive ``OR`` with one
  of the following values:

  ``RTLD_GLOBAL``
     The executable object file's symbols are made available for relocation
     processing of any other executable object file. In addition, symbol lookup
     using ``dlopen(NULL,mode)`` and an associated ``dlsym()`` allows
     executable object files loaded with this mode to be searched.

  ``RTLD_LOCAL``
    The executable object file's symbols shall not be made available for
    relocation processing of any other executable object files.

  If neither ``RTLD_GLOBAL`` nor ``RTLD_LOCAL`` is specified, the default
  behavior is unspecified.

  If ``RTLD_GLOBAL`` has been specified, the executable object file maintains
  it's ``RTLD_GLOBAL`` status regardless of any previous or future specification
  of ``RTLD_LOCAL``, as long as the executable object file remains in the
  address space.

  Symbols introduced through calls to ``dlopen()`` may be used in relocation
  activities. Symbols that duplicate symbols already defined by the base image
  or previous ``dlopen()`` calls are treated as an error and the object file is
  not loaded. Symbols introduced through loading dependent executable object
  files are ignored or not loaded depending on the method used to build the
  executable object files.

  The symbols introduced by ``dlopen()`` operations and available through
  ``dlsym()`` are at a minimum those which are exported as identifiers of global
  scope by the executable object file. Typically, such identifiers shall be
  those that were specified in (for example) C source code as having ``extern``
  linkage.

.. _dlclose:
.. index:: dlclose

``int dlclose(void* handle);``
  Releases a reference to the executable object file referenced by `handle`. If
  the reference count drops to ``0``, the executable object file's global symbol
  table is made unavailable. When all references to the global symbols the
  executable object file provided have been removed the object file is removed
  from the address space.

  If the executable object being removed has any termination routines in it they
  are called.

.. _dlsym:
.. index:: dlsym

``void* dlsym(void* handle, const char* symbol);``
 The ``dlsym()`` function obtains the address of a symbol (a function identifier
 or a data object identifier) defined in the symbol table identified by the
 handle argument. The handle argument is a symbol table handle returned from a
 call to ``dlopen()`` (and which has not since been released by a call to
 ``dlclose()``), and name is the symbol's name as a character string. The return
 value from ``dlsym()``, cast to a pointer to the type of the named symbol, can
 be used to call (in the case of a function) or access the contents of (in the
 case of a data object) the named symbol.

 The ``dlsym()`` function searches for the named symbol in the symbol table
 referenced by handle and returns the address of the code or data location
 specified by the null-terminated character string symbol. Which libraries and
 objects are searched depends on the `handle` parameter.

 Upon successful completion, if name names a function identifier, ``dlsym()``
 returns the address of the function converted from type pointer to function to
 type pointer to ``void``; otherwise, ``dlsym()`` shall return the address of
 the data object associated with the data object identifier named by name
 converted from a pointer to the type of the data object to a pointer to
 ``void``. If `handle` does not refer to a valid symbol table handle or if the
 symbol named by name cannot be found in the symbol table associated with
 `handle`, ``dlsym()`` shall return a null pointer.

.. _dlinfo:
.. index:: dlinfo

``int dlinfo(void* handle, int request, void* args);``

 The ``dlinfo()`` function provides information about dynamically loaded object.
 The action taken by ``dlinfo()`` and exact meaning and type of the argument
 `args` depend on value of the `request` argument provided by the caller.

 ``RTLD_DI_UNRESOLVED``
   Return ``1`` in an indexer value pointed to by `args` if the symbol table
   handle has unresolved relocation records to symbols. If the `handle` is the
   global symbol table handle or ``RTLD_SELF`` return ``1`` if any unresolved
   relocation records to symbols are present in any loaded executable object
   files..

.. _dlerror:
.. index:: dlerror

``const char *dlerror(void);``
 The ``dlerror()`` function returns a null-terminated character string (with no
 trailing ``<newline>``) that describes the last error that occurred during
 dynamic linking processing. If no dynamic linking errors have occurred since
 the last invocation of ``dlerror()``, ``dlerror()`` returns ``NULL``. Thus,
 invoking ``dlerror()`` a second time, immediately following a prior
 invocation, results in ``NULL`` being returned.

This example opens an object file, checks for any unresolved symbols the object
file may have, locates a global symbol in the object file, calls it then closes
the object file:

.. code-block:: c

 #include <stdbool.h>
 #include <stdio.h>
 #include <dlfcn.h>

 typedef int (*call_sig)(void);

 bool load_object (void)
 {
   void*    handle;
   call_sig call;
   int      unresolved;

   handle = dlopen ("/code.o", RTLD_NOW | RTLD_GLOBAL);
   if (handle == NULL)
   {
     printf ("dlopen failed: %s\n", dlerror ());
     return false;
   }

   if (dlinfo (handle, RTLD_DI_UNRESOLVED, &unresolved) < 0)
   {
     printf ("dlinfo failed: %s\n", dlerror ());
     dlclose (handle);
     return false;
   }

   if (unresolved != 0)
   {
     printf ("object.o has unresolved external symbols\n");
     dlclose (handle);
     return false;
   }

   call = dlsym (handle, "foo");
   if (call == NULL)
   {
     printf("dlsym failed: symbol 'foo' not found\n");
     dlclose (handle);
     return false;
   }

   printf ("'foo()' returns: %i\n", call ());

   if (dlclose (handle) < 0)
   {
     printf("dlclose failed: %s\n", dlerror());
     return false;
   }

   return true;
 }

Symbols
-------
.. index:: symbol
.. index:: global symbol
.. index:: function identifier
.. index:: data object identifier

The RTEMS link editor manages the symbols for the base image and all resident
executable object files. A symbol is an identifier string and a pointer value to
a function identifier or a data object identifier. The symbols held in the
symbol tables are used in the relocation of executable object files or they can
be accessed by application code using the :ref:`dlsym() <dlsym>` call.

.. index:: orphaned object file

An executable object file's symbols are removed from the global symbol table
when it is closed or orphaned. An executale object file cannot be unloaded if a
symbol it provides is referenced by another object and that object is still
resident. An executable object file that has no references to any of its symbols
and was not explicitly loaded using the :ref:`dlopen() <dlopen>` call is
orphaned and automatically removed from the address space.

Base Image Symbols
^^^^^^^^^^^^^^^^^^
.. index:: base image symbols

The base image symbol table provides access to the function and data objects
statically linked into the base image. Loaded executable object files can be
directly linked to the code and data resident in the base image.

A statically linked RTEMS executable does not contain a symbol table, it has to
be generated and either embedded into the executable or loaded as a specially
created executable object file.

The base image symbol table is dependent on the contents of the base image and
this is not known until it has been linked. This means the base image symbol
table needs to be constructed after the base image executable has been linked
and the list of global symbols is known.

The RTEMS Tools command :program:`rtems-syms` (see :ref:`RTEMSSymbols`) extracts
the global and weak symbols from an RTEMS static executable file, creates a C
file and compiles it creating a relocatable executable object file. This file
can be linked with the static executable's object files and libraries to create
a static executables with an embedded symbol table or the executable file can be
loaded dynamically at run-time. The following needs to be observed:

#. The option ``-e`` or ``--embedded`` to :program:`rtems-syms` creates an
   executable object file to be embedded in the base image and not providing
   either of these options creates a symbols executable object file that is
   loaded at run-time. The same executable object file cannot be used to
   embedded or load.

#. The target C compiler and machine options need to be provided to make sure
   the correct ABI for the target is used. See :ref:`MachineFlagsandABI`.

.. index:: embedded symbol table
.. _EmbbeddedSymbolTable:

Embedded Symbols
^^^^^^^^^^^^^^^^

An embedded symbol table is *embedded* within the base image executable file and
loaded when the static executable is loaded into memory by the bootloader. The
symbol table is automatically added to the link editor's global symbol table
when the first executable object file is loaded.

The process to embed the symbol table requires linking the base image twice.
The first link is to create a static executable that collects together the
symbols to make the symbol table. The RTEMS Tools command `rtems-syms` extracts
the global and weak symbols from the static executable ELF file, creates a C
file and compiles it to create an executable object file. The base image is
linked a second time and this time the symbol table executable object file is
added to the list of object files.

Embedding the symbol table means the chances of the symbol table and base image
not matching is low, however it also means the symbol table is always present in
the kernel image when dynamic loading may be optional. A project's build system
is made more complex as it needs to have extra steps to link a second time.

This example shows creating an embedded symbol table object file and linking it
into the base image.

.. code-block:: none

 $ sparc-rtems@rtems-ver-major@-gcc -mcpu=cypress foo.o -lrtemsbsp -lrtemscpu -o foo.pre
 $ rtems-syms -e -C sparc-rtems@rtems-ver-major@-gcc -c "-mcpu=cypress" -o foo-sym.o foo.pre
 $ sparc-rtems@rtems-ver-major@-gcc -mcpu=cypress foo.o foo-sym.o -lrtemsbsp -lrtemscpu -o foo.exe

The link command line steps in this example are not complete.

.. _LoadableSymbolTable:

Loadable Symbols
^^^^^^^^^^^^^^^^

A run-time loaded symbol table is the default for the command
:program:`rtems-syms`. The symbol table executable object file is packaged with
the other files to be dynamically loaded at run-time and placed on the target's
file system. It needs to be loaded before any other executable object file are
loaded or unresolved symbols can occur that will not be resolved.

A run-time loaded symbol table does not consume any target resources until it is
loaded. This is useful in a system that optionally needs to dynamically load
code, for example as a development environment. The symbol table executable
needs to exactly match the base image loading it or the behavior is
unpredictable. No checks are made.

The example shows creating and loading a symbol table executable object
file. First create the symbol table's executable object file:

.. code-block:: none

 $ sparc-rtems@rtems-ver-major@-gcc -mcpu=cypress foo.o -lrtemsbsp -lrtemscpu -o foo.exe
 $ rtems-syms -C sparc-rtems@rtems-ver-major@-gcc -c "-mcpu=cypress" -o foo-sym.o foo.exe

The link command line steps in this example are not complete.

Load the symbol table:

.. code-block:: c

 #include <stdbool.h>
 #include <stdio.h>
 #include <dlfcn.h>

 bool load (void)
 {
  void* handle = dlopen ("/foo-sym.o", RTLD_NOW | RTLD_GLOBAL);
  if (handle == NULL)
  {
    printf ("failed to load the symbol table: %s\n", dlerror ());
    return false;
  }
  return true;
 }

Unresolved Symbols
------------------

The RTEMS link editor does not return an error when an executable object file is
loaded with unresolved symbols. This allows dependent object files to be
loaded. For example an executable object file :file:`foo.o` contains the
function ``foo()`` and that function calls ``bar()`` and an executable object
file :file:`bar.o` contains a function ``bar()`` that calls the function
``foo()``. Either of these executable object files can be loaded first as long
both are loaded before any symbols are accessed.

The link editor defers the resolution of unresolved symbols until the symbol is
available in the global symbol table. Executing code or accessing data in a
loaded executable object file with unresolved external symbols results in
unpredictable behavior.

All unresolved symbols are checked after an executable object file has been
loaded. If a symbol is found and resolved any relocations that reference the
symbol are fixed. If valid library files have been configured the symbol table's
of each library are searched and if the symbol is found the dependent executable
object file is loaded. This process repeats until no more symbols can be
resolved.

The ``dlinfo()`` call can be used to see if a loaded executable object file has
any unresolved symbols:

.. code-block:: c

 #include <stdbool.h>
 #include <stdio.h>
 #include <dlfcn.h>

 bool has_unresolved(void* handle)
 {
   int unresolved;
   if (dlinfo (handle, RTLD_DI_UNRESOLVED, &unresolved) < 0)
   {
     printf ("dlinfo failed: %s\n", dlerror ());
     return false;
   }
   return unresolved != 0;
 }

The handle ``RTLD_SELF`` checks for any unresolved symbols in all resident
object files:

.. code-block:: c

 if (has_unresolved(RTLD_SELF))
   printf("system has unsolved symbols\n");

Libraries
---------

The RTEMS link editor supports loading executable object files from
libraries. Executable object files can be explicitly loaded from a library using
a specific path to :ref:`dlopen() <dlopen>` and treated the same as loading a
stand alone executable object file. Libraries can be searched and an executable
object file containing the search symbol can be loaded automatically as a
dependent executable object file. A dependent executable object file loaded from
a library with no symbol references to it's symbols is orphaned and
automatically unloaded and removed from the address space.

.. _fig-dl-libs:

.. figure:: ../../images/user/libdl-load.png
   :width: 65%
   :alt: Loading Executable Object Files
   :figclass: align-center

   Loading Executable Object Files

A library is an archive format file created using the RTEMS architecture
prefixed :program:`ar` command. The RTEMS tool suite provides the :program:`ar`
program and system libraries such as :file:`libc.a` and :file:`libm.a` for each
architecture and ABI. Libraries used by the RTEMS link editor for searching must
contain a symbol table created by the :program:`ranlib` program from the RTEMS
tool suite.

Searching a library's symbol table and loading an executable object file
containing the symbol is called *dependent loading*. Dependent loading provides
a simple way to manage the dependencies when loading an executable object
file. If code in an executable object file references functions or data objects
that are part of a library and the symbols are not part of the base image those
symbols will not resolve unless the library is on the target and available for
searching and loading. Dependent loading from libraries on the target provides a
simple and understandable way to manage the dependency issue between the base
image, loaded code and the system libraries.

The RTEMS link editor checks for the configuration file :file:`/etc/libdl.conf`
on each call to :ref:`dlopen() <dlopen>`. If the file has changed since the last
check it is loaded again and the contents processed. The file format is:

#. Comments start with the ``#`` character.
#. A line is a wildcard path of libraries to search for. The wildcard search
   uses the ``fnmatch()`` call. The ``fnmatch()`` function matches patterns
   according to the rules used by a shell.

Files that match the search pattern are verified as a library and if a symbol
table is found it is loaded and the symbols it contains made search-able.

A call to :ref:`dlopen() <dlopen>` checks the global symbols table and any
references to relocation symbols not found are *unresolved* and added to the
unresolved symbol table. Once the executable object file is loaded the link
editor attempts to resolve any unresolved symbols. The unresolved symbol
resolver checks each unresolved symbol against the global symbol table and if
not found the available library symbol tables are searched. If a symbol is found
in a library the dependent executable object file is loaded. The process repeats
until all unresolved symbols have been resolved and the remaining unresolved
symbols are not in the global symbol table or any libraries. The loading of a
library executable object file will resolve at least one symbol and it may add
more unresolved symbols requiring further searching of the libraries.

.. index:: strip library

A library of executable object files built by the RTEMS Tool suite can contain
debug information and this should be stripped before loading on to the
target. The tool suite's command :program:`strip` can strip all the object files
in a library with a single command.

.. code-block:: none

  $ sparc-rtems@rtems-ver-major@-strip libc.a

Large Memory
------------

The RTEMS link editor supports large memory relocations. Some architectures have
instructions where the relative branch or jump offset from the instruction to
the target address is limited. These instructions provide improved performance
because less code generated compared to larger instructions which contain full
address space references. The compact code helps lower cache pressure as well
and providing improved performance for localalized functions and loops. The
compiler defaults to generating the smaller instruction and as the final address
map not known when generating the code, linkers need to provide glue code to
extend the small address range to the enitre address space. This is called a
trampoline. A trampoline is transparent to the execution of the code.

The link editor parses an executable object file's relocation records to
determine the number of trampolines needed. Added to this value are all
unresolved symbols present in an executable object file after it is
loaded. There is a slot allocated even if the symbol ends up being within range
as there is no way to determine a symbol's address until it is loaded and the
range calculated.

The trampoline table is allocated a separate block of memory to the executable
object file's text, data and constants memory. The trampoline parsing requires
the executable object file's instructions (text) be in memory as the
instructions are inspected by the architecture specific relocation support to
determine an instruction's range. As a result the allocation for the trampoline
table has to occur after the text memory has been allocated. Most instructions
have relative offsets and the trampoline table is allocated at one end limiting
the size of an object to half the maximum range.

Trampolines support is available for the ARM and PowerPC architectures. The
SPARC and Intel x86 architectures do not need trampolines and MIPS needs support
added.

Allocator
---------

The RTEMS link editor supports custom allocators. A custom allocator lets you
manage the memory used by the RTEMS link editor as it runs. Allocators could
provide:

#. Support for the various types of memory that can be allocated allowing
   specialised target support for specific use cases.
#. Locking of read-only memory. The link editor unlocks read-only memory when it
   needs to write to it.
#. Separation of memory holding code and data from the heap.

The allocator can be hooked using the ``rtems_rtl_alloc_hook`` call before any
calls to :ref:`dlopen() <dlopen>` are made. The hook call returns the current
allocate allowing the allocators to be chained.

The default allocator uses the heap.

.. _rtems_rtl_alloc_tags:
.. index:: rtems_rtl_alloc_tags

The allocator tags specify the type of memory the allocator is handling. The tag
used to allocate memory at an address must be used when making allocator
calls. The ``rtems_rtl_alloc_tags`` are:

 .. index:: RTEMS_RTL_ALLOC_OBJECT

 ``RTEMS_RTL_ALLOC_OBJECT``
  Allocate a generic object. The link editor uses this memory for data
  structures it uses to manage the linking process and resident executable
  object files.

 .. index:: RTEMS_RTL_ALLOC_SYMBOL

 ``RTEMS_RTL_ALLOC_SYMBOL``
  Allocate memory to hold symbol data.

 .. index:: RTEMS_RTL_ALLOC_EXTERNAL

 ``RTEMS_RTL_ALLOC_EXTERNAL``
  Allocate memory for unresolved external symbols.

 .. index:: RTEMS_RTL_ALLOC_READ

 ``RTEMS_RTL_ALLOC_READ``
  Allocate memory for read-only data such as constants and exception tables.

 .. index:: RTEMS_RTL_ALLOC_READ_WRITE

 ``RTEMS_RTL_ALLOC_READ_WRITE``
  Allocate memory for read-write data such as a initialised, uninitialized and
  common variables.

 .. index:: RTEMS_RTL_ALLOC_READ_EXEC

 ``RTEMS_RTL_ALLOC_READ_EXEC``
  Allocate memory for code to be executed in. The address space is configure for
  read and execute.

.. _rtems_rtl_alloc_cmd:
.. index:: rtems_rtl_alloc_cmd

The commands are used to control the action the allocator performs. The
``rtems_rtl_alloc_cmd`` are:

 .. index:: RTEMS_RTL_ALLOC_NEW

 ``RTEMS_RTL_ALLOC_NEW``
  Allocate memory of the ``tag`` type. Returns ``NULL`` if the allocation fails.

 .. index:: RTEMS_RTL_ALLOC_DEL

 ``RTEMS_RTL_ALLOC_DEL``
  Delete a previous allocation freeing the memory. The ``tag`` has to match
  address of the memory being deleted.

 .. index:: RTEMS_RTL_ALLOC_WR_ENABLE

 ``RTEMS_RTL_ALLOC_WR_ENABLE``
  Enable writes to a region of memory previously allocated. The ``tag`` has to
  match the address of the memory being write enabled. The link editor may call
  issue this command for memory that is already write enabled.

 .. index:: RTEMS_RTL_ALLOC_WR_DISABLE

 ``RTEMS_RTL_ALLOC_WR_DISABLE``
  Disable writes to a region of memory previously allocated. The ``tag`` has to
  match address of the memory being write disabled. The link editor may call
  issue this command for memory that is writable and not to be write
  disabled. The allocator need to manage this case.

.. _rtems_rtl_allocator:
.. index:: rtems_rtl_allocator

The allocator handler is a single call to handle all allocator requests. The
handler called on evey allocation action made by the link editor. The type of
the function you need is:

.. code-block:: c

 typedef void (*rtems_rtl_allocator)(rtems_rtl_alloc_cmd cmd,
                                     rtems_rtl_alloc_tag tag,
                                     void**              address,
                                     size_t              size);


The arguments are:

``cmd``
 The command to action. See `rtems_rtl_alloc_cmd <rtems_rtl_alloc_cmd_>`_.

``tag``

 The type of memory the command is for. The ``tag`` must match the
 address for commands other than ``RTEMS_RTL_ALLOC_OBJECT``.  See
 `rtems_rtl_alloc_tags <rtems_rtl_alloc_tags_>`_.

``address``
 Pointer to the address. This is set of the ``RTEMS_RTL_ALLOC_OBJECT`` command
 and read for the other commands. The ``tag`` must match the address for
 commands that read the address from the pointer.

``size``
 The size of the memory to allocate. This is only valid for the
 ``RTEMS_RTL_ALLOC_OBJECT`` command.

The call to hook the allocator is:

.. code-block:: c

 rtems_rtl_allocator rtems_rtl_alloc_hook (rtems_rtl_allocator handler);

The current allocator is returned. You can provide a full allocator or you can
filter commands.

Languages
---------

C is supported.

C++ is supported. Initializer functions are called when an object is loaded and
finalizer functions are called before it is unloaded and removed. Static
constructions are initializer functions and static destructors are finalizer
functions.

C++ exceptions are handled across modules. The compiler generated exception
tables present in an executable object file are registered with the architecture
specific mechanism when loaded and deregistered when unloaded. An exception
thrown in loaded code can be caught in the base image or another loaded
module. If you are using C++ and exceptions it is recommended some exception
code is added to the base image to place the architecture specific support in
the base image.

Thread Local Storage
--------------------

Thread local storage (TLS) is currenly not supported by the RTEMS link
editor. The RTEMS executive needs to have a special allocator added to manage
dynamically allocating TLS variables in a thread.

If you need TLS support in dynamically loaded code please consider the RTEMS
support options.

Architectures
-------------

The following architectures are supported:

 - AArch64
 - ARM
 - Blackfin
 - H8300
 - Intel x86 (i386)
 - LM32
 - M68K
 - MIPS
 - Moxie
 - PowerPC
 - SPARC
 - V850

AArch64
^^^^^^^

The AArch64 relocation backend supports veneers which is trampolines.

The veneer implementation is two instructions and a 64bit target address
making the overhead 16 bytes for each veneer. The performance overhead is two
instructions.

ARM
^^^

The ARM relocation backend supports veneers.

The veneer implementation is a single instruction and a 32bit target address
making the overhead 8 bytes for each veneer. The performance overhead is a
single instruction.

PowerPC
^^^^^^^

The PowerPC relocation backend support trampolines and small data.

The trampoline is four instructions and uses register 12 which the PowerPC ABI
reserves for scratch use. The implementation loads the counter register and
branches to the address it contains. The trampoline size is 16 bytes. The
performance overhead is four instructions.

The PowerPC relocation backend also supports small data. The sections of an
executable object file are parsed and small data are tagged as needing
architecture specific allocations. These sections are not allocated as part of
the standard section allocation. Small data sections are allocated in the global
small data region of memory. The size of this region is defined in the BSP's
linker command file by setting ``bsp_section_small_data_area_size`` variable:

.. code-block:: c

 bsp_section_small_data_area_size = 65536;

The maximum size of the small data region is 65536 bytes. It is recommended code
built for loading uses the same settings for small base as the base image.