mrpre 发表于 2015-04-30 09:31

extern 一个函数指针 引发的问题

本帖最后由 mrpre 于 2015-04-30 20:01 编辑

首先是这样的,我在一个文件里面 定义了一个函数指针:
s32 (*test_func_ptr)(void * buf, s32 len, void * session) = dummy_func();


我需要在另外一个文件使用该函数,第一次向下面一样使用(死的稀里哗啦的)
extern s32 test_func_ptr(void * buf, s32 len, void * session);
int test_func()
{
    void *ptr1, *ptr2;
    int a;
   
    test_func_ptr(ptr1, a, ptr2);
   
    return 0;
}

panic了。我看了一下汇编


0xffffffffc0380198 test_func:         daddiu    sp,sp,-16
0xffffffffc038019c test_func+0x4:   lui       v0,0xc045
0xffffffffc03801a0 test_func+0x8:   move      a0,zero
0xffffffffc03801a4 test_func+0xc:   move      a1,zero
0xffffffffc03801a8 test_func+0x10:    sd      ra,8(sp)
0xffffffffc03801ac test_func+0x14:    daddiu    v0,v0,30544
0xffffffffc03801b0 test_func+0x18:    jalr      v0                   //v0 是 test_func_ptr这个符号
0xffffffffc03801b4 test_func+0x1c:    move      a2,zero
0xffffffffc03801b8 test_func+0x20:    ld      ra,8(sp)
0xffffffffc03801bc test_func+0x24:    move      v0,zero
0xffffffffc03801c0 test_func+0x28:    jr      ra
0xffffffffc03801c4 test_func+0x2c:    daddiu    sp,sp,16

kdb> 0xffffffffc0450000+30544
0xffffffffc0450000 = 0xffffffffc0457750 ( test_func_ptr)


然后我把 extern s32 test_func_ptr(void * buf, s32 len, void * session);
变换为 extern s32 (*test_func_ptr)(void * buf, s32 len, void * session);
这下总对了吧,果然,不再panic
但是问题来了,我查看了一下 test_func 对应的汇编代码。。。居然和上面的没区别(基本没区别)。
kdb> id test_func
0xffffffffc037d040 test_func:         lui       v0,0xc045
0xffffffffc037d044 test_func+0x4:   daddiu    sp,sp,-16
0xffffffffc037d048 test_func+0x8:   move      a0,zero
0xffffffffc037d04c test_func+0xc:   move      a1,zero
0xffffffffc037d050 test_func+0x10:    ld      v0,30544(v0)
0xffffffffc037d054 test_func+0x14:    sd      ra,8(sp)
0xffffffffc037d058 test_func+0x18:    jalr      v0   //v0 还是 test_func_ptr这个符号,我觉得应该jalr dummy_func
0xffffffffc037d05c test_func+0x1c:    move      a2,zero
0xffffffffc037d060 test_func+0x20:    ld      ra,8(sp)
0xffffffffc037d064 test_func+0x24:    move      v0,zero
0xffffffffc037d068 test_func+0x28:    jr      ra
0xffffffffc037d06c test_func+0x2c:    daddiu    sp,sp,16


我对底层的东西不太平白,觉得如果和“编译”没关系的话,是不是和“链接”有关系?

望有大神释疑。

linuxfellow 发表于 2015-04-30 09:43

本帖最后由 linuxfellow 于 2015-04-30 10:14 编辑

C语言的问题,与编译器和底层无关。


nswcfd 发表于 2015-04-30 09:52

这个区别很大吧。
x86下是两种不同的call:

[~]$ cat a.c
externvoid f1(void);
externvoid (*f2)(void);

void f(void)
{
      f1();
      f2();
}
[~]$ objdump -d a.o

a.o:   file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <f>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   e8 00 00 00 00          callq9 <f+0x9>   #直接寻址
   9:   48 8b 05 00 00 00 00    mov    0x0(%rip),%rax      # 10 <f+0x10>
10:   ff d0                   callq*%rax   #间接寻址
12:   c9                      leaveq
13:   c3                      retq

karma303 发表于 2015-04-30 12:56

本帖最后由 karma303 于 2015-04-30 12:59 编辑

是编译阶段的问题。
你已经在另一个模块里,把test_func_ptr定义成函数指针。那么,“test_func_ptr”就是个普通的symbol,这个symbol本身的值不重要(假定是804a010),在804a010内存处存放的只是一个4byte的数值,value是test_func这个函数的地址。
再回到当前的模块。
你欺骗编译器说test_func_ptr只是个函数,编译器认为,804a010内存地址起,存放着一段函数代码(instruction)。编译器当然直接跳过去:push eip; jmp (804a010-当前eip)----------也就是call test_func_ptr.
如果编译器知道test_func_ptr只是一小块儿函数指针,它会jmp dword ,就是从test_func_ptr这儿取出真正的目标函数地址,来调整eip。写成mov eax,;jmp eax大同小异。

-----------------------
借一下3楼的代码,用intel汇编看一下:
<a.c>
void f2(void){ }
void (*f1)(void) = f2;
<t.c>
extern void (*f1)(void);
extern void f2(void);
void main(void){
        f1();
        f2();
}

gcc -o t t.c a.c
objdump -d -Mintel ./t
080483b4 <main>:
80483b4:        55                           push   ebp
80483b5:        89 e5                        mov    ebp,esp
80483b7:        83 e4 f0                     and    esp,0xfffffff0
80483ba:        a1 10 a0 04 08               mov    eax,ds:0x804a010
80483bf:        ff d0                        call   eax
80483c1:        e8 02 00 00 00               call   80483c8 <f2>
80483c6:        c9                           leave
80483c7:        c3                           ret


------------PS:上面有些“jmp”该写成“call”,我是觉得jmp清晰些。

mrpre 发表于 2015-04-30 20:07

看大家的回复,意思说 理论上确实两段汇编代码不一样......我也理解大家说的指针和变量之间的关系,间接寻址和直接寻址之间的关系(一开始我没看汇编,也这么理解,后来看了汇编我就郁闷了)。可是这的的确确发生了,两个相似的汇编,一个跑起来了一个panic了……难道是mips的问题?
页: [1]
查看完整版本: extern 一个函数指针 引发的问题