So I was studying about shared libraries and I read that an implicit dlclose() is performed upon process termination.
I want to know who is responsible for this call. For example, if I wrote:
#include <stdio.h>
int main() {
printf("Hello World\n");
return 0;
}
And then if I did ldd ./a.out then I get a list of these libraries:
linux-vdso.so.1 => (0x00007ffd6675c000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2569866000)
/lib64/ld-linux-x86-64.so.2 (0x0000562b69162000)
Linker is responsible for loading these right, so who is responsible upon termination of this ./a.out executable for implicit dlclose() of these libraries?
I do not have Kerrisk's book, but if you have accurately characterized its contents then they seem to be a bit simplified. It is not strictly correct to say that whenever a process terminates, the function dlclose() is called for each of its open shared libraries, but it is reasonable to say that whenever a process terminates, all its handles on open shared libraries are closed. As a result, the operating system recognizes that one fewer process references each of those shared libraries, and if that brings any shared libraries' reference counts to zero then the OS may choose to unload them from memory.
dlclose() does more work than that. In particular, it causes any destructor functions in the library to run. Those functions will also run when the process exits normally by returning from main() or by calling exit(), but not if the process terminates by other means, such as calling _exit() or in response to receiving a signal. In the normal-exit case, the net effect may be the same as if dlclose() were called for each open shared library, but even then, that's not necessarily achieved by actually calling dlclose().
Finally, do be aware that although the dl*() functions are defined by POSIX, substantially all details of dynamic / shared libraries are left at the discretion of implementations. Since you've asked about a Linux book, I've referenced a few Linux-specific details.
I suspect the book is only talking about normal process termination when calling exit() or returning from main(). dlopen() presumably registers an atexit() handler that executes all the termination functions of the dynamic libraries.
It's not feasible for libraries to execute any code when a process is terminated abnormally. If the process is terminated by the OS instead of by exiting normally, the OS just releases any file handles, but it won't execute code in the context of the process.
Related
I've come across at_quick_exit and quick_exit while going over stdlib.h and looking for functions that I haven't implemented.
I don't understand the point of having these two functions. Do they have any practical usage?
Basically it exists in C because of C++. The relevant document from WG 14 C standard committe can be found here.
The document was adapted from the paper accepted by the C++ standard. The idea behind quick_exit is to exit the program without canceling all threads and without executing destructors of static objects. C doesn't has language support for such things as "destructors" at all and the thread support library in C is almost nowhere implemented. The at_quick_exit and quick_exit functions have very little to no meaning at all in C.
In C there is a function _Exit that causes normal program termination to occur and control to be returned to the host environment, but is not required to flush open file descriptors, write unbuffered data, close open files, as opposed to exit(). Basically the at_quick_exit and quick_exit functions are facilities build to run custom user handles and then execute _Exit, while atexit is a facility to execute custom handlers upon calling exit().
They essentially have no practical usage. The intent seems to be that a function that may have significant nontrivial atexit handlers could use quick_exit to exit with just a minimal subset of such handlers (that it defines by calling at_quick_exit) being called, under conditions where calling all the atexit handlers may not be safe. It may also be called from a signal handler, but it doesn't seem like there'd be anything meaningful you could do from the at_quick_exit handlers in that case.
I have read this discussion which discuss about how to check the signal actions of each process:
How can I check what signals a process is listening to?
However, I want to use C/C++, Python or other ways to get the userspace of the signal handler name of each process. Just like the psig in Solaris:
What is the meaning of every column when executing psig command?
Would it be possible to do that in Linux?
Because the Linux kernel does not expose the signal handlers (other than using the sigaction() (or signal()) syscall in the process itself), you need to inject executable code to the target process to obtain this information.
(Or, alternatively, create a Linux kernel module that exposes this information.)
So, this is definitely a c linux question.
Note that it is not possible to always obtain the name of a function, because the handler can be declared static void without any particular name in the binary.
The easiest approach would be to create a dynamic library to interpose signal() and sigaction(), with an ELF constructor function (not related to C++; Linux ELF binaries just support marking functions "constructor", in which case they are automatically executed prior to main()) that opens a suitable log file in write-only append mode, say /var/log/sighandlers/PID.log, and dumps the contents of /proc/self/maps to record the addresses the binaries are loaded in. The interposed functions will then simply write the addresses of newly assigned handlers to the log file.
It is important to note that both sigaction() and signal() are async-signal safe functions, so the interposed versions should be, too. (Fortunately, you only need write(), which is async-signal safe. I recommend using dlsym() to look up the original function pointers in the ELF constructor function.)
When examining the log file, the function addresses should be calculated relative to the beginning of the binary mapping, then objdump -tT binary or objdump -d binary to find the symbol the address belongs to.
I would personally not bother with any other approaches, even if this requires one to execute each binary using a special command (setting LD_LIBRARY_PATH) to find them out; it is either that, or a kernel module.
I learned how assembly (x86) globally works in the book : "Programming from ground up".
In this book, every program ends with an interruption call to exit.
However, in C compiled programs, I found out that programs end with a ret. This supposes that there is an address to be popped and that would lead to the end of the program.
So my question is :
What is this address? (And what is the code there?)
You start your program by asking the OS to pass control to the start or _start function of your program by jumping to that label in your code. In a C program the start function comes from the C library and (as others already said before) does some platform specific environment initialization. Then the start function calls your main and the control is yours. After you return from the main, it passes control back to the C library that terminates the program properly and does the platform specific system call to return control back to the OS.
So the address main pops is a label coming from the C library. If you want to check it, it should be in stdlib.h (cstdlib) and you will see it calling exit that does the cleanup.
Its function is to destroy the static objects (C++ of course) at program termination or thread termination (C++11). In the C case it just closes the streams, flushes their buffers, calls atexit functions and does the system call.
I hope this is the answer you seek.
It is implementation specific.
On Linux, main is called by crt0, and the _start entry point there is analyzing the initial call stack set up by the kernel interpreting the execve(2) system call of your executable program. On return from main the epilogue part of crt0 is dealing with atexit(3) registered functions and flushing stdio.
FWIW, crt0 is provided by your GCC compiler, and perhaps your C standard library. All this (with the Linux kernel) is free software on Linux distribution.
every program ends with an interruption call to exit.
Not really. It is a system call (see syscalls(2) for their list), not an interrupt. See also this.
I have a library which registers an atfork handler (via pthread_atfork()) which does not support multiple threads when fork() is called. In my case, I don't need the forked environment to be usable because all I want is to call exec() right after the fork(). So, I want the fork() but without any atfork handlers. Is that possible? Do I miss any important edge cases?
For background info, the library is OpenBlas, the issue is described here and here.
You could use vfork() (NPTL implementation doesn't call fork handlers). Although POSIX has removed vfork from the standard, it's likely available on your implementation.
Fork handlers established using pthread_atfork(3) are not called when
a multithreaded program employing the NPTL threading library calls
vfork(). Fork handlers are called in this case in a program using
the LinuxThreads threading library. (See pthreads(7) for a
description of Linux threading libraries.)
Or, posix_spawn(). This is similar to vfork. Man page says:
According to POSIX, it unspecified whether fork handlers established with pthread_atfork(3) are called when posix_spawn() is invoked. On glibc, fork handlers are called only if the child is created using fork(2).
Or, syscall and directly use SYS_clone. SYS_clone is the system call number used to create threads and processes on Linux. So syscall(SYS_clone, SIGCHLD, 0); should work, provided you would exec immediately.
syscall(SYS_fork); (as answered by Shachar) would likely work too. But note that SYS_fork not available on some platforms (e.g., aarch64, ia64). SYS_fork is considered as obsolete in Linux and it's only there for backward compatibility and Linux kernel uses SYS_clone for creating all "types" of processes.
(Note: These options are mostly limited to glibc/Linux).
Yes. The following should work on Linux (and, I think, all glibc based platforms):
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
...
syscall(SYS_fork);
This bypasses the library and directly calls the system call for fork. You might run into trouble if your platform does not implement fork as a single system call. For Linux, that simply means that you should use clone instead.
With that in mind, I'm not sure I'd recomment doing that. Since you're a library, you have no idea why someone registered an atfork. Assuming it's irrelevant is bad programming practice.
So you lose portability in order to do something that may or may not break stuff, all in the name of, what? Saving a few function calls? Personally, I'd just use fork.
I'm interested in whether I can call an arbitrary function on _exit(2) call, which bypasses other hooking architectures, so it doesn't seem easy to me.
If this is an ordinary exit(3) or return statement, obviously it's possible by atexit(3), on_exit(3), or __attribute__((destructor)) with gcc extension
It is possible by overriding _exit(2) with LD_PRELOAD; which I wish to avoid
Is there a way to do it without LD_PRELOAD, say, overriding _exit(2)?
Edit: The problem I'm facing is fork(2)ed Perl programs with CoW. The program's children processes run destructors on exit(3) call, in which they touch many memory locations, to cause large memory copy, in spite they will exit.
It's hard to bypass destructors with ordinary exit call in Perl, so an idea is call POSIX::_exit instead.
However, there is a dynamically loaded library with LD_PRELOAD, and I want to call a function in it on process exit.
AFAIU, it is simply not possible without LD_PRELOAD tricks, or ptrace(2) with PTRACE_SYSCALLfrom another process (e.g. the parent process running gdb). At the lowest level, _exit(2) is a system call so is an "atomic" operation using the SYSENTER machine instruction, e.g. thru vdso(7).
Notice that a C program could use some asm to invoke the _exit syscall (or use the indirect syscall(2))
Assuming a dynamically linked executable to GNU libc or musl-libc, your only way is to catch exit(3) library function (not the _exit(2) syscall!) using atexit(3)
You could redefine _exit and hope that the dynamic linker would call your _exit, not the one in libc. I won't play such tricks.
Alternatively, write a small wrapping C program which fork, execve and waitpid the original program.
could you make use of the 'atexit()' function call?
Near the beginning of main() call atexit() with a parameter of the function that you want executed when the program exits.
You can call atexit() numerous time, thereby stacking several things to be executed when the application exits.