免费注册 查看新帖 |

Chinaunix

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

[C] 如何引用没有分配内存的外部符号 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-05-23 20:28 |只看该作者 |倒序浏览
外部的符号,如果是变量的话,只需要声明一下extern就可以了,如果是函数,可以直接使用。
但是对那些没有分配内存的符号要怎么办。
http://forum.niosforum.com/forum/lofiversion/index.php/t4573.html
这里探讨了一下引用linker中符号的处理方法,但是最终没有给出一个好的解决方法。
在汇编里只要用只要用.extern或者public这样的命令就可以引用了。
可是C中似乎没有太好的方法。如果声明一个extern,不管它是什么类型,编译器会认为它是一个变量,一个被定义在某处的变量,这个变量有一个存储它值的内存地址。编译生成OBJ文件时,对这些符号值的引用是通过一个空白地址实现,这个空白的地址是留给连接器去填写的。对于没有地址的符号,它不是一个变量,连接器只是把它的值写在那个空白的地址中,这就导致了要用&symbol_name去访问symbol的结果。
我想一定能有代替这种丑陋用法的解决方法吧,就算不是ansi C,有些编译器也应该支持吧。哪位大侠能给提一个。

论坛徽章:
0
2 [报告]
发表于 2009-05-23 21:19 |只看该作者
原帖由 figure_hit 于 2009-5-23 20:28 发表
外部的符号,如果是变量的话,只需要声明一下extern就可以了,如果是函数,可以直接使用。
但是对那些没有分配内存的符号要怎么办。
http://forum.niosforum.com/forum/lofiversion/index.php/t4573.html
这 ...

不太明白你的需求。就以__bss_start为例,这些符号首先不是变量,它是个lable,所以它本身就代表了地址。
例如:
goto error:

error:
    xxxxxxxxxxx
这里error就是个lable。又比如汇编里面
.L2:
    jmp .L2
这里L2也是个label。它们本身就代表了一个地址。只是在汇编中它的名字就代表了地址。
在c语言里面你要引用这些符号代表的地址,不能直接使用它们的名字,需要用&取地址,所以
void *p = &__bss_start;
实际上得到了__bss_start这个符号本身所以代表的地址。
你可以把它声明为
extern unsigned long __bss_start;
extern char __bss_start
等等

论坛徽章:
0
3 [报告]
发表于 2009-05-24 08:00 |只看该作者
我也看不明白楼主是啥意思?是不是打算干扰链接器的工作?还是其它什么?

论坛徽章:
0
4 [报告]
发表于 2009-05-24 13:28 |只看该作者

回复 #2 zx_wing 的帖子

不管把__bss_start声明成什么都要靠&__bss_start去访问实际__bss_start的值,难道就没有其他的办法吗?这样做生成代码的效率肯定不如在汇编中直接使用__bss_start来的高。

论坛徽章:
0
5 [报告]
发表于 2009-05-24 14:16 |只看该作者
原帖由 figure_hit 于 2009-5-24 13:28 发表
不管把__bss_start声明成什么都要靠&__bss_start去访问实际__bss_start的值,难道就没有其他的办法吗?这样做生成代码的效率肯定不如在汇编中直接使用__bss_start来的高。

这怎么会有效率问题呢?
你在汇编中取__bss_start的地址是一条mov指令,这里c语言&编译后也是一条mov指令,不会有效率问题。
LZ你不要怪我借题发挥,这种多一条指令少一条指令(不包括专门优化的指令集,例如SSE)所谓的效率问题纯粹是想当然尔。大家可以自己做实验,做你所谓的优化,看能减少多少条指令,然后算出除去这些指令的程序执行一秒钟的cycle数算出来,和优化之前比较,看有多少提升。然后执行一次大应用(跑个半个小时),算一算百分比,都不知道算到小数点后多少位去了。
所以啊,指令优化90%的时候是写书时用的,让你看着很牛B

论坛徽章:
0
6 [报告]
发表于 2009-05-24 14:22 |只看该作者
[mik@localhost ~]$ cat f.c
#include <stdio.h>

char *p;

void foo()
{
        p = "hello";

        printf("in foo(): p = %p\n", p);
}


[mik@localhost ~]$ cat t.c
#include <stdio.h>

extern char *p;

int main()
{
        foo();

        printf("in main(): p = %p\n",p);
        printf("%s\n",p);

        return 0;
}

[mik@localhost ~]$ gcc f.c t.c -o t
[mik@localhost ~]$ ./t
in foo(): p = 0x400668
in main(): p = 0x400668
hello


extern 之后就直接用呀,需要 &p  吗?

论坛徽章:
0
7 [报告]
发表于 2009-05-24 14:29 |只看该作者
原帖由 mik 于 2009-5-24 14:22 发表
[mik@localhost ~]$ cat f.c
#include

char *p;

void foo()
{
        p = "hello";

        printf("in foo(): p = %p\n", p);
}


[mik@localhost ~]$ cat t.c
#include

extern char *p;

int main ...

他是在问怎么得到 linker内置的一些符号所代表的地址

论坛徽章:
0
8 [报告]
发表于 2009-05-24 14:42 |只看该作者
没 link 之前都,无论是 &p 还是 p 都以 0 代替,link 时 linker 会以真的地址代替。

没弄懂LZ 想知道啥,什么是linker内置一些符号的地址?

论坛徽章:
0
9 [报告]
发表于 2009-05-24 14:55 |只看该作者
原帖由 mik 于 2009-5-24 14:42 发表
没 link 之前都,无论是 &p 还是 p 都以 0 代替,link 时 linker 会以真的地址代替。

没弄懂LZ 想知道啥,什么是linker内置一些符号的地址?

你objdump一个就可以看到了,在symbol里,类似于__bss_start, __end之类的,定义在链接脚本中的符号,通常是用来定义最终生成的binary的格式的

论坛徽章:
0
10 [报告]
发表于 2009-05-24 15:02 |只看该作者
原帖由 figure_hit 于 2009-5-24 13:28 发表
不管把__bss_start声明成什么都要靠&__bss_start去访问实际__bss_start的值,难道就没有其他的办法吗?这样做生成代码的效率肯定不如在汇编中直接使用__bss_start来的高。

还有种方法,你直接
extern char __bss_start [];
因为数组名本身就代表地址,你就可以直接用了。当然,编译后的实质和&是一样的
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP