免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: 紫牧
打印 上一主题 下一主题

[函数] 一个面试题,说是考函数调用方式 [复制链接]

论坛徽章:
0
21 [报告]
发表于 2007-09-08 16:43 |只看该作者
原帖由 Solidus 于 2007-9-8 14:30 发表
这个是我在vc8上生成的汇编,实际上push ebp后,我定义两个变量的话确实是再push ebp后在stack上分配了8字节,如果只定义一个int变量的话,就生成个莫名其妙的push ecx指令(其实这个push ecx就是给 int t这个单 ...

改成 (&t)[4]=t;就可以了

论坛徽章:
0
22 [报告]
发表于 2007-09-08 16:52 |只看该作者
原帖由 drowsyboy 于 2007-9-8 16:43 发表

改成 (&t)[4]=t;就可以了



是这样的,这个跟具体的编译器汇编生成有关了,我的vc8没问题,汇编也确实是那么生成的,但是你用其他编译器就不好说了

论坛徽章:
0
23 [报告]
发表于 2007-09-08 17:17 |只看该作者
系统:Win2003
编译器:VC6
结果OK,用IDA看了下test函数。
  1. .text:00401000                 push    ebp
  2. .text:00401001                 mov     ebp, esp
  3. .text:00401003                 push    ecx
  4. //函数序言
  5. .text:00401004                 lea     eax, [ebp+var_4]
  6. // lea装入t的地址
  7. .text:00401007                 push    eax
  8. .text:00401008                 push    offset s_D      ; "%d"
  9. .text:0040100D                 call    _scanf
  10. .text:0040100D
  11. .text:00401012                 add     esp, 8
  12. //scanf 过程
  13. .text:00401015                 mov     ecx, [ebp+var_4]
  14. .text:00401018                 mov     [ebp+arg_0], ecx
  15. // (&t)[3] = t过程
  16. .text:0040101B                 mov     esp, ebp
  17. .text:0040101D                 pop     ebp
  18. .text:0040101E                 retn
  19. //函数结语
复制代码

论坛徽章:
0
24 [报告]
发表于 2007-09-08 17:44 |只看该作者
查了下书,记得有个地址输出说明符,重新整理了下程序。
#include<stdio.h>
void test()
{
    int t;
    scanf("%d",&t);
    printf("In test(),t=%d and &t=%p.\n",t,&t);   
    (&t)[3] = t;
      
}
int main()
{
     int m;
     test();
     printf("In main(),m=%d and &m=%p.",m,&m);
     return 0;
}

[ 本帖最后由 Cyg07 于 2007-9-9 09:47 编辑 ]

论坛徽章:
0
25 [报告]
发表于 2007-09-08 21:29 |只看该作者
原帖由 Cyg07 于 2007-9-8 17:44 发表
查了下书,记得有个地址输出说明符,重新整理了下程序。

WINXP,VC6,结果如下

论坛徽章:
0
26 [报告]
发表于 2007-09-08 21:36 |只看该作者
原帖由 Solidus 于 2007-9-8 14:30 发表
这个是我在vc8上生成的汇编,实际上push ebp后,我定义两个变量的话确实是再push ebp后在stack上分配了8字节,如果只定义一个int变量的话,就生成个莫名其妙的push ecx指令(其实这个push ecx就是给 int t这个单 ...

我在WINXP,VC6下试验看到的是push ebp之后在堆栈分配了44H字节
这个在不同系统,不同编译器上差别怎么这么大--?

论坛徽章:
0
27 [报告]
发表于 2007-09-08 21:46 |只看该作者
原帖由 Solidus 于 2007-9-8 14:30 发表
这个是我在vc8上生成的汇编,实际上push ebp后,我定义两个变量的话确实是再push ebp后在stack上分配了8字节,如果只定义一个int变量的话,就生成个莫名其妙的push ecx指令(其实这个push ecx就是给 int t这个单 ...

看你这个代码,VC8在分配堆栈的时候似乎是定义了多少变量就分配多少空间,在WINXP VC6 DEBUG模式下默认是sub  esp,44h,浪费了不少啊^_^
不知道在Linux等其它系统,其它编译器下是什么样的呢?
有适合各个平台的代码么--?

论坛徽章:
0
28 [报告]
发表于 2007-09-09 00:24 |只看该作者
#include <stdio.h>

void test()
{
    int t;
    scanf("%d", &t);
    *(int*)(*(char**)(&t + 1) - 8) = t;
}

main()
{
    int m;
    test();
    printf("%d\n", m);
}

我在Linux下, gcc编译可以, VC不一定行
(char**)(&t + 1) 获得上一帧的ebp指针
由于在main里,首先push 了ecx,所以要 -8才能得到m的地址。

论坛徽章:
0
29 [报告]
发表于 2007-09-09 00:44 |只看该作者
原帖由 Solidus 于 2007-9-8 13:02 发表
刚才说的没错,就是这样

main中的m被分配之后,先call的test 这里压入了eip,然后 test中又先压入了ebp,然后是t 这样子,
(&t)[0]就是t,(&t)[1]就是push 的ebp, (&t)[2]就是那个call压入的eip,(&t)[3]就是 ...


请问VC6-DEBUG编译,有什么特点吗?我感觉GCC不是这样处理的。

跟踪了一下,发现要写成(&t)[8] = t 才能实现功能。

[ 本帖最后由 naihe2010 于 2007-9-9 01:01 编辑 ]

论坛徽章:
0
30 [报告]
发表于 2007-09-09 01:43 |只看该作者
我觉得没啥必要在继续了,除非在插入代码的部分获得ebp的地址(函数被调用后-4的esp),否则用纯C没啥好办法了,因为这个本身就跟编译器有关了,没法预测泛用了
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP