{
	"id": "7a1b38cf-5dbd-4cd6-8b35-f64b6c5047eb",
	"created_at": "2026-04-06T03:37:37.223466Z",
	"updated_at": "2026-04-10T03:21:59.825035Z",
	"deleted_at": null,
	"sha1_hash": "d46e4689f7455d95d165485ad9e7be6e8cf013ec",
	"title": "Shared Libraries",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 83605,
	"plain_text": "Shared Libraries\r\nArchived: 2026-04-06 03:32:36 UTC\r\nShared libraries are libraries that are loaded by programs when they start. When a shared library is installed\r\nproperly, all programs that start afterwards automatically use the new shared library. It's actually much more\r\nflexible and sophisticated than this, because the approach used by Linux permits you to:\r\nupdate libraries and still support programs that want to use older, non-backward-compatible versions of\r\nthose libraries;\r\noverride specific libraries or even specific functions in a library when executing a particular program.\r\ndo all this while programs are running using existing libraries.\r\n3.1. Conventions\r\nFor shared libraries to support all of these desired properties, a number of conventions and guidelines must be\r\nfollowed. You need to understand the difference between a library's names, in particular its ``soname'' and ``real\r\nname'' (and how they interact). You also need to understand where they should be placed in the filesystem.\r\n3.1.1. Shared Library Names\r\nEvery shared library has a special name called the ``soname''. The soname has the prefix ``lib'', the name of the\r\nlibrary, the phrase ``.so'', followed by a period and a version number that is incremented whenever the interface\r\nchanges (as a special exception, the lowest-level C libraries don't start with ``lib''). A fully-qualified soname\r\nincludes as a prefix the directory it's in; on a working system a fully-qualified soname is simply a symbolic link to\r\nthe shared library's ``real name''.\r\nEvery shared library also has a ``real name'', which is the filename containing the actual library code. The real\r\nname adds to the soname a period, a minor number, another period, and the release number. The last period and\r\nrelease number are optional. The minor number and release number support configuration control by letting you\r\nknow exactly what version(s) of the library are installed. Note that these numbers might not be the same as the\r\nnumbers used to describe the library in documentation, although that does make things easier.\r\nIn addition, there's the name that the compiler uses when requesting a library, (I'll call it the ``linker name''), which\r\nis simply the soname without any version number.\r\nThe key to managing shared libraries is the separation of these names. Programs, when they internally list the\r\nshared libraries they need, should only list the soname they need. Conversely, when you create a shared library,\r\nyou only create the library with a specific filename (with more detailed version information). When you install a\r\nnew version of a library, you install it in one of a few special directories and then run the program ldconfig(8).\r\nldconfig examines the existing files and creates the sonames as symbolic links to the real names, as well as setting\r\nup the cache file /etc/ld.so.cache (described in a moment).\r\nhttps://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html\r\nPage 1 of 8\n\nldconfig doesn't set up the linker names; typically this is done during library installation, and the linker name is\r\nsimply created as a symbolic link to the ``latest'' soname or the latest real name. I would recommend having the\r\nlinker name be a symbolic link to the soname, since in most cases if you update the library you'd like to\r\nautomatically use it when linking. I asked H. J. Lu why ldconfig doesn't automatically set up the linker names. His\r\nexplanation was basically that you might want to run code using the latest version of a library, but might instead\r\nwant development to link against an old (possibly incompatible) library. Therefore, ldconfig makes no\r\nassumptions about what you want programs to link to, so installers must specifically modify symbolic links to\r\nupdate what the linker will use for a library.\r\nThus, /usr/lib/libreadline.so.3 is a fully-qualified soname, which ldconfig would set to be a symbolic link\r\nto some realname like /usr/lib/libreadline.so.3.0. There should also be a linker name,\r\n/usr/lib/libreadline.so which could be a symbolic link referring to /usr/lib/libreadline.so.3.\r\n3.1.2. Filesystem Placement\r\nShared libraries must be placed somewhere in the filesystem. Most open source software tends to follow the GNU\r\nstandards; for more information see the info file documentation at info:standards#Directory_Variables. The GNU\r\nstandards recommend installing by default all libraries in /usr/local/lib when distributing source code (and all\r\ncommands should go into /usr/local/bin). They also define the convention for overriding these defaults and for\r\ninvoking the installation routines.\r\nThe Filesystem Hierarchy Standard (FHS) discusses what should go where in a distribution (see\r\nhttp://www.pathname.com/fhs). According to the FHS, most libraries should be installed in /usr/lib, but libraries\r\nrequired for startup should be in /lib and libraries that are not part of the system should be in /usr/local/lib.\r\nThere isn't really a conflict between these two documents; the GNU standards recommend the default for\r\ndevelopers of source code, while the FHS recommends the default for distributors (who selectively override the\r\nsource code defaults, usually via the system's package management system). In practice this works nicely: the\r\n``latest'' (possibly buggy!) source code that you download automatically installs itself in the ``local'' directory\r\n(/usr/local), and once that code has matured the package managers can trivially override the default to place the\r\ncode in the standard place for distributions. Note that if your library calls programs that can only be called via\r\nlibraries, you should place those programs in /usr/local/libexec (which becomes /usr/libexec in a distribution). One\r\ncomplication is that Red Hat-derived systems don't include /usr/local/lib by default in their search for libraries; see\r\nthe discussion below about /etc/ld.so.conf. Other standard library locations include /usr/X11R6/lib for X-windows.\r\nNote that /lib/security is used for PAM modules, but those are usually loaded as DL libraries (also discussed\r\nbelow).\r\n3.2. How Libraries are Used\r\nOn GNU glibc-based systems, including all Linux systems, starting up an ELF binary executable automatically\r\ncauses the program loader to be loaded and run. On Linux systems, this loader is named /lib/ld-linux.so.X (where\r\nX is a version number). This loader, in turn, finds and loads all other shared libraries used by the program.\r\nThe list of directories to be searched is stored in the file /etc/ld.so.conf. Many Red Hat-derived distributions don't\r\nnormally include /usr/local/lib in the file /etc/ld.so.conf. I consider this a bug, and adding /usr/local/lib to\r\nhttps://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html\r\nPage 2 of 8\n\n/etc/ld.so.conf is a common ``fix'' required to run many programs on Red Hat-derived systems.\r\nIf you want to just override a few functions in a library, but keep the rest of the library, you can enter the names of\r\noverriding libraries (.o files) in /etc/ld.so.preload; these ``preloading'' libraries will take precedence over the\r\nstandard set. This preloading file is typically used for emergency patches; a distribution usually won't include such\r\na file when delivered.\r\nSearching all of these directories at program start-up would be grossly inefficient, so a caching arrangement is\r\nactually used. The program ldconfig(8) by default reads in the file /etc/ld.so.conf, sets up the appropriate symbolic\r\nlinks in the dynamic link directories (so they'll follow the standard conventions), and then writes a cache to\r\n/etc/ld.so.cache that's then used by other programs. This greatly speeds up access to libraries. The implication is\r\nthat ldconfig must be run whenever a DLL is added, when a DLL is removed, or when the set of DLL directories\r\nchanges; running ldconfig is often one of the steps performed by package managers when installing a library. On\r\nstart-up, then, the dynamic loader actually uses the file /etc/ld.so.cache and then loads the libraries it needs.\r\nBy the way, FreeBSD uses slightly different filenames for this cache. In FreeBSD, the ELF cache is /var/run/ld-elf.so.hints and the a.out cache is /var/run/ld.so.hints. These are still updated by ldconfig(8), so this difference in\r\nlocation should only matter in a few exotic situations.\r\n3.3. Environment Variables\r\nVarious environment variables can control this process, and there are environment variables that permit you to\r\noverride this process.\r\n3.3.1. LD_LIBRARY_PATH\r\nYou can temporarily substitute a different library for this particular execution. In Linux, the environment variable\r\nLD_LIBRARY_PATH is a colon-separated set of directories where libraries should be searched for first, before\r\nthe standard set of directories; this is useful when debugging a new library or using a nonstandard library for\r\nspecial purposes. The environment variable LD_PRELOAD lists shared libraries with functions that override the\r\nstandard set, just as /etc/ld.so.preload does. These are implemented by the loader /lib/ld-linux.so. I should note\r\nthat, while LD_LIBRARY_PATH works on many Unix-like systems, it doesn't work on all; for example, this\r\nfunctionality is available on HP-UX but as the environment variable SHLIB_PATH, and on AIX this functionality\r\nis through the variable LIBPATH (with the same syntax, a colon-separated list).\r\nLD_LIBRARY_PATH is handy for development and testing, but shouldn't be modified by an installation process\r\nfor normal use by normal users; see ``Why LD_LIBRARY_PATH is Bad'' at\r\nhttp://www.visi.com/~barr/ldpath.html for an explanation of why. But it's still useful for development or testing,\r\nand for working around problems that can't be worked around otherwise. If you don't want to set the\r\nLD_LIBRARY_PATH environment variable, on Linux you can even invoke the program loader directly and pass\r\nit arguments. For example, the following will use the given PATH instead of the content of the environment\r\nvariable LD_LIBRARY_PATH, and run the given executable:\r\n /lib/ld-linux.so.2 --library-path PATH EXECUTABLE\r\nhttps://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html\r\nPage 3 of 8\n\nJust executing ld-linux.so without arguments will give you more help on using this, but again, don't use this for\r\nnormal use - these are all intended for debugging.\r\n3.3.2. LD_DEBUG\r\nAnother useful environment variable in the GNU C loader is LD_DEBUG. This triggers the dl* functions so that\r\nthey give quite verbose information on what they are doing. For example:\r\n export LD_DEBUG=files\r\n command_to_run\r\ndisplays the processing of files and libraries when handling libraries, telling you what dependencies are detected\r\nand which SOs are loaded in what order. Setting LD_DEBUG to ``bindings'' displays information about symbol\r\nbinding, setting it to ``libs'' displays the library search paths, and setting ti to ``versions'' displays the version\r\ndepdendencies.\r\nSetting LD_DEBUG to ``help'' and then trying to run a program will list the possible options. Again, LD_DEBUG\r\nisn't intended for normal use, but it can be handy when debugging and testing.\r\n3.3.3. Other Environment Variables\r\nThere are actually a number of other environment variables that control the loading process; their names begin\r\nwith LD_ or RTLD_. Most of the others are for low-level debugging of the loader process or for implementing\r\nspecialized capabilities. Most of them aren't well-documented; if you need to know about them, the best way to\r\nlearn about them is to read the source code of the loader (part of gcc).\r\nPermitting user control over dynamically linked libraries would be disastrous for setuid/setgid programs if special\r\nmeasures weren't taken. Therefore, in the GNU loader (which loads the rest of the program on program start-up),\r\nif the program is setuid or setgid these variables (and other similar variables) are ignored or greatly limited in what\r\nthey can do. The loader determines if a program is setuid or setgid by checking the program's credentials; if the\r\nuid and euid differ, or the gid and the egid differ, the loader presumes the program is setuid/setgid (or descended\r\nfrom one) and therefore greatly limits its abilities to control linking. If you read the GNU glibc library source\r\ncode, you can see this; see especially the files elf/rtld.c and sysdeps/generic/dl-sysdep.c. This means that if you\r\ncause the uid and gid to equal the euid and egid, and then call a program, these variables will have full effect.\r\nOther Unix-like systems handle the situation differently but for the same reason: a setuid/setgid program should\r\nnot be unduly affected by the environment variables set.\r\n3.4. Creating a Shared Library\r\nCreating a shared library is easy. First, create the object files that will go into the shared library using the gcc -\r\nfPIC or -fpic flag. The -fPIC and -fpic options enable ``position independent code'' generation, a requirement for\r\nshared libraries; see below for the differences. You pass the soname using the -Wl gcc option. The -Wl option\r\npasses options along to the linker (in this case the -soname linker option) - the commas after -Wl are not a typo,\r\nand you must not include unescaped whitespace in the option. Then create the shared library using this format:\r\nhttps://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html\r\nPage 4 of 8\n\ngcc -shared -Wl,-soname,your_soname \\\r\n -o library_name file_list library_list\r\nHere's an example, which creates two object files (a.o and b.o) and then creates a shared library that contains both\r\nof them. Note that this compilation includes debugging information (-g) and will generate warnings (-Wall), which\r\naren't required for shared libraries but are recommended. The compilation generates object files (using -c), and\r\nincludes the required -fPIC option:\r\ngcc -fPIC -g -c -Wall a.c\r\ngcc -fPIC -g -c -Wall b.c\r\ngcc -shared -Wl,-soname,libmystuff.so.1 \\\r\n -o libmystuff.so.1.0.1 a.o b.o -lc\r\nHere are a few points worth noting:\r\nDon't strip the resulting library, and don't use the compiler option -fomit-frame-pointer unless you really\r\nhave to. The resulting library will work, but these actions make debuggers mostly useless.\r\nUse -fPIC or -fpic to generate code. Whether to use -fPIC or -fpic to generate code is target-dependent. The\r\n-fPIC choice always works, but may produce larger code than -fpic (mnenomic to remember this is that\r\nPIC is in a larger case, so it may produce larger amounts of code). Using -fpic option usually generates\r\nsmaller and faster code, but will have platform-dependent limitations, such as the number of globally\r\nvisible symbols or the size of the code. The linker will tell you whether it fits when you create the shared\r\nlibrary. When in doubt, I choose -fPIC, because it always works.\r\nIn some cases, the call to gcc to create the object file will also need to include the option ``-Wl,-export-dynamic''. Normally, the dynamic symbol table contains only symbols which are used by a dynamic object.\r\nThis option (when creating an ELF file) adds all symbols to the dynamic symbol table (see ld(1) for more\r\ninformation). You need to use this option when there are 'reverse dependencies', i.e., a DL library has\r\nunresolved symbols that by convention must be defined in the programs that intend to load these libraries.\r\nFor ``reverse dependencies'' to work, the master program must make its symbols dynamically available.\r\nNote that you could say ``-rdynamic'' instead of ``-Wl,export-dynamic'' if you only work with Linux\r\nsystems, but according to the ELF documentation the ``-rdynamic'' flag doesn't always work for gcc on\r\nnon-Linux systems.\r\nDuring development, there's the potential problem of modifying a library that's also used by many other programs\r\n-- and you don't want the other programs to use the ``developmental''library, only a particular application that\r\nyou're testing against it. One link option you might use is ld's ``rpath'' option, which specifies the runtime library\r\nsearch path of that particular program being compiled. From gcc, you can invoke the rpath option by specifying it\r\nthis way:\r\n -Wl,-rpath,$(DEFAULT_LIB_INSTALL_PATH)\r\nhttps://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html\r\nPage 5 of 8\n\nIf you use this option when building the library client program, you don't need to bother with\r\nLD_LIBRARY_PATH (described next) other than to ensure it's not conflicting, or using other techniques to hide\r\nthe library.\r\n3.5. Installing and Using a Shared Library\r\nOnce you've created a shared library, you'll want to install it. The simple approach is simply to copy the library\r\ninto one of the standard directories (e.g., /usr/lib) and run ldconfig(8).\r\nFirst, you'll need to create the shared libraries somewhere. Then, you'll need to set up the necessary symbolic\r\nlinks, in particular a link from a soname to the real name (as well as from a versionless soname, that is, a soname\r\nthat ends in ``.so'' for users who don't specify a version at all). The simplest approach is to run:\r\n ldconfig -n directory_with_shared_libraries\r\nFinally, when you compile your programs, you'll need to tell the linker about any static and shared libraries that\r\nyou're using. Use the -l and -L options for this.\r\nIf you can't or don't want to install a library in a standard place (e.g., you don't have the right to modify /usr/lib),\r\nthen you'll need to change your approach. In that case, you'll need to install it somewhere, and then give your\r\nprogram enough information so the program can find the library... and there are several ways to do that. You can\r\nuse gcc's -L flag in simple cases. You can use the ``rpath'' approach (described above), particularly if you only\r\nhave a specific program to use the library being placed in a ``non-standard'' place. You can also use environment\r\nvariables to control things. In particular, you can set LD_LIBRARY_PATH, which is a colon-separated list of\r\ndirectories in which to search for shared libraries before the usual places. If you're using bash, you could invoke\r\nmy_program this way using:\r\nLD_LIBRARY_PATH=.:$LD_LIBRARY_PATH my_program\r\nIf you want to override just a few selected functions, you can do this by creating an overriding object file and\r\nsetting LD_PRELOAD; the functions in this object file will override just those functions (leaving others as they\r\nwere).\r\nUsually you can update libraries without concern; if there was an API change, the library creator is supposed to\r\nchange the soname. That way, multiple libraries can be on a single system, and the right one is selected for each\r\nprogram. However, if a program breaks on an update to a library that kept the same soname, you can force it to\r\nuse the older library version by copying the old library back somewhere, renaming the program (say to the old\r\nname plus ``.orig''), and then create a small ``wrapper'' script that resets the library to use and calls the real\r\n(renamed) program. You could place the old library in its own special area, if you like, though the numbering\r\nconventions do permit multiple versions to live in the same directory. The wrapper script could look something\r\nlike this:\r\nhttps://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html\r\nPage 6 of 8\n\n#!/bin/sh\r\n export LD_LIBRARY_PATH=/usr/local/my_lib:$LD_LIBRARY_PATH\r\n exec /usr/bin/my_program.orig $*\r\nPlease don't depend on this when you write your own programs; try to make sure that your libraries are either\r\nbackwards-compatible or that you've incremented the version number in the soname every time you make an\r\nincompatible change. This is just an ``emergency'' approach to deal with worst-case problems.\r\nYou can see the list of the shared libraries used by a program using ldd(1). So, for example, you can see the shared\r\nlibraries used by ls by typing:\r\n ldd /bin/ls\r\nGenerally you'll see a list of the sonames being depended on, along with the directory that those names resolve to.\r\nIn practically all cases you'll have at least two dependencies:\r\n/lib/ld-linux.so.N (where N is 1 or more, usually at least 2). This is the library that loads all other libraries.\r\nlibc.so.N (where N is 6 or more). This is the C library. Even other languages tend to use the C library (at\r\nleast to implement their own libraries), so most programs at least include this one.\r\nBeware: do not run ldd on a program you don't trust. As is clearly stated in the ldd(1) manual, ldd works by (in\r\ncertain cases) by setting a special environment variable (for ELF objects, LD_TRACE_LOADED_OBJECTS) and\r\nthen executing the program. It may be possible for an untrusted program to force the ldd user to run arbitrary code\r\n(instead of simply showing the ldd information). So, for safety's sake, don't use ldd on programs you don't trust to\r\nexecute.\r\n3.6. Incompatible Libraries\r\nWhen a new version of a library is binary-incompatible with the old one the soname needs to change. In C, there\r\nare four basic reasons that a library would cease to be binary compatible:\r\n1. The behavior of a function changes so that it no longer meets its original specification,\r\n2. Exported data items change (exception: adding optional items to the ends of structures is okay, as long as\r\nthose structures are only allocated within the library).\r\n3. An exported function is removed.\r\n4. The interface of an exported function changes.\r\nIf you can avoid these reasons, you can keep your libraries binary-compatible. Said another way, you can keep\r\nyour Application Binary Interface (ABI) compatible if you avoid such changes. For example, you might want to\r\nadd new functions but not delete the old ones. You can add items to structures but only if you can make sure that\r\nold programs won't be sensitive to such changes by adding items only to the end of the structure, only allowing the\r\nhttps://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html\r\nPage 7 of 8\n\nlibrary (and not the application) to allocate the structure, making the extra items optional (or having the library fill\r\nthem in), and so on. Watch out - you probably can't expand structures if users are using them in arrays.\r\nFor C++ (and other languages supporting compiled-in templates and/or compiled dispatched methods), the\r\nsituation is trickier. All of the above issues apply, plus many more issues. The reason is that some information is\r\nimplemented ``under the covers'' in the compiled code, resulting in dependencies that may not be obvious if you\r\ndon't know how C++ is typically implemented. Strictly speaking, they aren't ``new'' issues, it's just that compiled\r\nC++ code invokes them in ways that may be surprising to you. The following is a (probably incomplete) list of\r\nthings that you cannot do in C++ and retain binary compatibility, as reported by Troll Tech's Technical FAQ:\r\n1. add reimplementations of virtual functions (unless it it safe for older binaries to call the original\r\nimplementation), because the compiler evaluates SuperClass::virtualFunction() calls at compile-time (not\r\nlink-time).\r\n2. add or remove virtual member functions, because this would change the size and layout of the vtbl of every\r\nsubclass.\r\n3. change the type of any data members or move any data members that can be accessed via inline member\r\nfunctions.\r\n4. change the class hierarchy, except to add new leaves.\r\n5. add or remove private data members, because this would change the size and layout of every subclass.\r\n6. remove public or protected member functions unless they are inline.\r\n7. make a public or protected member function inline.\r\n8. change what an inline function does, unless the old version continues working.\r\n9. change the access rights (i.e. public, protected or private) of a member function in a portable program,\r\nbecause some compilers mangle the access rights into the function name.\r\nGiven this lengthy list, developers of C++ libraries in particular must plan for more than occasional updates that\r\nbreak binary compatibility. Fortunately, on Unix-like systems (including Linux) you can have multiple versions of\r\na library loaded at the same time, so while there is some disk space loss, users can still run ``old'' programs\r\nneeding old libraries.\r\nSource: https://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html\r\nhttps://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html\r\nPage 8 of 8",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"references": [
		"https://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html"
	],
	"report_names": [
		"shared-libraries.html"
	],
	"threat_actors": [],
	"ts_created_at": 1775446657,
	"ts_updated_at": 1775791319,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/d46e4689f7455d95d165485ad9e7be6e8cf013ec.pdf",
		"text": "https://archive.orkl.eu/d46e4689f7455d95d165485ad9e7be6e8cf013ec.txt",
		"img": "https://archive.orkl.eu/d46e4689f7455d95d165485ad9e7be6e8cf013ec.jpg"
	}
}