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

📄 gcc-howto.txt

📁 linux-bible.rar linux-bible.rar
💻 TXT
📖 第 1 页 / 共 5 页
字号:
  Internal compiler error: cc1 got fatal signal 11     Signal 11是指 SIGSEGV,或者 ‘segmentation violation’。通常这是指   说gcc对自己所用的指标感到困惑,而且还尝试著把资料写入不属於它的记忆体里   。所以,这可能是一个gcc的bug。 然而,大体而言,gcc是一支经过严密测试且   可靠度良好的软体佳作。它也用了大量复杂的资料结构与惊人的指标数量。简言   之,若是要评选本世纪最挑惕与最一丝不□的RAM测试程式,gcc绝对可以一摘后   冠。假如你无法重新复制这只bug---当你重新开始编译时,错误的讯息并没有一   直出现在同一个地方---那几乎可以确定,是你的硬体本身有问题(CPU,记忆体,主   机板或是快取记忆体).千万不要因为你的电脑可以通过开机程序的测试、或   是Windows可以跑得很顺、或者其它什麽的,就回过头来大肆宣传说这是gcc的一   个bug;你所做的这些测试动作,通常没有什麽实际上的价值,这是很合理的结论   。另外,也不要因为编译核心时,总是停留在‘make zImage’的阶段,就要大骂   这是gcc的bug---当然它会停在那儿啊!做‘make zImage’时,需要编译的档案   可能就超过200档案;我们正在研拟一个替代的方案。      如果你可以重覆产生这个bug,而且(最好是这样啦!)可以写一个短小的程式来   展示这只bug的话,你就可以把它做成bug报告,然後email给FSF,或者   是linux-gcc通信论坛。你可以去参考gcc的说明文件,看看有什麽详细的资讯,是   他们所需要的。   4.3 移植能力   据报,近日来许多正面的消息指出,若是有某件东东到现在都还没移植到Linux上   去,那麽可以肯定的是,它一定一点价值也没有。:-)      嗯!正经一点。一般而言,原始码只需要做一些局部的修改,就可以克服Linux   100%与POSIX相容的特质。如果你做了任何的修改,而将此部份传回给原作者,会   是很有建设性的举动。这样日後就只需要用到‘make’,就能得到一个可执行的   档案了。     BSD教徒 (有 bsd_ioctl、daemon 与 <sgtty.h>)     编译程式时,可以配合-I/usr/include/bsd与连结-lbsd的程式库。(例如:在你   的Makefile档内,把-I/usr/include/bsd加到CFLAGS那一行;把-lbsd加   到LDFLAGS那一行)。如果你真的那麽想要BSD型态的信号行为,也不需要再加   上-D__USE_BSD_SIGNAL了。那是因为当你用了-I/usr/include/bsd与含括了标头   档<signal.h>之後,make时就会自动加入了。     失落的封印(SIGBUS, SIGEMT, SIGIOT, SIGTRAP, SIGSYS etc)     Linux与POSIX是完全相容的。不过,有些信号并不是POSIX定义的---ISO/IEC   9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:        “在POSIX.1中省略了SIGBUS、SIGEMT、SIGIOT、SIGTRAP与SIGSYS信号,那是     因为它们的行为与实作的方式息息相关,而且也无法进行适当的分类。确认实     作方式後,便可以发送这些信号,可是必须以文件说明它们是在什麽样的环境     底下发送出来的,以及指出任何与它们的发展相关的限制。”        想要修正这个问题,最简单也是最笨的方法就是用SIGUNUSED重新定义这些信号。   正确的方法应该是以条件式的编译#ifdef来处理这些问题才对:   #ifdef SIGSYS/* ... non-posix SIGSYS code here .... */#endif   11/15/97译 5/22/98修正     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会打开-fwritable-strings,使得   字串常数移至资料记忆体空间内(从程式码记忆体空间移出来,这个地方是不能任   意写入的)。这样做会让程式码的记忆体空间无形中增加的。     前置处理器的符号卯上函数原型宣告     最常见的问题是,如众所皆知,Linux中有许多常用的函数都定义成巨集存放在标   头档内,此时若有相似的函数原型宣告出现在程式码内,前置处理器会拒绝进行   语法分析的前置作业。常见的有atoi()与atol()。     sprintf()     在大部份的Unix系统上,sprintf(string, fmt, ...)传回的是string的指标,然   而,这方面Linux(遵循ANSI)传回的却是放入string内的字元数目.进行移植时   ,尤其是针对SunOS,需有警觉的心。     fcntl 与相关的函数;FD_*家族的定义到底摆在哪里?     就在<sys/time.h>里头。 为了真正的原型宣告,当你用了fcntl,可能你也想含   括标头档<unistd.h>进来。      一般而言,函数的manual page会在SYNOPSIS章节内列出需要的标头档。     select()的计时---程式执行时会处於忙碌-等待的状态     很久很久以前,,select()的计时参数只有唯读的性而已。即使到了最近   ,manual pages仍然有下面这段的警告:        select()应该是藉由修正时间的数值(如果有的话),再传回自原始计时开始     後所剩馀的时间。未来的版本可能会使这项功能实现。因此,就目前而言,若     以为呼叫select()之後,计时指标仍然不会被修正过,可是一种非常不明智的     想法喔!        未来就在我们的眼前了!至少,在这儿你绝对可以看到。函数select()传回的,   是扣除等待尚未到达的资料所耗费的时间後,其剩馀的时间数值。如果在计时结   束时,都没有资料传送进来,计时引数便会设为0;如果接著还有任何   的select(),以同样的计时structure来呼叫,那麽select()便会立刻结束。      若要修正这项问题,只要每次呼叫select()前,都把计时数值放到计时   structure内,就没有问题了。把下面的程式码,         struct timeval timeout;      timeout.tv_sec = 1; timeout.tv_usec = 0;      while (some_condition)            select(n,readfds,writefds,exceptfds,&timeout);   改成,         struct timeval timeout;      while (some_condition) {            timeout.tv_sec = 1; timeout.tv_usec = 0;            select(n,readfds,writefds,exceptfds,&timeout);      }   这个问题,在有些版本的Mosaic里是相当著名的,只要一次的等待,Mosaic就挂   在那里了。Mosaic的萤幕右上角,是不是有个圆圆的、会旋转的地球动画。那颗   球转得愈快,就表示资料从网路上传送过来的速率愈慢!     产生中断的系统呼叫    特徵:     当一支程式以Ctrl-Z中止、然後再重新执行时□或者是其它可以产生Ctrl-C中断   信号的情况,如子程序的终结等□系统就会抱怨说"interrupted system call"或   是"write: unknown error",或者诸如此类的讯息。     问题点:     POSIX的系统检查信号的次数,比起一些旧版的Unix是要多那麽一点。如果   是Linux,可能就会执行signal handlers了□        * 非同步地(计时器的滴答声)     * 系统呼叫的传回值     * 在下列系统呼叫的执行期间∶ 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.          就其它的作业系统而言,你需要的可能就是下面这些系统呼叫了: creat(),   close(), getmsg(), putmsg(), msgrcv(), msgsnd(), recv(), send(),   wait(), waitpid(), wait3(), tcdrain(), sigpause(), semop() to this   list.      在系统呼叫期间,若有一信号(那支程式本身应准备好handler因应了)产生   ,handler就会被呼叫。当handler将控制权转移回系统呼叫时,它会侦测出它已   经产生中断,而且传回值会立刻设定成-1,而errno设定成EINTR。程式并没有想   到会发生这种事,所以就挂了。      有两种修正的方法可以选择:      (1) 对每个你自行安装的signal handler,都须在sigaction的旗号加   上SA_RESTART。例如,把下列的程式,     signal (sig_nr, my_signal_handler);   改成,     signal (sig_nr, my_signal_handler);  { struct sigaction sa;    sigaction (sig_nr, (struct sigaction *)0, &sa);#ifdef SA_RESTART    sa.sa_flags |= SA_RESTART;#endif#ifdef SA_INTERRUPT    sa.sa_flags &= ~ SA_INTERRUPT;#endif    sigaction (sig_nr, &sa, (struct sigaction *)0);  }   要注意的是,当这部份的变更大量应用到系统呼叫之後,呼叫read()、write()   、ioctl()、 select()、 pause() 与 connect()时,你仍然得自行检查EINTR。   如下所示:      (2) 你自己得很明确地检查EINTR:      这里有两个针对read()与ioctl()的例子。      原始的程式片段,使用read():   int result;while (len > 0) {  result = read(fd,buffer,len);  if (result < 0) break;  buffer += result; len -= result;}   修改成,   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,其内定的行为是重新执行系统呼叫。若要让系   统呼叫中断,得使用 SV_INTERRUPT或SA_INTERRUPT旗号。     可以写入的字串     gcc对其users总怀抱著乐观的想法,相信当他们打算让某个字串当作常数来用   时---那它就真的只是字串常数而已。因此,这种字串常数会储存在程式码的记忆   体区段内。这块区域可以page到磁碟机的image上,避免耗掉swap的记忆体空间,   而且任何尝试写入的举动都会造成分页的错误(segmentation fault)。这可是一   种特色呢!      对老旧一点的程式而言,这可能会产生一个问题。例如,呼叫mktemp(),传递的   引数(arguments)是字串常数。 mktemp()会尝试著在*适当的位置*重新写入它的   引数。      修正的方法不外乎(a)以-fwritable-strings编译,迫使gcc将此常数置放在资料   记忆体空间内;或者(b)将侵犯地权的部份重新改写,配置一个不为常数的字串,   在呼叫前,先以strcpy()将资料拷贝进去。     为什麽呼叫execl()会失败?     那是因为你呼叫的方式不对。execl的第一个引数是你想要执行的程式名.第二个   与接续的引数会变成你所呼叫的程式的argv阵列。记住:传统上,argv[0]是只有   当程式没有带著引数执行时,才会有设定值。所以罗,你应该这样写:   execl("/bin/ls","ls",NULL);

⌨️ 快捷键说明

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