如何强制gcc直接在PIC代码中调用函数? [英] How do I force gcc to call a function directly in PIC code?

查看:323
本文介绍了如何强制gcc直接在PIC代码中调用函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑下面的函数:

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



$ b

这是gcc生成的代码,没有 -fpic on amd64 Linux:

  test2:
jmp test1

当我使用 -fpic 进行编译时,gcc通过PLT显式调用以启用符号interposition:

  test2:
jmp test1 @ PLT

然而,这对位置无关的代码并不是严格需要的,如果我不想支持,可以省略。如果有必要,链接器无论如何都会将跳转目标重写为PLT符号。



如何在不更改源代码的情况下使编译代码不适合共享库,使函数调用直接进入目标,而不是直接通过PLT?

解决方案

如果声明 test1() hidden( __属性__((__ visibility __(hidden))),跳转将直接进行。
$ b

现在 test1 ()可能不会在其源代码翻译单元中定义为隐藏,但我相信除了C语言保证& test1 ==&如果其中一个指针是通过隐藏引用获取的,另一个是通过公共引用获取的(公共引用可能已经通过预加载或在当前之前出现的DSO插入),那么在运行时可能会破坏test1 一个在查找范围中,而隐藏引用(导致直接跳转)有效防止任何类型的干扰)。

处理这个问题的更合适的方法是为定义两个名称test1() - 一个公共名称和一个私有/隐藏的名称。

在$ g $和$ g $中, ,这可以用一些别名魔术来完成,这可以只能在定义符号的翻译单元中完成。



宏可以使它更漂亮:

  #define PRIVATE __attribute __((__ visibility __(hidden)))
#define PUBLIC __attribute __((__ visibility __(default)))
#define PRIVATE_ALIAS(别名,OfWhat )\
extern __typeof(OfWhat)别名__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(); }

上面编译(-O3,x86-64)为:

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



<定义HERE = 1内联测试1调用,因为它很小,本地和-O3打开)。



现场示例 https://godbolt.org/g/eZvmp7

-fno-semantic- interpose 也可以完成这项工作,但它也打破了C语言的保证,这是一个没有锯齿粒度的大锤。


Consider the following function:

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

This is the code gcc generates without -fpic on amd64 Linux:

test2:
    jmp test1

When I compile with -fpic , gcc explicitly calls through the PLT to enable symbol interposition:

test2:
    jmp test1@PLT

This however is not strictly needed for position independent code and could be left out if I don't want to support. If necessary, the linker rewrites the jump target to the PLT symbol anyway.

How can I, without changing the source code and without making the compiled code unsuitable for a shared library, make function calls go directly to their targets instead of going explicitly through the PLT?

解决方案

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.

-fno-semantic-interposition will do the job too, but it also breaks the C language guarantee, and it's kind of a big hammer that doesn't have the granularity of aliasing.

这篇关于如何强制gcc直接在PIC代码中调用函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆