Last active
August 12, 2022 18:31
-
-
Save toasterparty/c39ef97787154d53c7ba9f77e61b5f4c to your computer and use it in GitHub Desktop.
Abuse GCC's section attribute to iterate through compile-defined (but dynamically included/excluded) data.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// If you want to play with this code, I reccomend https://jdoodle.com/ia/tPT | |
// Most other online compilers fail to respect the section definitions | |
// | |
// This file is a demonstration on how you can use macros and gcc section attributes to | |
// arbitrarily access functions/memory from another file's static scope at *link time* | |
// and without the use of runtime function pointers. It ONLY works with projects linked using gcc. | |
// | |
// Real world usage of this include: | |
// - Implementing a component-oriented API where each components adds support for their | |
// specific command(s) without having to maintain a large API manifest. | |
// - Callback handlers + handler data without consuming RAM | |
// - Executing tests on non-production code without polluting non-test code | |
// - Kernel Security Magic that goes above my head | |
#include <stdio.h> | |
/*** Magical Tools ***/ | |
/* Neatly define a function pointer with no arguments and no return value */ | |
typedef void (*magic_function_t)(void); | |
/* Define struct to contain smuggled data */ | |
typedef struct { | |
magic_function_t function; | |
} magic_struct_t; | |
/* Helper macro for instantiating a unique instance of the above struct */ | |
#define DECLARE_HELPER_STRUCT(fn) static const magic_struct_t magic_struct_##fn __attribute__((unused)) = {.function = fn} | |
/* Macro to define a constant function pointer inside of a constant struct, and then | |
define a pointer to that struct inside of our custom section which we use to smuggle data. | |
If we don't use a pointer to a struct, discrepancies in .text and .data/.bss memory alignment | |
can cause severe problems. Ideally the compiler chooses to place these constants in .text to | |
save memory, but we don't have direct control of that as the programmer. */ | |
#define DECLARE_FUNCTION_MAGICAL(fn) \ | |
DECLARE_HELPER_STRUCT(fn); \ | |
static const magic_struct_t* magic_struct_ptr##fn __attribute__((section("magic"))) __attribute__((unused)) = &(magic_struct_##fn) | |
/* GCC automatically defines these during link-time (__start_<section-name-here> and __stop_<section-name-here>). As such, this trick only works | |
with GCC compilers. */ | |
extern magic_struct_t* __start_magic; | |
extern magic_struct_t* __stop_magic; | |
/*** Magical Instantiation ***/ | |
/* From this section's perspective, what goes on appears like magic */ | |
static void magic_function_a(void) { | |
printf("Compiler Magic Occured (a)\n"); | |
} | |
static void magic_function_b(void) { | |
printf("Compiler Magic Occured (b)\n"); | |
} | |
DECLARE_FUNCTION_MAGICAL(magic_function_a); | |
DECLARE_FUNCTION_MAGICAL(magic_function_b); | |
/*** Magical Invocation ***/ | |
/* This could be litterally anywhere as long as it gets linked at the same time as the above */ | |
int main(void) { | |
/* Iterate through struct-sized chunks of our custom | |
segment until we reach the linker-provided end of | |
segment address */ | |
magic_struct_t **iter = &__start_magic; | |
for ( ; iter < &__stop_magic; ++iter) { | |
magic_struct_t* magic_struct = *iter; | |
magic_struct->function(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment