From c4eb2b4e80d2ac9e23763544773615b86c75bfff Mon Sep 17 00:00:00 2001 From: Ben Woodard Date: Wed, 3 Jun 2015 10:31:03 -0700 Subject: [PATCH] Add a new dynamic chapter to the manual. Signed-off-by: Ben Woodard --- ChangeLog | 5 + manual/Makefile | 3 +- manual/dynamic.texi | 1172 +++++++++++++++++++++++++++++++++++++++++++++++++++ manual/libdl.texi | 10 - manual/signal.texi | 2 +- 5 files changed, 1180 insertions(+), 12 deletions(-) create mode 100644 manual/dynamic.texi delete mode 100644 manual/libdl.texi diff --git a/ChangeLog b/ChangeLog index f750412..cb52b22 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-06-02 Ben Woodard + + * manual/Makefile (chapters): Add dynamic chapter. + * manual/dynamic.texi: New file + 2015-06-01 Martin Sebor [BZ #18116] diff --git a/manual/Makefile b/manual/Makefile index 5382208..e2f7b3c 100644 --- a/manual/Makefile +++ b/manual/Makefile @@ -38,7 +38,8 @@ chapters = $(addsuffix .texi, \ message search pattern io stdio llio filesys \ pipe socket terminal syslog math arith time \ resource setjmp signal startup process ipc job \ - nss users sysinfo conf crypt debug threads probes) + nss users sysinfo conf crypt debug threads \ + dynamic probes) add-chapters = $(wildcard $(foreach d, $(add-ons), ../$d/$d.texi)) appendices = lang.texi header.texi install.texi maint.texi platform.texi \ contrib.texi diff --git a/manual/dynamic.texi b/manual/dynamic.texi new file mode 100644 index 0000000..dd5f10d --- /dev/null +++ b/manual/dynamic.texi @@ -0,0 +1,1172 @@ +@node Dynamic Linking, Program Basics, Signal Handling, Top +@c %MENU% Loading libraries, finding functions, and other symbols +@chapter Dynamic Linker + +On every operating system currently supported by @Theglibc{}, the +operating system provides a facility for run time dynamic +linking. This facility is implemented by @Theglibc{}'s dynamic linker. +This benefits the operating system by allowing the resident RAM used +by libraries to be shared between processes. Runtime dynamic linking +also enhances the security and maintainability of the operating +system. As long as the ABI, application binary interface, is +maintained through proper library versioning, a new version of a +library can be installed on a system to fix bugs or resolve a security +issue without the need to recompile all the applications which make +use of that library. + +Because run time linking is so intimately involved with the lauching +of almost every program, it exists at the interface between the +operating system kernel and the system libraries. Thus configuration +and administration of the run time dynamic linker is operating system +specific. Individuals who are interested in this topic are encouraged +to look at the operating system documentation. +@c which is often found in +@c the @cite{ld.so(8)} and the @cite{ldconfig(8)} man pages. +@c pindex ld.so +@c pindex ldconfig + +The same run time dynamic linking capability which allows applications +to be loaded along with their libraries at initial execution time has +also been made available to application programmers through a group of +run time dynamic linker function explained below. This facility is +often used for plugins to add optional or extended features to an +application without introducing library dependencies. + +The run time dynamic linker also provides several mechanisms which +allow the system administrator or user to modify its operation when +running an application. Many of the tools to modify glibc's run time +linker's operation are environmental variables. However, if more +sophisticated manipulation of the process of run time linking and +symbol resolution is needed, the dynamic has a kind of plugin +called an audit library. + +@menu +* Concepts of Dynamic Linking:: Introduction to dynamic linking. +* Environmental Variables:: Variables that can be used affect the operation + of dynamic linker. +* Dynamic Linker API Functions:: Functions to load libraries, find functions + and other symbols. +* Audit Interface:: Monitor or intercede in the operation of the dynamic linker +@end menu + +@node Concepts of Dynamic Linking +@section Concepts of Dynamic linking + +When you compile a file and are left with an object file that is +called a compilation unit. At the time that it is compiled, the +compiler can see all the variables and functions that are within the +file and it can fill in references to those function and +variables. Many times there are functions or variables that exist +outside of a particular compilation unit. If you link object files +then the linker is able to find the location of referenced symbols or +functions in other compilation unit's object files, insert them into +the resulting executable, and bind the references to them. + +Libraries are a special kind object file which include the partially +linked aggregation of many compilation unit's object files. You can +link with a library one of two ways. Linking with a library statically +is the old original way of linking. This is no different than linking +with any other object file. Linking statically is not recommended in +almost all cases. The second way of linking is dynamically linking +with the library. In this case, the linker makes sure that all the +functions and symbols referred to by your program can be found in the +libraries that you are linking with but instead of copying the +function or variable over into the resulting executable, it stores a +reference to the library in the executable's header and replaces the +references to the function with calls to stub functions that will make +sure that the needed library is loaded into memory and then will +ultimately call the required function. Variables that exist in +libraries are handled similarly through a level of indirection. + +@menu +* Finding a Library:: The process of resolving the location of a library +* Finding a Symbol:: The process of resolving symbols within libraries +* Binding a Variable:: How the GOT is used to bind a variable in a library +* Binding a Function:: How the PLT is used to bind functions from libraries +* Linkage Tables:: Using non-global linking to avoid potential symbol conflicts +@end menu + +@node Finding a Library +@subsection Finding a Library +@cindex Finding a Library, Dynamic Linking +Binaries that are not linked statically require the dynamic linker to +load the libraries into the process's address space before beginning +to run the executable. The shared libraries needed by am executable or +a library are stored in dynamic section of the ELF header. The list of +the libraries needed can be quickly enumerated with the +@command{readelf} command. +@pindex readelf + +@cindex NEEDED, dynamic linking +@cindex DT_NEEDED +@example +$ readelf -d /usr/bin/ls | grep NEEDED +0x0000000000000001 (NEEDED) Shared library: [libselinux.so.1] +0x0000000000000001 (NEEDED) Shared library: [libcap.so.2] +0x0000000000000001 (NEEDED) Shared library: [libacl.so.1] +0x0000000000000001 (NEEDED) Shared library: [libc.so.6] +$ readelf -d /lib64/libselinux.so.1 | grep NEEDED +0x0000000000000001 (NEEDED) Shared library: [libpcre.so.1] +0x0000000000000001 (NEEDED) Shared library: [liblzma.so.5] +0x0000000000000001 (NEEDED) Shared library: [libdl.so.2] +0x0000000000000001 (NEEDED) Shared library: [libc.so.6] +0x0000000000000001 (NEEDED) Shared library: [ld-linux-x86-64.so.2] +@end example + +The full set libraries needed by an executable or a library and all of +its dependencies and where they are currently being found can be +enumerated with the @command{ldd} command. +@pindex ldd + +@example +$ ldd /usr/bin/ls +linux-vdso.so.1 => (0x00007fff3e5e9000) +libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f0e913ce000) +libcap.so.2 => /lib64/libcap.so.2 (0x00007f0e911c9000) +libacl.so.1 => /lib64/libacl.so.1 (0x00007f0e90fbf000) +libc.so.6 => /lib64/libc.so.6 (0x00007f0e90c02000) +libpcre.so.1 => /lib64/libpcre.so.1 (0x00007f0e90995000) +liblzma.so.5 => /lib64/liblzma.so.5 (0x00007f0e9076f000) +libdl.so.2 => /lib64/libdl.so.2 (0x00007f0e9056b000) +/lib64/ld-linux-x86-64.so.2 (0x00007f0e9160b000) +libattr.so.1 => /lib64/libattr.so.1 (0x00007f0e90366000) +libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f0e90149000) +@end example + +@pindex ldd +To make the association between between the library listed as needed +in the ELF dynamic section and where they are located as shown by the +@command{ldd} command, the run time linker has to look in several +places. This process is known as object search. A library can audit or +interpose itself into this process of locating a library by +implementing the the @code{la_objsearch()} function. +@findex la_objsearch + +If a library listed as NEEDED includes a slash in its name, then it is +assumed to be either an absolute or relative pathname as is often the +case when a library is specified on the command line. When a pathname +is found as the target of the NEEDED section it is resolved as such. + +@vindex LD_LIBRARY_PATH +@cindex RPATH +@cindex DT_RPATH +Sometimes a library's location will be explicitly referenced using a +deprecated feature called a RPATH. Specifying the location of a +library using RPATHs is not recommended for a variety of reasons +including the fact that it its extremely high precedence makes it +impossible for system administrators to point at other locations using +things like @env{LD_LIBRARY_PATH} and the inability to edit the RPATHs +because limited space in the ELF header for the pathname prevents +changing it to something suitable for file hierarchy appropriate to +that system. Any RPATHs found in a binary or a library can found using +the readelf command as follows. + +@pindex readelf +@example +$ readelf -d /usr/bin/apropos | grep RPATH +0x000000000000000f (RPATH) Library rpath: [/usr/lib64/man-db] +@end example + +@vindex LD_LIBRARY_PATH +The first place that the run time linker looks for a NEEDED library +after following RPATHs is in any directory found in the colon +separated list of directories found in the @env{LD_LIBRARY_PATH} +environmental variable. This list of directories is searched first to +facilitate replacing libraries found elsewhere in the search +path. This is particularly useful when debugging problems but +extensive use of @env{LD_LIBRARY_PATH} is not recommended because it +bypasses the caching of where to find libraries which is done later in +the object search process. This caching greatly improves the +performance of object search by avoiding the necessity to enumerate +the contents of every directory containing libraries configured into +the system. Thus extensive use of @env{LD_LIBRARY_PATH} could have +substantial negative performance implications. + +@cindex RUNPATH +@cindex DT_RUNPATH +After processing @env{LD_LIBRARY_PATH}, an ELF directive similar to RPATH +called RUNPATH is searched. This ELF directive is what libtool and +other compile time linkers insert when linking with libraries in +unusual directories specified on the link command line. Any RUNPATHs +found in an ELF executable or library can be listed by printing the +dynamic section of the ELF header. + +@pindex readelf +@example +$ readelf -d /usr/bin/tracker-control | grep RUNPATH +0x000000000000001d (RUNPATH) Library runpath: [/usr/lib64/tracker-1.0] +@end example + +Very occasionally RPATH and RUNPATH may include some macros that will +be expanded before objects search is performed in the directories +specified. Users are encouraged to look at the linux ld.so man page +for more details. + +@pindex ldconfig +@cindex ld.so.cache +@vindex LD_LIBRARY_PATH +While RPATH and RUNPATH ELF entries are quite rare and while use of +@env{LD_LIBRARY_PATH} is well known its use is uncommon, the normal +behavior of the run time linker starts out looking in the +@file{/etc/ld.so.cache} which is created when @command{ldconfig} is +run. + +@pindex ldconfig +@cindex ld.so.conf +@command{ldconfig} will cache the location of the libraries in the trusted +library directories (@file{/lib} and @file{/usr/lib} and also +@file{/lib64} and @file{/usr/lib64} on 64bit systems). The operating +system provider or the local sysadmin may also include additional +directories that the linker should search for libraries. These are +specified in @file{/etc/ld.so.conf} but before they are searched, this +configuration file must be compiled into @file{ld.so.cache} by the +@command{ldconfig} command. + +@node Finding a Symbol +@subsection Finding a Symbol +When two objects are linked dynamically, the location of symbols which +are referenced in one object file which exist an an other object file +cannot be resolved until run time. This is because the location within +a process's address space where a library will be loaded is +intentionally slightly non-deterministic to make hacking more +difficult and because different applications can load the same object +file in different locations. This is why libraries must be compiled as +position independent code. These unresolved symbols are known as +relocations. You can use the @command{readelf} command to list the +relocations needing to be satisfied within an object file. + +@example +$ readelf --relocs /usr/bin/ls + +Relocation section '.rela.dyn' at offset 0x1688 contains 9 entries: + Offset Info Type Sym. Value Sym. Name + Addend +00000061af88 000800000006 R_X86_64_GLOB_DAT 0000000000000000 free + 0 +00000061af90 000f00000006 R_X86_64_GLOB_DAT 0000000000000000 stdout + 0 +00000061af98 001d00000006 R_X86_64_GLOB_DAT 0000000000000000 optind + 0 +00000061afa0 004500000006 R_X86_64_GLOB_DAT 0000000000000000 optarg + 0 +[...] + +Relocation section '.rela.plt' at offset 0x1760 contains 115 entries: + Offset Info Type Sym. Value Sym. Name + Addend +00000061b018 000100000007 R_X86_64_JUMP_SLO 0000000000000000 __ctype_toupper_loc + 0 +00000061b020 000200000007 R_X86_64_JUMP_SLO 0000000000000000 __uflow + 0 +00000061b028 000300000007 R_X86_64_JUMP_SLO 0000000000000000 getenv + 0 +00000061b030 000400000007 R_X86_64_JUMP_SLO 0000000000000000 cap_to_text + 0 +00000061b038 000600000007 R_X86_64_JUMP_SLO 0000000000000000 sigprocmask + 0 +00000061b040 000700000007 R_X86_64_JUMP_SLO 0000000000000000 raise + 0 +00000061b048 000800000007 R_X86_64_JUMP_SLO 0000000000000000 free + 0 +[...] +@end example + +The dynamic linker's job is to find the required symbol in the shared +libraries. The symbols available within an object file can be +enumerated with the @command{readelf --dyn-sym} command. + +@example +$ readelf --dyn-syms /usr/lib64/libc.so.6 | grep -v " _" + +Symbol table '.dynsym' contains 2224 entries: + Num: Value Size Type Bind Vis Ndx Name + 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND + 1: 000000000001f4f0 0 SECTION LOCAL DEFAULT 12 + 2: 00000000003b3568 0 SECTION LOCAL DEFAULT 22 + 10: 00000000000717c0 348 FUNC GLOBAL DEFAULT 12 putwchar@@GLIBC_2.2.5 + 14: 0000000000115d70 192 FUNC GLOBAL DEFAULT 12 setrpcent@@GLIBC_2.2.5 + 17: 0000000000100770 33 FUNC GLOBAL DEFAULT 12 epoll_create@@GLIBC_2.3.2 + 18: 00000000000e42b0 33 FUNC WEAK DEFAULT 12 sched_get_priority_min@@GLIBC_2.2.5 + 20: 0000000000100980 33 FUNC GLOBAL DEFAULT 12 klogctl@@GLIBC_2.2.5 + 22: 0000000000053920 143 FUNC GLOBAL DEFAULT 12 dprintf@@GLIBC_2.2.5 + [...] +@end example + +All of the relocations needed by the executable and all its libraries +will be satisfied by the objects loaded. For example two of the +symbols needed by the @command{ls} can be found in the +@file{/usr/lib64/libc.so.6} library. + +@example +$ readelf --relocs /usr/bin/ls | egrep stdout\|opendir +00000061af90 000f00000006 R_X86_64_GLOB_DAT 0000000000000000 stdout + 0 +00000061b0e0 001e00000007 R_X86_64_JUMP_SLO 0000000000000000 opendir + 0 +$ readelf --dyn-syms /usr/lib64/libc.so.6 | egrep " stdout| opendir" + 1036: 00000000003b88e8 8 OBJECT GLOBAL DEFAULT 32 stdout@@GLIBC_2.2.5 + 1270: 00000000000c0350 13 FUNC WEAK DEFAULT 12 opendir@@GLIBC_2.2.5 +@end example + +After the symbol is found in the object file, the reference to the +symbol must be patched so that the code can referring to it can make +use of it. This is known as binding a symbol. + +@node Binding a Variable +@subsection Binding a Variable +Binding a variable is the process of patching the location of a symbol +in the processes current address space into the code which refers to +it. There might be hundreds if not thousands of uses of a particular +variabletherefore patching in the location into every one of those +uses would increase the amount of time spent in the dynamic linker +before main was started. Also patching the actual destination memory +address into the code of the object that refers to it would change the +in memory version of that object so that it could no longer be shared +with all the other processes using that object. The solution to these +two problems is to have indirect references to the external variables +and to place tables of these indirect references in a region of memory +not shared by users of that object. This indirection can be easily +seen when looking at the assembly code for a simple function. In this +case x86_64 is used but a similar mechanism is used for most +architectures. + +@example +$ cat test.c +extern int foo; + +int function(void) @{ + return foo; +@} +$ gcc -shared -fPIC -g -o libtest.so test.c +$ gdb libtest.so -q -ex "disassemble function" -ex quit +Reading symbols from libtest.so...done. +Dump of assembler code for function function: + 0x00000000000006d0 <+0>: push %rbp + 0x00000000000006d1 <+1>: mov %rsp,%rbp + 0x00000000000006d4 <+4>: mov 0x200905(%rip),%rax # 0x200fe0 + 0x00000000000006db <+11>: mov (%rax),%eax + 0x00000000000006dd <+13>: pop %rbp + 0x00000000000006de <+14>: retq +End of assembler dump. +$ readelf --relocs libtest.so | egrep dyn\|Type\|foo +Relocation section '.rela.dyn' at offset 0x470 contains 9 entries: + Offset Info Type Sym. Value Sym. Name + Addend +000000200fe0 000400000006 R_X86_64_GLOB_DAT 0000000000000000 foo + 0 +$ readelf --sections libtest.so | egrep -A1 Nr\|20\]\|Key\|order + [Nr] Name Type Address Offset + Size EntSize Flags Link Info Align +-- + [20] .got PROGBITS 0000000000200fd0 00000fd0 + 0000000000000030 0000000000000008 WA 0 0 8 +-- +Key to Flags: + W (write), A (alloc), X (execute), M (merge), S (strings), l (large) + I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) + O (extra OS processing required) o (OS specific), p (processor specific) +@end example + +The address of the variable foo is located at the address 0x200905 +past the current instruction pointer. GDB nicely computes this for you +to be 0x200fe0. This matches the address of the location in the +relocation section. When you find that address in the list of sections +within the ELF file you find that it is in a section called the +``GOT'' which stands for the global offset table. We can see from the +flags that this region is both wriable and dynamically allocated. At +run time it is allocated and then then the dynamic linker inserts the +location of foo into 0x200fe0. This is the process known as binding a +symbol. + +@node Binding a Function +@subsection Binding a Function + +@cindex procedure linkage table +@cindex PLT +Binding a function is very similar to binding a variable except there +are a couple of other features and requirements that add a little bit +of additional complexity. Some of the additional complexity is due to +the need to make function calls between position independent code +which needs to be in read only memory. A couple of other important +features are lazy binding and the ability to audit function calls +between objects. + +Like variable relocations, the requirement to have references in read +only memory so executable sections can be shared necessitates the use +of indirection. A simple approach would be to put the address to the +function in the GOT. However, another layer of indirection is needed +to support lazy binding of functions. + +The way this is accomplished is through another section of read-only +executable code called the Procedure Linkage Table, or PLT. The +executing code calls a tiny bit of stub code in the PLT. This stub +code jumps to the location of an associated entry in the GOT. This is +not a call, this is a jump and so returning the function's return +value and call stack is not disturbed. + +@example +$ cat test.c +int foo(void); + +int function(void) @{ + return foo(); +@} +$ gcc -shared -fPIC -o libtest.so test.c +$ gdb libtest.so -q -ex "disassemble function" -ex quit +Reading symbols from libtest.so...done. +Dump of assembler code for function function: + 0x00000000000006e0 <+0>: push %rbp + 0x00000000000006e1 <+1>: mov %rsp,%rbp + 0x00000000000006e4 <+4>: callq 0x5c0 + 0x00000000000006e9 <+9>: pop %rbp + 0x00000000000006ea <+10>: retq +End of assembler dump. +$ gdb libtest.so -q -ex "disassemble 0x5c0" -ex quit +Reading symbols from libtest.so...done. +Dump of assembler code for function foo@@plt: + 0x00000000000005c0 <+0>: jmpq *0x200a5a(%rip) # 0x201020 + [...] +End of assembler dump. +$ readelf --relocs libtest.so +[...] +Relocation section '.rela.plt' at offset 0x530 contains 3 entries: + Offset Info Type Sym. Value Sym. Name + Addend +[...] +000000201020 000400000007 R_X86_64_JUMP_SLO 0000000000000000 foo + 0 +[...] +@end example + +After a function is bound, the entry in the GOT pointed to by the PLT +stub code will contain the address of the function in the process's +address space. Before the function is bound, usually at the time when +the object is loaded, the dynamic later inserts value in the GOT that +enables lazy binding and auditing. This value and the mechanism by +which these stub functions work is explained below. + +@cindex Lazy Binding +@cindex Binding, Lazy +When the dynamic linker loads an object, it doesn't take the time to +process all the relocations for functions. Instead it preloads the +entries for each function in the GOT with the value of the instruction +immediately after the jump made from the PLT's stub function. + +Continuing with our example from above: + +@example +$ gdb libtest.so -q -ex "disassemble 0x5c0" -ex "x 0x201020" -ex quit +Reading symbols from libtest.so...done. +Dump of assembler code for function foo@@plt: + 0x00000000000005c0 <+0>: jmpq *0x200a5a(%rip) # 0x201020 + 0x00000000000005c6 <+6>: pushq $0x1 + 0x00000000000005cb <+11>: jmpq 0x5a0 +End of assembler dump. +0x201020 : 0x000005c6 +@end example + +So in this case the address 0x201020 from the current instruction +would be initially set to the address of the pushq instruction found +at the offset of 0x5c6. + +The push stores the function within the object on the stack. Then it +jumps to 0x5a0 which is a special entry in the PLT called PLT0. It +pushes the offset of the library onto the stack and then jumps to a +resolver function which is in part of the dynamic linker. At the end +of the resolution function, if the library is not being profiled or +audited then, the resolver function will store the location of the +function in the GOT. + +@example +$ gdb libtest.so --quiet -ex "disassemble 0x5a0, 0x5ac" -ex quit +Reading symbols from libtest.so...done. +Dump of assembler code from 0x5a0 to 0x5ac: + 0x00000000000005a0: pushq 0x200a62(%rip) # 0x201008 + 0x00000000000005a6: jmpq *0x200a64(%rip) # 0x201010 +End of assembler dump. +@end example + +While calling into some static stub code which does an indirect jump +to a function pointer from the GOT is straight forward enough, this +trick of preloading the GOT entries for a function with the +instruction immediately after the indirect jump to the very next +instruction after the indirect jump can be confusing at first. The +trick to understanding it is realizing that after the function is +bound, the code after that indirect jump is never reached. + +@node Linkage Tables +@subsection Linkage Tables +@findex dlopen +@findex dlmopen +Linkage tables are lists of the objects that the dynamic linker has +loaded into the process's address space. They are defined in +@file{} and made up of the @code{link_map} structure. The +executable, the libraries that it needs to run, and any object files +that it opens with @code{dlopen} will be linked together in a doubly +linked list in a base link map. However, a process which opens objects +using @code{dlmopen} will have other link maps as well. + +These @code{link_map} structures should be considered read only and +should not be modified. In addition to the the @code{l_next} and +@code{l_prev} pointers connecting the list, each @code{link_map} +structure has the @code{l_name} which is the name of the object +represented by this structure. In most cases, this value is filled in, +however the name of the executable object being run is not set because +it is loaded before the dynamic linker object @code{ld_linux} is +loaded. Each @code{link_map} structure also has a @code{l_addr} which +provides the difference between the address in ELF file and the +address of the object in memory. This can be used to associate the +location in the object file with the associated location in +memory. Finally, they also have a @code{l_ld} pointer which points to +the object file's ELF dynamic section. The contents of the ELF dynamic +section can be viewed using the @command{readelf} command. + +@example +$ readelf -d /usr/bin/ls + +Dynamic section at offset 0x1ad88 contains 27 entries: + Tag Type Name/Value + 0x0000000000000001 (NEEDED) Shared library: [libselinux.so.1] + 0x0000000000000001 (NEEDED) Shared library: [libcap.so.2] + 0x0000000000000001 (NEEDED) Shared library: [libacl.so.1] + 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] + 0x000000000000000c (INIT) 0x402228 + 0x000000000000000d (FINI) 0x412bfc + 0x0000000000000019 (INIT_ARRAY) 0x61a290 + 0x000000000000001b (INIT_ARRAYSZ) 8 (bytes) + 0x000000000000001a (FINI_ARRAY) 0x61a298 + 0x000000000000001c (FINI_ARRAYSZ) 8 (bytes) + 0x000000006ffffef5 (GNU_HASH) 0x400298 + 0x0000000000000005 (STRTAB) 0x400f30 + 0x0000000000000006 (SYMTAB) 0x4002d0 + 0x000000000000000a (STRSZ) 1468 (bytes) + 0x000000000000000b (SYMENT) 24 (bytes) + 0x0000000000000015 (DEBUG) 0x0 + 0x0000000000000003 (PLTGOT) 0x61b000 + 0x0000000000000002 (PLTRELSZ) 2760 (bytes) + 0x0000000000000014 (PLTREL) RELA + 0x0000000000000017 (JMPREL) 0x401760 + 0x0000000000000007 (RELA) 0x401688 + 0x0000000000000008 (RELASZ) 216 (bytes) + 0x0000000000000009 (RELAENT) 24 (bytes) + 0x000000006ffffffe (VERNEED) 0x4015f8 + 0x000000006fffffff (VERNEEDNUM) 2 + 0x000000006ffffff0 (VERSYM) 0x4014ec + 0x0000000000000000 (NULL) 0x0 +@end example + +For further information regarding the dynamic section the @cite{Executable and Linkable Format (ELF)} standard. + +@node Environmental Variables +@section Environmental Variables +@c TODO: currently nothing here + +@env{LD_LIBRARY_PATH} +@vindex LD_LIBRARY_PATH +@c TODO + +@env{LD_PRELOAD} +@vindex LD_PRELOAD +@c TODO + +@env{LD_DEBUG} +@vindex LD_DEBUG +@c TODO + +@env{LD_DEBUG_OUTPUT} +@vindex LD_DEBUG_OUTPUT +@c TODO + +@env{LD_PROFILE} +@vindex LD_PROFILE +@c TODO + +@env{LD_PROFILE_OUTPUT} +@vindex LD_PROFILE_OUTPUT +@c TODO + +@env{LD_HWCAP} +@vindex LD_HWCAP +@c TODO + +@env{LD_AUDIT} +@vindex LD_AUDIT +@c TODO + +@env{LD_ASSUME_KERNEL} +@vindex LD_ASSUME_KERNEL +@c TODO + +@env{LD_BIND_NOW} +@vindex LD_BIND_NOW +@c TODO + +@env{LD_BIND_NOT} +@vindex LD_BIND_NOT +@c TODO + +@env{LD_TRACE_LOADED_OBJECTS} +@vindex LD_TRACE_LOADED_OBJECTS +@c TODO + +@env{LD_TRACE_PRELINKING} +@vindex LD_TRACE_PRELINKING +@c TODO + +@env{LD_SHOW_AUXV} +@vindex LD_SHOW_AUXV +@c TODO + +@env{LD_USE_LOAD_BIAS} +@vindex LD_USE_LOAD_BIAS +@c TODO + +@env{LD_WARN} +@vindex LD_WARN +@c TODO + +@env{LD_VERBOSE} +@vindex LD_VERBOSE +@c TODO + +@env{LDD_ARGV0g} +@vindex LDD_ARGV0g +@c TODO + +@node Dynamic Linker API Functions +@section Dynamic Linker API Functions +@cindex Dynamic Linker API Functions +@theglibc in conjunction with the underlying operating system provides +several functions which can be called from applications to load +linkable objects, most frequently libraries and plugins, and find the +addresses of symbols within them so that they can subsequently be +called through a function pointer. These functions are well documented +in their associated man pages. + +These functions are all defined in @file{} and exist in the +@file{libdl} library. + +@findex dlopen +@deftypefun void *dlopen(const char *@var{filename}, int @var{flag}) +@c TODO +@end deftypefun + +@findex dlmopen +@deftypefun void *dlmopen(Lmid_t @var{lmid}, const char *@var{filename}, int @var{flag}) +@c TODO - there isn't even a man page for this +@end deftypefun + +@findex dlerror +@deftypefun char *dlerror() +@c TODO +@end deftypefun + +@findex dlsym +@deftypefun void *dlsym(void *@var{handle}, const char @var{*symbol}) +@c TODO +@end deftypefun + +@findex dlclose +@deftypefun int dlclose(void *@var{handle}) +@c TODO +@end deftypefun + +@node Audit Interface +@section Audit Interface +@cindex rtld-audit +@cindex Audit, dynamic linking + +The dynamic linker provides an interface to monitor and intercept its +functioning. Since this interface was modeled after the Solaris's +audit interface, a good reference to it's operation is the Oracle +@cite{Solaris Linker and Libraries Guide}. +@c The linux man page for +@c rtld-audit(7) has a brief summary of the interface. + +@vindex LD_AUDIT +To run a program with an audit library, set the @env{LD_AUDIT} +environment variable to a colon separated list of shared libraries +which implement any subset of the functions listed above containing +@code{la_version()} which is required to be present in all audit libraries. +@findex la_version + +The current implementation of the run time linker audit interface +currently includes the following functions. + +@menu +* la_version:: Negotiate the version of the audit interface. +* la_objsearch:: Called when searching for a library. +* la_activity:: Called the link map is updated. +* la_objopen:: Called when an object file is opened. +* la_objclose:: Called just before the object file is unloaded. +* la_preinit:: Called after libraries are loaded but before main is called. +* la_symbind:: Called when a symbol is bound. +* la_pltenter:: Called when entering the PLT. +* la_pltexit:: Called when exiting the PLT. +@end menu + +@node la_version +@subsection la_version +@deftypefun unsigned int la_version(unsigned int @var{version}) +@findex la_version + +This is the only function guaranteed to be implemented by the every +version of the audit interface. It is also the only function required +to be defined in every audit library. + +The parameter passed in, is the highest version of the audit interface +that the run time linker implements. An audit library should check +this version to make sure that the run time linker implements a +version of the audit interface that is compatible and sufficient for +its needs. The audit library should return the version of the +interface that it intends to use to use. While this is likely to be +the same as the version passed in as a parameter, it can also be an +older version. This allows an older audit library to still work with a +newer version of the audit interface. Currently, the run time linker +supports all previous versions of the audit interface and it is +expected that it will continue to provide backward compatibility with +these older versions of the interface for the foreseeable future. It +is unlikely that this guarantee of backward compatibility will be +broken during the lifetime of the ELF, Executable and Linkable File, +file format, but if the run time linker cannot support the version of +the audit interface returned by the auditing library's la_version() +function then that audit library will be ignored. One example where +this might be the case is if an audit library was compiled against a +newer version of glibc which implemented a newer version of the +interface and it required those new capabilities to run properly. The +audit library can also choose to return zero and the run time linker +will then ignore that audit library. + +The current version of the audit interface implemented by the run time +linker is defined as LAV_CURRENT in @file{link.h}. Thus a suggested +implementation of @code{la_version()} without the capability to run against +version one of the audit interface would be: + +@example +#define _GNU_SOURCE +#include + +#define LAV_DESIGN 2 +#if LAV_DESIGN > LAV_CURRENT +#error Please compile against a newer version of glibc +#endif + +unsigned int la_version(unsigned int version)@{ + if(version >= LAV_CURRENT) + return version; + return 0; +@} +@end example + +Since the difference between version one and version two of the audit +interface are very minor. It is very likely that almost all audit +libraries were either designed to be run against version one of the +interface or can easily be modified to run in a backward compatibility +mode with version one of the audit interface. +@end deftypefun + +@node la_objsearch +@subsection la_objsearch +@deftypefun char *la_objsearch(const char *@var{name}, uintptr_t *@var{cookie}, unsigned int @var{flag}) +@findex la_objsearch + +Within a run time linker audit library @code{la_obsearch()} is +invoked each time the run time dynamic linker is going to search for +an object. This function may be called multiple times during the +process of resolving the location of a library. Initially, the run +time linker passes in the name of the object found from DT_NEEDED +record in the dynamic section of the ELF header or the name passed +into the @code{dlopen()} function. This results in the first +invocation of the @code{la_objsearch()} function with the name of the +name of the object being searched for and the flag being set to +LA_SER_ORIG. Subsequent steps in the object resolution process such as +RPATH and RUNPATH records in the ELF header or @env{LD_LIBRARY_PATH} +passed in through the environment will result in invocations of the +@code{la_objsearch()} function. For example a simple program that just +needs libc for printf will result in two invocations of +@code{la_objsearch()}. The first will be the initial search and the +second will be from the paths found in the @file{ld.so.cache}. + +@pindex nm +@pindex readelf +@example +$ nm ./main | grep `` U `` + U __libc_start_main@@GLIBC_2.2.5 + U printf@@GLIBC_2.2.5 +$ readelf -d ./main | egrep ``NEEDED|RPATH|RUNPATH'' + 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] +$ LD_AUDIT=./audit.so ./main +name=libc.so.6 cookie=0x7f7bc625b5c8 flag=LA_SER_ORIG +name=/lib64/libc.so.6 cookie=0x7f7bc625b5c8 flag=LA_SER_CONFIG +@end example + +The possible values for flag are: + +@var{LA_SER_ORIG} This is the original name either found in the ELF +dynamic header or the parameter passed in by dlopen(3). + +@var{LA_SER_CONFIG} This is the name found in +@file{/etc/ld.so.cache}. Most of the time system libraries will be +found in the cache rather than being found by using +@var{LA_SER_DEFAULT}. + +@var{LA_SER_DEFAULT} This is much more unusual than might be +expected. This will only happen if ldconfig has never been run or if +new libraries were added to the default directories since the last +time that ldconfig(8) was run. + +@var{LA_SER_LIBPATH} This flag is returned when the library is found in one +of the directories specified in the environment variable +@env{LD_LIBRARY_PATH}. +@vindex LD_LIBRARY_PATH + +@var{LA_SER_RUNPATH} This flag is returned when the library is found +in a directory specified in either the RPATH or RUNPATH ELF headers. + +The @var{cookie} is an opaque handle that refers to the object file +which requested the object be opened. In the case of shared libraries +needed by the original executable's object file, the @var{cookie} will +refer to an unnamed object at the root of the link-map. When an object +being searched for is required by another object as is the case when +you have library dependencies, the cookie will refer to the object +which has the dependency. In the case, where @code{dlopen} or +@code{dlmopen} is called the cookie will refer to the object which +initiated one of those function calls. +@findex dlopen +@findex dlmopen +@end deftypefun + +@node la_activity +@subsection la_activity +@findex la_activity +@deftypefun void la_activity( uintptr_t *@var{cookie}, unsigned int @var{flag}) + +@findex dlmopen +The dynamic linker will call the @code{la_activity()} function any +time that it is updating the link-map. @var{cookie} identifies the +head of the chain of link maps that is being updated. Most +applications will have a single link-map that will be updated, the +global link map. However an application that makes use of +@code{dlmopen()} will have other link maps. The @var{flag} will be one +of the following values. + +@vindex LA_ACT_ADD +@var{LA_ACT_ADD} indicates that new objects are being added to the +link map. During initial executable startup, the object that you are +executing and ld.so and a third unnamed object that is part of the +dynamic linker are inserted into the base link map before +@code{la_activity} is called for the first time with @var{LA_ACT_ADD} +indicating that the link map is going to be added to. It may be +important for some audit libraries expecting a static link map to +recognize that the link map may be updated without notification before +the first call of @code{la_activity} with @var{LA_ACT_ADD}. + +@findex dlclose +@vindex LA_ACT_DELETE +@var{LA_ACT_DELETE} indicates that objects are being removed from the link +map. This only will happen as a result of a @code{dlclose} function +call. + +@vindex LA_ACT_CONSISTENT +@var{LA_ACT_CONSISTENT} indicates that the link-map activity has finished +and that the link-map is now consistent. + +If an application doesn't call any of the @code{dl*} functions, then +before starting @code{main} then the dynamic linker will first add the +shared libraries and then report that the link map is consistent. It +does not repeatedly call la_activity each and every time a library is +added to the link map. For that, an audit library should implement +@code{la_objopen()}. +@findex la_objopen + +@example +$ readelf -d /usr/bin/ls | grep NEEDED +0x0000000000000001 (NEEDED) Shared library: [libselinux.so.1] +0x0000000000000001 (NEEDED) Shared library: [libcap.so.2] +0x0000000000000001 (NEEDED) Shared library: [libacl.so.1] +0x0000000000000001 (NEEDED) Shared library: [libc.so.6] +$ LD_AUDIT=./audit.so ls +cookie=0x7fcd7463d5c8 flag=LA_ACT_ADD +cookie=0x7fcd7463d5c8 flag=LA_ACT_CONSISTENT +@end example +@end deftypefun + +@node la_objopen +@subsection la_objopen +@findex la_objopen +@deftypefun unsigned int la_objopen( struct link_map *@var{map}, Lmid_t @var{lmid}, uintptr_t *@var{cookie}) + +The @code{la_objopen} function is called every time an object is added +to the link map. The first time that it is called is when the actual +binary that you are running is loaded. Since this is before even the +dynamic linker is fully loaded, the @var{l_name} is not set. The next +time it is run is when the dynamic linker itself being loaded. This +brings along another unnamed object in the link map. After that, every +shared library triggers a call to @code{la_objopen}. + +@findex la_symbind +@findex la_pltenter +@findex la_pltexit +Implementing @code{la_objopen} is practically required in every audit +library that is interested in implementing @code{la_symbind}, +@code{la_pltenter}, @code{la_pltexit} because it must set flags when +the object is being opened that indicate to the dynamic linker that +further auditing is desired. + +@findex dlopen +@findex dlmopen +@vindex LM_ID_BASE +@vindex LM_ID_NEWLM +There can be multiple @code{link_maps}. When an object is loaded at +process startup or with the normal @code{dlopen} function, then +@var{lmid} will be set to @var{LM_ID_BASE}. However when an object is +opened with @code{dlmopen}, lmid will be set to @var{LM_ID_NEWLM} +indicating that the object has been loaded into its own link map. + +The link map is the top of a NULL terminated doubly linked list of +@code{link_map} structures. In the case of the base link map, at the +root of the list are three objects. The first is the executable being +run and the other two are part of the dynamic linker itself. + +The cookie is an opaque handle that associates operations pertaining +to that object to an object being loaded. Since, this is the first use +of each cookie, the cookie provided to @code{la_objopen} serves as the +declaration of cookie for subsequent use. + +@vindex LA_FLG_NOBIND +@vindex LA_FLG_BINDFROM +@vindex LA_FLG_BINDTO +@findex la_symbind +The return value of the function is either @var{LA_FLG_NOBIND} which +is defined to be zero, or it is a bitwise OR of one or more of +@var{LA_FLG_BINDFROM} and @var{LA_FLG_BINDTO}. For the +@code{la_symbind} function to be called, the symbol being referenced +must be in an object where the return value of @code{la_objopen} must +include @var{LA_FLG_BINDTO} and the object from where it is referenced +must have had a return value that included @var{LA_FLG_BINDFROM}. + +If you wanted to see all the places where a particular executable +calls a function from libc, the @code{la_objopen} might include a +fragment of code like: +@example + if(map->l_prev==NULL) // the main executable + retval=LA_FLG_BINDFROM; + if( strstr(map->l_name,"libc.so")!=NULL) + retval=LA_FLG_BINDTO; + return retval; +@end example + +@vindex LA_FLG_NOBIND +The return value of either @var{LA_FLG_NOBIND} or 0 indicates that +no further monitoring is desired for this particular object by this +auditing library. In other words you are not interested in auditing +the binding of symbols within this object. + +Unless it is needed, it is advisable to not audit the binding of +symbols. The auditing of the binding of symbols not without costs. In +the normal case when a function in a separate object is first +referenced, the location is determined and it is stored in the GOT so +that subsequent calls do not incur additional overhead. However, when +an object's symbol binding is audited, then each reference is +intercepted for auditing. + +@vindex LA_FLG_BINDTO +The @var{LA_FLG_BINDTO} flag is set when auditing symbols that exists +in the object currently being opened. These are the symbols being called. + +@vindex LA_FLG_BINDFROM +The @var{LA_FLG_BINDFROM} flag is set when auditing references to +symbols that exist in other objects. These are the calls from this +object to symbols found in other objects. +@end deftypefun + +@node la_objclose +@subsection la_objclose +@findex la_objclose +@deftypefun unsigned int la_objclose(uintptr_t *@var{cookie}) + +This function is called after any termination code in the object has +been executed and just prior to the object being unloaded from +memory. The @var{cookie} is the one for the object returned by +@var{la_objload}. Currently the return value from this function being +is ignored. + +@findex dlclose +When the libraries are loaded as part of the standard process startup, +they are not closed when a process exits therefore this function is +not called except as a result of @code{dlclose()} +@end deftypefun + +@node la_preinit +@subsection la_preinit +@findex la_preinit +@deftypefun void la_preinit(uintptr_t *@var{cookie}) + +The @code{la_preinit} is called after all the shared libraries are +loaded, the link map is consistent, and after @code{__libc_start_main} +but before the executable object's @code{main} is called. + +The cookie passed in refers to the executable object being run. +@end deftypefun + +@node la_symbind +@subsection la_symbind +@findex la_symbind +@deftypefun uintptr_t la_symbind(Elf_Sym *@var{sym}, unsigned int @var{ndx}, uintptr_t *@var{refcook}, uintptr_t *@var{defcook}, unsigned int *@var{flags}, const char *@var{symname}) + +@code{uintptr_t la_symbind(Elf_Sym *@var{sym}, unsigned int @var{ndx}, uintptr_t *@var{refcook}, uintptr_t *@var{defcook}, unsigned int *@var{flags}, const char *@var{symname})} + +@code{uintptr_t la_symbind64(Elf64_Sym *@var{sym}, unsigned int @var{ndx}, uintptr_t *@var{refcook}, uintptr_t *@var{defcook}, unsigned int *@var{flags}, const char *@var{symname})} + +The exact name and argument types of vary from architecture to +architecture. The definition or definitions appropriate to your +architecture can be found in @file{/usr/include/bits/link.h}. The one +used above as an example is from the x86_64 where there are two +versions of @code{la_symbind} one for 32 bit symbols and one for 64 +bit symbols. + +@findex la_objopen +@findex la_pltenter +@vindex LA_FLG_BINDFROM +@vindex LA_FLG_BINDTO +One of these functions is invoked when symbol binding occurs between +objects. It is only called when the object from which the binding was +triggered is marked @var{LA_FLG_BINDFROM} and the function being +called is in an object marked @var{LA_FLG_BINDTO} by +@code{la_obopen}. Usually, with normal lazy binding, this symbol +binding occurs when the function is first called. This symbol binding +occurs before the @code{la_pltenter} function is called. This symbol +binding can occur at different times if lazy binding is not being +used. + +@vindex st_name, Elf_Sym +@var{sym} is a pointer to a Elf structure defined in +@file{elf.h}. There are different versions of this structure with +different word sizes for multilib systems. The structure +includes @var{st_value} which is the function pointer to the function +which is being called. + +@var{ndx} refers to the index into the table of symbols within the +object being referred to by @var{defcook}, the cookie for the object +where the symbol is defined. From the command line this same table +along with its indexes can be printed by using the @command{readelf +-s} command. + +The symbol is being called from the symbol referred to by +@var{refcook}, the cookie for the object referencing the symbol. + +@vindex LA_SYMB_DLSYM +@vindex LA_SYMB_ALTVALUE +@findex dlsym +The flags parameter is a pointer to a bit mask. The +@var{LA_SYMB_DLSYM} indicates that the symbol was as a result of a +call through @code{dlsym}. The other flag @var{LA_SYMB_ALTVALUE} +indicates that @code{la_symbind} provided an alternative value for the +symbol. + +@vindex LA_SYMB_NOPLTENTER +@vindex LA_SYMB_NOPLTEXIT +Applications wishing to prevent subsequent passes through the +@code{ls_pltenter} or the @code{ls_pltexit} functions can or in +@var{LA_SYMB_NOPLTENTER} and/or @var{LA_SYMB_NOPLTEXT} +respectively. These flags can be subsequently re-enabled if +desired. However, modifying the variable pointed to by the @var{flags} +parameter outside of the scope of this function will lead to +unspecified behavior. +@end deftypefun + +@node la_pltenter +@subsection la_pltenter +@findex la_pltenter +@deftypefun Elf64_Addr la_x86_64_gnu_pltenter (Elf64_Sym *@var{sym}, unsigned int @var{ndx}, uintptr_t *@var{refcook}, uintptr_t *@var{defcook}, La_x86_64_regs *@var{regs}, unsigned int *@var{flags}, const char *@var{symname}, long int *@var{framesizep}) + +The exact name and argument types of vary from architecture to +architecture. The definition or definitions appropriate to your +architecture can be found in @file{/usr/include/bits/link.h}. The one +used above as an example is from the x86_64. + +@vindex LA_FLG_BINDFROM +@vindex LA_FLG_BINDTO +@findex la_symbind +@findex la_pltexit +@vindex LA_SYMB_NOPLTENTER +This function is invoked just before calling a function through the +PLT. It is only called when the the object making the call is marked +@var{LA_FLG_BINDFROM} and the function being called is in an object +marked @var{LA_FLG_BINDTO} and when no previous calls to +@code{la_sybind}, @code{la_pltenter}, or @code{la_pltexit} have set +the @var{LA_SYMB_NOPLTENTER} bit in their @var{flags} parameter. + +@vindex st_name, Elf_Sym +@var{sym} is a pointer to a Elf structure defined in +@file{elf.h}. There are different versions of this structure with +different word sizes for multilib systems. The structure +includes @var{st_value} which is the function pointer to the function +which is being called. + +@var{ndx} refers to the index into the table of symbols within the +object being referred to by @var{defcook}. From the command line this +same table along with its indexes can be printed by using the +@command{readelf -s} command. + +The symbol is being called from the symbol referred to by @var{refcook}. + +The @var{regs} parameter is highly architecturally specific. It +contains the registers that are used for the call to this PLT +entry. It is defined in @file{/usr/include/bits/link.h}. + +@vindex LA_SYMB_DLSYM +@vindex LA_SYMB_ALTVALUE +@findex dlsym +@findex la_symbind +The flags parameter is a pointer to a bit mask and has the same +meaning as it does as when used in la_symbind. The @var{LA_SYMB_DLSYM} +indicates that the symbol was as a result of a call through +@code{dlsym}. The other flag @var{LA_SYMB_ALTVALUE} indicates that +@code{la_symbind} provided an alternative value for the symbol. + +@findex ls_pltenter +@findex ls_pltexit +@vindex LA_SYMB_NOPLTENTER +@vindex LA_SYMB_NOPLTEXIT +Applications wishing to prevent subsequent passes through the +@code{ls_pltenter} or the @code{ls_pltexit} functions can or in +@var{LA_SYMB_NOPLTENTER} and/or @var{LA_SYMB_NOPLTEXIT} +respectively. These flags can be subsequently re-enabled if +desired. However, modifying the variable pointed to by the @var{flags} +parameter outside of the scope of this function will lead to +unspecified behavior. + +@var{framesizep} +@c TODO +@end deftypefun + +@node la_pltexit +@subsection la_pltexit +@findex la_pltexit +@deftypefun unsigned int la_i86_gnu_pltexit(Elf32_Sym *@var{sym}, unsigned int @var{ndx}, uintptr_t *@var{refcook}, uintptr_t *@var{defcook}, const La_i86_regs *@var{inregs}, La_i86_retval *@var{outregs}, const char *@var{symname}) + +The exact name and argument types of vary from architecture to +architecture. The definition or definitions appropriate to your +architecture can be found in @file{/usr/include/bits/link.h}. The one +used above as an example is from the x86_64. + +@findex la_objopen +@findex la_pltenter +@vindex LA_FLG_BINDFROM +@vindex LA_FLG_BINDTO +@findex la_sybind +This function is invoked just before control returns to the caller for +the symbol referenced by this PLT entry. It is only called when the +the object making the call is marked @var{LA_FLG_BINDFROM} and the +function being called is in an object marked @var{LA_FLG_BINDTO} and +the function being called is in an object marked @var{LA_FLG_BINDTO} +and when no previous calls to @code{la_sybind}, @code{la_pltenter}, or +@code{la_pltexit} have set the @var{LA_SYMB_NOPLTEXIT} bit in their +@var{flags} parameter. + +@vindex st_name, Elf_Sym +@var{sym} is a pointer to a Elf structure defined in +@file{elf.h}. There are different versions of this structure with +different word sizes for multilib systems. The structure +includes @var{st_value} which is the function pointer to the function +which is being called. + +@var{ndx} refers to the index into the table of symbols within the +object being referred to by @var{defcook}. From the command line this +same table along with its indexes can be printed by using the +@command{readelf -s} command. + +The symbol is being called from the symbol referred to by @var{refcook}. + +The @var{inregs} and @var{outregs} are both architecture dependent +and are defined by in @file{/usr/include/bits/link.h}. The +@var{inregs} parameter points to a structure containing the registers +used to call this PLT entry. Similarly, @var{outregs} points to a +structure containing the return values for the call to this PLT +entry. This value can be modified and the changes will be visible to +the caller of this PLT entry. + +The return value for this function is currently ignored. +@end deftypefun diff --git a/manual/libdl.texi b/manual/libdl.texi deleted file mode 100644 index e3fe045..0000000 --- a/manual/libdl.texi +++ /dev/null @@ -1,10 +0,0 @@ -@c FIXME these are undocumented: -@c dladdr -@c dladdr1 -@c dlclose -@c dlerror -@c dlinfo -@c dlmopen -@c dlopen -@c dlsym -@c dlvsym diff --git a/manual/signal.texi b/manual/signal.texi index 77f3d7c..e53ff8d 100644 --- a/manual/signal.texi +++ b/manual/signal.texi @@ -1,4 +1,4 @@ -@node Signal Handling, Program Basics, Non-Local Exits, Top +@node Signal Handling, Dynamic Linking, Non-Local Exits, Top @c %MENU% How to send, block, and handle signals @chapter Signal Handling -- 2.1.0