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

📄 gcc-howto.txt

📁 linux-bible.rar linux-bible.rar
💻 TXT
📖 第 1 页 / 共 5 页
字号:
   要版本是1,次要版本是2。次要版本的编号可能真有其事,也可能什麽都没   有---libc在这一点上用了*修正程度*的观念,而订出了像libc.so.5.2.18这样的   程式库名称。次要版本的编号内若是放一些字母、底线、或是任何可以列印   的ASCII字元,也是很合理的。      ELF与a.out格式最主要的差别之一就是在设置共享程式库这件事上;我们先   看ELF,因为它比较简单一些。     ELF?它到底是什麽东东ㄋㄟ?     ELF(Executable and Linking Format)最初是由USL(UNIX System   Laboratories)发展而成的二进位格式,目前正应用於Solaris与System V   Release 4上。由於ELF所增涨的弹性远远超过Linux过去所用的a.out格式,因   此GCC与C程式库的发展人士於1995年决定改用ELF为Linux标准的二进位格式。     怎麽又来了?     这一节是来自於‘/news-archives/comp.sys.sun.misc’的文件。        ELF(“Executable Linking Format”)是於SVR4所引进的新式改良目的档格     式。ELF比起COFF可是多出了不少的功能。以ELF而言,它*是*可由使用者自行     延伸的。ELF视一目的档为节区(sections),如串列般的组合;而且此串列     可为任意的长度(而不是一固定大小的阵列)。这些节区与COFF的不一样,并     不需要固定在某个地方,也不需要以某种顺序排列。如果使用者希望补捉到新     的资料,便可以加入新的节区到目的档内。ELF也有一个更强而有力的除错法     式,称为DWARF(Debugging With Attribute Record Format)□目前Linux并     不完全支援。DWARF DIEs(Debugging Information Entries)的连结串列会     在ELF内形成 .debug的节区。DWARF DIEs的每一个 .debug节区并非一些少量     且固定大小的资讯记录的集合,而是一任意长度的串列,拥有复杂的属性,而     且程式的资料会以有□围限制的树状资料结构写出来。DIEs所能补捉到的大量     资讯是COFF的 .debug节区无法望其项背的。(像是C++的继承图。)          ELF档案是从SVR4(Solaris 2.0 ?)ELF存取程式库(ELF access library)     内存取的。此程式库可提供一简便快速的介面予ELF。使用ELF存取程式库最主     要的恩惠之一便是,你不再需要去察看一个ELF档的qua了。就UNIX的档案而言     ,它是以Elf*的型式来存取;呼叫elf_open()之後,从此时开始,你只需呼     叫elf_foobar()来处理档案的某一部份即可,并不需要把档案实际在磁碟上     的image搞得一团乱。        ELF的优缺点与升级至ELF等级所需经历的种种痛苦,已在ELF-HOWTO内论及;我并   不打算在这儿涂浆糊。ELF HOWTO应该与这份文件有同样的主题才是。     ELF共享程式库     若想让libfoo.so成为共享程式库,基本的步骤会像下面这样:   $ 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   这会产生一个名为libfoo.so.1.0的共享程式库,以及给予ld适当的连结   (libfoo.so)还有使得动态载入程式(dynamic loader)能找到它   (libfoo.so.1)。为了进行测试,我们将目前的目录加到LD_LIBRARY_PATH里。      当你津津乐道於程式库制做成功之时,别忘了把它移到如/usr/local/lib的目录   底下,并且重新设定正确的连结路径。libfoo.so.1与libfoo.so.1.0的连结会   由ldconfig依日期不断的更新,就大部份的系统来说,ldconfig会在开机过程中   执行。libfoo.so的连结必须由手动方式更新。如果你对程式库所有组成份子(如   标头档等)的升级,总是抱持著一丝不□的态度,那麽最简单的方法就是   让libfoo.so -> libfoo.so.1;如此一来,ldconfig便会替你同时保留最新的连   结。要是你没有这麽做,你自行设定的东东就会在数日後造成千奇百怪的问题出   现。到时候,可别说我没提醒你啊!   $ su# cp libfoo.so.1.0 /usr/local/lib# /sbin/ldconfig# ( cd /usr/local/lib ; ln -s libfoo.so.1 libfoo.so )  版本编号、soname与符号连结     每一个程式库都有一个soname。当连结器发现它正在搜寻的程式库中有这样的一   个名称,连结器便会将soname箝入连结中的二进位档内,而不是它正在运作的实   际的档名。在程式执行期间,动态载入程式会搜寻拥有soname这样的档名的档案   ,而不是程式库的档名。因此,一个名为libfoo.so的程式库,就可以有一   个libbar.so的soname了。而且所有连结到libbar.so的程式,当程式开始执行时   ,会寻找的便是libbar.so了。      这听起来好像一点意义也没有,但是这一点,对於了解数个不同版本的同一个程   式库是如何在单一系统上共存的原因,却是关键之钥。Linux程式库标准的命名方   式,比如说是libfoo.so.1.2,而且给这个程式库一个libfoo.so.1的soname。如   果此程式库是加到标准程式库的目录底下(e.g. /usr/lib),ldconfig会建立符   号连结libfoo.so.1 -> libfoo.so.1.2,使其正确的image能於执行期间找到。你   也需要连结libfoo.so -> libfoo.so.1,使ld能於连结期间找到正确的soname。      所以罗,当你修正程式库内的bugs,或是添加了新的函数进去(任何不会对现存   的程式造成不利的影响的改变),你会重建此程式库,保留原本已有的soname,   然後更改程式库档名。当你对程式库的变更会使得现有的程式中断,那麽你只需   增加soname中的编号---此例中,称新版本为libfoo.so.2.0,而soname变   成libfoo.so.2。紧接著,再将libfoo.so的连结转向新的版本;至此,世界又再   度恢复了和平!      其实你不须要以此种方式来替程式库命名,不过这的确是个好的传统。ELF赋予你   在程式库命名上的弹性,会使得人气喘呼呼的搞不清楚状况;有这样的弹性在,   也并不表示你就得去用它。      ELF总结:假设经由你睿智的观察发现有个惯例说:程式库主要的升级会破坏相容   性;而次要的升级则可能不会;那麽以下面的方式来连结,所有的一切就都会相   安无事了。   gcc -shared -Wl,-soname,libfoo.so.major -o libfoo.so.major.minor  a.out---旧旧的格式□     建立共享程式库的便利性是升级至ELF的主要原因之一。那也是说,a.out可能还是   有用处在的。上ftp站去抓   [22]ftp://tsx-11.mit.edu/pub/linux/packages/GCC/src/tools-2.17.tar.gz;   解压缩後你会发现有20页的文件可以慢慢的读哩。我很不喜欢自己党派的偏见表   现得那麽的淋璃尽致,可是从上下文间,应该也可以很清楚的嗅出我从来不拿石   头砸自己的脚的脾气吧!:-)     ZMAGIC vs QMAGIC     QMAGIC是一种类似旧格式的a.out(亦称为ZMAGIC)的可执行档 格式,这种格式   会使得第一个分页无法map。当0-4096的□围内没有mapping存在时,则可允   许NULL dereference trapping更加的容易。所产生的边界效应是你的执行档会比   较小(大约少1K左右)。      只有即将作废的连结器有支援ZMAGIC,一半已埋入棺材的连结器有支援这两种格   式;而目前的版本仅支援QMAGIC而已。事实上,这并没有多大的影响,那是因为   目前的核心两种格式都能执行。      *file*命令应该可以确认程式是不是QMAGIC的格式的。     档案配置     一a.out(DLL)的共享程式库包含两个真实的档案与一个连结符号。就*foo*这个用   於整份文件做为□例的程式库而言,这些档案会是libfoo.sa与libfoo.so.1.2;   连结符号会是libfoo.so.1,而且会指向libfoo.so.1.2。这些是做什麽用的?      在编译时,ld会寻找libfoo.sa。这是程式库的*stub*档案。而且含有所有执行期   间连结所需的exported的资料与指向函数的指标。      执行期间,动态载入程式会寻找libfoo.so.1。这仅仅是一个符号连结,而不是真   实的档案。故程式库可更新成较新的且已修正错误的版本,而不会损毁任何此时   正在使用此程式库的应用程式。在新版---比如说libfoo.so.1.3---已完整呈现时   ,ldconfig会以一极微小的操作,将连结指向新的版本,使得任何原本使用旧版   的程式不会感到丝毫的不悦。      DLL程式库(我知道这是无谓的反覆---所以对我提出诉讼吧!)通常会比它们的   静态副本要来得大多。它们是以*洞(holes)*的形式来保留空间以便日後的扩充   。这种*洞*可以不占用任何的磁碟空间。一个简单的cp呼叫,或是使用makehole   程式,就可以达到这样效果。因为它们的位址是固定在同一位置上,所以在建立   程式库後,你可以把它们拿掉。不过,千万不要试著拿掉ELF的程式库。     ``libc-lite''?     libc-lite是轻量级的libc版本。可用来存放在磁碟片上,也可以替大部份低微   的UNIX任务收尾。它没有包含curses, dbm, termcap等等的程式码。如果你   的/lib/libc.so.4是连结到一个lite的libc,那麽建议你以完整的版本取代它。     连结:常见的问题     把你连结时所遭遇的问题寄给我!我可能什麽事也不会做,但是只要累积了足够   的数量,我会把它们写起来*。      你想共享,偏偏程式却连结成静态的!          检查你提供给ld的连结是否正确,使ld能找到每一个对应的共享程式库,          就ELF而言,这是指一个符号连结libfoo.so,连结至image;就a.out而言          ,就是libfoo.sa档了。很多人将ELF binutils 2.5升级至2.6之後,就产          生了这个问题---早期的版本搜寻共享程式库时较有智慧,所以并没有将          所有的连结建立起来。後来,为了与其它的架构相容,这项充满智慧的行          为被人给删除掉了,另外,这样的*智慧*判断错误的机率相当高,所造成          的麻烦比它所解决的问题还多,所以留著也是害人精;不如归去兮!             DLL的工具程式‘mkimage’找不到libgcc?           自libc.so.4.5.x之後,libgcc已不再是共享的格式。因此,你必须          在*-lgcc*出现之处以`gcc -print-libgcc-file-name`替代(完整的倒单          引号(back-quotes))。另外,删除所有/usr/lib/libgcc*的档案。这          点很重要哩。             __NEEDS_SHRLIB_libc_4 multiply defined messages           是同样的问题所造成的另一种结果。             ``Assertion failure'' message when rebuilding a DLL ?          这一条神秘的讯息最有可能的原因是,在原始的jump.vars档案内,由於          保留的空间太少,以致於造成其中一个jump table slots溢满。你可以执          行工具程式□由2.17.tar.gz套件所提供的‘getsize’命令,定出所有嫌          疑犯的踪迹。可能唯一的解决方法是,解除此程式库主要的版本编号,强          迫它回到不相容的年代。             ld: output file needs shared library libc.so.4           通常这是发生在当你连结的程式库不是libc(如X程式库),而且在命令          列用了-g的参数,却没有一并使用-static,所发出的错误讯息。                    共享程式库的.sa stubs通常有一个未定义的符号_NEEDS_SHRLIB_libc_4          ;这一点可藉由libc.sa stub来解决,然而,以-g来编译时,会使得连结          以libg.a或libc.a来结束;因此这个符号一直就没有解决,也就会导致上          面的错误讯息了。                    总之,以-g的旗号编译时别忘了加上-static,不然就别用-g来连结。通          常,以-g编译各个独立的档案时,所获得的除错资讯已经足够,连结时就          可以不需要它了。          7. 动态载入   这一章节目前是简短了一点;当我掠尽ELF HOWTO时,就是这部份再度扩展的时候   了。   7.1 基本概念   Linux有共享程式库,如果之前你已坐著读完上一章节,想必现在一听到像这样的   说词,便会立刻感到头昏。有一些照惯例而言是在连结时期便该完成的工作,必   须延迟到载入时期才能完成。   7.2 错误讯息   把你连结的错误寄给我!我不会做任何的事,不过我可以把它们写起来**      can't load library: /lib/libxxx.so, Incompatible version          (a. out only) 这是指你没有xxx程式库的正确的主要版本。可别以为          随随 便便弄个连结到你目前拥有的版本就可以了,如果幸运的话,就只          会造成你的程式分页错误而已。去抓新的版本.ELF类似的情况会造成像下          面这样的讯息:          ftp: can't load library 'libreadline.so.2'   warning using incompatible library version xxx          (a. out only)你的程式库的次要版本比起这支程式用来编译的还要旧          。程式依然可以执行。只是可能啦!我想,升个级应该没什麽伤害吧!          7.3 控制动态载入器的运作   有一组环境变数会让动态载入器有所反应。大部份的环境变数对ldd的用途要比起   对一般users的还要来得更多。而且可以很方便的设定成由ldd配合各种参数来执   行。这些变数包括,        * LD_BIND_NOW --- 正常来讲,函数在呼叫之前是不会让程式寻找的。设定这       个旗号会使得程式库一载入,所有的寻找便会发生,同时也造成起始的时间       较慢。当你想测试程式,确定所有的连结都没有问题时,这项旗号就变得很       有用。     * LD_PRELOAD可以设定一个档案,使其具有*覆盖*函数定义的能力。例如,如       果你要测试记忆体分配的方略,而且还想置换*malloc*,那麽你可以写好准       备替换的副程式,并把它编译成mallolc.,然後:       $ LD_PRELOAD=malloc.o; export LD_PRELOAD$ some_test_program       LD_ELF_PRELOAD 与 LD_AOUT_PRELOAD 很类似,但是仅适用於正确的二进位       型态。如果设定了 LD_something_PRELOAD 与 LD_PRE

⌨️ 快捷键说明

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