3 ms·
I guess they mean to overwrite the pointers: void (*foo)(void) int main(){ *foo(); } void foo1(){...} foo = &foo1; // will be overwritten later
by Y_Y 2y ago
I guess they mean to overwrite the pointers:
void (*foo)(void)
int main(){
*foo();
}
void foo1(){...}
foo = &foo1; // will be overwritten later
void foo2(){...}
foo = &foo2;
I'm on my phone so I haven't compiled it, but that's the rough idea I got, define lots of versions and then set the version to the latest one.
(You can skip the address-of for functions by punning, but reading the types is hard enough already.)
- kragen 2y agoThat's not valid C; you can't put statements outside of functions, not even assignment statements or other expression statements. No C compiler I've ever used will accept it. Where would the compiled version of those statements go, in an init function? Linkers added support for those for C++ static initializers, where execution order isn't defined; C doesn't have anything similar. Are you expecting the compiler to execute the assignment statements at compile time, with a C interpreter?
- Y_Y 2y ago(What's the language lawyer equivalent of an ambulance chaser?) Fair point, I hadn't thought it all the way through. It's also all too easy to assume you can use C++ features or GNU extensions if you're not in the habit of enforcing the standard. For your trouble here are two partial solutions: --- 1. CPP abuse If I was doing this myself I'd probably just use the preprocessor to make the last function my entry point like SOURCE=file.c gcc -DLATEST_MAIN=$(grep -E "^[a-zA-Z_].*\(.*\)\s*\{" ${SOURCE} | tail -1 | grep -Po "[a-zA-Z_]\w*(?=\()") ${SOURCE} and then you can start with int main(void){LATEST_MAIN();}; and append void foo(){...} ... void bar(){...} and execution will start from the last defined function (that matches the regex). --- 2. Pre-defining non-static functions If that's cheating then you can redefine "external" functions before the linker has a chance to provide them. For example: #include <stdlib.h> int (*foo)(void); int main(void){exit(0); *foo();} is a valid program, and you can append void f1(){puts("oh");} int exit(){foo=&f1;} and foo will indeed be called. It does require some forward planning if you want to append multiple times, but it shouldn't be so difficult to generate a library full of dummy functions to use.
- kragen 2y agoThis isn't a language-lawyer kind of thing, and, as I said, I don't think C++ features or GNU extensions will help. The pre-defining extern functions approach will get you a finite number of tries, but I suppose it could be a fairly large finite number. If for some reason I had to solve this problem in real life I would do it with a postprocesing step like your #1 suggestion. But once you're putting code into your Makefile anything goes.
- Y_Y 2y agoYou can just append a function with __attribute__((constructor)) if GNU extensions are allowed and that will run before main and let you mess with the function pointers.
- kragen 2y agoIn an undefined order?
- Y_Y 2y agoObjection! Badgering the witness! I'm sure you know, but the undefined order is easily fixed by e.g. keeping a priority queue for your appended functions and then each time you add one you can include a constructor that enters it in the queue with a priority corresponding to its desired position.
- kragen 2y agoAnd then main() pops the latest override off the priority queue? I guess you're right; GCC extensions do solve the problem. And you can do the same thing with static object constructors in C++, though language-lawyeringly I'm not sure the standard guarantees enough about static initialization order to give the first constructor a well-defined empty queue.