- How Do so (Shared Object) Filenames Work in Linux
- What are Shared Objects (so) Files?
- How Shared Object Filenames Work
- Examples of Shared Object Filenames
- libcrypto.so.1.1
- libssl.so.1.1
- libX11.so.6
- libgtk-3.so.0
- How Shared Object Files are Found
- Benefits of Shared Objects
- Major vs. Minor Version Numbers
- Managing Shared Objects
- Conclusion
- What is the difference between Shared object file and Relocatable file?
- 2 Answers 2
How Do so (Shared Object) Filenames Work in Linux
Linux is an open-source operating system that provides users with a wide range of features and functions. One of essential aspects of Linux is use of shared objects (so) files. Shared objects are files that are used by Linux programs to share code and data between different processes. In this article, we will discuss how shared object filenames work in Linux and provide examples to illustrate concepts.
What are Shared Objects (so) Files?
Shared objects are a type of file that contains code and data that can be shared between multiple processes in Linux. They are similar to dynamic link libraries (DLLs) in Windows systems. When a Linux program needs to use a shared object, it loads it into memory and uses code and data contained in file.
Shared objects are used to reduce size of executable files and reduce amount of memory needed to run a program. They also provide a way to share code and data between different programs, allowing for more efficient and modular programming.
How Shared Object Filenames Work
Shared object filenames in Linux follow a specific naming convention that is used to identify file and its contents. filename consists of several parts, each of which provides information about file.
The naming convention for shared object filenames is as follows −
The parts of filename are −
- lib − This is a prefix that indicates that file is a shared library.
- − This is name of library. It is typically a short, descriptive name that identifies purpose of library.
- .so − This is a suffix that indicates that file is a shared object.
- − This is a number that indicates major version of library. A change in major version number indicates a significant change in API or ABI of library.
- − This is a number that indicates minor version of library. A change in minor version number indicates a small change in API or ABI of library.
Examples of Shared Object Filenames
Let’s take a look at some examples of shared object filenames to see how they work.
libcrypto.so.1.1
This filename indicates that file is a shared library called «crypto». major version number is 1, and minor version number is 1. This indicates that this is first major version of library and that there have been some minor changes to API or ABI.
libssl.so.1.1
This filename indicates that file is a shared library called «ssl». major version number is 1, and minor version number is 1. This indicates that this is first major version of library and that there have been some minor changes to API or ABI.
libX11.so.6
This filename indicates that file is a shared library called «X11». major version number is 6, and minor version number is 0. This indicates that this is sixth major version of library and that there have been no minor changes to API or ABI.
libgtk-3.so.0
This filename indicates that file is a shared library called «gtk-3». major version number is 0, and minor version number is 0. This indicates that this is first major version of library and that there have been no minor changes to API or ABI.
How Shared Object Files are Found
Shared objects are searched for and loaded by dynamic linker at runtime. dynamic linker is responsible for resolving symbols and linking shared objects with rest of program.
The dynamic linker searches for shared objects in several directories, including −
- /lib
- /usr
- /usr/local/lib
- Directories listed in LD_LIBRARY_PATH environment variable
When a program is compiled, it includes a list of shared object dependencies that it requires to run. When program is executed, dynamic linker searches for these dependencies in directories listed above. If it finds required shared objects, it loads them into memory and links them with program.
If required shared objects are not found, program will fail to run, and an error message will be displayed. To resolve this issue, you can install missing shared objects or add directory containing missing shared objects to LD_LIBRARY_PATH environment variable.
Benefits of Shared Objects
Shared objects provide several benefits over static libraries, including −
- Reduced memory usage − Shared objects are loaded into memory only when they are needed, reducing amount of memory needed to run a program.
- Dynamic linking − Shared objects allow programs to link with libraries at runtime, enabling them to adapt to changes in environment and load libraries only when they are required.
- Code reusability − Shared objects allow developers to reuse code across different programs, reducing development time and improving code maintainability.
- Faster program startup − Shared objects are loaded only when they are needed, reducing program startup time and improving program performance.
Major vs. Minor Version Numbers
The major and minor version numbers in shared object filenames provide information about compatibility of library with other programs. A change in major version number indicates a significant change in API or ABI of library. Programs that use old version of library may not be compatible with new version.
A change in minor version number indicates a small change in API or ABI of library. Programs that use old version of library should still be compatible with new version, but may not be able to take advantage of new features or improvements in library.
Managing Shared Objects
Managing shared objects in Linux can be challenging, particularly when dealing with dependencies between libraries. Here are some tips for managing shared objects in Linux −
- Use package managers − Most Linux distributions come with package managers that allow you to install and manage shared objects and their dependencies. Using a package manager can help ensure that your system is up-to-date and that you have all necessary dependencies.
- Avoid modifying system directories − Modifying system directories such as /lib and /usr can cause issues with dynamic linker and may break other programs. Instead, install shared objects in directories such as /usr/local/lib or in your home directory.
- Use symbolic links − If you have multiple versions of a shared object, you can use symbolic links to point to current version. This can help ensure that programs that depend on shared object can still find it even if version number changes.
- Check LD_LIBRARY_PATH − If you are experiencing issues with missing shared objects, check LD_LIBRARY_PATH environment variable to ensure that it includes directories containing required shared objects.
Conclusion
Shared objects are an essential part of Linux operating system. They allow programs to share code and data between processes, reducing size of executable files and amount of memory needed to run a program. Shared object filenames in Linux follow a specific naming convention that provides information about file’s contents, including name of library, major and minor version numbers, and file type. dynamic linker searches for shared objects at runtime in several directories, including /lib, /usr, and directories listed in LD_LIBRARY_PATH environment variable. Understanding how shared object filenames work is crucial for developing and running Linux programs efficiently.
What is the difference between Shared object file and Relocatable file?
https://unix.stackexchange.com/a/476157/674 shows that a kernel module is REL. Why is it REL not DYN? What is the difference between DYN and REL? Thanks.
2 Answers 2
See the System V ABI, which contains the specifications of the ELF format. It says
- In relocatable files, r_offset holds a section offset. That is, the relocation section itself describes how to modify another section in the file; relocation offsets designate a storage unit within the second section.
- In executable and shared object files, r_offset holds a virtual address. To make these files’ relocation entries more useful for the dynamic linker, the section offset (file interpretation) gives way to a virtual address (memory interpretation).
Relocatable files are still fully relocatable, whereas shared objects are one step further along the linking process and have been largely relocated. Shared objects are only relocatable if their code is position-independent (e.g. it was built with GCC’s -fPIC option).
Kernel modules need to be relocatable without being position-independent, so they are shipped as relocatable files.
(1) Is it correct that static linking translates relocatable address to virtual address, and dynamic linking accepts virtual address and doesn’t output different address or translates place holder to virtual address? (2) Do static and dynamic loading perform some address translation? (3) Do loading (be it static and dynamic) always happen before linking (be it static or dynamic)?
people.cs.pitt.edu/~xianeizhang/notes/Linking.html says «shared obj file. A special type of relocatable obj file that can be loaded into mem and linked dynamically, at either load time or run time. Compilers and assemblers generate relocatable obj files (including shared obj files).» I am confused that shared library file contains relocatable address or virtual address?
Thanks. Is it correct that a shared library file contains virtual addresses by default, and relocatable addresses if it was built with GCC’s -fPIC option?
Linux does not use the ELF methods for dynamic objects in the kernel, Linux instead still uses a basic method to load drivers that is from the mid 1980s and that worked already with the a.out format. There are relocatable files (similar to .o files) that are linked for the kernel and then loaded.
The method that has been introduced in the mid 1980s work this way, either by calling a program that does the following or by having a user space daemon that does the following:
- Take the driver .o file or a file linked from several .o files via ld -o driver -r *.o and perform a final link step (using ld ) that links that driver to load address 0. This is needed since the COMMON variables do not show up in the size output.
- Now call size on the resulting file to get the size needed by the driver.
- Open a module loading driver and use an ioctl to tell that driver the size of the module.
- The module loading driver calls kmem_alloc() in the kernel for text, data and bss segments and returns the addresses returned by kmem_alloc() in the result structure of the ioctl .
- Call the linker ( ld ) again but now link the driver to the addresses that have been returned by the module loading driver.
- Use another call to the module loading driver that tells this driver to slurp in the driver variant that has been linked to the addresses allocated by the kernel and puts the driver content to the allocated space.
- The loaded driver is now usable
If you like to look at a kernel that uses the ELF methods, I recommend to look at the Solaris kernel.
The first file that is loaded for Solaris is e.g. /platform/i86pc/kernel/amd64/unix and this file is marked as an excutable that depends on two shared «libraries». You can list this with the standard ELF tool dump :
dump -Lv /platform/i86pc/kernel/amd64/unix /platform/i86pc/kernel/amd64/unix: **** DYNAMIC SECTION INFORMATION **** .dynamic: [INDEX] Tag Value [1] NEEDED genunix [2] NEEDED dtracestubs [3] HASH 0xfffffffffb8c1040 [4] STRTAB 0xfffffffffb8e4e10 [5] STRSZ 0xf584 [6] SYMTAB 0xfffffffffb8c9fc0 [7] SYMENT 0x18 [8] CHECKSUM 0x4445 [9] TEXTREL 0 [10] RELA 0xfffffffffb8f4398 [11] RELASZ 0x16470 [12] RELAENT 0x18 [13] FEATURE_1 PARINIT [14] SUNW_CAP 0xfffffffffb8a37a8 [15] FLAGS TEXTREL [16] FLAGS_1 [ NOHDR ] [17] SUNW_STRPAD 0x200 [18] SUNW_LDMACH EM_AMD64 file /platform/i86pc/kernel/unix /platform/i86pc/kernel/unix: ELF 32-bit LSB executable 80386 Version 1, dynamically linked, not stripped, no debugging information available
As you see here, the shared libraries, the basic kernel depends on are: genunix and dtracestubs .
So if you like to boot a Solaris kernel, you need to have a bootloader that knows about ELF and is able to load and link the shared objects, the kernel depends on.
BTW: Solaris has an in-kernel dynamic linker, so dynamically loading a driver takes less steps.