1.2. 作者的私语(Administrata) 版权说明(copyright information)与合法的行迳规定(legalese),就摆在这份文件的尾端.除此之外,我......,我还有一些不得不提醒你的话要讲:就算你□著没事干,也不要在Usenet上丢一些呆瓜问的问题;还有啊,不要老以为自己C的功力深厚,专门发表一些不是bugs的bugs出来丢人现眼, 告诉别人你不学无术.最後;嚼口香糖的时候,不妨挖挖你的鼻孔(,and picking your nose while chewing gum)! [译者注:不知道这是那一国的幽默? eh? :-)另一种可能是原文有缺漏字汇, 像是"and not picking your nose while chewing gum."]
4.3.3. K & R gcc是个与ANSI相容的编译器;希奇的是,目前大多数的程式码都不符合ANSI所定的标准.假如你热爱ANSI,喜欢用ANSI提供的标准来撰写C程式,似乎除了在编译器的旗号上加上-traditional之外,就没有什麽其它的可以多谈的了. There is a certain amount of finer-grained control over which varieties of brain damage to emulate; 请自行查阅gcc info page. 要注重的是,尽管你用了-traditional来改变语言,它的效果也仅局限在gcc所能够接受的□围.例如, -traditional会打开(turn on)-fwritable-strings,使得字串常数(string constants)移至资料记忆体空间(data space)内(从程式码记忆体空间(text space),这地方是不能任意写入的).这样做会让程式码的记忆体空间无形中增加的.
4.3.8. 产生中断的系统呼叫(Interrupted system calls) 4.3.8.1. 徵兆(Symptom): 当一支程式以Ctrl-Z中止(stop),然後再重新执行(restart)时--或者是其它可以产生Ctrl-C中断(interruption)信号的情况,如子程序(child process)终结(termination)等--系统就会抱怨说"interrupted system call"或是"write: unknown error",或者诸如此类的讯息.
4.3.8.2. 问题点: POSIX的系统检查信号的次数,比起一些旧版的Unix是要多那麽一点.假如是Linux,可能就会执行signal handlers了--非同步地(asynchronously)(计时器的滴答声) 系统呼叫的传回值(on return from any system call) 在下列系统呼叫的执行期间: select(), pause(), connect(),accept(), read() on terminals, sockets, pipes or files in /proc, write() on terminals, sockets, pipes or the line printer, open() on FIFOs, PTYs or serial lines,ioctl() on terminals, fcntl() with command F_SETLKW, wait4(), syslog(), any TCP or NFS Operations.
修改成, int result; while (len > 0) { result = read(fd,buffer,len); if (result < 0) { if (errno != EINTR) break; } else { buffer += result; len -= result; } }
原始的程式片段,使用ioctl().
int result; result = ioctl(fd,cmd,addr);
修改成, int result; do { result = ioctl(fd,cmd,addr); } while ((result == -1) && (errno == EINTR)); 注重一点,有些版本的BSD Unix,其内定的行为(default behaviour)是重新执行系统呼叫.若要让系统呼叫中断,得使用 SV_INTERRUPT或SA_INTERRUPT旗号.
4.3.9. 可以写入的字串(Writable strings) gcc对其users总怀抱著乐观的想法(optimistic view),相信当他们打算让某个字串当作常数来用时---那它就真的只是字串常数而已.因此,这种字串常数会储存在程式码的记忆体区段内(in the code area of the program).这块区域可以page到磁碟机的image上,避免耗掉swap的记忆体空间,而且任何尝试写入的举动都会造成分页的错误(segmentation fault).这可是一种特色呢! 对老旧一点的程式而言, 这可能会产生一个问题.例如,呼叫mktemp(),传递引数(arguments)是字串常数. mktemp()会尝试著在*适当的位置(in place)*重新写入它的引数. 修正的方法不外乎(a)以-fwritable-strings编译,迫使gcc将此常数置放在资料记忆体空间(data space)内.或者(b)将侵犯地权的部份(offending parts)重新改写,配置一个不为常数的字串(non-constant string),在呼叫前,先以strcpy()将资料拷贝进去.
执行程式而不带任何引数(with no arguments),可解释成(construe)是一种邀请函(invitation),目的是把此程式的动态程式库独立(dynamic library dependencies)的特性印出来(print out).至少,a.out是这样的.就ELF而言,事情就不是这样了.
(假如你想得知此程式库的资讯,有一些更简单的介面可用;参考动态载入(dynamic loading)那一章节,或是ldd的manual page.) 11/16/97译 5. Debugging and Profiling 5.1. Preventative maintenance (lint) lint对Linux而言并没有很广泛的用途,主要是因为大部份的人都能满足於gcc所提供的警告讯息(warnings).可能最有用的就是-Wall参数了---这个参数的用途是要求gcc将所有的警告讯息显现出来. but probably has more mnemonic value if thought of as the thing you bang your head against.
另外,UPS除错程式已由Rick Sladkey移植成功.UPS可以在X底下活得很好,不像xxgdb那样---仅仅是gdb的X前端介面(X front end).这支除错程式有一大堆优良的特点,and if you spend any time debugging stuff, you probably should check it out.先前编译(precompiled)好的Linux版与修正版(patches)的原始码可以在ftp://sunsite.unc.edu/pub/Linux/devel/debuggers/找到.而最初的原始程式则放在 ftp://ftp.x.org/contrib/ups-2.45.2.tar.Z.
你可能会发现另一个用来除错的工具strace,也是相当的有用.它可以显示出由程序(process)所产生的系统呼叫,而且还拥有其它众多繁复的功能(multiplicity),像是假如你手边没有原始码的话,strace可以帮你找出(figure out)有那些路径(path-names)已编译进执行档(binaries)内; exacerbating race conditions in programs that you suspect contain them;还有,strace可拿来学习程式是怎麽在电脑中执行的.最新的版本(目前是3.0.8)可在找到 ftp://ftp.std.com/pub/jrs/. 5.2.3. 背景程式(Background (daemon) programs) 早期典型的常驻程式(daemon programs)是执行fork(),然後终止(terminate)父程序(parent).这样的做法使得除错的时间减短了. 了解(get around)这点的最简单的方法就是替fork()设一个breakpoint.当程式停止时,强迫fork()传回0.
(gdb) list 1 #include 2 3 main() 4 { 5 if(fork()==0) printf("child "); 6 else printf("parent "); 7 } (gdb) break fork Breakpoint 1 at 0x80003b8 (gdb) run Starting program: /home/dan/src/hello/./fork Breakpoint 1 at 0x400177c4
Breakpoint 1, 0x400177c4 in fork () (gdb) return 0 Make selected stack frame return now? (y or n) y #0 0x80004a8 in main () at fork.c:5 5 if(fork()==0) printf("child "); (gdb) next Single stepping until exit from function fork, which has no line number information. child 7 }
假如你想要有个多才多艺(versatility)的核心档命名(core file naming)(for example, if you're trying to conduct a post-mortem using a debugger that's buggy itself) ,那麽你可以对你的核心程式(kernel)做一点小小的更动(mod).找一找fs/binfmt_aout.c与fs/binfmt_elf.c档内与下列相符的程式片段(in newer kernels, you'll have to grep around a little in older ones): memcpy(corefile,"core.",5); #if 0 memcpy(corefile+5,current->comm,sizeof(current->comm)); #else corefile[4] = ''; #endif 将0换成1.
6. 连结(Linking) 由於静态(static)与共享(shared)程式库两者间不相容的格式(incompatible binary formats)的差异性(distinction)与动词*link*过量使用(overloading)於指称*编译完成後的事情*与*当编译过的程式使用时(invoke)所发生的事情*这两件事上头,使得这一章节变得复杂了许多.( and, actually, the overloading of the word `load' in a comparable but opposite sense)不过,再复杂也就是这样了,所以阁下不必过於担心. 为了稍微减轻读者的困惑,我们称执行期间(runtime)所发生的事为*动态载入(dynamic loading)*,这一主题会在下一章节中谈到.你也会在别的地方看到我把动态载入描述成*动态连结(dynamic linking)*,不过不会是在这一章节中.换句话说,这一章节所谈的,全部是指发生在编译结束後的连结(linking).
The DLL tool `mkimage' fails to find libgcc, or 从libc.so.4.5.x之後,libgcc已不再是共享的格式.因此,你必须在*-lgcc*出现之处以`gcc -print-libgcc-file-name`取代(完整的倒单引号(back-quotes)).另外,删除所有/usr/lib/libgcc*的档案.这点很重要哩.
Only presidents, editors, and people with tapeworms have the right to use the editorial ``we''. (Mark Twain)
这份HOWTO文件几乎完全根植於Mitchum Dsouza的GCC-FAQ; 文件内大部份的资讯(not to mention a reasonable amount of the text)是直接来自於GCC-FAQ的. 这份HOWTO文件用到的第一人称代名词,可视为我们两人其中一个;通常,要是有人说"我还没有测试过这些;假如它烧了(toast)你的硬碟/系统/配偶,可别怪我!",那这样的话适用於我俩身上. 对这份文件有贡献的名人雅士如下所列(以名字的ASCII码的顺序): Andrew Tefft, Axel Boldt, Bill Metzenthen, Bruce Evans, Bruno Haible, Daniel Barlow, Daniel Quinlan, David Engel, Dirk Hohndel, Eric Youngdale, Fergus Henderson, H.J. Lu, Jens Schweikhardt, Kai Petzke, Michael Meissner, Mitchum DSouza, Olaf Flebbe, Paul Gortmaker, Rik Faith, Steven S. Dick, Tuomas J Lukka, 当然还有Linux Torvalds,没有了他,这整个运动就会变得一点意义也没有了,所以不可能让他孤单的.:-)
9.3. 欢迎任何的回馈(Feedback) 寄信给我dan@detached.demon.co.uk.我的PGP public key (ID 5F263625) 可在我的烘培鸡web pages上使用, 假如你觉得事情有必要保密的话.
9.4. 合法的行迳规定 All trademarks used in this document are acknowledged as being owned by their respective owners.
This document is copyright (C) 1996 Daniel Barlow It may be reproduced and distributed in whole or in part, in any medium physical or electronic, as long as this copyright notice is retained on all copies. Commercial redistribution is allowed and encouraged; however, the author would like to be notified of any such distributions.
All translations, derivative works, or aggregate works incorporating any Linux HOWTO documents must be covered under this copyright notice. That is, you may not produce a derivative work from a HOWTO and impose additional restrictions on its distribution. Exceptions to these rules may be granted under certain conditions; please contact the Linux HOWTO coordinator at the address given below.
In short, we wish to promote dissemination of this information through as many channels as possible. However, we do wish to retain copyright on the HOWTO documents, and would like to be notified of any plans to redistribute the HOWTOs.
If you have questions, please contact Greg Hankins, the Linux HOWTO coordinator, at gregh@sunsite.unc.edu via email.'