Windows runtime dynamic library search path priority:
At Windows runtime, the search paths for dynamic libraries (usually referred to as DLL files) follow a certain order of priority to ensure that the program is able to load the required dynamic libraries correctly. The following is a summary of the Windows runtime dynamic library search path priorities:
- The directory where the application resides:
- When an application (such as an exe file) tries to load a DLL, it first looks for the DLL file in the directory it is in. This is the first priority in the search path.
- System directory (System32):
- If the DLL is not found in the directory where the application is located, the system next looks for it in the system directory. In Windows operating systems, this is usually
C:\Windows\System32
directory. This directory contains a large number of system-level DLL files that are critical to the proper functioning of the operating system.
- Windows Catalog:
- If the required DLL is not found in the system directory either, the search continues to the Windows directory, the
C:\Windows
。
- The directory specified in the environment variable PATH:
- If the DLL is not found in any of the above three locations, the system checks all directories listed in the environment variable PATH.The PATH environment variable is a system-level variable that contains paths to several directories and is used to direct the system to search for the paths to the relevant files when executing a file or script. Therefore, users can add additional search paths by modifying the PATH environment variable.
I. Linux runtime dynamic library search path prioritization basics:
The search path priority for runtime dynamic libraries (shared libraries) on Linux systems is determined by a number of factors. The following is a detailed explanation and prioritization of these factors:
1. RPATH
- define: RPATH (also known as DT_RPATH) is a path set in the executable at compile time that specifies where library files should be searched for when the program is run.
- prioritization: If the executable contains an RPATH, the linker first searches for the required libraries according to the path specified by the RPATH.
-
Viewing and modifying methods: can be used
readelf -d xxx | grep rpath
to see if rpath is specified for library files, you can set RPATH at compile time.
// Setting the rpath at compile time if(OS_LINUX) set_target_properties(xxx PROPERTIES LINK_FLAGS "-Wl,-rpath='$ORIGIN' ") endif() Remarks: $ORIGIN is a dynamic linker special variable that indicates the directory where the executable or shared library file is located, and can be used to specify a relative path.
2. LD_LIBRARY_PATH environment variable
- define: LD_LIBRARY_PATH is an environment variable that the user can set at runtime to add additional library search paths.
- prioritization: The path specified in LD_LIBRARY_PATH is looked up before the system default path, but has a lower priority than RPATH.
-
Setting method:
- Temporary setup: this can be done with the
export LD_LIBRARY_PATH=/my/lib/path/
to set environment variables; - Permanent settings (unsafe and not recommended): can be added to the shell's configuration file, such as: ~/.bashrc or ~/.bash_profile, after setting, execute the source command to take effect immediately.
- Temporary setup: this can be done with the
3. RUNPATH
- define: RUNPATH is another feature similar to RPATH, also set when executables or shared libraries are linked, and is used to specify the path to find shared libraries at runtime. It is worth noting that when RUNPATH exists, it overrides the RPATH setting.
- prioritization: The path specified in RUNPATH is looked up before the system default path, but has a lower priority than LD_LIBRARY_PATH.
-
Viewing and Setting Methods: can be used
readelf -d xxx | grep runpath
to see if the library file specifies a runpath, and use tools such as patchelf to set and modify RUNPATH.
// Use the tool to modify the runpath patchelf --set-rpath '$ORIGIN' xxx
4.
- define: /etc/ is a cache file for the dynamic linker that stores information about the paths and names of all available shared libraries on the system. /etc/ is generated by the ldconfig command. ldconfig scans the system for shared library files under the specified path and updates the /etc/ file.
- prioritization: has a lower priority than LD_LIBRARY_PATH and RUNPATH, but higher than the others, this is to quickly find and load the needed shared libraries.
-
Update method: Run
sudo ldconfig
command to update the cache.
// /etc/ is a binary file whose contents can be viewed with the strings command, e.g. the search path for libstdc++.so. strings /etc/ | grep libstdc++.so
5. Configuration files /etc/ and /etc// directory
- define: /etc/ is the system's library configuration file and contains the system-level library search path. The /etc// directory is used to store additional configuration files.
- prioritization: The linker reads these files and searches for libraries according to the paths listed in them, with a lower priority than LD_LIBRARY_PATH and RUNPATH.
-
Modification method: After modifying these files, you can run
sudo ldconfig
command to update the cache.
6. Default system path
- define: The /lib and /usr/lib directories (and their 64-bit counterparts /lib64 and /usr/lib64) are the default library search paths on most Linux systems.
- prioritization: These paths have the lowest priority, and the linker will fall back to these default paths if the required library is not found in any of the previous paths.
summarize
The search path priority for Linux runtime dynamic libraries is roughly as follows:
- RPATH(DT_RPATH)
- LD_LIBRARY_PATH environment variable
- RUNPATH (if DT_RPATH is empty)
- Configuration files /etc/ and /etc// directory
- Default system path (/lib, /usr/lib, /lib64, /usr/lib64)
1 commencement 2 ├──> Check RPATH (DT_RPATH) 3 │ ├──> If the library is found, it is loaded and used 4 │ └──> Otherwise, continue 5 ├──> Checking the LD_LIBRARY_PATH environment variable 6 │ ├──> If the library is found, it is loaded and used 7 │ └──> Otherwise, continue 8 ├──> Check RUNPATH (if DT_RPATH is empty) 9 │ ├──> If the library is found, it is loaded and used 10 │ └──> Otherwise, continue 11 ├──> Search Cache 12 │ ├──> If the library is found, it is loaded and used 13 │ └──> Otherwise, continue 14 ├──> Read configuration file/etc/up to/etc//catalogs 15 │ ├──> For each path in the configuration file 16 │ │ ├──> Search this path 17 │ │ │ ├──> If the library is found, it is loaded and used 18 │ │ │ └──> Otherwise, continue searching 19 │ │ └──> End the search for the path 20 │ └──> If not found in all configuration files, continue 21 └──> Search for the default system path(/lib, /usr/lib, /lib64, /usr/lib64) 22 ├──> If the library is found, it is loaded and used 23 └──> if not,Reporting errors,Unable to find library
Note that this order may vary depending on the specific Linux distribution and linker implementation. In practice, theldd
command to see the dependencies of an executable or library file and how they are resolved.
Additional Notes:
The difference between $ORIGIN and . / difference
On Linux and other Unix-like systems, when dynamically linked libraries (such as .so files) are loaded, the system needs to know where to look for these libraries. rpath (runtime library search path) is a mechanism stored in the executable or in the library itself to instruct the dynamic linker where to look for dependent libraries.
Library rpath:[$ORIGIN/] and Library rpath:[. /] specify two different relative paths.
1. [$ORIGIN/]:
- $ORIGIN is a special placeholder for the directory of the executable or library file itself;
- When set to [$ORIGIN/], it tells the dynamic linker to look for dependent libraries in the same directory where the executable or library is located;
- This means that if your executable is located in /path/to/app/myapp, then the dynamic linker will look for dependent libraries in the /path/to/app directory.
2. [. /]:
- . / indicates the current working directory, i.e. the directory where the executable was launched;
- When set to [. /], it instructs the dynamic linker to look for dependent libraries in the current directory of the startup executable;
- This means that if you run /path/to/app/myapp in the /home/user/ directory, the dynamic linker will look for dependent libraries in the /home/user/ directory, not in the /path/to/app/ directory where the executable is located.
The main difference between the two is that they reference different datums: [$ORIGIN/] is relative to the location of the executable or library, while [. /] is relative to the current working directory. In practice, which one you choose depends on your specific needs, such as how your applications and libraries are deployed and used. Typically, [$ORIGIN/] is more flexible and reliable because it does not depend on which daybook the user launches the application from.
2) Confirmation of dynamic library priority commonly used commands
ldd: ldd is a tool to display the shared libraries on which an executable or shared library depends. Its usage is as follows:ldd xxx
orldd
。
readelf: readelf is a command line tool designed to view information about ELF (Executable and Linkable Format) files. Its usage includes:readelf -d xxx
orreadelf -d
。
ps and lsof: When using ps and lsof in combination, you first need to utilize theps -ef | grep xxx
command to find the process ID that matches the requirements, and then utilize thelsof -p [PID]
command to see all the files opened by the process, thus confirming the path where the module is loaded.
strace: strace is a powerful tool to prioritize executable programs by printing out their load paths. An example of its use is:strace -e open,openat -o ./xxx
. This command will execute the executable program named xxx and capture all open and openat system calls, outputting the relevant information to a file. The path where the module was loaded can also be confirmed by looking at the log.
II. Linux runtime dynamic library search path prioritization rules exploration:
With a good grasp of the cornerstone concept of dynamic library search path prioritization, we can initially predict how to pinpoint and load specific dynamic libraries during program execution. However, in the context of large and intricate projects, it is not uncommon to encounter scenarios where the same dynamic library is in multiple versions. A deeper understanding of the search path prioritization principle is essential to ensure that the program loads the required version of the library accurately.
Exploration of core issues:
When using the ldd command to review the list of shared libraries on which an executable or dynamic library depends, does this list necessarily reflect the dynamic libraries that will be loaded when the program is run?
This topic can be further analyzed by breaking it down into two key questions:
1. Prioritization of dual dependencies: If both an executable and a dynamic library depend on a dynamic library, what is the prioritization mechanism for searching and loading?
2. Prioritization of Indirect Dependencies: If multiple dynamic libraries depend on the same dynamic library, and the dependency chain is not directly related to the executable, how is the search and load prioritized?
Rules Summary:
- Prioritize basic steps: In general, follow the established prioritized base steps for searching.
- Architecture-specific path prioritization: Under each search path, combining the characteristics of system architecture, thread local storage, etc. (e.g. glibc-hwcaps/x86-64-v4, tls/x86_64/x86_64, etc.), the search is prioritized to look up in the paths that have been spliced by this.
- chronology: Based on the order in which the dynamic libraries are loaded.
- Principle of prioritization of dynamic pools at the same level: When a dynamic library depends on a dynamic library, and the dependent dynamic library is not loaded before it is loaded, then the path specified by the dynamic library itself will be looked up first, and then the path specified by the executable program will be looked up first, with the same level of priority.
- path de-duplication: It is worth noting that the system will avoid repeating searches for paths that have been confirmed not to exist.
case study:
To enhance understanding, we will make predictions and validations through specific examples to visualize the application and practice of the above principles.
Example analysis images omitted here ......
Through the above figure you can see that the load path of the dynamic library is consistent with the results of our analysis, the detailed search steps can be verified by the strace command.
summarize
In this paper, we have combed through the basic rules of search path priority of shared libraries in Linux system, and on the basis of this, we have analyzed and summarized the operation mechanism of these priority rules with the help of specific examples. In addition, this paper also proposes a practical reference program for troubleshooting dynamic library loading problems that may be encountered in real projects. We hope that this article can provide strong support and help you in the future work encountered in the dynamic library dependency problems (such as version compatibility issues, etc.).