高级DotNet调试 (Advanced .NET Debugging)

用强大的调试器来解决 .NET 问题

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  16 随笔 :: 6 文章 :: 35 评论 :: 3 引用

2008年12月30日 #

     摘要: SSO(Single Sign-on) in Action1. SSO 原理浅谈 SSO 是一个非常大的主题,我对这个主题有着深深的感受,自从广州 UserGroup 的论坛成立以来,无数网友都在尝试使用开源的 CAS , Kerberos 也提供另外一种方式的 SSO ,即基于 Windows 域的 SSO ,还有就是从 2005 年开始一直兴旺不衰的 SAML 。 如果将这些免费的 SSO... 阅读全文
posted @ 2008-12-30 16:14 softfair 阅读(469) | 评论 (1)编辑

2008年12月14日 #

阿里巴巴将跌破1元股价

预测:阿里巴巴将跌破1元股价
  历史总是惊人的相似。2000年的美国,B2B的概念也曾经一度火热,当时在B2B行业领头的企业叫Commerce One,曾经享有过200亿美元的市值,被预期可能成长为全球最大的软件企业,可惜好景不长,2004年9月,曾经在B2B电子商务领域极尽风光的美国Commerce One公司宣布破产,当时风光一时的一批B2B企业也均破产或转型。

  成批的B2B公司破产的主要原因有两个,一是因为搜索引擎的崛起,使得B2B彻底成为了一个过渡型的服务。越来越多的采购商习惯了通过搜索引擎寻找供应商的时候,供应商就开始逐步逃离B2B平台。二当时的美国经济进入了下行通道,供应商们开始要更加计较手头的预算,这就加速了B2B服务的灭亡。
  事实上,阿里巴巴目前正面临着和Commerce One完全相同的境地。相同的是,根据阿里巴巴的财报显示,阿里巴巴的付费会员数的增长在逐步减少,搜索引擎的替代性已经逐步显示;金融危机的爆发导致阿里巴巴的外贸业务受到了致命的打击,加速了阿里巴巴走向衰败。不同的是,阿里巴巴还面对一个强大的对手百度。百度要进军B2B的新闻,对阿里巴巴来讲,无疑是雪上加霜。资本市场已经率先显露出了阿里衰败的端倪,阿里巴巴曾一度跌到3.5港元,跌幅高达91%,与最风光的时候相比,将近900亿的市值灰飞烟灭。
  让我们深入分析一下阿里巴巴的B2B服务。阿里巴巴的崛起实际上是在中国互联网的发展初期,中小企业对网络营销认知度非常的低,而阿里巴巴依靠着强大的市场营销能力,吸引了众多的中小企业到B2B网站上建站,之后将其转变成自己的收费客户。
  但是,随着中小企业对网络营销和电子商务越来越了解,随着建站成本越来越低,中小企业开始重视自己网站的建设,并通过自己独立的企业网站,建立自己的客户关系和电子商务。
  这样一来,中小企业在阿里巴巴上注册网店成会员的需求,急剧减少。

  阿里巴巴本身并没有太多的流量来源,主要通过两种方式获得,一是购买搜索引擎的关键词,这次百度阿里交战也让大家了解到,阿里每年在百度上投放的推广费高达请数千万元,这实际上是阿里巴巴采购商的来源。而另一方面是做线下推广,到各地去参加展会,帮助自己的客户发布名录。实际上可以看到,阿里巴巴的会员收入,至少有一半以上都是拿来做推广使用了,阿里巴巴的业务可拓展性是非常差的。
  另外,阿里巴巴有一个核心功能叫做询盘功能,也就是说采购商到了阿里巴巴平台上,可以向多家发起询盘请求,并且,为了增加会员的价值感受,阿里巴巴后台也会对这些询盘信息进行处理,发布给更多的会员。这就造成了阿里巴巴的供应商为了一个询盘打成一片,最终引发价格战,企业的利润率逐年下降。
  美国宾夕法尼亚大学的乔治·德教授早就指出,B2B正在走向失败。美国股市目前尚存的几家B2B公司都是股价极低的渣渣股。阿里巴巴如果不极早的寻求转型,最终也将沦为来垃圾股的结局。

http://www.sula.cn

posted @ 2008-12-14 23:03 softfair 阅读(375) | 评论 (2)编辑

2008年11月25日 #

 

你已经知道的,但你并不了解的世界--献给80年代出生的人们

 

 

1983年流行词:春晚

 

    在娱乐、综艺节目满天飞的今天,人们无法想象1983年春晚是多么地“前卫”。它在稚嫩中透着勇气,它在随意中显露真诚,它在轻松中远离教化。在1983年“严打”和“清理精神污染”的大环境中,它的诞生可谓一个奇迹。它虽然只是一台以欢乐为主题的综艺节目,但对于中国人的观念解放,却是至关重要的一步。

 

    只要考察这台晚会前的几个没有,就能意识到它的创造性了。在这以前,中国几乎没有电视综艺节目这个概念;在这以前,文艺节目只有报幕员,没有主持人;在这以前,没有文艺节目直播的先例,更没有以互动为目的热线电话这一说;在这以前,小品只是艺术专业表演技能训练的一种方式,从未面对过公众。这些都是1983年春晚创下的第一,20多年后的今天,春晚也没有走出过这个模式。
   
    1983年春晚的总导演是黄一鹤,从他在那个年代迈出的这一大步来说,他无疑是一个伟大的导演。他可以说在第一届就把握住了春节和综艺晚会之间的所有要素,使这一抹亮色直到今天看来,也毫不逊色。

 

    “你的声音,你的歌声,永远印在我的心中,昨天虽已消逝,分别难相逢,怎能忘记你的一片深情……”李谷一演唱的《乡恋》,无疑是这届春晚中的最强音。说它是最强音,是因为当时在除夕之夜演出这一首歌,是需要付出极大的勇气的。

 

    早在1980年,李谷一演唱的《乡恋》就被主管宣传的高级官员几次点名,措辞严厉,媒体称这首歌是“低沉缠绵的靡靡之音”。李谷一从“歌坛新秀”一夜之间变成了“黄色歌女”,被指责为“大陆邓丽君”,有文章甚至视她为“腐蚀青年人的罪人”。

 

    春晚就是在这样的大环境下,请来李谷一作为当晚最重要的独唱歌手。这在当时是需要勇气的,因为李谷一几乎包揽当晚的大部分歌曲。然而对于“禁歌”《乡恋》,导演黄一鹤和当时在现场的广电部部长吴冷西,迟迟没敢下达演出指令。这事关所有人的政治生命,尤其在那个文艺还未走出政治阴影的年代。这时,现场4部观众点播电话起了作用,因为大多数点播的都是《乡恋》。越来越多的点播条,让吴冷西坐不住了,汗也出来了,在场边走来走去。最终观众的意志,超过了吴冷西对自己政治生命的顾虑。吴冷西一跺脚,操着南方口音说:“黄一鹤,播!”这时,李谷一已经唱了8首歌,并不知道幕后发生的这一切。据她回忆,当她突然听到主持人姜昆、刘晓庆拉长了声音说出:“乡——恋——”时,几乎不相信自己的耳朵,心里只涌现出三个字:“解禁了”。

 

    1983年春晚中,类似《乡恋》这样,敢于突破禁区的节目并不是一个。王景愚表演的哑剧《吃鸡》,过去也被批判过,说他是在用一只煮不烂、做不熟、咬不动的鸡,讽刺社会主义。这导致王景愚开始不敢演这个节目,他觉得这个节目上春晚有点“胡闹、庸俗”。然而在导演黄一鹤和编创马季等人的坚持下,他的节目还是上了。同样的节目还有严顺开小品《阿Q独白》,可以说都是冒了一些风险的。他们极富远见地将这届春晚定调为“欢乐”二字,所选取的节目也强调以远离主流意识、远离宏大主题、弱化政治功能为主。正是这一这一创举,使这届春晚一出炉,就广受民众好评。春晚也很快便被普及为一个家喻户晓的名词。

 

    即使在20多年后回顾这届春晚,也觉得他们当年那种精神,在今天已成为一种稀缺的资源。我们重温1983年的春晚,不仅因为是它使春晚成为了中国的一种民俗、春天的一个符号,更值得探究的是它赋予电视的一种宽容的人文关怀精神。

 

1983年备忘

 

    精神污染:1983年10月,中共十二届二中全会上提出“思想战线不能搞精神污染”。很快出现了对女青年烫发、搽雪花膏、着奇装异服、跳集体舞的指责,甚至养花也被说成了“资产阶级生活方式”。因《马克思传》内有燕妮身着袒肩欧洲装束的照片,被视为“黄色书籍”没收;《瞭望》封面因刊登女子体操运动员高低杠动作,被当作“黄色照片”收缴。好在很快有相关领导指示,一场扩大化的清除精神污染运动被及时叫停。
 
    严打:1983年初,沈阳“二王”案发。王宗玮、王宗王方兄弟因偷窃,制造数人死伤的枪案,并从北到南开始了大逃亡,不断制造新血案。8月,一场浩大的严打运动开始了,公判大会、挂牌游街、打着红勾的布告充斥街头。犯罪分子和一些生活前卫的人,在严打中付出惨痛代价。“严打”中,各地均有干部子弟落网,上海市委书记胡立教儿子胡晓阳、上海市委宣传部副部长陈其五儿子陈晓蒙以强奸罪、流氓罪被判死刑。电影明星迟志强,因“一夜情”被判刑4年,事业正如日中天时陨落。

posted @ 2008-11-25 13:11 softfair 阅读(359) | 评论 (4)编辑

2008年11月15日 #

故障现象
    向正在编辑的Word文档中插入一个图形时,发现插入的图形只显示出了一部分。下半部分,图片上面有文字,还能输入文字和回车。好像图片在文字下面一样,就露出了一个底部。无论怎样调整都不能解决问题,如果用浮于文字上方,那是可以的,但我现在需要的是嵌入式的版式。请问应如何处理?感觉是高度被限制了。
<--------------------------------->

分析处理
    出现此故障的原因有可能是设置为固定值的文档行距小于图形的高度,从而导致插入的图形只显示出了一部分。可以采用如下的方法解决:
  一. 首先,选定该图形,单击【开始】tab页中的【段落】项的右方的箭头,打开【段落】对话框。
  二. 在【段落】对话框中,单击【缩进和间距】选项卡,在【行距】框中选择【单倍行距】,如果在【行距】框中选择了【固定值】,就需要注意将【设置值】框中的数值改为合适的高度值
  三. 单击【确定】按钮。
      四.也可以全部选择文档,把那个【段落】中的【行距】都改掉。

posted @ 2008-11-15 20:57 softfair 阅读(936) | 评论 (4)编辑

2008年10月29日 #

最近爱看《血色迷雾》,尤其喜欢那里面的经典话语

一、关于国人

为什么中华民族会遭受外来侵略,为什么30年代的上海会沦陷,剧中文康有一段话,将民族及国人的劣根性披露无余。

文康道:我终于明白了,秦桧怎样以莫须有的罪名,谋害了爱国忠良岳飞铸成了千古奇冤。还有无辜的女子窦娥,面对地痞无赖的谋名胁婚,屈招领刑,终至天悲地恸,六月飞雪。我此次来梧桐,以君子始,以小人止,最终祸起萧墙。自己人先打得头破血流,我深深地感到悲哀。外族咄咄逼人,大兵压境之时,我们国人的精力却放在了如何琢磨人,整人,坑人,害人上。人与人之间,尔虞我诈,国不和,外族欺,邻不睦,外人辱。我想:我不会死在杀手的手上,倒可能死在自己人的飞短流长上。

有一个哲人说过:每一个中国人都是一条龙,上可以把太阳一口气吹灭,下可以安邦治国平天下,但当又有两个中国人来了,成为三个人的时候,这三条龙就变成了三条虫,因为三个中国人,永远抱不成一个团,也永远系不上一个结。

二、关于缘分

晓聪和文康同住上海,却在梧桐相识,剧中有一段关于缘分的解读,思想飘逸,富于哲理。

什么叫缘分,春风春雨,桃李花开;什么叫没缘分,人到码头船离岸,枯木落叶降甘霖。缘分是不可争的,缘是命,命是缘,可遇不可求。就仿佛云起云落,随风东西,茫茫人海,浮华世界,有太多的人擦肩而过。男女之间有两种情感,一种是相濡以沫,还有一种是相忘于江湖。和能爱的人在一起相濡以沫,和不能爱的人在一起相望于江湖。一席话语无不体现出作品对生活的豁达境界和信奉随缘的儒家思想

三、关于中庸

探长文康是一个正直而有血性的人,他对中庸之道的理解:意味着既不纵欲,也不禁欲;既不愚忠,也不奸诈;既不轻生厌世,也不贪生失节;升迁了,不专横跋扈;丢官了,不低三下四;发财了,不要为富不仁;贫穷了,不要人穷志短;既不让天下人负我,我也不负天下人;做人不亢不卑,不左不右;富贵不能淫,贫贱不能移,心性之沉静,取舍之中和,方能超越世俗浮躁。这样的解读忠勇正义、亦情亦理,使其意念灿然生辉,境界为之旷达,观后令人难忘。

四、关于人性

关于人和人之间关系,剧中采用了借喻的表达方式,论述精辟。众生轮回于生死苦海,生生不息。却就是一颗人心,危面难安。人心叵测,深不见底。泰山之路可推车,若比人心是坦途。黄河之水能覆舟,若比人心是安流。

西方大思想家采尼说过:他人永远是我之地狱,人和人之间,就象水上漂浮的一座冰山,每当春天来临,它们想早日靠近,获取一丝温暖。但是不靠近会冷,靠近可能会相撞,甚至会粉身碎骨。此喻独辟蹊径,揭示了人性的阴险与残酷。

五、关于茶道

在一起喝酒的人可以是敌人,在一起喝茶的人一定是朋友。剧中侦探文康和日本商人马太一郎论茶道,乃是挥洒着地有声的锦言妙语,令人叫绝。

中国人性格如茶,佛家喝茶,伴青灯孤影,晨钟暮鼓,明心见性。道家喝茶,求空谷虚灵,宁静致远,脱俗超尘。儒家喝茶为励志上进,发愤图强,积极入世,各种茶道中都讲究一个和字。以茶求得文探长的一个和。

有人品茶,绵里藏针,品出明争暗斗尔虞我诈;有人品茶,风声鹤唳,品出刀光剑影,金戈铁马,有人虚怀若谷,有人气定神闲,人喝茶有的讲究茶的品,有的讲究茶的韵,还有讲茶的德,还有讲究茶的味。精彩论述启迪心智,赏心悦目。

六、关于道路

所谓路,敢为人先的精神引领人们,在没有路的地方行走,在布满荆棘的地方开辟。文康肩负着沉重的使命艰难跋涉,在破案遭遇困难重重之时,找到了道长。看着一身正义的侦探文康,他全力相助,指点迷津。道长说:这路便是道,道是不会绝的,道无处不在,道在天上,道在地下,道在你的心里,道就在你的脚下,道在无语之中。字里行间,流露出道长的真诚情意,增添信心给人力量,在困境中看到光明和希望。

posted @ 2008-10-29 09:45 softfair 阅读(398) | 评论 (5)编辑

2008年10月8日 #

到这时,胡润和他的排行榜,已经构成了一个十分有趣的商业人文现象:对财富的追逐和关注,使排行榜倍受瞩目,而原始积累的灰色、排名的不科学乃至相当多人的仇富情结,则造成了观念及商业运作层面的混乱。以至于每次排行榜公布,便会有税务机构前去上榜富豪的公司查税,而往往又是一查一个准,那些因上榜而突然曝光的顶级富豪――尤其是排在前10位的则常常在传媒的追踪下突然显出不该有的“尾巴”来,如仰融、杨斌、顾稚军等,都是靠富豪榜出名的,可又是在传媒的高度关注中,眼睁睁地看他们或塌或萎,令人寒意顿生。甚至有人称之为“囚徒榜”或者“杀猪榜”。

胡润对自己在中国商业界所造成的轰动颇有点得意,在一次访谈中,他直截了当地说,“福布斯排行榜是我的一个工具。如果是一个中国人,或者中国机构来做这个排行榜,都会被骂死,但是,我恰巧是一个英国人,还有一个美国杂志,我们来做,就顺利一点。”胡润的这个说法无疑是真实的,这位30 出头的英国青年以他的大胆和鲁莽意外地打开了一扇“窥视的天窗”。

从2003年起,胡润与《福布斯》分道扬镳,他先是与《欧洲货币》杂志合作制作富豪榜,2005年,他推出以自己的名字命名的“胡润百富榜”。他已经完全地融入到了富有中国特色的财富游戏中,并且显得那么的如鱼得水,他相继搞出了一大堆的子榜单,诸如房地产富豪榜、慈善家榜、IT富豪榜、金融富豪榜、钢铁富豪榜以及奢侈品榜等等,甚至专门为温州做了一个温州富豪榜。他还出版一本叫《百富》的直投杂志。

 

我与胡润见面第一次见面是在2003年底。跟他约定八点三十分在上海波特曼大酒店见面,结果他迟到了。在十来分钟里,他连接打来两个电话,为上海的交通向我们致歉。访谈在波特曼边上的星巴克进行,这也是胡润建议的,他说,波特曼一杯咖啡要50 多元,而星巴克只要10来元。

这天,胡润穿的很休闲,浅黄的外套,围着一条黑灰相间的格子围巾,这让我想起了塞林格对英国绅士的一个描述,“他们要么夹着一把雨伞,要么叼着一根烟斗,要么,就不分季节地披着一条格子相间的围巾。”胡润说话的样子很细致,很注意对方的感受,并时不时地用英国式的表情来对你的言谈做出反应。他不但中文好得出奇,而且对汉文化的了解更是让人意外,他反问我,“中国历史上的第一次工业文明是出现在什么时候?”。就在我迟疑不决的时候,他得意地说,“那不就是在宋朝嘛,四大发明。”

就在那次访谈中,我已经注意到胡润开始拥有了一种时空跨度背景下的观察。譬如,他注意到,中国的富豪中最多的是房地产商,2003年则多了很多与农业――也就是说与土地有关的新富。与IT行业有关的只有4、5个人,而在美国,前10名富豪中有3名是出身IT。零售业方面,沃尔玛家族占去富豪榜前10名中的四席,而中国只有国美和家世界两个。在全美400强中,美国人数最多的是做娱乐媒体的,而中国只有一个人。

胡润“富豪俱乐部”的门槛,在1999年是600万美金,2002年就上涨到了8000万美金。这些大陆富豪的平均年龄为46岁,其中能说流利的英文的,才3个人,而这些富豪的孩子们能说英文的,就占到了50%以上。在全球10亿美金以上的富豪排行榜中,香港人有13个,而他们的平均年龄你猜猜是多少?72岁,台湾有5个人,平均年龄近80岁。这说明,我们的富豪还是第一代,在成长期中。2002年,广东地区有17名上榜,前三名都是外省移民,这一特征举国唯一••••••

posted @ 2008-10-08 12:33 softfair 阅读(89) | 评论 (0)编辑

说到胡润,我常常会想起另外一个“四肢发达、长得十分英俊”的英国人。

1942年11月,李约瑟(Joseph Needham 1900-1995)从伦敦出发,过了四个月,才由昆明辗转抵达重庆。他是英国剑桥大学的生化学家,从1943年到1946年,李约瑟以“中英科学合作馆”馆长的身份,先后做了十一次的长途考察,路程长达3万里左右。就是在这个过程中,他提出了一个日后十分著名的“李约瑟难题”(Needham’s Grand Question)。

据李约瑟的观察,16世纪之前的中国是世界上科技最先进的国家,中国人在公元868年印刷出了第一本表明出版日期的图书,在公元1088年,发明了“磁力导向”的指南针,在公元1161年发明了能够抛出炸弹的投石机,可是为何在日后停滞不前,居然成了一个倍受欺辱的衰老帝国?这个“难题”改变了李约瑟的此后人生,他从一个生化学家成为了举世闻名的中国科学史专家,他在1954年出版了《中国科学技术史》第一卷,到去世前的1995年共出版了十七卷。在西方的学术世界,他与美国人费正清是研究中国问题的两座让人仰止的高峰。

我知道今天的胡润还没有达到李约瑟式的高度,不过,他似乎正在做了一项几乎同等重要的工作。而他也提出了一个十分难解而迷人的问题:当代中国商人的财富到底是怎样积累起来的?他们是一群怎样的人?以及,他们是怎样“演化”的?

如果有足够的坚持――当然最好他还有同样的长寿,那么,也许在若干年后,他可能是另外一个经常被中国史学者提及的英国人。

胡润将在国庆后的第一周将公布新的“百富榜”,此次的入榜富豪人数将达到1000个,比去年多200个。这位英国人的“排行榜游戏”已经做到了第十年头,这是一个了不起的成绩。

胡润的本名是Rupert Hoogewerf,他是一个出生于1970年、毕业于著名的伊顿公学的英国人。如果说李约瑟是因为他的学生情人鲁桂珍小姐――他们在1989年才结为夫妻,当时,李约瑟89岁,鲁小姐85岁――才引发了对中国的好奇,那么,胡润与中国的缘分,则带有更强的时代气质。

胡润到中国是 1990年,他作为一个进修生到中国人民大学学习了一段时间的中文。1997年9月,在全球五大会计师事务所之一的安达信工作了一段时间后,胡润又回到了中国。他在上海滩上混了日子,东闯西突的搞不个名堂,很苦恼,便向家乡的老爸诉苦。老头子一语惊醒梦中人:你有没有搞明白,在中国,在上海你是谁?胡润说,从那时开始,他知道只有出名,让自己成为一个“谁”,那才会有机会。于是,他想到发挥自己的会计师才能,为中国富人做一个排行榜的主意。

早在1995年2月,《福布斯》曾经搞出过一个中国富豪榜,之后就因难以操作而中断。1999年,胡润搞出一份十分粗糙的排行榜出来了,以创造“金钱名利场”为己任的《福布斯》表示了兴趣,并将之放上了《福布斯全球版》的封面。就这样,胡润出名了。

名单刚一问世,质疑、谴责之声便铺天盖地而来。一些上榜的企业家要和胡润对簿公堂,没有上榜的富豪也要“讨个说法”,甚至有媒体说,这是一份十分“好笑”的名单,资料不准确、关注范围狭窄、计算方法错误,甚至这种做法本身都暴露出了无数问题。可是,无论如何,胡润因此成了一个让人又爱又恨的角色,几乎所有的中国顶级富豪都生怕他遗漏了自己,可是当自己真的出现在排行榜上的时候,却又避之唯恐不及便是在这样的舆论聚焦中,胡润一夜之间暴得大名,他出没在各种媒体之上,他对某一位企业家的些许点评都能成为财经或八卦新闻的发酵源。他上中央台《实话实说》节目时,主持人崔永元用当年毛主席写白求恩的语调介绍他,“胡润,一位英国小伙子,不远千里来到中国,做了一个中国人本来不知道的百富榜,把中国富人推向了世界,让世界了解了中国••••••”

posted @ 2008-10-08 12:30 softfair 阅读(106) | 评论 (0)编辑

2008年9月17日 #

Linux 动态库剖析

 

动态链接的共享库是 GNU/Linux® 的一个重要方面。该种库允许可执行文件在运行时动态访问外部函数,从而(通过在需要时才会引入函数的方式)减少它们对内存的总体占用。本文研究了创建和使用静态库的过程,详细描述了开发它们的各种工具,并揭秘了这些库的工作方式。

库用于将相似函数打包在一个单元中。然后这些单元就可为其他开发人员所共享,并因此有了模块化编程这种说法 — 即,从模块中构建程序。Linux 支持两种类型的库,每一种库都有各自的优缺点。静态库包含在编译时静态绑定到一个程序的函数。动态库则不同,它是在加载应用程序时被加载的,而且它与应用程序是在运行时绑定的。图 1 展示了 Linux 中的库的层次结构。


图 1. Linux 中的库层次结构
Linux 中的库层次结构。

使用共享库的方法有两种:您既可以在运行时动态链接库,也可以动态加载库并在程序控制之下使用它们。本文对这两种方法都做了探讨。

静态库较适宜于较小的应用程序,因为它们只需要最小限度的函数。而对于需要多个库的应用程序来说,则适合使用共享库,因为它们可以减少应用程序对内存(包括运行时中的磁盘占用和内存占用)的占用。这是因为多个应用程序可以同时使用一个共享库;因此,每次只需要在内存上复制一个库。要是静态库的话,每一个运行的程序都要有一份库的副本。

GNU/Linux 提供两种处理共享库的方法(每种方法都源于 Sun Solaris)。您可以动态地将程序和共享库链接并让 Linux 在执行时加载库(如果它已经在内存中了,则无需再加载)。另外一种方法是使用一个称为动态加载的过程,这样程序可以有选择地调用库中的函数。使用动态加载过程,程序可以先加载一个特定的库(已加载则不必),然后调用该库中的某一特定函数(图 2 展示了这两种方法)。这是构建支持插件的应用程序的一个普遍的方法。我稍候将在本文探讨并示范该应用程序编程接口(API)。


图 2. 静态链接与动态链接
图 2. 静态链接与动态链接

用 Linux 进行动态链接

现在,让我们深入探讨一下使用 Linux 中的动态链接的共享库的过程。当用户启动一个应用程序时,它们正在调用一个可执行和链接格式(Executable and Linking Format,ELF)映像。内核首先将 ELF 映像加载到用户空间虚拟内存中。然后内核会注意到一个称为 .interp 的 ELF 部分,它指明了将要被使用的动态链接器(/lib/ld-linux.so),如清单 1 所示。这与 UNIX® 中的脚本文件的解释器定义(#!/bin/sh)很相似:只是用在了不同的上下文中。


清单 1. 使用 readelf 来显示程序标题
            mtj@camus:~/dl$ readelf -l dl
            Elf file type is EXEC (Executable file)
            Entry point 0x8048618
            There are 7 program headers, starting at offset 52
            Program Headers:
            Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
            PHDR           0x000034 0x08048034 0x08048034 0x000e0 0x000e0 R E 0x4
            INTERP         0x000114 0x08048114 0x08048114 0x00013 0x00013 R   0x1
            [Requesting program interpreter: /lib/ld-linux.so.2]
            LOAD           0x000000 0x08048000 0x08048000 0x00958 0x00958 R E 0x1000
            LOAD           0x000958 0x08049958 0x08049958 0x00120 0x00128 RW  0x1000
            DYNAMIC        0x00096c 0x0804996c 0x0804996c 0x000d0 0x000d0 RW  0x4
            NOTE           0x000128 0x08048128 0x08048128 0x00020 0x00020 R   0x4
            GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4
            ...
            mtj@camus:~dl$
            

注意,ld-linux.so 本身就是一个 ELF 共享库,但它是静态编译的并且不具备共享库依赖项。当需要动态链接时,内核会引导动态链接(ELF 解释器),该链接首先会初始化自身,然后加载指定的共享对象(已加载则不必)。接着它会执行必要的再定位,包括目标共享对象所使用的共享对象。LD_LIBRARY_PATH 环境变量定义查找可用共享对象的位置。定义完成后,控制权会被传回到初始程序以开始执行。

再定位是通过一个称为 Global Offset Table(GOT)和 Procedure Linkage Table(PLT)的间接机制来处理的。这些表格提供了 ld-linux.so 在再定位过程中加载的外部函数和数据的地址。这意味着无需改动需要间接机制(即,使用这些表格)的代码:只需要调整这些表格。一旦进行加载,或者只要需要给定的函数,就可以发生再定位(稍候在 用 Linux 进行动态加载 小节中会看到更多的差别)。

再定位完成后,动态链接器就会允许任何加载的共享程序来执行可选的初始化代码。该函数允许库来初始化内部数据并备之待用。这个代码是在上述 ELF 映像的 .init 部分中定义的。在卸载库时,它还可以调用一个终止函数(定义为映像的 .fini 部分)。当初始化函数被调用时,动态链接器会把控制权转让给加载的原始映像。







用 Linux 进行动态加载

Linux 并不会自动为给定程序加载和链接库,而是与应用程序本身共享该控制权。这个过程就称为动态加载。使用动态加载,应用程序能够先指定要加载的库,然后将该库作为一个可执行文件来使用(即调用其中的函数)。但是正如您在前面所了解到的,用于动态加载的共享库与标准共享库(ELF 共享对象)无异。事实上,ld-linux 动态链接器作为 ELF 加载器和解释器,仍然会参与到这个过程中。

动态加载(Dynamic Loading,DL)API 就是为了动态加载而存在的,它允许共享库对用户空间程序可用。尽管非常小,但是这个 API 提供了所有需要的东西,而且很多困难的工作是在后台完成的。表 1 展示了这个完整的 API。


表 1. Dl API
函数 描述
dlopen 使对象文件可被程序访问
dlsym 获取执行了 dlopen 函数的对象文件中的符号的地址
dlerror 返回上一次出现错误的字符串错误
dlclose 关闭目标文件

该过程首先是调用 dlopen,提供要访问的文件对象和模式。调用 dlopen 的结果是稍候要使用的对象的句柄。mode 参数通知动态链接器何时执行再定位。有两个可能的值。第一个是 RTLD_NOW,它表明动态链接器将会在调用 dlopen 时完成所有必要的再定位。第二个可选的模式是 RTLD_LAZY,它只在需要时执行再定位。这是通过在内部使用动态链接器重定向所有尚未再定位的请求来完成的。这样,动态链接器就能够在请求时知晓何时发生了新的引用,而且再定位可以正常进行。后面的调用无需重复再定位过程。

还可以选择另外两种模式,它们可以按位 ORmode 参数中。RTLD_LOCAL 表明其他任何对象都无法使加载的共享对象的符号用于再定位过程。如果这正是您想要的的话(例如,为了让共享的对象能够调用原始进程映像中的符号),那就使用 RTLD_GLOBAL 吧。

dlopen 函数还会自动解析共享库中的依赖项。这样,如果您打开了一个依赖于其他共享库的对象,它就会自动加载它们。函数返回一个句柄,该句柄用于后续的 API 调用。dlopen 的原型为:

#include <dlfcn.h>
            void *dlopen( const char *file, int mode );
            

有了 ELF 对象的句柄,就可以通过调用 dlsym 来识别这个对象内的符号的地址了。该函数采用一个符号名称,如对象内的一个函数的名称。返回值为对象符号的解析地址:

void *dlsym( void *restrict handle, const char *restrict name );
            

如果调用该 API 时发生了错误,可以使用 dlerror 函数返回一个表示此错误的人类可读的字符串。该函数没有参数,它会在发生前面的错误时返回一个字符串,在没有错误发生时返回 NULL:

char *dlerror();
            

最后,如果无需再调用共享对象的话,应用程序可以调用 dlclose 来通知操作系统不再需要句柄和对象引用了。它完全是按引用来计数的,所以同一个共享对象的多个用户相互间不会发生冲突(只要还有一个用户在使用它,它就会待在内存中)。任何通过已关闭的对象的 dlsym 解析的符号都将不再可用。

char *dlclose( void *handle );
            






动态加载示例

了解了 API 之后,下面让我们来看一看 DL API 的例子。在这个应用程序中,您主要实现了一个 shell,它允许操作员来指定库、函数和参数。换句话说,也就是用户能够指定一个库并调用该库(先前未链接于该应用程序的)内的任意一个函数。首先使用 DL API 来解析该库中的函数,然后使用用户定义的参数(用来发送结果)来调用它。清单 2 展示了完整的应用程序。


清单 2. 使用 DL API 的 Shell
            
Code

要构建这个应用程序,需要通过 GNU Compiler Collection(GCC)使用如下的编译行。选项 -rdynamic 用来通知链接器将所有符号添加到动态符号表中(目的是能够通过使用 dlopen 来实现向后跟踪)。-ldl 表明一定要将 dllib 链接于该程序。

gcc -rdynamic -o dl dl.c -ldl
            

再回到 清单 2main 函数仅充当解释器,解析来自输入行的三个参数(库名、函数名和浮点参数)。如果出现 bye 的话,应用程序就会退出。否则的话,这三个参数就会传递给使用 DL API 的 invoke_method 函数。

首先调用 dlopen 来访问目标文件。如果返回 NULL 句柄,表示无法找到对象,过程结束。否则的话,将会得到对象的一个句柄,可以进一步询问对象。然后使用 dlsym API 函数,尝试解析新打开的对象文件中的符号。您将会得到一个有效的指向该符号的指针,或者是得到一个 NULL 并返回一个错误。

在 ELF 对象中解析了符号后,下一步就只需要调用函数。要注意一下这个代码和前面讨论的动态链接的差别。在这个例子中,您强行将目标文件中的符号地址用作函数指针,然后调用它。而在前面的例子是将对象名作为函数,由动态链接器来确保符号指向正确的位置。虽然动态链接器能够为您做所有麻烦的工作,但这个方法会让您构建出极其动态的应用程序,它们可以再运行时被扩展。

调用 ELF 对象中的目标函数后,通过调用 dlclose 来关闭对它的访问。

清单 3 展示了一个如何使用这个测试程序的例子。在这个例子中,首先编译程序而后执行它。接着调用了 math 库(libm.so)中的几个函数。完成演示后,程序现在能够用动态加载来调用共享对象(库)中的任意函数了。这是一个很强大的功能,通过它还能够给程序扩充新的功能。


清单 3. 使用简单的程序来调用库函数
            mtj@camus:~/dl$ gcc -rdynamic -o dl dl.c -ldl
            mtj@camus:~/dl$ ./dl
            > libm.so cosf 0.0
            1.000000
            > libm.so sinf 0.0
            0.000000
            > libm.so tanf 1.0
            1.557408
            > bye
            mtj@camus:~/dl$
            






工具

Linux 提供了很多种查看和解析 ELF 对象(包括共享库)的工具。其中最有用的一个当属 ldd 命令,您可以使用它来发送共享库依赖项。例如,在 dl 应用程序上使用 ldd 命令会显示如下内容:

mtj@camus:~/dl$ ldd dl
            linux-gate.so.1 =>  (0xffffe000)
            libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0xb7fdb000)
            libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7eac000)
            /lib/ld-linux.so.2 (0xb7fe7000)
            mtj@camus:~/dl$
            

ldd 所告诉您的是:该 ELF 映像依赖于 linux-gate.so(一个特殊的共享对象,它处理系统调用,它在文件系统中无关联文件)、libdl.so(DL API)、GNU C 库(libc.so)以及 Linux 动态加载器(因为它里面有共享库依赖项)。

readelf 命令是一个有很多特性的实用程序,它让您能够解析和读取 ELF 对象。readelf 有一个有趣的用途,就是用来识别对象内可再定位的项。对于我们这个简单的程序来说(清单 2 展示的程序),您可以看到需要再定位的符号为:

mtj@camus:~/dl$ readelf -r dl
            Relocation section '.rel.dyn' at offset 0x520 contains 2 entries:
            Offset     Info    Type            Sym.Value  Sym. Name
            08049a3c  00001806 R_386_GLOB_DAT    00000000   __gmon_start__
            08049a78  00001405 R_386_COPY        08049a78   stdin
            Relocation section '.rel.plt' at offset 0x530 contains 8 entries:
            Offset     Info    Type            Sym.Value  Sym. Name
            08049a4c  00000207 R_386_JUMP_SLOT   00000000   dlsym
            08049a50  00000607 R_386_JUMP_SLOT   00000000   fgets
            08049a54  00000b07 R_386_JUMP_SLOT   00000000   dlerror
            08049a58  00000c07 R_386_JUMP_SLOT   00000000   __libc_start_main
            08049a5c  00000e07 R_386_JUMP_SLOT   00000000   printf
            08049a60  00001007 R_386_JUMP_SLOT   00000000   dlclose
            08049a64  00001107 R_386_JUMP_SLOT   00000000   sscanf
            08049a68  00001907 R_386_JUMP_SLOT   00000000   dlopen
            mtj@camus:~/dl$
            

从这个列表中,您可以看到各种各样的需要再定位(到 libc.so)的 C 库调用,包括对 DL API(libdl.so)的调用。函数 __libc_start_main 是一个 C 库函数,它优先于程序的 main 函数(一个提供必要初始化的 shell)而被调用。

其他操作对象文件的实用程序包括:objdump,它展示了关于对象文件的信息;nm,它列出来自对象文件(包括调试信息)的符号。还可以将 EFL 程序作为参数,直接调用 Linux 动态链接器,从而手动启动映像:

mtj@camus:~/dl$ /lib/ld-linux.so.2 ./dl
            > libm.so expf 0.0
            1.000000
            >
            

另外,可以使用 ld-linux.so 的 --list 选项来罗列 ELF 映像的依赖项(ldd 命令也如此)。切记,它仅仅是一个用户空间程序,是由内核在需要时引导的。

 

兼容性不仅是为了关联

这意味着您最终要链接的程序库最好与调用它的代码相兼容。使用静态链接的可执行文件,可以在某种程度上保证不会发生任何改变。如果使用动态链接,就得不到这样的保证。

当出现新版本的程序库时会怎样?特别是新版本改变了某个给定函数的调用次序时,又会怎样?

版本号可以解决这个问题 —— 共享的程序库将拥有一个版本号。当一个程序链接到某个程序库时,程序中会存储一个它计划支持的版本号。如果更改程序库,那么版本号就会不匹配,程序也就不会被链接到较新版本的程序库。

不过,动态链接的可能优势之一在于修正缺陷。如果可以修正程序库中的缺陷,而且不必重新编译上千个程序,就可以利用这一修正功能,这将是非常令人愉快的。有时,需要链接到某个较新的版本。

不幸的是,这会导致在某些情况下,您希望链接到较新的版本,而在另外一些情况下,您宁愿坚持使用较老的版本。不过,有一个解决方案 —— 使用两类版本号:

  • 主版本号表明程序库版本之间的潜在不兼容性。
  • 次要版本号表明只是修正了缺陷。

这样,在大部分情形下,加载具有相同主版本号和更高次要版本号的程序库是安全的;而加载主版本号更高的程序是不安全的行为。

为了让用户(和程序员)不必追踪程序库版本号和更新,系统提供了大量的符号链接。通常,其模式是:

libexample.so

将是一个指向

libexample.so.N

的链接,其中 N 是在系统中可以找到的最高的 版本号。

对受支持的每一个主版本号而言,

libexample.so.N

将是一个指向

libexample.so.N.M

的链接,其中 M 是最高的 次要 版本号。

这样,如果为链接器指定了 -lexample,那么它会去寻找 libexample.so,这是一个符号链接,指向某个指向最新版本的符号链接。另一方面,当加载某个现有程序时,它将尝试去加载 libexample.so.N,其中 N 是它先前链接的版本。各得其所!






为了进行调试,首先必须知道如何编译

为了调试使用共享程序库的问题,对它们如何编译有更多一些了解会对您有所帮助。

在传统的静态程序库中,生成的代码通常封装在一个程序库文件中(其名称以 .a 结尾),然后传递给链接器。在动态程序库中,程序库文件的名称通常以 .so 结尾。文件结构稍有不同。

常规的静态程序库的格式是 ar 工具(一个非常简单的存档程序,类似于 tar,但是更简单)所创建的那种格式。相反,共享程序库通常以更复杂的文件格式存储。

在现代 Linux 系统中,这一格式通常是 ELF 二进制格式(可执行与可链接格式(Executable and Linkable Format))。在 ELF 中,每个文件的组成包括:一个 ELF 头,随后是零或者一些段(segments),以及零或者一些区段(sections)。 中包含文件的运行时执行所需要的信息,而 区段 中包含用于链接和重定位的重要数据。整个文件中的每个字节每次只能由一个区段使用,不过可以存在不被任何区段所包含的孤立字节。通常,在 UNIX 可执行文件中,一个或多个区段会封装在一个段内。

ELF 格式中包含用于应用程序和程序库的规范。但程序库格式要复杂得多,不仅仅是对象模块的简单存档。

链接器将所有对符号的引用进行分类,标识出它们是在哪个程序库中找到的。将静态程序库的符号添加到最终的可执行文件中;然后将共享程序库的符号放入 PLT 中,最后创建对 FLT 的引用。在完成这些任务之后,生成的可执行文件会拥有一个列表,该列表列出了计划从运行期将加载的程序库中找出的那些符号。

在运行期间,应用程序将加载动态链接器。实际上,动态链接器本身使用与共享程序库相同种类的版本号。例如,在 SUSE Linux 9.1 中, /lib/ld-linux.so.2 文件是一个指向 /lib/ld-linux.so.2.3.3 的符号链接。另一方面,寻找 /lib/ld-linux.so.1 的程序不会尝试使用新的版本。

然后动态链接器开始进行所有有趣的工作。它会查明某个程序先前链接到了哪些程序库(以及哪个版本),然后加载它们。加载程序库的步骤包括:

  • 找到程序库(它可能在系统中若干个目录中的任意一个目录中)。
  • 将程序库映射到程序的地址空间。
  • 分配程序库可能需要的由零填充的内存块。
  • 添加程序库的符号表。

调试这一过程可能会比较困难。您可能会遇到多种问题。例如,如果动态链接器不能找到某个给定的程序库,那么它将停止加载程序。如果它找到了所有需要的程序库,但却无法找到某个符号,那么它也可能会因此而停止加载操作(但是可能直到真正尝试去引用那个符号时才会发生这种情形) —— 这是一种很少见的情况,因为通常如果不存在某个符号,那么在初始化链接的时候就会被警告。

posted @ 2008-09-17 10:27 softfair 阅读(207) | 评论 (1)编辑

2008年8月25日 #

 最近在做的项目,发两个图片,记录一笔,历次版本更新后可以查看。

再来一个:

要低调一点。

posted @ 2008-08-25 11:17 softfair 阅读(31) | 评论 (0)编辑

2008年7月7日 #

     摘要: 经常性做服务端开发的,如果在服务器端 有一个很好用户管理界面,那将是非常完美的事情,服务端的管理界面,不求华丽,但求实用,而MMC控制管理台将是很专业的选择。SMCCAddIn 工程 是一个主工程,是MMC的插件,也是AssemblyAddIn 的容器。在bin/debug 下有个AddIns 目录,是存放插件dll的。 AssemblyAddIn 是一个插件实例工程。本源代码 在我去掉一些敏感词... 阅读全文
posted @ 2008-07-07 15:03 softfair 阅读(1708) | 评论 (6)编辑