Objects can now reference foo(), and at runtime the best variant is chosen. To observe this, a simple executable is sufficient.
$ cat main.c extern void foo(); int main() { foo(); return (0); } $ cc -o main.1 main.c -R. libfoo.so.1
In this example, libfoo.so.1 requires object capabilities. These capabilities originate from additional objects that the compiler added to the creation of libfoo.so.1.
$ elfdump -H libfoo.so.1 ... Object Capabilities: index tag value [0] CA_SUNW_HW_1 0x800 [ SSE ] ...
The generic foo() variant can be exercised by restricting the capabilities available within a process to the object capabilities required by libfoo.so.1.
$ LD_HWCAP=SSE LD_CAP_FILES=libfoo.so.1 ./main.1 called: foo-generic
Each variant within libfoo.so.1 can be exercised by establishing the capabilities that each variant requires together with the object capabilities that libfoo.so.1 requires.
$ LD_HWCAP=SSE,AES LD_CAP_FILES=libfoo.so.1 ./main.1 called: foo-HWCAP-1 $ LD_HWCAP=SSE,AVX LD_CAP_FILES=libfoo.so.1 ./main.1 called: foo-HWCAP-2
Similarly, the variants within an executable containing symbol capabilities can be exercised.
$ LD_HWCAP=SSE LD_CAP_FILES=main.2 ./main.2 called: foo-generic $ LD_HWCAP=SSE,AES LD_CAP_FILES=main.2 ./main.2 called: foo-HWCAP-1 $ LD_HWCAP=SSE,AVX LD_CAP_FILES=main.2 ./main.2 called: foo-HWCAP-2
This example demonstrates the creation and execution of a capabilities family. A real solution would substitute the foo() capabilities variants with code that is targeted to use specific capabilities. The appropriate capabilities variant is then chosen based on the capabilities available to the process at runtime from the system on which the process executes.