/* 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 spike/x86/cells.sh. */ #define _GNU_SOURCE #include #include #include 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; }