免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1562 | 回复: 4
打印 上一主题 下一主题

[内核入门] extern 一个函数指针 引发的问题 [复制链接]

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-04-30 09:31 |只看该作者 |倒序浏览
本帖最后由 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

[0]kdb> 0xffffffffc0450000+30544
0xffffffffc0450000 = 0xffffffffc0457750 ([modlue_net] 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 对应的汇编代码。。。居然和上面的没区别(基本没区别)。
[0]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


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

望有大神释疑。

论坛徽章:
1
拜羊年徽章
日期:2015-03-03 16:15:43
2 [报告]
发表于 2015-04-30 09:43 |只看该作者
本帖最后由 linuxfellow 于 2015-04-30 10:14 编辑

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


论坛徽章:
20
程序设计版块每日发帖之星
日期:2015-08-17 06:20:00程序设计版块每日发帖之星
日期:2016-07-16 06:20:00程序设计版块每日发帖之星
日期:2016-07-18 06:20:00每日论坛发贴之星
日期:2016-07-18 06:20:00黑曼巴
日期:2016-12-26 16:00:3215-16赛季CBA联赛之江苏
日期:2017-06-26 11:05:5615-16赛季CBA联赛之上海
日期:2017-07-21 18:12:5015-16赛季CBA联赛之青岛
日期:2017-09-04 17:32:0515-16赛季CBA联赛之吉林
日期:2018-03-26 10:02:16程序设计版块每日发帖之星
日期:2016-07-15 06:20:0015-16赛季CBA联赛之江苏
日期:2016-07-07 18:37:512015亚冠之萨济拖拉机
日期:2015-08-17 12:21:08
3 [报告]
发表于 2015-04-30 09:52 |只看该作者
这个区别很大吧。
x86下是两种不同的call:

[~]$ cat a.c
extern  void f1(void);
extern  void (*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          callq  9 <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  

论坛徽章:
13
程序设计版块每日发帖之星
日期:2016-06-29 06:20:00每日论坛发贴之星
日期:2016-08-14 06:20:00操作系统版块每日发帖之星
日期:2016-08-14 06:20:00每日论坛发贴之星
日期:2016-08-13 06:20:00数据库技术版块每日发帖之星
日期:2016-08-13 06:20:00程序设计版块每日发帖之星
日期:2016-08-13 06:20:00IT运维版块每日发帖之星
日期:2016-08-13 06:20:00每日论坛发贴之星
日期:2016-08-12 06:20:00数据库技术版块每日发帖之星
日期:2016-08-12 06:20:00程序设计版块每日发帖之星
日期:2016-08-12 06:20:00操作系统版块每日发帖之星
日期:2016-08-12 06:20:00综合交流区版块每日发帖之星
日期:2016-08-09 06:20:00
4 [报告]
发表于 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],就是从test_func_ptr这儿取出真正的目标函数地址,来调整eip。写成mov eax,[test_func_ptr];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清晰些。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
5 [报告]
发表于 2015-04-30 20:07 |只看该作者
看大家的回复,意思说 理论上确实两段汇编代码不一样......我也理解大家说的指针和变量之间的关系,间接寻址和直接寻址之间的关系(一开始我没看汇编,也这么理解,后来看了汇编我就郁闷了)。可是这的的确确发生了,两个相似的汇编,一个跑起来了一个panic了……难道是mips的问题?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP