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 :

Segment de code et segment de données


Sujet :

C

  1. #1
    Membre à l'essai
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2016
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2016
    Messages : 12
    Points : 10
    Points
    10
    Par défaut Segment de code et segment de données
    Bonjour,

    Après de multiples recherche sur google et autre au sujet de la ségmentation mémoire de l'espace de code et des données je n'ai rien trouver de clair.

    Je récapitule ma compréhension:
    ----------------------------------------------


    Lors de l'exécution d'un processus (programme) , ce dernier est chargé en mémoire centrale (load-store technique) , ensuite, chaque adresse mémoire contenant l'instruction est placée dans le registre

    d'instruction(registre EIP) par ordre d'exécution séquentiel hors saut conditionnel.

    Mais les instructions sont séparées des données ( variables et constantes) qui sont elles mêmes segmentées en différentes sections (variables en attente de saisie,valeur direct).

    Que contient donc la pile ? les instructions et les données (pile unique) ou il existe une pile pour les instructions et une pile pour les données?

  2. #2
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Bonjour,

    Un programme, c'est un fichier qui contient des 'explications' sur les données et déroulements de traitements à effectuer.

    Lors du lancement du programme :
    * des zones des mémoires sont initialisées
    * un contexte d'exécution est mis en place (interactions avec le système d'exploitation)
    * le déroulement du code démarre (EIP est positionné sur la 1ère instruction à effectuer, puis il 'parcours' le code)
    On parle alors d'un processus et de son contexte

    Les zones de mémoire:
    * La zone constante (elle de changera jamais, elle peut être mise en ROM si système embarqué)
    -- contient les instructions assembleurs du code programme
    -- contient les données constantes
    * La zone des variables
    -- à chaque variable globale ou statique a été attribuée une adresse et une taille
    * Le tas (où heap)
    -- c'est une zone où seront allouées les variables dynamiques
    * La pile
    -- elle contient l'ensemble des données de fonctionnement (jamais du code)
    === les variables locales
    === les données temporaires
    === les paramètres passés lors de l'appel d'un fonction
    === les données nécessaires au déroulement (p.e adresse de retour de fonction, données sauvées temporairement)

    Le tas et la pile peuvent 'grossir' si le processus demande plus de mémoire, on peut aussi créer d'autres piles si des threads sont lancés)

    Exemples:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const char[] txt = "Hello";      // var txt et son contenu dans zone const
    int x;                           // adresse x réservée dans zone des var
    char *fct( int lg ) {            // code de la fonction dans zone const
       static char* y = NULL;        // adresse y réservée dans zone des var
       char* z = malloc( lg+1 );
       return z;
    }
    int main() {                     // code de main() dans zone const
       printf("%d" , fct( 3 ) );     // la fonction printf est aussi en zone const
    }
    Quand le code se déroule :
    * mis sur la pile, le 3, l'adresse de retour dans main
    * la fonction appelée réserve une var lg sur la pile qui reçoit le 3, elle reserve aussi de la place pour 'z'
    * la fonction appelle malloc après avoir mis 4 sur la pile, qui réserve 3 octets dans le heap
    * la fonction retourne (les données précédentes disparaissent de la pile)
    * un nouvel empilage est effectué pour l'appel de printf()

  3. #3
    Membre à l'essai
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2016
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2016
    Messages : 12
    Points : 10
    Points
    10
    Par défaut
    Merci dalfab,


    Tu m'as donné les infos qu'ils me manquaient, , explication clair et bien détaillée.

  4. #4
    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 dalfab Voir le message
    Bonjour,

    Un programme, c'est un fichier qui contient des 'explications' sur les données et déroulements de traitements à effectuer.

    Lors du lancement du programme :
    * des zones des mémoires sont initialisées
    * un contexte d'exécution est mis en place (interactions avec le système d'exploitation)
    * le déroulement du code démarre (EIP est positionné sur la 1ère instruction à effectuer, puis il 'parcours' le code)
    On parle alors d'un processus et de son contexte
    J’ai du mal avec la définition donnée ou l'explication fournis sur ce que sont un processus et un programme car selon moi, et d’après votre définition, sans jouer sur les mots, on entend par processus le lancement du programme et son contexte qui sont les étapes citées précédemment. Ou encore, que le programme est un processus. au final un ensemble très vague qui, au final, ne définit pas de manière précise ce que sont réellement un processus et un programme (programme exécutable).

    Je pense avant tout qu'il faut bien faire la différence entre ce qu’est un programme, ce qu’est un processus, et ce que l'on appelle réellement un contexte d’exécution ou encore contexte de processus.

    Je m'explique, de manière brève, un processus est un environnement d'exécution qui consiste en trois segments : un segment d'instructions, un segment de données de l'utilisateur et un segment de données système. Tant dis qu'un programme est un fichier contenant des instructions et les données utilisées pour initialiser les segments d'instructions et des données utilisateur d'un processus.

    En clair, un processus n'est pas un programme exécutable mais plutôt une unité d'exécution, c'est-à-dire de partage du temps processeur et mémoire. Donc un processus correspond à une suite d'actions dynamiques réalisées lors d'une exécution et un programme est une suite statique d'instructions (un ensemble ou des ensembles de suites d'instructions précises mais statiques de ce qu'il faut faire et dans quel ordre faut-il qu’il le fasse).
    Il faut savoir également qu’il n’existe aucune description statique qui permette de prévoir ou savoir à l'avance les différentes conditions de déroulement de son exécution car elle peut changer d’une exécution à l’autre. Tout comme il n’existe aucune interaction entre le programme et le système d'exploitation (noyau).

    Pour exécuter un programme, le système ou noyau crée d'abord un nouveau processus qui est l'environnement dans lequel le programme va s'exécuter et le programme lui est utilisé pour initialiser les instructions et les données utilisateur. Après ces initialisations, il n’y a plus de connexion concrète ou directe entre un processus et le programme qu’il exécute.

    Ce qu’on appelle «*contexte d'un processus*» c'est l'ensemble : des états ou de son son états, des valeurs des registres actifs, des valeurs des variables globales statiques et/ou dynamiques, des entrées dans la table des processus, de son compteur ordinal, des zones de code et de données, des piles etc.
    Le «*contexte d'exécution*» comprend les structures ou tableaux contenant l'ensemble des valeurs du registre (pointeur d'instruction, état de la pile, valeur des variables etc..).

    Un programme exécutable dit «*fichier exécutable*», ou tout simplement «*programme*», est (je le rappelle) une collection d'instructions et de données conservées dans un fichier ordinaire sur le disque dur et identifié par le système d'exploitation en tant qu'exécutable. De ce fait, l’exécution d’un programme provoque la création d'un processus qui est l'environnement d'exécution dans lequel le programme s'exécute. On appelle alors «*processus*», l'exécution d'un programme et son contexte l’ensemble des ressources nécessaires à son exécution ou l'ensemble des données qui permettent de reprendre l'exécution d'un processus.

    En résumé, un processus se caractérise donc par :

    • Ses données
    • Sa pile d'exécution
    • Son programme exécutable
    • Son compteur ordinal
    • Son pointeur de pile
    • Les autres registres (toutes les autres informations nécessaires à l'exécution d'un programme ou manipulation de données).


    Citation Envoyé par dalfab Voir le message
    Bonjour,
    * le déroulement du code démarre (EIP est positionné sur la 1ère instruction à effectuer, puis il 'parcours' le code)
    On parle alors d'un processus et de son contexte
    EIP n’est pas positionné sur la 1re instruction à effectuer, mais plutôt qu’elle contient l’offset de la prochaine instruction à exécuté en l’occurrence la prochaine instruction à exécuter

    Rappelons que le point d'entrée d’un programme EXE (si en parle de windows) peut se trouver n’importe où dans le programme. Le véritable point d’entrée du programme EXE est défini après une directive précise « ORG 0100h » grâce au label qui suit cette directive (de façon immédiate) le EIP va contenir l’offset de la prochaine instruction à exécuté donc la toute première instructions.


    à 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

  5. #5
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 371
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 371
    Points : 23 626
    Points
    23 626
    Par défaut
    Bonsoir,

    Citation Envoyé par shin101 Voir le message
    Lors de l'exécution d'un processus (programme) , ce dernier est chargé en mémoire centrale (load-store technique) , ensuite, chaque adresse mémoire contenant l'instruction est placée dans le registre d'instruction(registre EIP) par ordre d'exécution séquentiel hors saut conditionnel.
    En fait, de façon plus générale, un micro-processeur prend généralement la forme d'un petit composant électronique qui, d'abord, est en principe complètement indépendant de la machine dans laquelle il prend place. On peut trouver le même micro-processeur dans des ordinateurs très différents. Et quand je dis « différents », je parle bien d'architectures complètement distinctes et probablement incompatibles (je ne parle pas de simples PC de différentes marques, par exemple). Ce composant est par ailleurs doté d'au moins trois choses :

    • Un certain nombre de broches (généralement 16, 32 ou 64 pour les plus sophistiqués) dont les niveaux électriques leur servent à coder chacune un bit et qui, toutes ensembles, servent à représenter un nombre binaire entier, lequel correspond en fait à un numéro d'adresse, c'est-à-dire le numéro d'emplacement mémoire à lire ou à écrire. Ces lignes sont véhiculées en parallèle à tous les composants reliés au micro-processeur et capables de communiquer avec lui (les « périphériques »). C'est donc le « bus d'adresse » ;
    • Un certain autre nombre de broches en plus des premières (8, 16 ou 32, plus rarement 64) qui vont être distribuées exactement de la même façon mais qui vont servir à faire transiter la donnée du micro-processeur vers la case mémoire concerné, ou l'inverse. C'est le « bus de données » ;
    • Une ligne nommée « R/W » qui, selon son état, sert à dire si le micro-processeur souhaite écrire une donnée en mémoire (l'envoyer depuis le micro-processeur vers l'emplacement désigné) ou la lire (la rapatrier depuis l'emplacement vers le micro-processeur).


    Ces trois bus fonctionnent toujours de concert. Chaque périphérique est conçu pour réagir à certaines combinaisons du bus d'adresse et se mettre automatiquement en état de haute impédance lorsqu'elles ne correspondent pas à ce qui s'y trouve, de sorte qu'un seul périphérique au plus peut « avoir la parole » à la fois. Vu depuis le micro-processeur, cela donne l'impression que les différents périphériques sont localisés à certains endroits du plan mémoire.

    Ce plan mémoire va être majoritairement occupé par de grandes plages de mémoire vive (RAM, qui peut être lue et écrite mais qui perd son contenu si on coupe son alimentation électrique) ou morte (ROM, en lecture seule, mais qui conserve son contenu ad vitam æternam, même sans alimentation électrique), et à certains endroits assez restreints, par les ports d'entrée/sorties (I/O). Lire ou écrire dans ces ports va directement influer sur l'état du matériel de ta machine. C'est ainsi que tu vas allumer une LED, lire le contenu de ton disque dur, piloter ta carte son, etc. Tout.

    Une fois tout ceci posé, quand tu vas mettre ta machine sous tension, ton micro-processeur va automatiquement lire le premier octet de ta mémoire, considérer sa valeur comme correspondant à une instruction, exécuter cette instruction, puis passer à la suivante (donc lire l'octet qui suit). Cette valeur est donc un « code opération », abrégé en « code-op » en français ou « opcode » chez les anglo-saxons (très répandu).

    L'instruction n'est donc pas « chargée » dans EIP : IP signifie ici Instruction Pointer et est devenu EIP à partir des 386, mais peut s'appeler PC pour Program Counter sur Motorola ou autre dénomination sur d'autres marques. Comme ses noms l'indiquent toutefois, il s'agit d'un « pointeur de programme », c'est-à-dire que ce registre contient toujours l'adresse de la prochaine instruction à lire. Modifier la valeur de ce registre revient donc à faire un saut (JMP ou GOTO) bien qu'il existe toujours une instruction dédiée pour cela.

    Ces instructions, cependant, tiennent rarement sur un seul octet. EIP peut donc pointer « quelques octets plus loin » et pas forcément sur le suivant. Par ailleurs, et c'est là l'une des réponses à tes questions, ces instructions ont souvent besoin « d'opérandes ». Un « opérande » au sens large est l'une des valeurs sur laquelle s'applique une opération arithmétique (+, -, ×, ÷) mais en assembleur, il s'agit généralement d'un paramètre obligatoire à la majeure partie des instructions et qui fait partie intégrante du code opération. Ça peut être une indication du registre sur lequel travailler, une adresse mémoire en particulier, ou une valeur donnée. Dans ce dernier cas, par exemple lorsqu'on veut charger la valeur « 5 » (au hasard) dans le registre EAX, on considère qu'il s'agit d'une lecture ordinaire en mémoire mais donc l'adresse est forcément celle qui suit immédiatement le code opération. Ce mode d'adressage est donc appelé « immédiat ».

    On peut donc déduire deux choses de tout cela :

    • Un micro-processeur ne fait que lire des données en mémoire, leur appliquer un traitement arithmétique et logique simple, et les réécrire autre part en mémoire. Et toute l'informatique est basée sur ce simple concept ;
    • Le mode immédiat, qui te permet d'écrire des choses aussi simples que « MOV EAX,5 » et les autres modes d'adressage font qu'au départ, les données se trouvent au sein du code avant d'être redéposées ailleurs, sauf quand le programme est compilé pour générer une plage de données qui sera chargée à un endroit particulier et que le programme est conçu pour aller la lire directement.


    Ça veut dire aussi qu'a priori, il n'y a ni notion de segment, ni distingo a priori entre code et données. Tout se retrouve en mémoire sans protection particulière. Les choses dont tu parles sont en fait des sophistications qui ont été mises en place avec l'évolution des micro-processeurs.

    Sur x86, en mode réel, les « segments » étaient des plages de 64 Ko qui se chevauchaient toutes avec un décalage de 16 octets à chaque fois, architecture mise en place quand on est passé de 16 à 20 bits d'adresses. À partir du mode protégé et sur la plupart des machines fonctionnant sur le même principe, il s'agit désormais d'une zone contiguë et arbitrairement longue de mémoire, débutant et finissant à des adresses choisies par le système d'exploitation (ou à défaut par le programmeur lui-même) auxquelles on va attribuer des droits particuliers, gérés électroniquement par le micro-processeur. Et c'est ainsi qu'on va séparer par exemple code et données en les déposant chacun dans leur propre segment.

    Comment cela va-t-il se traduire techniquement ? En fait, à défaut d'indication explicite, l'adresse pointée EIP va l'être par rapport au début du segment de code (indiqué par CS) et non plus par rapport au début de la mémoire entière, et toutes les instructions de lecture ou d'écriture de données en mémoire vont le faire par rapport au début du segment de données (indiqué par DS) et plus par rapport au début de la mémoire entière, là non plus. Un des avantages est qu'il est alors très facile de déplacer ces segments en mémoire au gré des besoins. L'autre avantage est que cela permet de protéger le segment de code en écriture tout en laissant le segment de données en accès libre.

    Que contient donc la pile ? les instructions et les données (pile unique) ou il existe une pile pour les instructions et une pile pour les données?
    La « pile » est avant tout une structure de données abstraire qui doit être comprise comme une « pile d'assiettes », c'est-à-dire un empilement. La caractéristique de toute pile, quelle qu'elle soit, est que le dernier élément empilé est le premier à ressortir (LIFO). C'est nécessaire pour tout un tas d'opérations théoriques, à commencer par l'implémentation des sous-programmes et des fonctions. Tu pourrais la gérer toi-même mais la plupart des micro-processeurs ont des instructions dédiées à la gestion d'une pile, ne serait-ce que parce qu'ils l'utilisent eux-mêmes.

    En réalité, la pile d'un micro-processeur va simplement consister en un simple registre contenant l'adresse mémoire où lire ou enregistrer le prochain élément, et qui va être automatiquement décrémenté en cas d'empilement ou décrémenté en cas de dépilement.

    La pile contient donc des données. À ce titre, elle peut prendre place à la fin du segment de données mais en général, elle dispose de son propre segment. On y trouve tout ce que le programmeur voudra y mettre, mais elle est aussi utilisée par le langage C et d'autres langages pour implémenter les variables locales. Enfin, le micro-processeur lui-même va s'en servir soit pour sauvegarder temporairement des registres, soit surtout pour implémenter les sauts aux sous-programmes avec CALL. Lors d'un tel appel, La valeur d'EIP est tout simplement empilée avant de faire un saut ordinaire vers le sous-programme. Lors d'un RET (Return), le micro-processeur va tout simplement dépiler la première valeur de la pile et la mettre dans EIP.

  6. #6
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Une fois tout ceci posé, quand tu vas mettre ta machine sous tension, ton micro-processeur va automatiquement lire le premier octet de ta mémoire, considérer sa valeur comme correspondant à une instruction, exécuter cette instruction, puis passer à la suivante (donc lire l'octet qui suit).
    À noter que ceci également est un détail du modèle de microprocesseur. Par exemple, un processeur de la famille Motorola 68000 ne considèrera pas les premiers octets de la mémoire comme instructions, mais comme adresses (256 adresses sur 32 bits chacune pour être exact). Au démarrage, le processeur 68k utilise les deux premières pour déterminer où placer la pile (en gros, la valeur initiale du pointeur de pile) et à quelle instruction commencer (en gros, la valeur initiale du Program Counter).
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  7. #7
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 371
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 371
    Points : 23 626
    Points
    23 626
    Par défaut
    Tout-à-fait !
    J'ai parti pour préciser ce point également mais quand j'ai jeté un œil à l'horloge, j'ai décider d'abréger. ;-)

Discussions similaires

  1. Pourquoi ce code plante (segmentation fault)
    Par fcjunic dans le forum Débuter
    Réponses: 3
    Dernier message: 19/01/2011, 12h05
  2. erreur dans mon code de segmentation (seed)
    Par kbazin dans le forum MATLAB
    Réponses: 2
    Dernier message: 07/10/2010, 14h51
  3. code de segmentation d'image
    Par bleuneige dans le forum Images
    Réponses: 8
    Dernier message: 20/06/2010, 16h40
  4. [Débutant] Questions sur un code de segmentation d'images
    Par nadjib2007 dans le forum Images
    Réponses: 2
    Dernier message: 30/08/2007, 01h32
  5. GDT Descripteur de segment de code & segment de données
    Par Edouard Kaiser dans le forum x86 32-bits / 64-bits
    Réponses: 15
    Dernier message: 03/04/2004, 12h40

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