IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

[Linux -- gcc] besoin d'éclaircissements concernant le rôle du compilateur


Sujet :

C

  1. #1
    Membre averti

    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2012
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2012
    Messages : 313
    Points : 354
    Points
    354
    Par défaut [Linux -- gcc] besoin d'éclaircissements concernant le rôle du compilateur
    Bonjour à toutes et tous, salutations !!

    Je suis toujours en train de mettre à jour, tenter d'améliorer une sorte de référentiel pour mes élèves au laboratoire.

    Je tente de leur apprendre à programmer en langage ANSI C.

    Voici mon petit soucis: j'essaye de leur expliquer le rôle du compilateur lors de la création d'une variable.

    Je n'ai pas envie de rentrer dans les détails liés à l'assembleur, et encore moins expliquer en détail comment le compilateur va créer un fichier exécutable à partir d'un code source
    et "préparer" le "plan d'éxécution" de celui-ci. Par contre, dans la partie de mon référentiel où j'introduis la notion de variables, j'ai besoin de plus d'informations.

    Le compilateur va compiler le code source sur une machine, imaginons que celle-ci soit équipée d'une mémoire de 1Go, et que, pour on ne sait quelles raisons, les variables et données
    manipulées par le programme que l'on cherche à compiler (le Data Segment) dépasse la mémoire équipée de l'ordinateur... que va-t-il se passer à la compilation ?

    Ceci introduit une sous-question: est-ce que le compilateur a pour rôle de vérifier si la mémoire installée de l'ordinateur qui compile le code source est suffisante pour gérer toutes les variables déclarées et utilisées dans le code source ?

    Je ne suis pas certain (il faut le dire: j'ai été un peu flemmard au niveau de mes recherches sur le fonctionnement d'un compilateur comme GNU C Compiler gcc) de l'assertion que j'ai mise dans mon référentiel.
    Je dis que si nous cherchons à déclarer une variable, à la compilation, le compilateur va vérifier si il reste de la place en mémoire, si il reste de la place pour réserver l'espace mémoire correspondant au type de variable déclaré,
    dans ce cas il "attribue" une adresse à cette variable -- on considère que l'espace réservé pour cette variable dépend de son type mais qu'elle commence à l'adresse fournie par le compilateur.
    Dans le cas contraire le compilateur devrait spécifier qu'il n'y a plus de place disponible en mémoire.

    Quels seraient vos avis ? Est-ce que je vais dans la bonne direction ?

    Merci d'avance pour vos éclaircissements ^^

  2. #2
    Membre émérite
    Homme Profil pro
    sans emploi
    Inscrit en
    Janvier 2014
    Messages
    539
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : sans emploi
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2014
    Messages : 539
    Points : 2 601
    Points
    2 601
    Par défaut
    Bonjour,

    Citation Envoyé par hurukan Voir le message
    [...]
    Le compilateur va compiler le code source sur une machine, imaginons que celle-ci soit équipée d'une mémoire de 1Go, et que, pour on ne sait quelles raisons, les variables et données
    manipulées par le programme que l'on cherche à compiler (le Data Segment) dépasse la mémoire équipée de l'ordinateur... que va-t-il se passer à la compilation ?

    Ceci introduit une sous-question: est-ce que le compilateur a pour rôle de vérifier si la mémoire installée de l'ordinateur qui compile le code source est suffisante pour gérer toutes les variables déclarées et utilisées dans le code source ?
    [...]
    Non, car un compilateur ne produit pas un exécutable spécifiquement pour la machine sur laquelle il tourne mais pour une architecture bien prédéfinie. Par exemple par défaut un gcc linux64 de «base» va produire du code pour une architexture x86/64 générique (souvent sans extensions sse par exemple) au format elf. Il existe évidemment des options pour tuner l'architecture cible. Cela est encore plus évident avec les cross compilateurs.

  3. #3
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 453
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 453
    Points : 43 106
    Points
    43 106
    Par défaut
    Une variable prend peu de place en RAM 1 int=16 ou 32 bits. De là à saturer la RAM...

    Pour les plus grosses allocations, c'est malloc qui est utilisé, si pas assez de RAM, le retour sera ENOMEM, il est impératif de tester le retour de malloc.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  4. #4
    Membre émérite
    Homme Profil pro
    sans emploi
    Inscrit en
    Janvier 2014
    Messages
    539
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : sans emploi
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2014
    Messages : 539
    Points : 2 601
    Points
    2 601
    Par défaut
    Citation Envoyé par chrtophe Voir le message
    Une variable prend peu de place en RAM 1 int=16 ou 32 bits. De là à saturer la RAM...

    Pour les plus grosses allocations, c'est malloc qui est utilisé, si pas assez de RAM, le retour sera ENOMEM, il est impératif de tester le retour de malloc.
    Je pense que la discussion se plaçait plus sur les grosses variables statiques, genre un énorme tableau static en BSS comme par exemple static int big_table[1024*1024*1024];

  5. #5
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 453
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 453
    Points : 43 106
    Points
    43 106
    Par défaut
    ça compilera je pense, par contre si manque de RAM la création du process échouera lors de la tentative de lancement de l’exécutable.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  6. #6
    Membre émérite
    Homme Profil pro
    sans emploi
    Inscrit en
    Janvier 2014
    Messages
    539
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : sans emploi
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2014
    Messages : 539
    Points : 2 601
    Points
    2 601
    Par défaut
    C'est clair, le compilateur est chargé de la création d'un exécutable pour une plateforme cible c'est tout. Ensuite c'est le loader qui le charge et gère les erreurs à ce moment là (pas assez de mémoire) où le processeur (?*à vérifier) dans le cas d'une instruction illégale.

  7. #7
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Je pense que cela dépend aussi des cibles.

    Je vais parler de ce que je connais sur les micro-contrôleurs Cortex-M.
    - Pour ce qui est des instructions illégales (ex: un opcode valable sur Cortex-M4 qu'on tente d'exécuter sur Cortex-M3 qui a un jeu assembleur plus restreint), c'est bien le processeur qui génère une erreur en tentant de l'exécuter.
    - Pour ce qui est des allocations dynamiques, c'est évidemment l'allocation qui vérifiera l'espace restant dans le tas et échouera si le tas est plein. Le compilateur n'y est pour rien dans tout ça.
    - Pour ce qui est des allocations automatiques, personne ne vérifie cela a priori, ta pile système déborde. Si tu as un OS, il peut faire des vérifications sur les piles des threads.
    - Pour ce qui est des allocations statiques, c'est le rôle du linker* de vérifier cela. Tes fichiers de link décrivent ta quantité de RAM et de flash, ainsi que les adresses de ces différentes régions. Il est donc capable de vérifier cela et de générer une erreur si tu fais quelque chose comme static int big_table[1024*1024*1024];.

    Le dernier contrôle n'est possible que lorsqu'on connait très bien la cible. Sur PC, la quantité de mémoire peut varier d'une machine à l'autre. C'est donc l'OS qui lors du chargera du binaire exécutable pourra faire des vérifications.

    * : il s'agit bien du linker et pas du compilateur a proprement parlé. Le compilateur vérifie le code et traduit, fichier par fichier, rien de plus.

  8. #8
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 453
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 453
    Points : 43 106
    Points
    43 106
    Par défaut
    Pour ce qui est des instructions illégales (ex: un opcode valable sur Cortex-M4 qu'on tente d'exécuter sur Cortex-M3 qui a un jeu assembleur plus restreint), c'est bien le processeur qui génère une erreur en tentant de l'exécuter.
    Il n'y a cependant aucune raison pour qu'un compilateur génère du code à instructions illégales.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  9. #9
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Bien sûr ! Il traduit pour une cible donnée, dont l'architecture est potentiellement différente de l'architecture de l'hôte de la compilation (cross-compilation, comme évoquée par picodev), et normalement il traduit bien. Mais tu peux ensuite exécuter le programme sur une mauvaise cible

  10. #10
    Membre émérite
    Homme Profil pro
    sans emploi
    Inscrit en
    Janvier 2014
    Messages
    539
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : sans emploi
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2014
    Messages : 539
    Points : 2 601
    Points
    2 601
    Par défaut
    Mis à part l'abus de langage malheureusement trop courant consistant à parler de compilation pour toute la chaîne pré processeur → compilateur → édition des liens (sans compter les multiples étapes intermédiaires), on peut considérer que pour les architectures classiques (linux,win.mac) gcc ne propose que des cross compilateurs. La cible étant principalement l'os considéré sur une base de processeur pentium pour taper large. Dès que l'on s'amuse à fine tuner l'architecture avec les options du genre -march, -msse*, -mavx* et compagnie on compile pour une «autre» architecture.

    Le «compilateur» (entendre chaîne de «compilation») ne fait que créer un fichier à un certain format (elf32, elf64, PE32, fatbinary, …) contenant un ou plusieurs code machine dépendant des options de compilation ciblant un processeur, compréhensible par le loader de l'OS ciblé.

  11. #11
    Membre expérimenté
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    543
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 543
    Points : 1 745
    Points
    1 745
    Par défaut
    Bonjour

    Citation Envoyé par picodev
    Le «compilateur» (entendre chaîne de «compilation») ne fait que créer un fichier à un certain format (elf32, elf64, PE32, fatbinary, …) contenant un ou plusieurs code machine dépendant des options de compilation ciblant un processeur, compréhensible par le loader de l'OS ciblé.
    Sur ce point je suis tout à fait d’accord avec vous. Pour apporter quelques précisions et tenter de répondre à la question posée par le primo-postant. Le compilateur a pour tâche de traduire un programme écrit dans un langage dans un autre langage et ce en quatre étapes.

    La première étape du compilateur fait appel à un analyser lexical pour traiter les séquences de caractères en groupe de mots, c'est-à-dire les mots avec leur type et leur valeurs.
    La deuxième étape est le regroupement et l’identification du rôle de chacun des mots du groupe de mots réalisés par l’analyse lexicale. C’est la tâche de l’analyse syntaxique.*
    La troisième étape est la génération du code : plus exactement, la traduction du résultat de l’analyse syntaxique dans le langage cible.

    La dernière étape est l’optimisation du code généré. Ici, le compilateur (plus exactement l’optimiser si je peux ainsi dire) va remplacer certains voire la totalité du code généré précédemment par un meilleur code (le cas du langage C est qu’avant la phase d'analyse lexicale, il y a un traitement préalable du pré-processeur. Plus techniquement, je dirais qu’il s’apparente à un mimi-compilateur (si je peux dire ainsi) qui possède les mêmes phases de traitement (lexicale et syntaxique et qui génère du code sauf qu’il traite le cas d'include & #define »)).

    Au final, le compilateur a seulement pour rôle la traduction du langage source en langage cible (machine) de façon indépendante. Je veux dire par là que le compilateur compile indépendamment chacun des fichiers source et pour chacun de ces fichiers source, il le traduit en langage machine le tout avec ce que l’on appelle la table des symboles qui est le fichier objet possédant l’extension « .o»
    Plus exactement, le compilateur, après avoir traduit le langage source en langage machine, va spécifier à quel endroit précis de la mémoire les instructions vont être placées et spécifie également que les instructions sont placées à partir de l’adresse (exemple) « 0x01 » ajouté au langage machine et génère la table des symboles qui contient tous les endroits où une adresse est utilisée par le compilateur, mais également ceux que le compilateur ne connaît pas. Exemple avec l'adresse de la fonction « scanf, fprintf, etc..» qui n'est pas définie dans le code et ce, pour la simple raison que le programme, après avoir été compilé, fait appel à ces fonctions qu’il n’a pas définies lui-même, mais qui le sont dans des bibliothèques. Donc, l’éditeur de lien va se charger de récupérer l’ensemble des codes qui correspond aux fonctions citées précédemment et l’ajouter.

    Citation Envoyé par Bktero Voir le message
    - Pour ce qui est des allocations statiques, c'est le rôle du linker* de vérifier cela. Tes fichiers de link décrivent ta quantité de RAM et de flash, ainsi que les adresses de ces différentes régions. Il est donc capable de vérifier cela et de générer une erreur si tu fais quelque chose comme static int big_table[1024*1024*1024];.

    Le dernier contrôle n'est possible que lorsqu'on connait très bien la cible. Sur PC, la quantité de mémoire peut varier d'une machine à l'autre. C'est donc l'OS qui lors du chargera du binaire exécutable pourra faire des vérifications.
    * : il s'agit bien du linker et pas du compilateur a proprement parlé. Le compilateur vérifie le code et traduit, fichier par fichier, rien de plus.
    Effectivement, l’éditeur de liens regroupe l’ensemble des fichiers objet dans un seul et même fichier en leur assignant des adresses différentes à l’aide de la table de symboles, tout en mettant à jour les adresses modifiées.

    Cependant, J’ai des doutes quant à la de générer d'erreur du cas de « static int big_table[1024*1024*1024];. » car le mot-clé, « static » affecté à la variable ou au tableau, permet d’éviter que celle-ci n'apparaisse dans la table des symboles, permettant ainsi son utilisation dans d'autres fichiers (contrairement à « extern » qui spécifie que l’on doit définir la chose) et par la même occasion, permet la détection de la variable dans d'autres fichiers. Par contre, il ne permet pas la détection d’une erreur ou la génération d'erreur (sauf si c’est bien moi qui commais une erreur sur ce point dans mes dire et corrigé moi si c'est le cas).

    On peut éventuellement, lors de la phase de compilation avec les options d’avertissement, avoir un avertissement. Cet avertissement peut être un « overflow in expression , integer-overflow du type int" ». Dans le cas où on utilise une variable typé pour parcourir de très très grand tableaux genre static int big_tab_a[1024*1024*1024*9*7*1024*999]; . Toute fois la compilation finira tout de même sa phase de compilation avec succès plus des warning et l’erreur sera peut-être détectée si on 'y prête attention ou pendant l’exécution du programme voire pas du tout. En revanche, si on se base sur votre exemple le compilateur avec les warning adéquat ne détecte ou ne génère aucune erreur et de plus le binaire génère s'exécute sans problème mais en réalité si l'on effectue un examen approfondi en utilisant les outils adéquats comme «valgrind», on remarque tout de suite qu’il y’a une erreur (un problème que @picodev à soulevez) «mmap-FIXED(0x100002000, 4294967296) failed in UME (load_segment2) (Invalid argument) ou un Bus error: 10». Et en vue de ces résultats, on peut conclure que exécutables utilise de de très grands segments texte , de données ou BSS dû a l’utilisation abusive de allocation static de mémoire.

    Bref, honnêtement peut-être que je me trompe mais, je ne pense pas que l’éditeur de liens puisse détecter ces erreurs et en plus, la conception de compilateur est laissée à la discrétion des concepteurs qui s’efforcent de respecté la norme. (mais bon c'est un autre débat

    à bientôt
    Celui qui peut, agit. Celui qui ne peut pas, enseigne.
    Il y a deux sortes de savants: les spécialistes, qui connaissent tout sur rien,
    et les philosophes, qui ne connaissent rien sur tout.
    George Bernard Shaw

  12. #12
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 690
    Points : 30 985
    Points
    30 985
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par chrtophe Voir le message
    ...c'est malloc qui est utilisé, si pas assez de RAM, le retour sera ENOMEM,
    Bonjour

    Pour être plus précis, si pas assez de RAM le retour de malloc sera NULL et c'est NULL qu'il faut tester à l'exclusion de tout autre chose.
    Dans le même temps, la variable globale "errno" sera positionnée à ENOMEM. Celui qui veut être plus précis pourra alors afficher cette valeur de errno ou mieux, strerror(errno) lequel renvoie le message textuel correspondant à cette valeur.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  13. #13
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par sambia39 Voir le message
    Cependant, J’ai des doutes quant à la de générer d'erreur du cas de « static int big_table[1024*1024*1024];[...]

    Bref, honnêtement peut-être que je me trompe mais, je ne pense pas que l’éditeur de liens puisse détecter ces erreurs et en plus, la conception de compilateur est laissée à la discrétion des concepteurs qui s’efforcent de respecté la norme. (mais bon c'est un autre débat)
    Tu penses que j'ai dit que le linker ppuvait générer de telles erreurs au hasard ? Je te parle avec pleeeeein d'expériences avec 4 linkers différents pour Cortex-M Regarde par exemple cette FAQ d'Arm : http://www.keil.com/support/docs/3691.htm

    Le fait que la variable soit statique l'empêche d'être visible des autres unités de compilation mais il faut bien la placer en mémoire !

  14. #14
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 860
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 860
    Points : 219 062
    Points
    219 062
    Billets dans le blog
    120
    Par défaut
    Bonjour,

    Citation Envoyé par chrtophe Voir le message
    Il n'y a cependant aucune raison pour qu'un compilateur génère du code à instructions illégales.
    Sauf que l'on peut injecter du code ASM directement dans le code C, donc ce cas peut arriver (la faute à l'utilisateur). Toutefois, le code doit être correct. Aussi, le cas qui peut se produire (sur ARM) c'est de tenter d'accéder à des registres de debug/protégés, alors que l'on a pas l'accès au mode debug ... ça fait le même crash : illegal instruction.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  15. #15
    Membre averti

    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2012
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2012
    Messages : 313
    Points : 354
    Points
    354
    Par défaut
    Merci beaucoup... je me rend effectivement compte que je n'ai pas été très précis en parlant de "compilateur"... j'ai effectivement dans le référentiel indiqué quelles étaient les phases de compilation... et j'ai
    volontairement "simplifié" dans mes semblants d'explications tout ce processus par "compilateur"... je me demande finalement si j'ai bien fait...

    Je relis encore une fois toutes vos interventions plus intéressantes les unes que les autres, puis je reviens ^^

    Me revoilou...

    Donc, si je tente de résumer ce que j'ai compris:
    ...il est clair que dans ma volonté de ne pas brusquer les élèves débutants en langages compilés comme l'ANSI C, j'ai été un peu trop "simpliste".
    Il semble clair que ce n'est pas à la compilation que nous saurons si oui ou non le programme qui va être rendu exécutable dans la phase suivante (linker) va pouvoir être chargée en mémoire vive.
    Au niveau du "linker" (éditeur de liens) non plus, même si celui-ci est censé savoir si nous voulons un loader elf/elf64/PE/..., c'est quelque part "obligatoire" si nous utilisons un "cross-compiler".
    Par contre, lorsque le loader (sous Linux: elf ou elf64) entrera en action, ce serait à ce moment là que nous pourrions avoir des soucis, ça me paraît d'une logique impliquable vu que c'est à ce moment là que
    nous sommes au plus près du système d'exploitation.
    En ce qui concerne l'allocation dynamique (utilisation de malloc() et fonctions dérivées realloc(), etc...) c'est clair que nous devons être prudents, par contre concernant les variables censées
    être placées dans le "code segment" et non dans le "heap", j'ai peur de comprendre que rien n'est vraiment mis en place, même si quelque part cela m'arrangerait bien (je fais abstraction volontairement
    des données qui se retrouveraient dans la pile).

    Ce serait le système d'exploitation qui prendrait le relais avec, je supposes, tout l'attirail de gestion de la mémoire virtuelle (pagination, page faults, swapping, etc...) avec le risque d'un "trashing" du système.

    Donc en conclusion, du fait que je n'ai pas été précis, la question ne se pose pas "au moment de la compilation" mais bien au moment "du chargement du code exécutable par le système d'exploitation qui
    vérifie à ce moment si le programme exécutable peut tenir dans la mémoire vive"...

  16. #16
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 453
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 453
    Points : 43 106
    Points
    43 106
    Par défaut
    Sauf que l'on peut injecter du code ASM directement dans le code C, donc ce cas peut arriver (la faute à l'utilisateur). Toutefois, le code doit être correct. Aussi, le cas qui peut se produire (sur ARM) c'est de tenter d'accéder à des registres de debug/protégés, alors que l'on a pas l'accès au mode debug ... ça fait le même crash : illegal instruction.
    Je sors un peu du sujet, mais Pour moi, une instruction illégale, c’est un opcode/instruction invalide, que ne laissera normalement pas passer le compilateur. Dans le cas du x86 en mode protégé, ça lève une exception, sur ARM je ne sais pas. Le cas ou ça peu crasher, c'est si on adresse une adresse mémoire supérieure à 1 Mo dans un système de 1 Mo sans qu'il n'y ai de gestion, ce qui peut être le cas dans de l'embarqué sans OS. Et même sous le vieux MS-DOS, je pense que ça crashe.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  17. #17
    Membre émérite
    Homme Profil pro
    sans emploi
    Inscrit en
    Janvier 2014
    Messages
    539
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : sans emploi
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2014
    Messages : 539
    Points : 2 601
    Points
    2 601
    Par défaut
    Citation Envoyé par hurukan Voir le message
    [...]
    Donc, si je tente de résumer ce que j'ai compris:
    ...il est clair que dans ma volonté de ne pas brusquer les élèves débutants en langages compilés comme l'ANSI C, j'ai été un peu trop "simpliste".
    Il semble clair que ce n'est pas à la compilation que nous saurons si oui ou non le programme qui va être rendu exécutable dans la phase suivante (linker) va pouvoir être chargée en mémoire vive.
    Au niveau du "linker" (éditeur de liens) non plus, même si celui-ci est censé savoir si nous voulons un loader elf/elf64/PE/..., c'est quelque part "obligatoire" si nous utilisons un "cross-compiler".
    Il y a un exemple tout simple qui montre qu'un compilo vérifie uniquement ce qu'il peut vérifier :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include <stdio.h>
     
    #define BIGSIZE 8ULL*1024*1024*1024
    static unsigned long long big_table[BIGSIZE]={0};
     
    int main(void)
    {
     
      printf("%llu\n", big_table[20161115]);
     
      return 0;
    }
    Je crée un super grand tableau de 64Go. On commence en demandant à gcc de créer un exécutable pour linux64 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $ gcc -Wall -Wextra -o mem mem.c
    $
    Rien à signaler → tout c'est bien passé. Remarque que tu peux demander au compilo d'émettre des warnings comme ici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $ gcc -Wall -Wextra -Wlarger-than=10000000 -o mem mem.c
    mem.c:4:27: warning: size of ‘big_table’ is larger than 10000000 bytes [-Wlarger-than=]
     static unsigned long long big_table[BIGSIZE]={0};
                               ^~~~~~~~~
    L'exécutable a bien été crée. Si on le regarde de plus près :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $ size -x mem
       text	   data	    bss	    dec	    hex	filename
      0x4aa	  0x228	0x1000000020	68719478514	10000006f2	mem
    On voit bien que les segment bss vaut dans les 64Go.
    À l'exécution en revanche :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $ ./mem
    Segmentation fault
    Bah oui, je n'ai pas suffisamment de mémoire sur ma machine, mais sur une autre qui en possèderait suffisamment le programme fonctionnerait.

    Essayons de compiler pour un linux32 maintenant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $ gcc -m32 -Wall -Wextra -o mem mem.c
    mem.c:4:27: error: size of array ‘big_table’ is too large
     static unsigned long long big_table[BIGSIZE]={0};
                               ^~~~~~~~~
    mem.c:4:27: warning: ‘big_table’ defined but not used [-Wunused-variable]
    Ici il y carrément un message d'erreur car en 32 bits on ne peut adresser autant de mémoire … ce qu'il arrive à contrôler ou ce que tu lui demande de contrôler, le compilo le contrôle.


    Prenons un autre exemple plus matheux :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    #include <stdio.h>
     
    int main()
    {
      float a[100]={0.f};
      float b[100]={0.f};
      float c[100]={0.f};
     
      for(int i=0; i<100; ++i) {
        a[i]=i;
        b[i]=2*i;
      }
     
      for(int i=1; i<100; ++i)
        c[i]=a[i-1]+a[i]*b[i];
     
      float d=0;
      for(int i=0; i<100; ++i)
        d+=c[i];
     
      printf("%f\n",d);
      return 0;
    }
    Une compilation «simple», tout passe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $ gcc -Wall -Wextra -o avx avx.c
    $ ./avx 
    661551.000000
    Une compilation «particulière» passe mais coince à l'exécution :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $ gcc -Wall -Wextra -mavx2 -o avx avx.c
    $ ./avx 
    Illegal instruction
    Tout ça est fait avec un simple gcc de base. Tu peux tuner l'exécutable produit pour un OS et pour un proc.

  18. #18
    Membre expérimenté
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    543
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 543
    Points : 1 745
    Points
    1 745
    Par défaut
    Bonsoir,

    Citation Envoyé par Bktero Voir le message
    Tu penses que j'ai dit que le linker ppuvait générer de telles erreurs au hasard ? Je te parle avec pleeeeein d'expériences avec 4 linkers différents pour Cortex-M Regarde par exemple cette FAQ d'Arm : http://www.keil.com/support/docs/3691.htm
    Le fait que la variable soit statique l'empêche d'être visible des autres unités de compilation mais il faut bien la placer en mémoire !
    Non, ce que je dis c’est que l’éditeur de liens ne génère pas une telle erreur (cas de compilateur standard), c’est plutôt le contrôleur statique qui le fait (plus précisément le contrôleur de types). Je m’explique. Le compilateur après l’analyse syntaxique doit contrôler les types pour savoir s’ils sont conformes aux conventions sémantiques du langage source et convention syntaxique de celui-ci et ainsi s’assurer que certain type d’erreur de programmation soit préalablement détectée et signalé. En clair, le contrôleur de types vérifie que le type d’une variable correspond à son contexte Exemple, il peut vérifier si vraiment la valeur de la variable « x » qui est du type entier a pour valeur que des entiers cas contraire il signale une erreurs ou un avertissement autre exemple « (int x + strict y) » génère une erreur.

    Lors de la phase de compilation, le compilateur effectue donc de nombreux contrôles dits statiques (Contrôle de type, contrôle d’unicité ou encore de flot d’exécution etc.), contrairement à un contrôle dynamique qui est effectué lors de l’exécution du programme. Cependant, certains contrôles sont obligés de se faire de façon dynamique exemple:
    Si vos faites « int ITab[127]; » et « int i; » pour parcourir le tableau, le compilateur ne pourras pas garantir que la variable « i » restera dans l’intervalle « 0-126 ». Bref, la plupart des contrôles se font pendant la phase de compilation et les autres lors de l’exécution du programme.

    Citation Envoyé par Bktero Voir le message
    ...
    Le fait que la variable soit statique l'empêche d'être visible des autres unités de compilation mais il faut bien la placer en mémoire !
    Il est vrai que l’on doit réserver de la mémoire mais cette mémoire qui est réservée doit correspondre au type.
    Donc, la quantité de mémoire nécessaire à une variable est déterminé à partir de son type. Exemple sur une machine 64 bits (à titre exemple simple) peut dans une variable du type entier stocker jusqu'à « 2147483647 » un nombre qui est supérieur à « 1024*1024*1024 » donc « static int big table[1024*1024*1024]; » est valide en revanche sur une machine (architecture) 32 bits. Ce n’est peut-être pas possible (en complément voir l’exemple de @picodev) vous allez avoir comme erreurs « array is To large ». Pour une valeur supérieure il faut soit un "long" où utiliser une bibliothèque additionnelle qui permet d’exploité de très grandes valeurs mais à l’exécution du programme ça pourrais coincé (cela dépend fortement de l'architecture).
    Il vrais que je connais pas comment le compilateur Cortex-M gère la chose. En revanche ce que moi je sais, c’est que les compilateurs que l'on connais effectuent des contrôles avant la phase édition de liens et encore une fois, la conception de compilateur est laissée à la discrétion des concepteurs et certains compilateurs sont conçus pour des architectures bien précises.
    Mais si vous avez d'autre avis sur le sujet je suis preneur en attendant j'ai peur de faire du hors-sujet et j'en suis désolé si c'est le cas.
    à bientôt
    Celui qui peut, agit. Celui qui ne peut pas, enseigne.
    Il y a deux sortes de savants: les spécialistes, qui connaissent tout sur rien,
    et les philosophes, qui ne connaissent rien sur tout.
    George Bernard Shaw

  19. #19
    Membre habitué
    Homme Profil pro
    ingénieur calcul
    Inscrit en
    Décembre 2007
    Messages
    363
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : ingénieur calcul
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2007
    Messages : 363
    Points : 180
    Points
    180
    Par défaut
    Super discussion les gars; j'en ai appris quelque kilos, et ça m'a rappelé ma jeunesse, à La Réunion, où j'ai été enseignant; et où pour enseigner quoi que ce soit de simpliste, on se sent obligé de connaître le domaine "à fond", mais alors vraiment "à fond", c'est-à-dire de nombreux niveaux d'études "au dessus" de ceux à qui on enseigne.

    En tant qu'ingénieur, j'étais à l'aise pour enseigner les maths en collège, (heureusement, OUF) mais pour enseigner l'électrotechnique ou la physique à des élèves de première et terminale F3 (électrotechnique, justement) j'étais quand même parfois obligé de réviser la veille pour le lendemain !
    David
    P.S. Dis Toto, pourquoi l'univers existe-t'il ?
    Je vais y réfléchir avec Morphée et lui dès avant 22h55, donc ici, il faut se causer avant.

Discussions similaires

  1. Réponses: 2
    Dernier message: 08/12/2006, 23h32
  2. Besoin d'aide concernant le diapo Flash.
    Par simplyme dans le forum Flash
    Réponses: 3
    Dernier message: 31/10/2006, 20h22
  3. [vb6] traitement d'images, besoin d'éclaircissements
    Par Asdorve dans le forum VB 6 et antérieur
    Réponses: 4
    Dernier message: 01/08/2006, 10h20
  4. [JGoodies] besoin d'éclaircissements
    Par sozie9372 dans le forum Interfaces Graphiques en Java
    Réponses: 4
    Dernier message: 26/06/2006, 23h10
  5. Besoin d'aide concernant 1 exo
    Par Shakan972 dans le forum Algorithmes et structures de données
    Réponses: 9
    Dernier message: 29/11/2005, 11h31

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo