flan/test/cell-override.c

32 lines
1.3 KiB
C

/* Redefine flan.cell.twice from outside the program, without a compiler.
*
* A dev build exports one cell per function -- a mutable global holding the
* address of the body that is current -- and it is -rdynamic, so the cell is
* in .dynsym and dlsym can find it by name. Storing a different function
* pointer there is the whole of what a redefinition does to an existing call
* site; the rest of the dev loop is about producing the new body, and none of
* that is needed to answer "does a call actually read the cell".
*
* A Flan function's signature is its parameters followed by the transfer
* channel, so this takes (i64, void *) where the Flan body takes (n i64). It
* never transfers, so it never writes through the channel.
*
* A release build has no cells, dlsym answers NULL, and this does nothing --
* which is the control: it shows the change below comes from the indirection
* and not from ordinary symbol interposition. See test/cells.sh.
*/
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stddef.h>
#include <stdint.h>
static int64_t instead(int64_t n, void *xfer) {
(void)xfer;
return n + 1;
}
__attribute__((constructor)) static void install(void) {
void **cell = (void **)dlsym(RTLD_DEFAULT, "flan.cell.twice");
if (cell != NULL) *cell = (void *)instead;
}