celfweak-linking

How to use REAL function once it is declared as WEAK function in C?


I have a problem when using WEAK reference in C. Make assumption, I have the src code structure as follows:

//Eclipse C project structure

    drv
     |   dummy      
     |     |  dummy_Test.h
     |     |  dummy_TestWeakAttribute.h
     |   src
     |     |  source_sample.c
     |   test
     |     |  myModules
     |             strong_test_case.c
     |             weak_test_case.c
    test_program.c

And:

//test_program.c

#include "drv/dummy/dummy_TestWeakAttribute.h"
#include "drv/dummy/dummy_Test.h"

int main() {
    printf("===================\n");
    printf("  Welcome to main  \n");
    printf("===================\n");
                            // Expectation
    test();                 //-->real function
    function();             //-->real function
    test_function_strong(); //-->real function
    test_function_weak();   //-->weak function

    return 0;
}

//source_sample.c

#include "../dummy/dummy_TestWeakAttribute.h"
#include "../dummy/dummy_Test.h"

static void test(void) {
    printf("NOT overridden!\n");
}

static void function(void){

    int a =1;
    a++;
    test();
}

//dummy_Test.h

#ifndef DRV_DUMMY_DUMMY_TEST_H_
#define DRV_DUMMY_DUMMY_TEST_H_

#define static
//definitions

//struct definitions

//dummy functions

static void test(void);
static void function(void);

//global variable definitions

#endif /* DRV_DUMMY_DUMMY_TEST_H_ */

//dummy_TestWeakAttribute.h

#define static //disable static keyword

static void __attribute__((weak)) test(void);

//weak_test_case.c

#include "../../dummy/dummy_TestWeakAttribute.h"
#include "../../dummy/dummy_Test.h"

static void test(void){
    printf("overridden successfully!\n");
}

void test_function_weak(void){
    function();
}

//strong_test_case.c

#include "../../dummy/dummy_Test.h"

void test_function_strong(void){
    function();
}

I got the result on the screen:

===================
  Welcome to main  
===================
overridden successfully!
overridden successfully!
overridden successfully!
overridden successfully!

I can't use the REAL function anymore. All my making calls to the real test function is impossible because it was declared as __attribute__((weak)) before. So, Is there anybody having idea on this case ? The main purpose, I'd like to call my real test (in source_sample.c) but don't remove weak attribute as well.


Solution

  • First off, be aware that weak linkage is not a C concept. It is an ELF concept, at least for our purposes, and GCC (and other compiler) support for it is a C extension. Therefore, little of what I have to say is based on the C standard. With that said ...

    Your program has two functions test(), both with weak linkage. If there were an alternative with strong linkage then that would override both. Since there is not, it is unspecified which of the two is linked to any given reference (call), but it follows from the mechanism of ELF dynamic linking that the same one would would be linked to every reference in any given dynamic object.

    Other than system libraries, you have only one dynamic object in play -- the program -- so it stands to reason that the same implementation of test() is called at every point. It's unclear to me why you suppose it would be otherwise. Note in particular that the weird games you are playing with the static keyword are strictly obfuscatory. You have no actual static declarations anywhere in the code you present.

    You indeed could declare a static function test in some file, and in that case you would expect calls to test() from within that file to be linked to the internal static version. To the best of my knowledge, however, a static function cannot also be weak. That wouldn't make any sense.

    The main purpose, I'd like to call my real test (in source_sample.c) but don't remove weak attribute as well.

    So you want to provide for overriding some references to the function but not others? Are you nuts? What a nightmare that would be to build, and I don't even want to think about maintaining it.

    If you want to provide a default implementation that you can always call then you cannot make that the weak function. Doing so is inconsistent with always being able to call it. You can, however, make it a separate, ordinary function that the weak one calls, and any other function also can call:

    test.h:

    #ifndef TEST_H
    #define TEST_H
    
    void test(void) __attribute__((weak));
    void test_default(void);
    
    #endif
    

    test.c:

    #include "test.h"
    
    void test_default(void) {
        printf("I am the default implementation");
    }
    
    void test(void) {
        test_default();
    }
    

    Anyone with access to test_default() can then call it, but whether it gets called as a result of calling test() depends on what version of test() is linked to the call -- it is weak, so a different version could be provided.

    Note also that depending on the scope you want test_default() to have, it might be both possible and sensible to make it static, whereas test() must not be static as long as it is weak.