clinkerweak-linking

Getting the address of a overwritten weak symbol


My question assumes gcc or clang for x86 or x86_64.

Let's say I have the following files:

// weak.c

#include <stdio.h>

__attribute__((weak))
void i_am_weak(void)
{
    printf("I am weak\n");
}

int main()
{
    i_am_weak();
    return 0;
}
// not_weak.c

#include <stdio.h>

void i_am_weak(void)
{
    printf("I am not weak\n");
}

If I compile just weak.c: cc weak.c -o weak and then I run it I get the message "I am weak". In turn, if I compile and link both: cc weak.c not_weak.c I get the message "I am not weak". Which is to be expected.

Can I somehow obtain the address of the weak symbol? Let's say that I want to invoke i_am_weak from weak.c from not_weak.c, similar to how I can use __real_i_am_weak from __wrap_i_am_weak when using the --wrap linker flag.


Solution

  • Can I somehow obtain the address of the weak symbol?

    The usual technique is to use a strong internal symbol, to which i_am_weak is a weak alias (documentation):

    #include <stdio.h>
    
    void i_am_internal(void)
    {
        printf("I am weak\n");
    }
    
    void i_am_weak(void) __attribute__((weak, alias("i_am_internal"))) 
    
    int main()
    {
        i_am_weak();
        i_am_internal();
        return 0;
    }
    
    $ gcc weak.c && ./a.out
    I am weak
    I am weak
    
    $ gcc weak.c not_weak.c && ./a.out
    I am not weak
    I am weak
    

    You can now also take address of weak and non-weak symbols.