Problem:
On AIX, functions registered by atexit in a shared library are not run
when the library is dlclosed, but instead run (and fail because the
function pointer is no longer valid) during main program exit.
The profile-rt registers some functions with atexit:
1. writeFileWithoutReturn that writes out the profile file
2. llvm_delete_reset_function_list that does some cleanup in the gcov
instrumentation library (not sure)
And so right now, we get an "Illegal instruction (core dumped)" when an
instrumented shared object is dlopen'ed and dlclosed.
Solution:
When a shared library is dlclose'd, destructors from the library are
called. So create a destructor function that iterates over all known
functions that profile-rt registers with atexit, and unregister the ones
that have been registered and execute them.
Scenarios tested:
(0) gcov dlopen/dlclose (AIX/gcov-dlopen-dlclose.test)
(1) multiple dlopen/dlclose of the same lib and multiple libs (instrprof-dlopen-dlclose.test)
(2) dlopen but no dlclose (exists: Posix/instrprof-dlopen.test)
(3) a simple fork testcase with dlopen/dlclose (instrprof-dlopen-dlclose.test)
(4) dlopen/dlclose by multiple threads. (instrprof-dlopen-dlclose.test)
(5) regular dynamic-linking of instrumented shared libs (exists: AIX/shared-bexpall-pgo.c)
(6) a simple fork testcase produces correct profile (instrprof-fork.c)
---------
Co-authored-by: Hubert Tong <hstong@ca.ibm.com>