How do I force gcc to call a function directly in PIC code?

后端 未结 2 1919
走了就别回头了
走了就别回头了 2021-02-15 23:40

Consider the following function:

extern void test1(void);
extern void test2(void) {
    test1();
}

This is the code gcc generates without

2条回答
  •  感情败类
    2021-02-15 23:43

    If you declare test1() hidden (__attribute__((__visibility__("hidden"))), the jump will be direct.

    Now test1() may not be defined in its source translation unit as hidden, but I believe no harm should come from that discrepancy except the C language guarantee that &test1 == &test1 might be broken for you at runtime if one of the pointers was obtained via a hidden reference and one via a public one (the public reference might have been interposed via preloading or a DSO that came before the current one in the lookup scope, while the hidden reference (which results in direct jumps) effective prevents any kind of interposition)

    A more proper way to deal with this would be to define two names for test1()—a public name and a private/hidden name.

    In gcc and clang, this can be done with some alias magic, which can only be done in the translation unit that defines the symbol.

    Macros can make it prettier:

    #define PRIVATE __attribute__((__visibility__("hidden")))
    #define PUBLIC __attribute__((__visibility__("default")))
    #define PRIVATE_ALIAS(Alias,OfWhat) \
        extern __typeof(OfWhat) Alias __attribute((__alias__(#OfWhat), \
                                     __visibility__("hidden")))
    
    #if HERE
    PUBLIC void test1(void) { }
    PRIVATE_ALIAS(test1__,test1);
    #else
    PUBLIC void test1(void);
    PRIVATE void test1__(void);
    #endif
    
    void call_test1(void) { test1(); }
    void call_test1__(void) { test1__(); }
    
    void call_ext0(void) { void ext0(void); ext0(); }
    void call_ext1(void) { PRIVATE void ext1(void); ext1(); }
    

    The above compiles (-O3, x86-64) into:

    call_test1:
            jmp     test1@PLT
    call_test1__:
            jmp     test1__
    call_ext0:
            jmp     ext0@PLT
    call_ext1:
            jmp     ext1
    

    (Defining HERE=1 additionally inlines the test1 call since it's small and local and -O3 is on).

    Live example at https://godbolt.org/g/eZvmp7.

提交回复
热议问题