Home > Blockchain >  Is it possible to point several different function declarations into a single function definition
Is it possible to point several different function declarations into a single function definition

Time:09-17

Say, I have several declarations of functions which should perform similar action across several library files:

// file0.h
void delay_ms0(unsigned int);

// file1.h
void delay_ms1(int);

// file2.h
extern void delay_ms2(int);

// file3.h
int delay_ms3(unsigned int);

// file4.h
void delay_ms4(unsigned char);

// file5.h
void delay_us(unsigned long long);

// file6.h
void delay_ms6(const int *);

// file7.h
// (in some cases, structs used to pass several functions)
typedef void (*const delay_fptr_t)(int);
extern delay_fptr_t delay_ms7;

And in my main app I have actual definition with platform-specific implementation:

// main.c
void delay_ms(unsigned int time_ms) { platform_shutdown(time_ms*128); };

So, the question is: is it somehow possible to point some or all of them to the same implementation without using additional instructions in the compiled program, i.e. somehow instruct compiler or linker where to send function calls. Particularly speaking of GCC. If it is, it would be more convenient to develop and integrate libraries...

Currently, standard solutions usually look something like that:

// main.c

// these are extra function calls, and not always optimized out. Consumes both RAM and ROM.
void delay_ms0(unsigned int val) { delay_ms(val); };
void delay_ms1(int val) { delay_ms((unsigned int) val); }; 

// Somehow not always linked properly, so when called at runtime, causes hardfaults, or just nothing happens
inline void delay2(int val) { delay_ms((unsigned int) val); }; 

// most probably there is no way around that, as we have to return something
int delay_ms3(unsigned int) { delay_ms((unsigned int) val); return 0; }; 

// most probably there is no way around that, as 'c_val' has to be expanded
void delay_ms4(unsigned char c_val) { delay_ms((unsigned int) c_val); }; 

// most probably there is no way around that, as 'll_val' has to be processed before passing further
void delay_us(unsigned long long ll_val) { delay_ms((unsigned int) ll_val/1000); }; 

// most probably there is no way around that, as 'p_val' has to be dereferenced
void delay_ms6(const int *p_val) { delay_ms((unsigned int) *p_val); }; 

// this is my favorite so far, as it does not use extra RAM and allows some slack, when function definitions do not exactly match, but it certainly does use ROM to store pointers
delay_fptr_t delay_ms7 = (delay_fptr_t)delay_ms; 
// I would like to see something like that^, but for standard declarations
// I.e. are there any alternatives to:
void (*delay2_ms)(int) = delay_ms; // gcc error: 'delay2_ms' redeclared as different kind of symbol

CodePudding user response:

Yes it is possible. The straightforward way is to use the alias attribute (see the GCC docs). A tiny example:

int some(int x) {
    return 2*x;
}

int more(int y) __attribute__((alias("some")));

Now, some and more are the same function.

But note that you will have to make sure the calling convention is the same. That should be pretty much obvious as otherwise, there would have to be some conversion code (still, in many cases the wrapper boils down to a few instructions ending with a JMP [or equivalent; unless you adjust return value or likewise], that shouldn’t add much to the trampolines used for linking libraries together).

However, if you really care of performance, you may consider using link-time optimization. It is now supported by GCC; search for -flto in the docs. (in a nutshell: pass -flto to GCC both while compiling and linking)

  • Related