nisse@lysator.liu.se (Niels Möller) writes:
Clearly, this will be more useful after adding support for fat binaries, detecting presence of these instructions at runtime.
I've now had a first go at fat-library support. Checked in on the branch fat-library. See https://git.lysator.liu.se/nettle/nettle/blob/fat-library/x86_64/fat/fat.c
Configuration is a bit clumsy and should probably be reorganized when as functions are added, but it seems to work. Except that I try to make it more verbose if NETTLE_FAT_VERBOSE is set in the environment, but on the machine where I tested static library build, there's no output. Maybe the initialization is this case is done before stderr is setup properly. There may be some remaining problems in getting the Makefiles and configure to work with machine-specific files which are C rather than assembly code.
Let me quote the initial comment in fat.c:
/* Fat library initialization works as follows. The main function is fat_init. It tries to do initialization only once, but since it is idempotent and pointer updates are atomic on x86_64, there's no harm if it is in some cases called multiple times from several threads.
The fat_init function checks the cpuid flags, and sets function pointers, e.g, _aes_encrypt_vec, to point to the appropriate implementation.
To get everything hooked in, we use a belt-and-suspenders approach.
When compiling with gcc, we try to register a constructor function which calls fat_init as soon as the library is loaded. If this is unavailable or non-working, we instead arrange fat_init to be called on demand.
For the actual indirection, there are two cases.
If ifunc support is available, function pointers are statically initialized to NULL, and we register resolver functions, e.g., _aes_encrypt_resolve, which calls fat_init, and then returns the function pointer, e.g., the value of _aes_encrypt_vec.
If ifunc is not available, we have to define a wrapper function to jump via the function pointer. (FIXME: For internal calls, we could do this as a macro instead). We statically initialize each function pointer to point to a special initialization function, e.g., _aes_encrypt_init, which calls fat_init, and then invokes the right function. This way, all pointers are setup correctly at the first call to any fat function. */
Regards, /Niels