32 lines
1.3 KiB
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;
|
|
}
|