HOW TO LINK A SYSTEM EXECUTABLE Till Straumann, , 2003/7/22 COPYRIGHT/LICENSE: EPICS Open License, see LICENSE file which must be distributed with this README 1. INTRODUCTION =============== Runtime loading is still quite new to RTEMS. For a traditional application, the linker just puts all the required parts from various libraries (from libbsp to libc) into the final executable. This doesn't work for a system which wants to support runtime loading, because e.g. parts of the C library, which are unused at linkage time, might be needed _later_, when new code is loaded. Therefore, the 'system' executable must contain all relevant parts of basic components/libraries. The decision which parts are to be considered 'relevant' and hence should be included in the 'system' executable shall be termed "system configuration". This "system configuration" is in addition to normal RTEMS configuration (i.e. configuring the size of certain tables, networking etc. which are coded in 'config.c' and 'rtems_netconfig.c') and it is achieved by using linker scripts, Makefile rules and a special tool, 'ldep', to enforce linkage of symbols which otherwise would not be referenced. 1.1 MORE ABOUT SYSTEM CONFIGURATION = = = = = = = = = = = = = = = = = = Objects linked into the generic system can be divided into two disjunct sets. The "application" or "mandatory" set and an "optional" set. The "application" set comprises all objects that would go into a normal/traditional link of the application. A linker error would result if any of the "application" objects would not be present. The "optional" set of objects contains all object files (i.e. library members) the user wants to add to the generic system and on which run-time loaded code might depend. Unfortunately, constructing the "optional" set is not as simple as just throwing in 'everything' from a library such as 'libc.a'. Many libraries contain 'dead' objects that are e.g. the result of porting a library to RTEMS (most notably BSD networking). The bad thing about 'dead' objects is that they may contain 'dangling' references to symbols not defined anywhere. Normally, this is not a problem because the 'dead' object in question is never linked. If it is forcibly thrown into a link, however, a linker error may result due to unresolved references. In order to keep changes against the original code minimal, the RTEMS maintainers often decided to leave specific code in ported libraries although it references unimplemented system calls (often UNIX or BSD specific things) or is otherwise unsupported (e.g. RTEMS claims POSIX but not BSD compliance). Such "dead" library routines must not be used under RTEMS and hence linkage must not be enforced. Another example are 'driver' libraries which may reference BSP specific code that is not present on every BSP. Again, this only becomes a problem when trying to forcibly link a driver that is normally not meant to be used by a particular BSP. Hence, proper system configuration involves the following steps: a) Select a set of libraries. This must be a superset of the libraries needed by the generic system application itself. b) The set of all objects contained in all the libraries is divided into the "application" or "mandatory" and the "optional" set. c) All "optional" objects which directly or indirectly have unresolved symbol references are removed from the "optional" set. d) A user supplied "exclude list" of unwanted "optional" objects is removed from the "optional" set. e) Everything referencing anything on the "exclude list" must be removed from the "optional" set - otherwise, the linker would eventually still pull in unwanted pieces. Consider e.g. the "optional" set containing 'a.o', 'b.o' and 'c.o', where 'a.o' needs/depends on 'b.o'. If the user decides that 'b.o' should be excluded from the "optional" set, 'a.o' must be removed along with 'b.o'. The most difficult steps are: b) [because it is not obvious what pieces are indirectly referenced by the application and hence how to split "optional" from the "mandatory" set], c) [because it is hard to track dependencies] and e) [for the same reason]. (Actually, the order or c) and d) can be reversed and c) then be merged with e).) Because dependency analysis is a teadious task, the 'ldep' tool was created to perform steps b), c) and e) for us. All the user needs to do is a) provide a list of libraries to be added to the system d) provide an 'exclusion' list of objects to be removed from the optional link set. 1.2 COMPOSE A LIST OF OPTIONAL LIBRARIES = = = = = = = = = = = = = = = = = = = = = By default, GeSys links in as much as it can from any library it knows of: A) Core libraries added by the compiler driver: libgcc, libc, libstdc++, librtemscpu, librtemsbsp B) Libraries needed by GeSys libcexp, libbfd, libspencer_regexp, libopcodes, libiberty, libtecla_r, libbspExt, C) Optional libraries (by default): libm, librtems++ The set 'C)' may be modified by editing 'Makefile', where the variable 'OPT_LIBRARIES' is set. The default setting is OPT_LIBRARIES = -lm -lrtems++ Just add more libraries as needed using the usual '-l' flag. 1.3 CREATE LISTS OF OBJECTS TO BE EXCLUDED FROM THE OPTIONAL SET = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = The Makefile looks for files with an '.excl' extension in the 'config' subdirectory. An 'exclude list' lists object files, one per line, with a colon (':') appended (no space), e.g: objecta.o: unneeded.b: Note that lines not terminating in a ':' are ignored! (This is actually a feature, see below...). Because it is possible for objects with identical names to be present in different libraries, the object file name can be qualified by the library name: libxxx.a[objecta.o]:/* C-style comments are OK */ The 'exclude list' file may contain restricted C-style comments, the restriction being that a comment must not break words, i.e. hello.o/* this is an ILLEGAL comment */: Multiline comments are OK, however. The syntax of 'exclude list files' makes it possible to use symbol listings generated with the 'nm -g -fposix' utility as they are used by the 'ldep' tool verbatim as an exclude list! Name lists of all libraries are generated automatically in the 'o-optimize' subdirectory during the build process. However, you may explicitely generate these name lists by running gmake libnms thus generating a bunch of 'o-optimize/libxxx.nm' files. Hence, if you want to exclude all optional parts of a particular library, let's say, the 'libbfd.a' library, you can simply copy 'o-optimize/libbfd.nm' to 'config/libbfd.excl' - that's it. Even if you want to only exclude dedicated objects from a library, it is probably a good idea to copy the library's '.nm' file to 'config/yyy.excl' and comment/delete the _wanted_ parts. Recent versions of RTEMS only build two huge libraries 'librtemscpu.a' and 'librtemsbsp.a'. This is unfortunate, because it makes it more tedious to eliminate unwanted pieces. A small RTEMS patch (available in this directory; NOTE: RTEMS must be configured with --enable-maintainer-mode and you must have a recent version of the RTEMS-required autotools: rerunning the 'bootstrap' script after applying the patch is required! --------------------------------------------------------------------- ) will cause the RTEMS build process to install 'nm' files for the individual libraries 'librtemsbsp/librtemscpu' are composed of. You may generate 'exclude lists' from those 'nm' files by copying and editing them. Read the APPENDIX if you cannot or do not want to patch the RTEMS 'Makefile.am's. 1.4 HOW TO DEAL WITH 'multiple defined symbol' ERRORS = = = = = = = = = = = = = = = = = = = = = = = = = = = Multiply defined symbols are more serious issue. In fact, they must be considered a bug. You get these errors by forcefully triggering a 'sleeping name clash'. Some contributed code (which unfortunately has been made part of librtemscpu/librtemsbsp - the aforementioned patch also takes care of removing the worst from librtemscpu/bsp: 'libnetapps' [pppd, telnetd, httpd]') defines very bad symbols such as 'debug, drand48' which are either part of the C library already or prone to clashing otherwise. (The affected code was most likely ported from unix to RTEMS - in the single-process unix environment, these symbols were not a problem). There is no clean way to deal with name clashes. You must resolve them by renaming or removing one of the offending definitions. 1.5 FINAL NOTES = = = = = = = = The SSRL system application does not include the following libraries: - libblock [and depending libdosfs] (unused and at some time in the past I didn't like the implementation with possible negative impact on real-time [task dispatching] latencies). - libchip (and related libserialio, libnetchip) for the aforementioned reason. - libmisc parts of the monitor are used by a loadable module which is directly linked against libmisc - libnetapps contains a lot of name clashes and other unused things. We use our own variant of telnetd as a loadable module. All the stuff in this library does not belong into RTEMS core. It is a good idea to revise the scripts tuned so far and eliminate EXTERN()s for symbols which do not seem to belong into the system - YMMV. APPENDIX ======== What if I don't have 'nm' files for the individual libraries 'librtemsbsp/cpu' are assembled of? You might find them in the 'build' tree. Look into '/c//wrapup/Makefile' and /c//exec/wrapup/Makefile' for where the individual pieces come from. Also, if you are unable to apply the original patch (which tweaks the Makefile.am files in the source tree), you can simply hack the Makefiles: 1) in '/c//wrapup/Makefile, after install-data-local: @$(mkinstalldirs) $(DESTDIR)$(bsplibdir) $(INSTALL_DATA) $(LIB) $(DESTDIR)$(bsplibdir) add the lines (note that there must be NO empty line in between and that the first of the added lines MUST start with a 'tab' character and that there MUST be NO empty space after the trailing '\' chars): for instlib in $(SRCS) $(EXCLUDED); do \ $(NM) -g -fposix $$instlib | \ sed -e '/^.*lib[^.]*[.]a[[].*]:$$/s%^.*lib.*[.]a[[]%$(notdir $(LIB))[%' \ > $(DESTDIR)$(bsplibdir)/`basename $$instlib .a`.nm \ ; done 2) in '/c//exec/wrapup/Makefile, after install-data-hook: $(LIB) @$(mkinstalldirs) $(DESTDIR)$(libdir) $(INSTALL_DATA) $(LIB) $(DESTDIR)$(libdir) add the lines (observing the same rules as under 1) for instlib in $(LIBS) ; do \ -g -fposix $$instlib | \ sed -e '/^.*lib[^.]*[.]a[[].*]:$$/s%^.*lib.*[.]a[[]%$(notdir $(LIB))[%' \ > $(DESTDIR)$(libdir)/`basename $$instlib .a`.nm \ ; done Note that you have to substitute your 'cross-nm' program here, e.g. i386-rtems-nm