汇编网首页登录博客注册
tomato的学习博客
博客首页博客互动【做检测题】论坛求助

我的博客

个人首页 |  我的文章 |  我的相册 |  我的好友 |  最新访客 |  文章收藏 |  论坛提问 |  友情链接 |  给我留言  
图片载入中
学习动态
友情链接

[2012-05-25 23:37] 【转】一个C语言题目

在main函数中添加语句,使下面的程序可以打印出所有的函数的段地址和偏移地址
int a;
void f1(void)
{
a=1;
}
void f2(void)
{
a=2;
}
void f3(void)
{
a=3;
}
main()
{
...
}


转自:http://tieba.baidu.com/p/1611780801

学习C语言的哥们儿可以做一下哦!
评论次数(8)  |  浏览次数(1462)  |  类型(C) |  收藏此文  | 

[  chinatree   发表于  2012-05-26 18:09  ]

老师看看我这个:
#define FP_OFF(fp) ((unsigned)(fp))
#define FP_SEG(fp) ((unsigned)(unsigned long)(fp>>16))
/*这两个宏在Dos.h中定义*/
int main(void)
{
printf("f1=%#X %X\nf2=%#X %X\nf3=%#X %X",
FP_SEG(f1),FP_OFF(f1),FP_SEG(f2),FP_OFF(f2),FP_SEG(f3),FP_OFF(f3));
return 0;
}

[  chinatree   发表于  2012-05-26 18:14  ]

哦,忘记main的了,可以相同方法实现。
#define FP_OFF(fp) ((unsigned)(fp))
#define FP_SEG(fp) ((unsigned)(unsigned long)(fp>>16))
/*这两个宏在Dos.h中定义*/
int main(void)
{
printf("f1=%#X %X\nf2=%#X %X\nf3=%#X %X\nmain=%#X %X",
FP_SEG(f1),FP_OFF(f1),FP_SEG(f2),FP_OFF(f2),FP_SEG(f3),FP_OFF(f3),FP_SEG(main),FP_OFF(main));
return 0;
}

[  tomato   发表于  2012-05-26 19:35  ]

想复杂了。不用这么麻烦。

[  tomato   发表于  2012-05-26 19:37  ]

提示一下,看看《汇编语言》综合研究部分第四节中是如何打印main函数的地址的。

[  chinatree   发表于  2012-05-26 22:43  ]

那打印的只是偏移地址,段地址不能直接得到。
上面那个宏错了。应该是:
#define FP_SEG(fp) ((unsigned)((unsigned long)(fp)>>16))

[  tomato   发表于  2012-05-26 22:59  ]

不是不能直接得到,可以直接得到。

打印偏移地址用这个:
printf("%x",f1);

打印段地址用这个:
printf("%lx",f1);

试一下是不是这样。

可以简单解决的问题,尽量不要搞得很复杂。

[  chinatree   发表于  2012-05-27 00:26  ]

虽然复杂些,但是通用啊。支持取变量的段地址哩。

[  chinatree   发表于  2012-05-27 10:00  ]

在c中取段地址:
例:
        #include <stdio.h>
        f1()
        {
                return ;
        }
        int main()
        {
                printf("%lx",f1);
                return 0;
        }
例子很简单,用长整型16进制打印出f1的地址,反汇编后大致如下:
        push bp;        int main(){
        mov bp,sp
        mov ax,cs
        push ax
        mov ax,xxxx
        push ax;        f1地址压栈
        mov ax,xxxx;"%lx"压栈
        call printf
        add sp,6;平衡栈,c调用约定
        mov sp,bp
        mov ax,0
        ret;        return 0;}
可以看到,在压栈时,把段地址也压栈了.再来个例子
        int main()
        {
                int i;
                printf("%lx",&i);/*注意这里有错误*/
                return 0;
        }
反汇编后大致是这样的:
        push bp
        mov bp,sp
        lea ax,[bp-2]
        push ax                ;&i
        push xxxx; "%lx"
        call printf
        pop cx
        pop cx;编译器优化,add sp,4需要3字节
        mov sp,bp
        mov ax,0
        ret
可以看到,这次并不会把段地址压栈,也就是说printf("%lx",&i);会读越界,所显示的并不是i的段地址了.
再来一个:
        fun()
        {
                return ;
        }
        int main()
        {
                fun();
                return 0;
        }
反汇编后大致是这样的:
        retf ;fun(){return;}
        push bp;        int main(){ 
        mov bp,sp
        push cs
        call near ptr fun; fun();
        mov sp,bp
        xpr ax,ax        ;return 0;
        ret                        ;}
结论如下:
        对于函数名(本身也是个地址)参与时,会先把函数的段地址压栈.而对于普通指针而言,只是简单的把偏移地址压栈.另外有一种极端的情况,如: unsigned char *p=(unsigned char *)0xa0000000;这时p占两个字,当它参与时,如:printf("%lx",p);会把它的两个字都压栈,有兴趣的话可以试试.

 
 请输入验证码  (提示:点击验证码输入框,以获取验证码