Menu
Is free
registration
home  /  Internet/ Illustrated tutorial on Macromedia Flash MX. Flash soname shared library

Illustrated tutorial on Macromedia Flash MX. Flash soname shared library

Earlier we mentioned shared libraries as one of the advantages of paging and segment memory managers over basic and bank managers. In basic addressing, the image of each process must occupy contiguous areas in both the physical and logical address space. Under these conditions, it is impossible to implement the shared library. But even when using page addressing, things are not so simple.

The use of shared libraries and / or DLLs (in this case, the difference between them is not fundamental) presupposes some form of assembly at the time of loading: the executable module has unresolved address references and the names of the libraries it needs. When loaded, these libraries are loaded and links are resolved. The problem here is that when loading a library, it needs to be moved by reconfiguring absolute address references in its code and data (see Chapter 3). If in different processes the library is configured to different addresses, it will no longer be shared (Fig. 5.14)! If shared libraries may have unresolved links to other libraries, the problem is only exacerbated by adding external links to the relocatable links.

Rice. 5.14... Conflicting DLL mapping addresses

On older Unix systems that used absolute loadable modules of the format a.out Shared libraries were also shipped in absolute module format, set to fixed addresses. Each library has been set to ITS address. The supplier of the new libraries had to agree on this address with the system developers. This was very impractical, so there were very few shared libraries (especially apart from those that came with the OS).

A more acceptable solution to this problem is implemented in OS / 2 2.x and Win32 (both of these architectures are the development of systems with a single address space). The idea is to allocate an address area for loading DLLs and map this area to the address spaces of all processes. Thus, all DLLs loaded on the system are visible to everyone (Fig. 5.15).

Large programs often require ready-made libraries. A library is a collection of already compiled functions (for example, a math library). The library is requested when linking when the exe-shnik is generated. This is done with the -l option: cc -o badmath badmath.o -lm If you need to specify the path to a non-standard library: cc -o badmath badmath.o -lm -L / usr / junk / lib -lcrud If the library name ends in .a, then it is a static library. When a static library is linked, the linker simply copies whole chunks from it into the generated exe-file, which, as a result, can work autonomously without it. If exe-shnik uses a shared library, then the code is loaded only as needed. Libraries are usually located in the / lib and / usr / lib directories. There should be no static libraries in the / lib directory. The name of the shared library includes the .so prefix. To determine which libraries the program is using, you need to run the command: ldd prog The ld.so loader loads the shared libraries. The path to the library can lie inside the exe-shnik. If it is not there, the loader looks at the /etc/ld.so.cache file, which lists the directories. There is also a /etc/ld.so.conf file. If you manually added the path to the /etc/ld.so.cache file, then you need to run the command: ldconfig -v There is also the LD_LIBRARY_PATH system variable. Adding paths to the /etc/ld.so.conf file is not a good idea. Large libraries go into the system cache and you can get in trouble. The best way is to stitch the path to the library in exe-shnik: cc -o myprog myprog.o -Wl, -rpath = / opt / obscure / lib -L / opt / obscure / lib -lweird With the growth of shared libraries, problems with them are possible due to overlapping, etc. Using LD_LIBRARY_PATH is also problematic. A script can be used instead: LD_LIBRARY_PATH = / opt / crummy / lib export LD_LIBRARY_PATH exec / opt / crummy / bin / my_prog [email protected] The main compilation tool in Unix is ​​make. The most detailed description is given in The UNIX Programming Environment or in Managing Projects with make... Make always has a target - target - which can be either a file or a label. The goal can be primary and secondary. To build a target, make looks for rules. For instance: OBJS = aux.o main.o # object files all: myprog myprog: $ (OBJS) $ (CC) -o myprog $ (OBJS) The first target - all - is the main one by default. The rule for it is myprog, which can be another rule, another target, or a file. OBJS is a macro for building a target. This makefile will produce the following output: cc -c -o aux.o aux.c cc -c -o main.o main.c cc -o myprog aux.o main.o make can be run in conjunction with command options, for example: make aux.o Make options: -n -f Frequently used macros: CFLAGS - compiler options LDFLAGS - linker options make has several standard targets: clean distclean install test depend Makefile usually starts with either and includes, for example: X_INCLUDES = -I / usr / X11R6 / include X_LIB = -L / usr / X11R6 / lib -lX11 -Xt NG_INCLUDES = -I / usr / local / include PNG_LIB = -L / usr / local / lib -lpng Next are the options for the compiler and linker CFLAGS = $ (CFLAGS) $ (X_INCLUDES) $ (PNG_INCLUDES) LDFLAGS = $ (LDFLAGS) $ (X_LIB) $ (PNG_LIB) Then the source code can be listed: UTIL_OBJS = util.o BORING_OBJS = $ (UTIL_OBJS) boring.o TRITE_OBJS = $ (UTIL_OBJS) trite.o PROGS = boring trite And only now there are goals and rules: all: $ (PROGS) boring: $ (BORING_OBJS) $ (CC) -o [email protected]$ (BORING_OBJS) $ (LDFLAGS) trite: $ (TRITE_OBJS) $ (CC) -o [email protected]$ (TRITE_OBJS) $ (LDFLAGS) Shared libraries are a fundamental component of the Unix system. The standard C-library for example on Suse 9.1 is 1.3 MB in size. A copy of this library for all programs that use it in / usr / bin will take more than one gigabyte. Such libraries require not only disk space, but also memory. The kernel is designed to keep one copy of the shared library in memory. It should be remembered that when statically linking, the library code is statically added to the executable file code, and when you run it, we do not need the library - its code is already linked during compilation to the body of the executable file. With dynamic linking, the shared library is linked at runtime.
Dynamic linking is the predominant type of linking libraries. The standard library alone consists of over a thousand system calls. For really working programs, the so-called. Procedure Linkage Table (PLT) is a table consisting of calls to functions called from shared libraries. The first problem that can arise with this is a compatibility issue. With static compilation, this problem is solved at compile time. With dynamic linking, there is no such guarantee, because we can update the shared library after compilation. In this case, the check is the version number - when the dynamic linker tries to link the library, it checks the version number, and if the number does not match, then it is not linked. The version number consists of 2 parts - the major (major) number and the secondary (minor). If the main number is the same, then, as a rule, there should be no problems when loading the library. If we have the libexample.so library, then it will have a link to the version libexample.so.N where N is the major major version number, from which, in turn, there will be a link to libexample.so.N.M where M is the major secondary version number. In this case, the program will search for exactly the version N it needs.
In static libraries, the code is in files with the .a extension. For dynamic libraries, the files have the .so extension. The static library format is generated using the ar utility, and the format is similar to what the tar utility generates. For dynamic libraries on the latest Linux versions, this format is usually ELF binary. It consists of a header and segments, which are divided into sections. When linking, code from static libraries is directly added to the executable file of the program, and links from dynamic libraries are taken and added to the PLT. When loaded, the program loads a dynamic linker that loads the required libraries. When dynamically linking a program, you can add paths to search for libraries at compile time. For gcc, this syntax looks like -Wl, -R / path If the program is already linked, you can use the LD_LIBRARY_PATH variable. You can also run a special wrapper script before starting the program that specifically configures the library directories, as is done, for example, when starting Mozilla. The dynamic linker accesses the /etc/ld.so.conf config, which includes a directory listing. But first, the linker accesses LD_LIBRARY_PATH. ldd (list dynamic dependencies)- utility for debugging shared libraries. It lists the shared libraries for a given module, for example: ldd / bin / sh linux-gate.so.1 => (0xffffe000) libreadline.so.4 => /lib/libreadline.so.4 (0x40036000) libhistory.so.4 => /lib/libhistory.so.4 (0x40062000) libncurses.so.5 => /lib/libncurses.so.5 (0x40069000) libdl.so.2 => /lib/libdl.so.2 (0x400af000) libc.so.6 => / lib / tls /libc.so.6 (0x400b2000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
  • For Newbies: Linux Journal article "Linkers and Loaders" by Sandeep Grover
  • The book "Linkers and Loaders" manuscript online.
  • Recommended also 2002 by Ulrich Drepper titled "How to write shared libraries" (pdf). Slides (pdf), and a script mentioned in the slides

Building a shared library

Let's write a small library that does nothing, almost nothing, besides "hello world". First object:

/ * print1.c * / #include void print1 (void) (printf ("1 \ n");)

Similarly, the second object:

/ * print2.c * / #include void print2 (void) (printf ("2 \ n");)

Let's compile:

gcc -Wall -g -c -fpic print1.c gcc -Wall -g -c -fpic print2.c

Create a shared library:

gcc -shared -Wlsoname = libprint.so.1 -g \ -o libprint.so.1.0.1 print1.o print2.o

We make a link to the library:

ln -sf libprint.so.1.0.1 libprint.so

In order for others to be able to use this library, you need to write a header:

/ * print.h * / #ifndef PRINT_H #define PRINT_H void print1 (void); void print2 (void); #endif

Let's write a test program:

/ * print.c * / #include "print.h" int main () (print1 (); print2 (); return 0;)

Let's compile it:

gcc -Wall -g -L. -lprint -o print print.c

To run the program, the linker needs to tell where the library is located:

Overloading functions

Before loading a library, we can always tell the loader where to start searching and loading it.

Let's add a new function to the library we just wrote. This function is named fopen.

/ * fopen.c * / #include FILE * fopen (const char * fn, const char * mode) (printf ("fopen called \ n"); return NULL;)

Let's compile this function and put it in the library:

gcc -Wall -g -c -fpic fopen.c gcc -shared -Wlsoname = libprint.so.1 -g \ -o libprint.so.1.0.2 print1.o print2.o fopen.o ln -sf libprint.so .1.0.2 libprint.so

Let's write a program for testing:

/ * print-2.c * / #include int main () (FILE * f; f = fopen ("abc", "r"); if (f == NULL) (printf ("1");) else (printf ("2"); fclose (f);) return 0;)

Let's compile this program:

gcc -Wall -g -o print print.c

We must launch it with the following prefix:

LD_PRELOAD =. / Libprint.so ./print

If something is done wrong, the line will be displayed: fopen called

The process of creating a program.

Translation into Russian: Vladimir Popov

Today, in a constantly evolving environment, the software development process is a product of the evolution of skills and experience developed by programmers and developers.

This process consists of the following steps:

    Generating high-level language source code in a text editor. If we try to fit a very large program into one file, it becomes difficult to manage. For this reason, the source code is split into functional modules that are created from one or more source code files. The source code in these modules may not necessarily be written in the same language, as some languages ​​are better suited to solving a specific problem than others.

    After the files with the source code of the program have been created, they must be translated into blocks of code that can be executed by the machine. This code is usually referred to as object code... This code performs the same actions as the original code, except that it is written in a special language that can be directly executed by the machine. The process of translating source code into object code is known as compilation... Compilation is done in parts and compiles (depending on the compiler) part of the program and usually one or more files in one go. The compiled object code contains a program, subroutine, variables, etc. - the parts of the programs that have been translated and are ready for the next step.

    After all the program files with machine code have been created, they must be connected or linked using an operation performed by a special utility called linker... At this stage, all references that the module's code makes to code belonging to another module are "resolved" (such as calling a subroutine or references to variables owned or defined in another module). The resulting product is a program that can be directly loaded and executed.

    The execution of a program is carried out by a special kind of software, which is an essential part of the operating system, in the case of Linux it is the exec () system call. This function finds the file, allocates memory to the process, loads certain portions of the file's content (containing code and initial variable values), and transfers control to the processor at the "text" point in the program, which usually points to the executable itself.

2.- Brief history of the process of creating the program.

The process of creating a program is constantly evolving, it is necessary to achieve the most efficient execution of programs or the best use of system resources.

At the beginning, programs were written directly in machine code. Later it became clear that it was possible to write programs in a higher-level language, since the subsequent translation into machine code could be automated due to the systematic nature of translation. This increased the performance of the programs.

After learning how to compile programs (I simplified the evolution of compilation, in fact it was a very difficult step, since it is a very complex process), the process of creating programs began to consist of creating a file with the source code of the program, compiling it, and ultimately executing it.

It was soon noticed that the compilation process is very laborious and takes up a lot of resources, including machine time, and that many of the functions included in these programs were used over and over again in various programs. Moreover, when someone changed a part of the program, compiling the inserted code meant compiling the entire source code again, including a new translation of all the unchanged code.

For this reason, modular compilation began to be used. Its meaning was to divide the program into, on the one hand, the main program and, on the other hand, those functions that were often used over and over again and that had already been compiled and stored in a special place (we will call this the predecessor of the library).

Then it became possible to develop programs that support these functions without spending extra effort to code them over and over again. Even then, the process was complicated due to the fact that when linking programs, it was necessary to combine all the parts and they had to be known to the programmer (this introduced additional costs for checking the possibility of using a known function that uses / requires other unknown functions).

3.- What is a library?

The problem described above led to the creation of libraries. This is nothing more than a special kind of file (to be precise, an archive, tar (1) or cpio (1)) with special parameters, the format of which the linker understands, and when we point it to a library archive, the LINKER CHOOS ONLY THOSE MODULES WHICH NEEDED PROGRAM and excludes everything else. A new advantage has emerged. Now it was possible to develop programs that use large libraries of functions, and the programmer did not need to know all the dependencies of the functions in that library.

The libraries that we have discussed so far have not gone further in development. They just added a file, often found at the beginning of the archive, containing module descriptions and identifiers that the linker must resolve without reading the entire library (and thus eliminating the need to read the library multiple times). This process (adding the symbol table to the library archive) in Linux is performed by the ranlib (1) command. The libraries so far described are known as STATIC LIBRARIES.

Progress happened after the first multitasking system appeared: splitting code... If two copies of the same code were running on the same system, it would be desirable for both processes to be able to share the same code, since a program does not usually modify its own code. This idea eliminates the need to allocate multiple copies in memory, which frees up a lot of memory on huge multi-user systems.

Taking this last innovation one step further, someone (I don't know who it was, but the idea was great ;-) thought that very often many programs use the same library, but, being different programs, parts of the used the libraries were not necessarily the same parts used by another program. Moreover, the main code was different (they are different programs), so their texts were not shared. Well, our hero thought that if different programs using the same library could share this library among themselves, then we could gain some memory. Now different programs, having different text, work with the same library code.

However, the process has now become more complicated. The executable program is not fully linked, but resolution of library identifier references is deferred until the program is loaded. The linker (ld (1) in the case of Linux) recognizes shared library calls and does not include their code in the program. The system itself, the kernel, when executing exec () recognizes the launch of a program using shared libraries and executes special code that loads shared libraries (allocating shared memory for their text, allocating private memory for library values, etc.). Now this process is performed when loading the executable file and the whole procedure has become much more complicated.

Of course, when the linker encounters a regular library, it continues to behave as before.

A shared library is not an archive containing the object code, rather it is a file that contains the object code itself. When linking a program with a shared library, the linker does not examine the library, which modules should be added to the program and which should not. It only makes sure that unresolved links become resolved, and determines what needs to be added to the list when the library is included. It is possible to make an archive ar (1) library of all shared libraries, but this is often not done, since shared libraries are often the result of linking different modules, so the library will be needed later, at runtime. Perhaps the name shared library is not the most appropriate and it would be more accurate to call it a shared object (however, since we may not be understood, we do not use this term).

4.- Types of libraries.

As we said, there are two kinds of libraries in Linux: static and shared. Static libraries are a collection of modules that are combined into an archive using the ar (1) utility and indexed with the ranlib (1) utility. These modules are often stored in a file ending with .a (I don't use the term extension because Linux doesn't use the concept of file extension). The linker recognizes the end of the .a file and starts looking for modules as if it were a static library, and selects and adds to the program those modules that resolve unresolved references.

Unlike static libraries, shared libraries are not archives, but relocatable objects, designated by special code (which designates them as shared libraries). The ld (1) linker, as already mentioned, does not add modules to the program code, but selects the identifiers provided by the library as allowed, adds those that are required by the library itself, and continues to work without adding any code, assuming that the required code has already been added to the main code. The ld (1) linker recognizes shared libraries by ending with .so (not .so.xxx.yyy, we will discuss this later).

5.- The linking process in Linux.

Each program consists of object modules linked into an executable file. This is done by the ld (1) linker used in Linux.

ld (1) supports various options that change its behavior, but we will limit ourselves here to only those related to the use of libraries in general. ld (1) is not called directly by the user, but by the gcc (1) compiler itself at its final stage. Little knowledge about him modus operandis help us understand the way to use libraries in Linux.

For ld (1) to work properly, it needs a list of objects to link with the program. These objects can be specified in any order (*) as long as we follow the above convention, as already mentioned, the shared library is recognized by the ending .so (not .so.xx.yy) and the static library by .a (and of course simple object files are those whose name ends in .o).

(*) This is not entirely true. ld (1) includes only those modules that resolve links at the time of inclusion of the library, so a module included later may still have a link that later, since it does not appear at the time of inclusion of this library, can cause a command to include the necessary libraries ...

On the other hand, ld (1) allows standard libraries to be included thanks to the -l and -L options.

But ... What do we mean by the standard library, what is the difference? No. Only that ld (1) looks for standard libraries in certain places, while those described in the parameter list as objects are searched for by their filenames.

By default, libraries are searched for in the / lib and / usr / lib directories (although I've heard that depending on the version / implementation of ld (1), there may be additional directories). -L allows us to add directories to those searched by a normal library search. It is used by specifying -L directory for each directory we want to add. Standard libraries are specified with the -l Name option (where Name specifies the library to load) and ld (1) will search, in appropriate order, in the appropriate directories for a file named libName.so. If it is not found, an attempt will be made to find libName.a, its static version.

If ld (1) finds libName.so, it will link it as a shared library, whereas if it finds libName.a, it will link modules derived from it if they resolve any unresolved references.

Dynamic linking is performed when the executable is loaded by a special module (in fact, this special module is the shared library itself) called /lib/ld-linux.so.

There are actually two modules for linking dynamic libraries: /lib/ld.so (for libraries using the old a.out format) and /lib/ld-linux.so (for libraries using the new ELF format).

The peculiarity of these modules is that they must be loaded every time a program is dynamically linked. Their names are standard (the reason is that they cannot be moved from the / lib directory, and also their names cannot be changed). If we change the name /etc/ld-linux.so, then we will automatically stop using any program that uses shared libraries, since this module is responsible for resolving all links that are not resolved at runtime.

The last module is aided by the existence of the /etc/ld.so.cache file, which specifies for each library the most appropriate executable that contains that library. We will come back to this topic later.

7.- soname. Executable library versions. Compatibility.

This brings us to the most confusing topic of shared libraries: their versions.

We often see the message "library libX11.so.3 not found," which leaves us confused: having the libX11.so.6 library, we are unable to do anything. How is it possible that ld.so (8) recognizes libpepe.so.45.0.1 and libpepe.so.45.22.3 interchangeably and does not recognize libpepe.so.46.22.3?

On Linux (and on all operating systems using the ELF format), libraries are identified by their distinctive character sequence: soname.

soname is included in the library itself, and this sequence is determined when linking the objects that make up the library. When creating a shared library, to give a value to this character string, you must pass the ld (1) option (-soname<имя_библиотеки>).

This character sequence is used by the dynamic loader to identify the shared library to be loaded and to identify the executable. It looks something like this:
Ld-linux.so detects that the program requires a library and defines its soname. Then the name is searched in /etc/ld.so.cache and the name of the file containing this library is determined. Next, the requested soname is compared with the name of the existing library, and if they are identical, then we need it! If not, the search will continue until it is found, or if it is not found, an error message will be displayed.

The soname can be used to determine if the library is suitable for loading, because ld-linux.so checks if the required soname is the same as the required file. In case of difference, we can get the famous "libXXX.so.Y not found". It is the soname that is looked for and the error returned is determined by the soname.

If we change the name of the library, there can be a lot of confusion and the problem itself remains. But changing the soname is also not a good idea, because there is a convention in the Linux community for assigning soname:

The soname of a library, by default, should identify the corresponding library and the INTERFACE of that library. If we make changes to the library that affect only the internal functionality, but the interface remains unchanged (number of functions, variables, function parameters), then the two libraries will be interchangeable and in general we will say that the changes were minor (both libraries are compatible and we can replace one on top of the other). If this happens, then the minor number (which is not part of the soname) changes frequently and the library can be replaced without significant problems.

However, when we add functions, remove functions and, in general, CHANGE the INTERFACE of the library, it is no longer possible to say that this library is interchangeable with the previous one (for example, replacing libX11.so.3 with libX11.so.6 is part of the transition from X11R5 to X11R6, when this introduces new functions and therefore changes the interface). Moving from X11R6-v3.1.2 to X11R6-v3.1.3 will probably not change the interface and the library will have the same soname - although to keep the old version we need to give it a different name (for this reason, the version number ends the library name , whereas only major numbers are specified in the soname).

8.- ldconfig (8)

As we said earlier, /etc/ld.so.cache allows ld-linux.so to convert the soname of the file contained in the library. This is a binary (for efficiency) file generated by the ldconfig (8) utility.
ldconfig (8) creates a symbolic link with the library name soname for each DLL found in the directories specified in /etc/ld.so.conf. In this case, when ld.so wants to get the name of a file, what it does is select the file with the required soname from the directory list. And so there is no need to run ldconfig (8) every time you add a library. We only run ldconfig when we add a directory to the list.

9.- I want to make a dynamic library.

Before we start creating a dynamic library, we must think about whether it is really necessary. Dynamic libraries cause system overload for several reasons:
    Loading the program is carried out in several stages; one for loading the main program, the rest for each dynamic link library that this program uses (we will consider this for the corresponding dynamic link library, since this last point is no longer a rarity and becomes an advantage).

    DLLs must contain relocatable code because the address allocated to a process in virtual address space is unknown until loaded. In this case, the compiler is forced to reserve a register to store the loading position of the library and, as a result, we have one register less to optimize the code. This is not such a problem, since the resulting overload in most cases is no more than 5% overload.

For a dynamic library, the most acceptable case is when it is constantly used by some program (this helps to avoid unloading the library text after the termination of the process that loaded it. While other processes use the library modules, it remains in memory).

The shared library is fully loaded into memory (not just the modules it needs), so it must be used in its entirety to be useful. The worst example of using a dynamic link library is using only one function, and 90% of the library is hardly ever used.

The C standard library is a good example of a dynamic link library (it is used by all programs written in C). All functions are used on average.

A static library does not need to include infrequently used functions; as long as they are contained in their own module, they will not be linked with any program that does not require them.

9.1.- Compiling Source Codes
Compiling the source code is exactly the same as with the regular source code, except that we will use the "-f PIC" (position independent the code).

This step is fundamental because in a static library the position of the library objects is resolved during linking, so it takes a fixed amount of time. This step was not possible in the old a.out binaries, which resulted in each shared library being placed at a fixed position in the virtual address space. As a result, conflicts could arise at any time if the program wanted to use two libraries and loaded them into overlapping regions of virtual memory. This meant that you were forced to maintain a list in which everyone who wanted to make the library dynamic had to declare a range of addresses to use so that no one else could use it.

As we already noted, registering a dynamic library in the official list is not necessary, since when the library is loaded, it is placed in the position defined at the moment, despite the fact that the code must be moved.

9.2.- Linking Objects to the Library
After compiling all the objects, they need to be linked by specifying an option that creates a dynamically loadable object. gcc -shared -o libName.so.xxx.yyy.zzz -Wl, -soname, libName.so.xxx shared library. Let's deal with each one separately:
    -shared.
    This tells the linker that in the end it must create the shared library and therefore must contain executable code in the output file corresponding to the library.

    O lib Name.so.xxx.yyy.zzz.
    This is the name of the output file. It is not at all necessary to follow the naming convention, but if we want this library to become a standard for future development, then it is better to follow it.

    Wl, -soname, lib Name.so.xxx.
    The -Wl option tells gcc (1) to follow the options (separated by commas) that are for the linker. This mechanism is used by gcc (1) to pass options to ld (1). In the example, we pass the following options to the linker:

-soname libName.so.xxx This option changes the soname of the library, so this library will be loaded when requested by programs that require the specified soname.
9.3.- Installing the Library
Well, we already have the corresponding executable file. Now, in order to be able to use it, it must be installed in the appropriate location.

To compile a program that requires our new library, we need to use the following command:

Gcc -o program lib Name.so.xxx.yyy.zzz or, if the library was installed in the directory (/ usr / lib), it will suffice: gcc -o program -l Name (if the library is in / usr / local / lib, then just add the option "-L / usr / local / lib"). To install the library do the following:

    Copy the library to / lib or / usr / lib directory. If you choose to copy it to a different location (for example, / usr / local / lib), you cannot be sure that the ld (1) linker will find it automatically when you link your programs.

    Run ldconfig (1) to create a symlink libName.so.xxx.yyy.zzz to libName.so.xxx. At this step, we will know whether we have followed all the previous steps correctly and whether the library is recognized as dynamic. This step only affects the loading of the library at runtime, not the linking of programs.

    In order for the linker to find the library using the -l option, create a symbolic link from libName.so.xxx.yyy.zzz (or libName.so.xxx, soname) to libName.so. For this mechanism to work, the library name must match the pattern lib Name.so

10.- Creating a static library

If, on the other hand, you need to create a static library (or you need two versions to be able to create statically linked copies), then you need to do the following:

Note: When searching for libraries, the linker first looks for a file named libName.so, and only then libName.a. If we call both of these libraries (static and dynamic versions) the same name, in general it will be impossible to determine which of the two will be linked in each case (dynamic is always linked first, since the linker detects it first).

For this reason, if it is necessary to have two versions of the same library, it is always recommended to name the static one in the form libName_s.a, and the dynamic libName.so. Then, when linking, you will need to specify:

Gcc -o program -l Name_s for linking with static version, whereas for dynamic version: gcc -o program -l

10.1.- Compiling the Source Code
You don't have to take any special steps to compile the source code. Likewise, the position of the objects is decided at the link stage, it is not necessary to compile with the -f PIC option (although it is possible to continue to use it).
10.2.- Linking Objects to the Library
No linking is done for static libraries. All objects are archived into a library file with the ar (1) command. Further, in order to quickly resolve symbols, it is advisable to execute the ranlib (1) command on the library. Although not required, failure to execute this command can unlink modules in the executable because when the linker processes the module during library creation, not all indirect dependencies between modules are resolved immediately: say, a module at the end of an archive needs another module in the beginning of the archive, this means that it takes multiple passes through the same library to resolve all links.
10.3.- Installing the Library
It is advisable to name static libraries in the libName.a format only if you want to have only static libraries. In the case of two kinds of libraries, I would recommend calling them libName_s.a so that it is easier to distinguish between when to load a static library and when to load a dynamic library.

The build process allows you to enter the -static option. This option controls the loading of the /lib/ld-linux.so module, and does not affect the library search order, so if someone specifies -static and ld (1) finds a dynamic library, it will work with it (and not keep looking static library). This will lead to run-time errors due to procedure calls in a library that is not part of the executable - the module for automatic dynamic loading is not linked and therefore the process cannot be executed.

11.- Comparison of static and dynamic layout

Suppose we want to create a distribution of a program that uses a library that we can distribute only statically included in the program, and in no other form (an example of this case is applications built using Motif).

There are two ways to create such a program. The first is to create a statically linked executable (using only the .a libraries and not using a dynamic loader). This kind of programs is loaded once and does not require any libraries from the system (not even /lib/ld-linux.so). However, they have the disadvantage that everything you need must be kept in one binary file and therefore these are usually very large files. The second option is to create a dynamically linked program, that is, the environment in which our application will run must have all the corresponding dynamic libraries. The executable can be very small, although sometimes it is impossible to have absolutely all libraries (for example, there are people who do not have Motif).

There is a third option, mixed, in which some libraries are linked dynamically and others statically. In this case, it would be logical to select the conflicting library in its static form and all the others in their dynamic form. This variant is a very common form of software distribution.

For example, you can compile three different versions of a program as follows:

Gcc -static -o program.static program.o -lm_s -lXm_s -lXt_s -lX11_s \ -lXmu_s -lXpm_s gcc -o program.dynamic program.o -lm -lXm -lXt -lX11 -lXmu -lXpm gcc -o program. mixed program.o -lm -lXm_s -lXt -lX11 -lXmu -lXpm In the third case, only the Motif library (-lXm_s) is linked statically, and all others are linked dynamically. The environment in which the program will run must have the appropriate versions of the libraries libm.so.xx libXt.so.xx libX11.so.xx libXmu.so.xx and libXpm.so.xx

Shared library or shared library is a file that is intended to be shared by programs. The modules used by the program are loaded from separate shared objects into memory, rather than copied by the linker when it copies a single executable file for the program.

Shared libraries can be statically linked, which means that references to library modules are resolved and modules are allocated memory when the executable is created. But often linking shared libraries is delayed until they are loaded.

Some older systems like Burroughs MCP Multics also only have one format for executable files, whether or not they are generic. They have shared library files in the same format as executables. This has two main advantages: first, each only requires one bootloader, not two (having a separate bootloader brings additional complexity). Second, it also allows executables to be used as shared libraries if they have a symbol table. Typical formats for combined executable and shared libraries are ELF and Mach-O (both on Unix) and (Windows).

In some older environments like 16-bit Windows or MPE for HP 3000, in code with a shared library, only stack-based (local) data was allowed, or other significant restrictions were imposed on the shared library code.

Shared memory

The library code can be shared in memory with processes, as well as on disk. If virtual memory is used, processes will execute in a physical page of RAM, which maps to different process address spaces. This has its advantages. For example, on the OpenStep system, applications are often only a few hundred kilobytes in size and load quickly; most of their code was in libraries that were already loaded by the operating system for other purposes.

Programs can share RAM using independent code, as in Unix, resulting in a complex yet flexible architecture. This ensures that there is a greater likelihood of sharing through various techniques such as pre-mapping the address space and reserving pages for each shared library. The third option is single-tier storage used by IBM System / 38 and his successors.

In some cases, different versions of shared libraries can cause problems, especially when libraries of different versions have the same file names and are used for different applications installed on the system, each requires a specific version. Such a scenario is known as

A shared library lets you use the symbols it contains in multiple movies without copying those symbols to movie libraries. Because of this, the shared library objects are named resources(Assets). In this case, the shared library is used as an external file and is not added to the created (or edited) movie.

The use of shared libraries is advisable, for example, in the following cases:

  • when using the same soundtrack on several pages of the site;
  • when using text characters of the font on several pages of the site;
  • when you want to provide a single source for animation elements used in multiple scenes in a movie or in multiple movies;
  • when you need to have a central library of resources to make it easier to control the changes you make.

Flash MX supports two types of shared libraries:

  • Run-time- shared runtime library; symbols included in such a library are available for sharing by several films, however, such symbols can only be edited directly in the source film;
  • Author-time- library shared at the time of development; the symbols included in such a library are available for sharing by several films, and it is allowed to edit the contents of the library in any co-owner film.

For the shared library resources to be available in movies hosted on a remote site, the Flash file with the library must be exported to SWF format and uploaded to the Web site.

Comment
Previous version of Flash only supports the shared runtime library
.

To create a shared library like Run-time, necessary:

  1. Determine its resources (symbols included in it) in a separate film.
  2. Allow export of shared characters.
  3. Specify the URL of the site where the library will be hosted.
  4. Export the Flash file with this library to SWF format and upload to the website.

To be able to use shared library symbols Run-time in other films ("co-owners"), it is necessary in each of them to create a link to the shared characters.

Now let's look at the above steps in more detail.

After you create a shared library, you need to specify which included symbols can be exported to other movies. This requires the following steps:

  1. Select the symbol from the list that you want to make "shared".
  2. In the context menu of the symbol, select the command Linking(Binding).
  3. In the opened dialog box Symbol Linkage Properties(Symbol linking parameters), Fig. 10.12, check the box Export for runtime sharing(Allow export at runtime).
  4. In a text box Identifier enter the name (identifier) ​​of the symbol under which it will be exported to the co-owner movie; although the default is the library symbol name, if it contains spaces, remove them.
  5. In a text box Url enter the Internet address of the source movie (that is, the shared library SWF file).
  6. If the exported symbol is to be used directly from the first frame of the co-owner movie, select the Export in first frame.
  7. If you want to make the exported symbol available in ActionScript, select the Export for ActionScript.

Rice. 10.12... Shared Library Symbol Settings Dialog Box

To use shared library resources Run-time in a co-owner film, the following steps are required:

  1. Open the library of this movie by choosing from the menu Window command Library.
  2. From the library drop-down menu, choose the command New Symbol; as a result, a dialog box will appear on the screen Create New Symbol(Create a new symbol), the central part of which is similar in format to the dialog box Symbol Linkage Properties(fig.10.13).
  3. In a text box Identifier enter the name of the symbol to be imported into the co-owner movie.
  4. In a text box Url enter the internet address of the source movie.


Rice. 10.13... Dialog box for setting the parameters of the split character

Static and dynamic libraries.

Libraries are called "collections" of subroutines or objects, as a rule, focused on solving a set of related problems. From the point of view of their organization and use, libraries are static and dynamic.

Static libraries (static libraries) can be a set of source codes, included by the programmer in his program, or in the form of precompiled object files, linked together at the compilation stage. On Windows, these files usually have the extension<.lib>... As a result of linking with a static library, the program includes all the functions it uses, which increases its size, but makes it more self-contained.

Dynamic libraries (shared library, dynamic link library) are loaded by the operating system at the "demand" of a running program already during its execution. If the required library has already been loaded into memory, then the reload is not performed. In this case, the same set of functions or library objects can be used simultaneously by several running programs, which makes it possible to efficiently use the resources of the RAM. Shared libraries on Windows usually have the extension<.dll>.

To use the library, you need to tell the compiler that you need to connect it and call the function from the library (using the appropriate header file), while the source text of the function is not needed.

Creating a dynamic library.

In Microsoft Visual Studio, creating a project for building a dynamic link library is similar to the usual procedure for creating a project for a dumb application. The project type is Win32 Console Application, only now you need to select the "DLL" item in the new project wizard:

If there is no such item in the wizard, you can create a regular Console Application project, and then set its type in the project properties:

Configuration Properties => General => Configuration Type: Dynamic Library (.dll)

Declspec (dllexport) void display (const char * str);

#include "dlltest.h"

void display (const char * str)

The __declspec (dllexport) modifier allows the library to export the specified function for use by other applications.

As a result of building the project, a dynamic library file with the extension<.dll>and also an import library file with the extension<.lib>... The import library is intended to facilitate the subsequent use of the dynamic library. Although the file extension of the import library is the same as the standard extension for static libraries, they should not be confused.

Using a dynamic library.

There are two ways to use a dynamic library in a program. Implicit linking involves using an import library to determine the addresses of the functions provided by the library. The operating system loads the DLL after loading the program executable file. The executable file calls the exported DLL functions as if the functions were contained in the executable itself.

When explicitly linking, the executable that uses the DLL must make function calls to explicitly load and unload the DLL and access the exported DLL functions. The client executable calls the exported functions using a function pointer.

Regardless of the method chosen, the executable file can use the same DLL. Moreover, these mechanisms are not mutually exclusive, because while one executable is implicitly linking to a DLL, another can be explicitly linking.

As an example, we will use the implicit linking mechanism (as the simplest one) to connect the constructed simple library.

Let's create a separate project of a regular console application (it is possible within the framework of the same solution as the project of the library itself). To use the display function implemented in the library, you must:

    Connect the corresponding header file “dlltest.h”. To do this, either use the path to the file directly in the #include directive (if the projects are in the same solution folder, it is better to use a relative path), or in the project properties add the path to this header file in the section

Configuration Parameters => C / C ++ => General => Additional Include Directories

    Use the appropriate import library file. To do this, you can use a directive of the form (here the relative path to the built lib-file is used).

Alternatively, you can add the path to the import library file in the project properties under

Configuration Parameters => Linker => Input => Additional Dependencies

Now let's create the main program file with the following content:

#pragma comment (lib, "../Debug/dlltest.lib")

#include "dlltest.h"

display ("Hello");

system ("pause");

To successfully launch the program, all that remains is to ensure that the corresponding DLL is available. When the program starts, the operating system will look for all the required library files in the folder from which the program was launched, as well as in the system paths defined by the PATH environment variable. Accordingly, the DLL file of the built library must either be in the same folder with the executable file of the calling program, or in one of the folders defined in the PATH.