Vous pouvez trouver quels symboles votre version de gcc d�finit
automatiquement en le lan�ant avec l'option -v
.
Par exemple cela donne �a chez moi :
$ echo 'main(){printf("Bonjour !\n");}' | gcc -E -v -
Reading specs from /usr/lib/gcc-lib/i486-box-linux/2.7.2/specs
gcc version 2.7.2
/usr/lib/gcc-lib/i486-box-linux/2.7.2/cpp -lang-c -v -undef
-D__GNUC__=2 -D__GNUC_MINOR__=7 -D__ELF__ -Dunix -Di386 -Dlinux
-D__ELF__ -D__unix__ -D__i386__ -D__linux__ -D__unix -D__i386
-D__linux -Asystem(unix) -Asystem(posix) -Acpu(i386)
-Amachine(i386) -D__i486__ -
Si vous �crivez du code qui utilise des sp�cificit�s Linux, il
est souhaitable d'impl�menter le code non portable de la mani�re suivante
#ifdef __linux__
/* ... code linux ... */
#endif /* linux */
Utilisez __linux__
pour cela, et pas linux
.
Bien que cette macro soit d�finie, ce n'est pas une sp�cification POSIX.
La documentation des options de compilation se trouve dans les
pages info de gcc (sous Emacs, utilisez C-h i
puis
s�lectionnez l'option `gcc'). Votre distribution peut ne pas
avoir install� la documentation ou bien vous pouvez en avoir une
ancienne. Dans ce cas, la meilleure chose � faire est de r�cup�rer
les sources de gcc depuis
ftp://prep.ai.mit.edu/pub/gnu ou
l'un des ses nombreux miroirs dont
ftp://ftp.ibp.fr/pub/gnu.
La page de manuel gcc (gcc.1
) est en principe, compl�tement
d�pass�e. Cela vous met en garde si vous d�sirez la consulter.
gcc peut r�aliser un certain nombre d'optimisations sur le code g�n�r�
en ajoutant l'option -O
n � la ligne de commandes, o�
n est un chiffre. La valeur de n, et son effet exact,
d�pend de la version de gcc, mais s'�chelonne normalement entre
0 (aucune optimisation) et 2 (un certain nombre) ou 3 (toutes les
optimisations possibles).
En interne, gcc interpr�te les options telles que -f
et -m
.
Vous pouvez voir exactement ce qu'effectue le niveau sp�cifi� dans
l'option -O
en lan�ant gcc avec l'option -v
et l'option (non document�e)
-Q
. Par exemple, l'option -O2
, effectue les op�rations
suivantes sur ma machine :
enabled: -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks
-fexpensive-optimizations
-fthread-jumps -fpeephole -fforce-mem -ffunction-cse -finline
-fcaller-saves -fpcc-struct-return -frerun-cse-after-loop
-fcommon -fgnu-linker -m80387 -mhard-float -mno-soft-float
-mno-386 -m486 -mieee-fp -mfp-ret-in-387
Utiliser un niveau d'optimisation sup�rieur � celui que le compilateur
supporte (par exemple -O6
) aura le m�me effet qu'utiliser le plus
haut niveau g�r�. Distribuer du code o� la compilation est configur�e de
cette mani�re est une tr�s mauvaise id�e -- si d'autres optimisations
sont incorpor�es dans de versions futures, vous (ou d'autres utilisateurs)
pouvez vous apercevoir que cela ne compile plus, ou bien que le code
g�n�r� ne fait pas les actions d�sir�es.
Les utilisateurs de gcc 2.7.0 � 2.7.2 devraient noter qu'il y a un
bogue dans l'option -O2
. Plus pr�cis�ment, la
strength reduction ne fonctionne pas. Un patch a �t�
impl�ment� pour r�soudre ce probl�me, mais vous devez alors
recompiler gcc. Sinon, vous devrez toujours compiler avec l'option
-fno-strength-reduce
.
Il existe d'autres options -m
qui ne sont pas positionn�es
lors de l'utilisation de -O
mais qui sont n�anmoins utiles dans certains
cas. C'est le cas pour les options -m386
et -m486
,
qui indiquent � gcc de g�n�rer un code plus ou moins optimis�
pour l'un ou l'autre type de processeur. Le code continuera � fonctionner
sur les deux processeurs. Bien que le code pour 486 soit plus important, il
ne ralentit pas l'ex�cution du programme sur 386.
Il n'existe pas actuellement de -mpentium
ou -m586
. Linus
a sugg�r� l'utilisation des options
-m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2
,
pour exploiter les optimisations du 486 tout en perdant de la place
due aux probl�mes d'alignements (dont le Pentium n'a que faire).
Michael Meissner (de Cygnus) nous dit :
� Mon avis est que l'option-mno-strength-reduce
permet d'obtenir un code plus rapide sur un x86 (nota : je ne parle pas du bogue strength reduction, qui est un autre probl�me). Cela s'explique en raison du peu de registres dont disposent ces processeurs (et la m�thode de GCC qui consiste � grouper les registres dans l'ordre inverse au lieu d'utiliser d'autres registres n'arrange rien). La strength reduction consiste en fait � rajouter des registres pour remplacer les multiplications par des additions. Je suspecte �galement-fcaller-saves
de ne pas arranger la situation. �
Une autre id�e est que-fomit-frame-pointer
n'est pas obligatoirement une bonne id�e. D'un c�t�, cela peut signifier qu'un autre registre est disponible pour une allocation. D'un autre c�t�, vue la mani�re dont les processeurs x86 codent leur jeu d'instruction, cela peut signifier que la pile des adresses relatives prend plus de place que les adresses de fen�tres relatives, ce qui signifie en clair que moins de cache est disponible pour l'ex�cution du processus. Il faut pr�ciser que l'option-fomit-frame-pointer
, signifie que le compilateur doit constamment ajuster le pointeur de pile apr�s les appels, alors qu'avec une fen�tre, il peut laisser plusieurs appels dans la pile.
Le mot final sur le sujet provient de Linus :
Remarquez que si vous voulez des performances maximales, ne me croyez pas : testez ! Il existe tellement d'options de gcc, et il est possible que cela ne soit une r�elle optimisation que pour vous.
Internal compiler error: cc1 got fatal signal 11
Signal 11 correspond au signal SIGSEGV, ou bien segmentation violation. Normalement, cela signifie que le programme s'est m�lang� les pointeurs et a essay� d'�crire l� o� il n'en a pas le droit. Donc, cela pourrait �tre un bug de gcc.
Toutefois, gcc est un logiciel assez test� et assez remarquable de ce c�t�.
Il utilise un grand nombre de structures de donn�es complexes, et un
nombre impressionnant de pointeurs. En r�sum�, c'est le plus pointilleux
des testeurs de m�moire existants. Si vous n'arrivez pas � reproduire le
bogue
--- si cela ne s'arr�te pas au m�me endroit lorsque vous retentez la
compilation --- c'est plut�t un probl�me avec votre machine (processeur,
m�moire, carte m�re ou bien cache). N'annoncez pas la d�couverte
d'un nouveau bogue si votre ordinateur traverse tous les tests du BIOS,
ou s'il fonctionne correctement sous Windows ou autre : ces tests
ne valent rien. Il en va de m�me si le noyau s'arr�te lors du
`make zImage
' ! `make zImage
'
doit compiler plus de 200 fichiers, et il en faut bien moins pour arriver
� faire �chouer une compilation.
Si vous arrivez � reproduire le bogue et (mieux encore) � �crire un petit programme qui permet de mettre en �vidence cette erreur, alors vous pouvez envoyer le code soit � la FSF, soit dans la liste linux-gcc. Consultez la documentation de gcc pour plus de d�tails concernant les informations n�cessaires.
Cette phrase a �t� dite un jour : si quelque chose n'a pas �t� port� vers Linux alors ce n'est pas important de l'avoir :-).
Plus s�rieusement, en g�n�ral seules quelques modifications mineures sont n�cessaires car Linux r�pond � 100% aux sp�cifications POSIX. Il est g�n�ralement sympathique d'envoyer � l'auteur du programme les modifications effectu�es pour que le programme fonctionne sur Linux, pour que lors d'une future version, un `make' suffise pour g�n�rer l'ex�cutable.
bsd_ioctl
, daemon
et<sgtty.h>
) Vous pouvez compiler votre programme avec l'option
-I/usr/include/bsd
et faire l'�dition de liens avec -lbsd
(en ajoutant -I/usr/include/bsd
� la ligne CFLAGS
et -lbsd
� la ligne LDFLAGS
dans votre fichier
Makefile
). Il est �galement n�cessaire de ne pas
ajouter -D__USE_BSD_SIGNAL
si vous voulez
que les signaux BSD fonctionnent car vous les avez inclus automatiquement
avec la ligne
-I/usr/include/bsd
et en incluant le fichier d'en-t�te
<signal.h>
.
SIGBUS
, SIGEMT
, SIGIOT
, SIGTRAP
, SIGSYS
, etc.) Linux respecte les sp�cifications POSIX. Ces signaux n'en font pas partie (cf. ISO/IEC 9945-1:1990 - IEEE Std 1003.1-1990, paragraphe B.3.3.1.1) :
� Les signaux SIGBUS, SIGEMT, SIGIOT, SIGTRAP, et SIGSYS ont �t� omis de la norme POSIX.1 car leur comportement est d�pendant de l'impl�mentation et donc ne peut �tre r�pertori� d'une mani�re satisfaisante. Certaines impl�mentations peuvent fournir ces signaux mais doivent documenter leur effet �
La mani�re la plus �l�gante de r�gler ce probl�me est de
red�finir ces signaux � SIGUNUSED
. La mani�re normale de
proc�der est d'entourer le code avec les #ifdef
appropri�s :
#ifdef SIGSYS
/* ... code utilisant les signaux non posix .... */
#endif
GCC est un compilateur ANSI, or il existe beaucoup de code qui ne soit pas ANSI.
Il n'y a pas grand chose � faire, sauf rajouter l'option
-traditional
lors de la compilation. Il effectue certaines
v�rifications suppl�mentaires. Consultez les pages info gcc.
Notez que l'option -traditional
a pour unique effet de changer la forme
du langage accept� par gcc. Par exemple, elle active l'option
-fwritable-strings
, qui d�place toutes les cha�nes de caract�res
vers l'espace de donn�es (depuis l'espace de texte, o� elle ne
peuvent pas �tre modifi�es). Ceci augmente la taille de la m�moire
occup�e par le programme.
Un des probl�mes fr�quents se produit lorsque certaines fonctions
standards sont d�finies comme macros dans les fichiers d'en-t�te
de Linux et le pr�processeur refusera de traiter
des prototypes identiques. Par exemple, cela peut arriver
avec atoi()
et atol()
.
sprintf()
Parfois, soyez prudent lorsque vous effectuez un portage � partir
des sources de programmes fonctionnant sous SunOs, surtout avec
la fonction sprintf(string, fmt, ...)
car elle renvoie
un pointeur sur la cha�ne de caract�res alors que Linux (suivant la norme ANSI)
retourne le nombre de caract�res recopi�s dans la cha�ne de caract�res.
fcntl
et ses copains. O� se trouve la d�finition de FD_*
et compagnie ? Dans <sys/time.h>
. Si vous utilisez
fcntl
vous voudrez probablement inclure
<unistd.h>
�galement, pour avoir le prototype de la fonction.
D'une mani�re g�n�rale, la page de manuel pour une fonction donne la liste des fichiers d'en-t�te � inclure.
select()
. Les programmescommencent dans un �tat d'attente active A une certaine �poque, le param�tre timeout de la fonction
select()
�tait utilis� en lecture seule. C'est pourquoi la page
de manuel comporte une mise en garde :
select() devrait retourner normalement le temps �coul� depuis le
timeout initial, s'il s'est d�clench�, en modifiant la valeur point�e par
le param�tre time
. Cela sera peut-�tre impl�ment� dans les
versions ult�rieures du syst�me. Donc, il n'est pas vraiment prudent de
supposer que les donn�es point�es ne seront pas modifi�es lors de l'appel
� select().
Mais tout arrive avec le temps ! Lors d'un retour de
select()
, l'argument timeout
recevra le
temps �coul� depuis la derni�re r�ception de donn�es. Si aucune
donn�e n'est arriv�e, la valeur sera nulle, et les futurs
appels � cette fonction utilisant le m�me timeout
auront pour r�sultat un retour imm�diat.
Pour r�soudre le probl�me, il suffit de mettre la valeur timeout
dans la structure � chaque appel de select()
.
Le code initial �tait
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
while (some_condition)
select(n,readfds,writefds,exceptfds,&timeout);
et doit devenir :
struct timeval timeout;
while (some_condition)
{
timeout.tv_sec = 1;
timeout.tv_usec = 0;
select(n,readfds,writefds,exceptfds,&timeout);
}
Certaines versions de Mosaic �taient connues � une certaine �poque pour avoir ce probl�me.
La vitesse de rotation du globe terrestre �tait inversement proportionnelle � la vitesse de transfert des donn�es !
Lorsqu'un processus est arr�t� avec un Ctrl-Z et relanc� - ou bien lorsqu'un autre signal est d�clench� dans une situation diff�rente : par exemple avec un Ctrl-C, la terminaison d'un processus, etc, on dit qu'il y a � interruption d'un appel syst�me � , ou bien � write : erreur inconnue � ou des trucs de ce genre.
Les syst�mes POSIX v�rifient les signaux plus souvent que d'autres Unix plus anciens. Linux peux lancer les gestionnaires de signaux :
select()
, pause()
, connect()
,
accept()
, read()
sur des terminaux, des sockets, des pipes
ou des fichiers situ�s dans /proc
, write()
sur des
terminaux, des sockets, des pipes ou des imprimantes, open()
sur des FIFOs, des lignes PTYs ou s�ries,
ioctl()
sur des terminaux, fcntl()
avec la commande
F_SETLKW
, wait4()
, syslog()
, et toute op�ration
d'ordre TCP ou NFS. Sur d'autres syst�mes d'exploitation, il est possible que vous
ayez � inclure dans cette cat�gorie les appels syst�mes suivants :
creat()
, close()
, getmsg()
, putmsg()
,
msgrcv()
, msgsnd()
, recv()
, send()
,
wait()
, waitpid()
, wait3()
, tcdrain()
,
sigpause()
, semop()
.
Si un signal (que le programme d�sire traiter) est lanc� pendant
l'ex�cution d'un appel syst�me, le gestionnaire est lanc�. Lorsque
le gestionnaire du signal se termine, l'appel syst�me d�tecte qu'il a �t�
interrompu et se termine avec la valeur -1 et errno = EINTR
.
Le programme n'est pas forc�ment au courant de ce qui s'est pass� et
donc s'arr�te.
Vous pouvez choisir deux solutions pour r�soudre ce probl�me.
(1)Dans tout gestionnaire de signaux que vous mettez en place, ajoutez
l'option SA_RESTART
au niveau de sigaction. Par exemple,
modifiez
signal (signal_id, mon_gestionnaire_de_signaux);
en
signal (signal_id, mon_gestionnaire_de_signaux);
{
struct sigaction sa;
sigaction (signal_id, (struct sigaction *)0, &sa);
#ifdef SA_RESTART
sa.sa_flags |= SA_RESTART;
#endif
#ifdef SA_INTERRUPT
sa.sa_flags &= ~ SA_INTERRUPT;
#endif
sigaction (signal_id, &sa, (struct sigaction *)0);
}
Notez que lors de certains appels syst�mes vous
devrez souvent regarder si errno
n'a pas �t� positionn�e �
EINTR
par vous m�me comme avec read()
, write()
,
ioctl()
, select()
, pause()
et connect()
.
(2) A la recherche de EINTR
:
Voici deux exemples avec read()
et ioctl()
,
Voici le code original utilisant read()
int result;
while (len> 0)
{
result = read(fd,buffer,len);
if (result < 0)
break;
buffer += result;
len -= result;
}
et le nouveau code int result;
while (len> 0)
{
result = read(fd,buffer,len);
if (result < 0)
{
if (errno != EINTR)
break;
}
else
{
buffer += result;
len -= result;
}
}
Voici un code utilisant ioctl()
int result;
result = ioctl(fd,cmd,addr);
et cela devient
int result;
do
{
result = ioctl(fd,cmd,addr);
}
while ((result == -1) && (errno == EINTR));
Il faut remarquer que dans certaines versions d'Unix de type BSD
on a l'habitude de relancer l'appel syst�me. Pour r�cup�rer les interruptions
d'appels syst�mes, vous devez utiliser les options
SV_INTERRUPT
ou SA_INTERRUPT
.
GCC a une vue optimiste en ce qui concerne ses utilisateurs, en croyant qu'ils respectent le fait qu'une cha�ne dite constante l'est r�ellement. Donc, il les range dans la zone texte(code) du programme, o� elles peuvent �tre charg�es puis d�charg�es � partir de l'image binaire de l'ex�cutable situ�e sur disque (ce qui �vite d'occuper de l'espace disque). Donc, toute tentative d'�criture dans cette cha�ne provoque un � segmentation fault �.
Cela peut poser certains probl�mes avec d'anciens codes, par exemple
ceux qui utilisent la fonction mktemp()
avec une cha�ne constante
comme argument. mktemp()
essaye d'�crire dans la cha�ne pass�e
en argument.
Pour r�soudre ce probl�me,
-fwritable-strings
pour indiquer
� gcc de mettre les cha�nes constantes dans l'espace de donn�esexecl()
�choue ? Tout simplement parce que vous l'utilisez mal. Le premier argument
d'execl
est le programme que vous d�sirez ex�cuter. Le second et ainsi
de suite sont en fait le �l�ments du tableau argv
que vous appelez.
Souvenez-vous que argv[0]
est traditionnellement fix� m�me si
un programme est lanc� sans argument. Vous devriez donc �crire :
execl("/bin/ls","ls",NULL);
et pas
execl("/bin/ls", NULL);
Lancer le programme sans argument est consid�r� comme �tant une demande d'affichage des biblioth�ques dynamiques associ�es au programme, si vous utilisez le format a.out. ELF fonctionne d'une mani�re diff�rente.
(Si vous d�sirez ces informations, il existe des outils plus simples;
consultez la section sur le chargement dynamique, ou la page de manuel
de ldd
).
Hosting by: Hurra Communications GmbH
Generated: 2007-01-26 18:01:30