⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gcc-howto-6.html

📁 GCC的完整使用手册
💻 HTML
📖 第 1 页 / 共 2 页
字号:
<P>ELF的优缺点与升级至ELF等级所需经历的种种痛苦,已在ELF-HOWTO内论及;我并不打算在这儿涂浆糊。ELF HOWTO应该与这份文件有同样的主题才是。<P><H3>ELF共享程式库</H3><P>若想让<CODE>libfoo.so</CODE>成为共享程式库,基本的步骤会像下面这样:<P><BLOCKQUOTE><CODE><PRE>$ gcc -fPIC -c *.c$ gcc -shared -Wl,-soname,libfoo.so.1 -o libfoo.so.1.0 *.o$ ln -s libfoo.so.1.0 libfoo.so.1$ ln -s libfoo.so.1 libfoo.so$ LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH ; export LD_LIBRARY_PATH</PRE></CODE></BLOCKQUOTE><P>这会产生一个名为<CODE>libfoo.so.1.0</CODE>的共享程式库,以及给予ld适当的连结(<CODE>libfoo.so</CODE>)还有使得动态载入程式(dynamic loader)能找到它(<CODE>libfoo.so.1</CODE>)。为了进行测试,我们将目前的目录加到<CODE>LD_LIBRARY_PATH</CODE>里。<P><A NAME="index.72"></A>  <P>当你津津乐道於程式库制做成功之时,别忘了把它移到如<CODE>/usr/local/lib</CODE>的目录底下,并且重新设定正确的连结路径。<CODE>libfoo.so.1</CODE>与<CODE>libfoo.so.1.0</CODE>的连结会由<CODE>ldconfig</CODE>依日期不断的更新,就大部份的系统来说,ldconfig会在开机过程中执行。<CODE>libfoo.so</CODE>的连结必须由手动方式更新。如果你对程式库所有组成份子(如标头档等)的升级,总是抱持著一丝不□的态度,那麽最简单的方法就是让<CODE>libfoo.so -> libfoo.so.1</CODE>;如此一来,ldconfig便会替你同时保留最新的连结。要是你没有这麽做,你自行设定的东东就会在数日後造成<EM>千奇百怪的问题</EM>出现。到时候,可别说我没提醒你啊!<P><BLOCKQUOTE><CODE><PRE>$ su# cp libfoo.so.1.0 /usr/local/lib# /sbin/ldconfig# ( cd /usr/local/lib ; ln -s libfoo.so.1 libfoo.so )</PRE></CODE></BLOCKQUOTE><P><H3><A NAME="index.74"></A> <A NAME="index.73"></A> 版本编号、soname与符号连结  </H3><P>每一个程式库都有一个<EM>soname</EM>。当连结器发现它正在搜寻的程式库中有这样的一个名称,连结器便会将soname箝入连结中的二进位档内,而不是它正在运作的实际的档名。在程式执行期间,动态载入程式会搜寻拥有soname这样的档名的档案,而不是程式库的档名。因此,一个名为<CODE>libfoo.so</CODE>的程式库,就可以有一个<CODE>libbar.so</CODE>的soname了。而且所有连结到<CODE>libbar.so</CODE>的程式,当程式开始执行时,会寻找的便是<CODE>libbar.so</CODE>了。<P><P>这听起来好像一点意义也没有,但是这一点,对於了解数个不同版本的同一个程式库是如何在单一系统上共存的原因,却是关键之钥。Linux程式库标准的命名方式,比如说是<CODE>libfoo.so.1.2</CODE>,而且给这个程式库一个<CODE>libfoo.so.1</CODE>的soname。如果此程式库是加到标准程式库的目录底下(e.g. <CODE>/usr/lib</CODE>),<CODE>ldconfig</CODE>会建立符号连结<CODE>libfoo.so.1 -> libfoo.so.1.2</CODE>,使其正确的image能於执行期间找到。你也需要连结<CODE>libfoo.so -> libfoo.so.1</CODE>,使ld能於连结期间找到正确的soname。<P>所以罗,当你修正程式库内的bugs,或是添加了新的函数进去(任何不会对现存的程式造成不利的影响的改变),你会重建此程式库,保留原本已有的soname,然後更改程式库档名。当你对程式库的变更会使得现有的程式中断,那麽你只需增加soname中的编号---此例中,称新版本为<CODE>libfoo.so.2.0</CODE>,而soname变成<CODE>libfoo.so.2</CODE>。紧接著,再将<CODE>libfoo.so</CODE>的连结转向新的版本;至此,世界又再度恢复了和平!<P>其实你<EM>不须要</EM>以此种方式来替程式库命名,不过这的确是个好的传统。ELF赋予你在程式库命名上的弹性,会使得人气喘呼呼的搞不清楚状况;有这样的弹性在,也并不表示你就得去用它。<P><P>ELF总结:假设经由你睿智的观察发现有个惯例说:程式库主要的升级会破坏相容性;而次要的升级则可能不会;那麽以下面的方式来连结,所有的一切就都会相安无事了。<P><BLOCKQUOTE><CODE><PRE>gcc -shared -Wl,-soname,libfoo.so.major -o libfoo.so.major.minor</PRE></CODE></BLOCKQUOTE><P><H3>a.out---旧旧的格式□</H3><P>建立共享程式库的便利性是升级至ELF的主要原因之一。那也是说,a.out可能还是有用处在的。上ftp站去抓<A HREF="ftp://tsx-11.mit.edu/pub/linux/packages/GCC/src/tools-2.17.tar.gz">ftp://tsx-11.mit.edu/pub/linux/packages/GCC/src/tools-2.17.tar.gz</A>;解压缩後你会发现有20页的文件可以慢慢的读哩。我很不喜欢自己党派的偏见表现得那麽的淋璃尽致,可是从上下文间,应该也可以很清楚的嗅出我从来不拿石头砸自己的脚的脾气吧!:-)<P><H3><A NAME="index.76"></A> <A NAME="index.75"></A> ZMAGIC vs QMAGIC  </H3><P>QMAGIC是一种类似旧格式的a.out(亦称为ZMAGIC)的可执行档格式,这种格式会使得第一个分页无法map。当0-4096的□围内没有mapping存在时,则可允许NULL dereference trapping更加的容易。所产生的边界效应是你的执行档会比较小(大约少1K左右)。<P>只有即将作废的连结器有支援ZMAGIC,一半已埋入棺材的连结器有支援这两种格式;而目前的版本仅支援QMAGIC而已。事实上,这并没有多大的影响,那是因为目前的核心两种格式都能执行。<P>*file*命令应该可以确认程式是不是QMAGIC的格式的。<P><H3>档案配置</H3><P>一a.out(DLL)的共享程式库包含两个真实的档案与一个连结符号。就*foo*这个用於整份文件做为□例的程式库而言,这些档案会是<CODE>libfoo.sa</CODE>与<CODE>libfoo.so.1.2</CODE>;连结符号会是<CODE>libfoo.so.1</CODE>,而且会指向<CODE>libfoo.so.1.2</CODE>。这些是做什麽用的?<P>在编译时,<CODE>ld</CODE>会寻找<CODE>libfoo.sa</CODE>。这是程式库的*stub*档案。而且含有所有执行期间连结所需的exported的资料与指向函数的指标。<P>执行期间,动态载入程式会寻找<CODE>libfoo.so.1</CODE>。这仅仅是一个符号连结,而不是真实的档案。故程式库可更新成较新的且已修正错误的版本,而不会损毁任何此时正在使用此程式库的应用程式。在新版---比如说<CODE>libfoo.so.1.3</CODE>---已完整呈现时,ldconfig会以一极微小的操作,将连结指向新的版本,使得任何原本使用旧版的程式不会感到丝毫的不悦。<P>DLL程式库(我知道这是无谓的反覆---所以对我提出诉讼吧!)通常会比它们的静态副本要来得大多。它们是以*洞(holes)*的形式来保留空间以便日後的扩充。这种*洞*可以不占用任何的磁碟空间。一个简单的<CODE>cp</CODE>呼叫,或是使用<CODE>makehole</CODE>程式,就可以达到这样效果。因为它们的位址是固定在同一位置上,所以在建立程式库後,你可以把它们拿掉。不过,<B>千万不要试著拿掉ELF的程式库</B>。<P><H3>``libc-lite''?</H3><P>libc-lite是轻量级的libc版本。可用来存放在磁碟片上,也可以替大部份低微的UNIX任务收尾。它没有包含curses, dbm, termcap等等的程式码。如果你的<CODE>/lib/libc.so.4</CODE>是连结到一个lite的libc,那麽建议你以完整的版本取代它。<P><H3>连结:常见的问题</H3><P>把你连结时所遭遇的问题寄给我!我可能什麽事也不会做,但是只要累积了足够的数量,我会把它们写起来*。<P><DL><P><DT><B>你想共享,偏偏程式却连结成静态的!</B><DD><P><A NAME="index.77"></A>  <A NAME="index.78"></A>  <P>检查你提供给<CODE>ld</CODE>的连结是否正确,使ld能找到每一个对应的共享程式库,就ELF而言,这是指一个符号连结<CODE>libfoo.so</CODE>,连结至image;就a.out而言,就是<CODE>libfoo.sa</CODE>档了。很多人将ELF binutils 2.5升级至2.6之後,就产生了这个问题---早期的版本搜寻共享程式库时较有智慧,所以并没有将所有的连结建立起来。後来,为了与其它的架构相容,这项充满智慧的行为被人给删除掉了,另外,这样的*智慧*判断错误的机率相当高,所造成的麻烦比它所解决的问题还多,所以留著也是害人精;不如归去兮!<P><DT><B>DLL的工具程式‘mkimage’找不到libgcc? </B><DD><P><A NAME="index.79"></A>  <P>自<CODE>libc.so.4.5.x</CODE>之後,libgcc已不再是共享的格式。因此,你必须在*<CODE>-lgcc</CODE>*出现之处以<CODE>`gcc -print-libgcc-file-name`</CODE>替代(完整的倒单引号(back-quotes))。另外,删除所有<CODE>/usr/lib/libgcc*</CODE>的档案。这点很重要哩。<P><DT><B> <CODE>__NEEDS_SHRLIB_libc_4 multiply defined</CODE> messages </B><DD><P>是同样的问题所造成的另一种结果。<P><DT><B> ``Assertion failure'' message when rebuilding a DLL ?</B><DD><P>这一条神秘的讯息最有可能的原因是,在原始的<CODE>jump.vars</CODE>档案内,由於保留的空间太少,以致於造成其中一个jump table slots溢满。你可以执行工具程式□由2.17.tar.gz套件所提供的‘<CODE>getsize</CODE>’命令,定出所有嫌疑犯的踪迹。可能唯一的解决方法是,解除此程式库主要的版本编号,强迫它回到不相容的年代。<P><DT><B> <CODE>ld: output file needs shared library libc.so.4</CODE> </B><DD><P>通常这是发生在当你连结的程式库不是libc(如X程式库),而且在命令列用了<CODE>-g</CODE>的参数,却没有一并使用<CODE>-static</CODE>,所发出的错误讯息。<P>共享程式库的<CODE>.sa</CODE> stubs通常有一个未定义的符号<CODE>_NEEDS_SHRLIB_libc_4</CODE>;这一点可藉由<CODE>libc.sa</CODE> stub来解决,然而,以<CODE>-g</CODE>来编译时,会使得连结以<CODE>libg.a</CODE>或<CODE>libc.a</CODE>来结束;因此这个符号一直就没有解决,也就会导致上面的错误讯息了。<P>总之,以<CODE>-g</CODE>的旗号编译时别忘了加上<CODE>-static</CODE>,不然就别用<CODE>-g</CODE>来连结。通常,以<CODE>-g</CODE>编译各个独立的档案时,所获得的除错资讯已经足够,连结时就可以<EM>不需要</EM>它了。<P></DL><P><P><HR><A HREF="GCC-HOWTO-7.html">Next</A><A HREF="GCC-HOWTO-5.html">Previous</A><A HREF="GCC-HOWTO.html#toc6">Contents</A></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -