是否可以覆盖对象模块中的静态函数(gcc,ld,x86,objcopy)?

smc*_*ron 9 c gcc ld objcopy interposing

有没有办法在对象模块中覆盖静态范围的函数?

如果我从这样的东西开始,带有全局符号"foo"的模块是一个调用本地符号"bar"的函数,它调用本地符号"baz"

[scameron@localhost ~]$ cat foo.c
#include <stdio.h>
static void baz(void)
{
    printf("baz\n");
}

static void bar(void)
{
    printf("bar\n");
    baz();
}

void foo(void)
{
    printf("foo\n");
    bar();
}

[scameron@localhost ~]$ gcc -g -c foo.c
[scameron@localhost ~]$ objdump -x foo.o | egrep 'foo|bar|baz'
foo.o:     file format elf32-i386
foo.o
00000000 l    df *ABS*  00000000 foo.c
00000000 l     F .text  00000014 baz
00000014 l     F .text  00000019 bar
0000002d g     F .text  00000019 foo
Run Code Online (Sandbox Code Playgroud)

它有一个全球性的"foo"和两个当地人"bar"和"baz".

假设我想编写一些运动条和baz的单元测试,我可以这样做:

[scameron@localhost ~]$ cat barbaz
bar
baz
[scameron@localhost ~]$ objcopy --globalize-symbols=barbaz foo.o foo2.o
[scameron@localhost ~]$ objdump -x foo2.o | egrep 'foo|bar|baz'
foo2.o:     file format elf32-i386
foo2.o
00000000 l    df *ABS*  00000000 foo.c
00000000 g     F .text  00000014 baz
00000014 g     F .text  00000019 bar
0000002d g     F .text  00000019 foo
[scameron@localhost ~]$ 
Run Code Online (Sandbox Code Playgroud)

现在bar和baz是全局符号,可从模块外部访问.到现在为止还挺好.

但是,如果我想在"baz"之上设置我自己的功能,并且让"bar"调用我插入的"baz",该怎么办?

有没有办法做到这一点?

--wrap选项似乎没有这样做......

[scameron@localhost ~]$ cat ibaz.c
#include <stdio.h>
extern void foo();
extern void bar();

void __wrap_baz()
{
    printf("wrapped baz\n");
}
int main(int argc, char *argv[])
{
    foo();
    baz();
}

[scameron@localhost ~]$ gcc -o ibaz ibaz.c foo2.o -Xlinker --wrap -Xlinker baz
[scameron@localhost ~]$ ./ibaz
foo
bar
baz
wrapped baz
[scameron@localhost ~]$
Run Code Online (Sandbox Code Playgroud)

从main()调用的baz被包裹了,但是bar仍然调用当地的baz而不是包裹的baz.

有没有办法让酒吧打电话给被包裹的巴兹?

即使它需要修改目标代码以修改函数调用的地址,如果可以以自动方式完成,这可能已经足够好了,但在这种情况下它至少需要处理i386和x86_64.

- 史蒂夫

Zan*_*ynx 4

由于static是向 C 编译器承诺该函数或变量是文件的本地函数或变量,因此如果编译器可以在没有它的情况下获得相同的结果,则可以自由地删除该代码。

这可能是内联函数调用。这可能意味着用常量替换变量。如果代码位于if始终为 false 的语句内,则该函数甚至可能不存在于编译结果中。

所有这些意味着您无法可靠地将调用重定向到该函数。

如果使用新-lto选项进行编译,情况会更糟,因为编译器可以自由地重新排序、删除或内联整个项目中的所有代码。