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 :

Problème de linker avec ld


Sujet :

C++

  1. #1
    Membre du Club
    Inscrit en
    Juin 2008
    Messages
    85
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 85
    Points : 68
    Points
    68
    Par défaut Problème de linker avec ld
    Bonjour,

    J'essaye de compiler un programme mais j'ai une erreur d'édition de liens. J'ai 4 fichiers : Screen.h, Screen.cpp, type.h, main.cpp. Je compile main.cpp et screen.cpp sans erreur ni warning (avec gcc). Je fais ensuite la commande ld pour indiquer que mon code commence à l'adresse 0x10000. Voici mes lignes de compilation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    gcc -c main.cpp 
    gcc -c screen.cpp
    ld --oformat binary -Ttext 10000 main.o screen.o -o kernel
    Voici les erreurs lors de la commande ld :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    ld: AVERTISSEMENT: ne peut trouver le symbole d'entrée _start; utilise par défaut 0000000000010000
    main.o: dans la fonction "main":
    main.cpp:(.text+0x6b): référence indéfinie vers "_Unwind_Resume"
    main.o:(.eh_frame+0x12): référence indéfinie vers "__gxx_personality_v0"
    Merci d'avance

  2. #2
    Membre actif
    Profil pro
    Inscrit en
    Août 2007
    Messages
    190
    Détails du profil
    Informations personnelles :
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations forums :
    Inscription : Août 2007
    Messages : 190
    Points : 219
    Points
    219
    Par défaut
    Salut,

    Première chose : Il faut que tu utilises g++ pour compiler et non gcc.
    Si tu ne précises pas le point d'entrée (la première instruction qui sera exécutée au lancement de ton programme) ld prend par défaut _start. Pour modifier ce comportement il suffit d'utiliser l'option -e (--entry). Un petit :
    t'en diras plus.

  3. #3
    Membre du Club
    Inscrit en
    Juin 2008
    Messages
    85
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 85
    Points : 68
    Points
    68
    Par défaut
    Mon point d'entrée est bien _start c'est pour ça que je ne le redéfini pas. De plus avec g++ la même erreur survient.

  4. #4
    Membre actif
    Profil pro
    Inscrit en
    Août 2007
    Messages
    190
    Détails du profil
    Informations personnelles :
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations forums :
    Inscription : Août 2007
    Messages : 190
    Points : 219
    Points
    219
    Par défaut
    Dans ce cas, peux tu montrer le code ?

  5. #5
    Membre du Club
    Inscrit en
    Juin 2008
    Messages
    85
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 85
    Points : 68
    Points
    68
    Par défaut
    Bien sur le voici,

    type.h :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #ifndef _I386_TYPE_
    #define _I386_TYPE_
    #define NULL 0
     
    typedef unsigned char u8;
    typedef unsigned short u16;
    typedef unsigned int u32;
    typedef unsigned char uchar;
     
    #endif
    screen.h :

    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
    #include "type.h"
     
    class Cscreen
    {
    	private: //attribut
    		unsigned char m_x; //position du curseur en x
    		unsigned char m_y; //position du curseur en y
    		unsigned char m_attr; //attribut du caractère a afficher
     
    	private: //fonctions
    		void putChar(unsigned char); //affiche le charactere passer en parametre à l'ecran
     
    	public: //fonctions
    		Cscreen(void); //constructeur par défault
    		void clearScreen(void); //efface les données de l'ecran
    		void print(unsigned char*); // affiche la ligne à l'ecran
    		void movScrollRight(unsigned char); //déplace le scroll en x du nombre passer en parametre
    		void movScrollDown(unsigned char); //déplace le scroll en y du nombre passer en parametre
    		void movScrollUp(void); //efface la premiere ligne et met la derniere ligne libre
    		~Cscreen(); //destructeur
    };
    screen.cpp :

    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
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    #define RAMSCREEN 0xB8000       /* debut de la memoire video */
    #define SIZESCREEN 0xFA0        /* 4000, nombres d'octets d'une page texte */
    #define SCREENLIM 0xB8FA0	/* fin de la mémoire video */
     
    #include "screen.h"
     
    Cscreen::Cscreen() //constructeur par défault
    {
    	m_x = 0;
    	m_y = 0;
    	m_attr = 0x0E;
    }
     
    void Cscreen::putChar(unsigned char p_char)//affiche le charactere passer en parametre à l'ecran
    {
    	unsigned char* chardisplay = NULL;//pointe sur la zone mémoire qui contient le mappage de la mémoire vidéo
    	switch (p_char)
    	{
    		case 10 : m_y++; break; //New line
    		case 13 : m_x = 0; break; //Cariot return
    		case 9 : m_x = (m_x+8) - (m_x%8); break; //tab
    		default :  // caractere normal
    			chardisplay = (unsigned char*) (RAMSCREEN+2*m_x+m_y*160); //zone mémoire ou ecrire le char
    			*chardisplay = p_char;
    			*(chardisplay+1) = m_attr;
    			m_x++;
    			if (m_x == 80) //si on arrive a la derniere colonne
    			{
    				m_x = 0;
    				m_y++; //nouvelle ligne
    			}
    			if (m_y == 25) // si derniere ligne
    			{
    				movScrollUp(); //met la derniere ligne libre et remonte toutes les lignes
    			}
    			break;
    	}
    }
     
    void Cscreen::clearScreen() //efface les données de l'ecran
    {
    	for (unsigned char* videoram = (unsigned char*) RAMSCREEN; // debut mémoire video
    	     videoram != (unsigned char*) SCREENLIM; //jusqu a fin memoire video
    	     videoram = videoram+2) // mémoire video + 2 octets
    	{
    		// efface l'ecran
    		*videoram = 0;
    		*(videoram+1) = 0;
    	}
    	m_x = 0;
    	m_y = 0;
    }
     
    void Cscreen::print(unsigned char* p_chaine) // affiche la ligne à l'ecran
    {
    	int i = 0;
    	while (*(p_chaine+i) != '\0') //tant que pas caractere fin de chaine
    	{
    		putChar(*(p_chaine+i)); //affiche le caractere
    		i++; //passe au caractere suivant
    	}
    }
     
    void Cscreen::movScrollRight(unsigned char p_dep) //déplace le scroll en x du nombre passer en parametre
    {
    	if (p_dep<(80-m_x)) //si le déplacement ne deborde pas sur la ligne suivante
    		m_x+=p_dep; //ajoute p_dep a x (abscisse)
    }	
     
    void Cscreen::movScrollDown(unsigned char p_dep) //déplace le scroll en y du nombre passer en parametre
    {
    	if (p_dep<(25-m_y)) //si le deplacement ne deborde pas en y(ordonnée)
    		m_y+=p_dep; //ajoute p_dep en ordonnées(y)
    }	
     
    void Cscreen::movScrollUp() //efface la premiere ligne et met la derniere ligne libre
    {
    	unsigned char rowsav[4000]; // sauvegarde la zone memoire video
    	int i = 0;
     
    	// sauvegarde la memoire video
    	for (unsigned char* videoram = (unsigned char*) RAMSCREEN; // debut mémoire video
    	     videoram != (unsigned char*) SCREENLIM; //jusqu a fin memoire video
    	     videoram = videoram+2) // mémoire video + 2 octets
    	{
    		rowsav[i] = *videoram; //sauvegarde la ram
    		rowsav[i+1] = *(videoram+1); //sauvegarde la ram
    		i+=2;
    	}
     
    	i = 0;
    	//remplace la memoire video (monte tous d'une ligne)
    	for (unsigned char* videoram = (unsigned char*) RAMSCREEN; // debut mémoire video
    	     videoram != (unsigned char*) SCREENLIM; //jusqu a fin memoire video
    	     videoram = videoram+2) // mémoire video + 2 octets
    	{
    		if (i <= 3838) //si pas derniere ligne copier les données enregistrer dans la ram
    		{
    			*videoram = rowsav[i+160]; //remplace la ram
    			*(videoram+1) = rowsav[i+161]; //remplace la ram
    			i+=2;
    		}
    		else //sinon mettre 0 (ligne vide)
    		{
    			*videoram = 0; //remplace la ram
    			*(videoram+1) = 0x07; //remplace la ram
    		}
    	}
    }
     
    Cscreen::~Cscreen()//destructeur
    {
    }
    main.cpp :

    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
    #include "screen.h"
     
    int main();
     
    void _start(void)
    {
            main();
    }
     
    int main(void)
    {
    	Cscreen screen; //initialise l'ecran
    	screen.clearScreen(); //efface l'ecran
    	for (int i = 0; i != 5; i++)
    		screen.print((unsigned char*) "Bonjour");
    	while (1);
    }
    Merci de l'aide

  6. #6
    Membre actif
    Profil pro
    Inscrit en
    Août 2007
    Messages
    190
    Détails du profil
    Informations personnelles :
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations forums :
    Inscription : Août 2007
    Messages : 190
    Points : 219
    Points
    219
    Par défaut
    Le problème du _start vient du fait que le compilateur C++ décore le nom des fonctions ce qui permet entre autre la surcharge. Pour ne pas qu'il décore le nom de la fonction tu peux utiliser :
    Dans ton cas ca donne :
    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
    #include "screen.h"
     
    int main();
     
    extern "C" {
      void _start(void)
      {
        main();
      }
    }
     
    int main(void)
    {
      Cscreen screen; //initialise l'ecran
      screen.clearScreen(); //efface l'ecran
      for (int i = 0; i != 5; i++)
        screen.print((unsigned char*) "Bonjour");
      while (1);
    }
    Tu informes ainsi le compilateur que ta fonction à un "linkage C" et donc qu'il doit garder intact le nom de la fonction.

  7. #7
    screetch
    Invité(e)
    Par défaut
    g++ pour linker aussi. si tu veux passer des commandes a ld, utilise l'option -Wl,

    par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    g++ -c main.cpp 
    g++ -c screen.cpp
    g++ -Wl,--oformat,binary -Wl,-Ttext,10000 main.o screen.o -o kernel

  8. #8
    Membre du Club
    Inscrit en
    Juin 2008
    Messages
    85
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 85
    Points : 68
    Points
    68
    Par défaut
    Effectivement le fait de rajouter extern "C" m'enlève le warning sur le _start. Malheureusement j'ai toujours les deux autres erreurs d'édition de liens :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    main.o: dans la fonction "main":
    main.cpp:(.text+0x6b): référence indéfinie vers "_Unwind_Resume"
    main.o:(.eh_frame+0x12): référence indéfinie vers "__gxx_personality_v0"

  9. #9
    Membre actif
    Profil pro
    Inscrit en
    Août 2007
    Messages
    190
    Détails du profil
    Informations personnelles :
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations forums :
    Inscription : Août 2007
    Messages : 190
    Points : 219
    Points
    219
    Par défaut
    Les fonctions _Unwind_Resume et __gxx_personality_v0 font parti des fonctions qui permettent à g++ de gérer le traitement des exceptions (en particulier le nettoyage de la pile lors de la remontée d'exception). Vu que apparemment tu ne les utilises pas dans ton code tu devrais donc les désactiver avec -fno-exception.
    Ce qu'il est important de savoir c'est que quand tu te sers de g++ pour linker (comme l'a montrer screetch) plein de choses sont faites dans ton dos. Pour en savoir plus utilise l'option -v.

    Pour éliminer la dernière erreur un petit coup de -fno-stack-protector devrait suffir (je te laisse le soin de regarder le man de gcc).

    En résumé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    g++ -fno-exception -fno-stack-protector -c main.cpp
    g++ -fno-exception -fno-stack-protector -c screen.cpp
    ld --oformat binary -Ttext 10000 main.o screen.o -o kernel
    PS: J'espère que tu as bien conscience qu'en utilisant l'option --oformat binary le fichier de sortie de ld sera un fichier binaire brut de décoffrage et donc pas utilisable par ton système d'exploitation (mon petit doigt me dit que tu sais ce que tu fais mais je préfère te prévenir).

    Edit: le coup du -fno-stack-protector c'est parce que chez moi mon compilateur rajoute du code qui permet de se protéger des buffer overflow (stack smashing attacks). Apparemment tu n'as pas ce problème donc tu peux te passer de cette option.

  10. #10
    Membre du Club
    Inscrit en
    Juin 2008
    Messages
    85
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 85
    Points : 68
    Points
    68
    Par défaut
    Merci Ça a résolu tous mes problèmes.

    PS : ton petit doigt a raison

  11. #11
    Membre actif Avatar de Twindruff
    Inscrit en
    Janvier 2005
    Messages
    216
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 216
    Points : 237
    Points
    237
    Par défaut
    Par curiosité tu programmes pour quel type d'appareil? ça a l'air marrant

  12. #12
    Membre du Club
    Inscrit en
    Juin 2008
    Messages
    85
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 85
    Points : 68
    Points
    68
    Par défaut
    Pour mon PC C'est juste pour le fun et puis sa me permet de mieux comprendre le fonctionnement d'un PC.

  13. #13
    Membre actif Avatar de Twindruff
    Inscrit en
    Janvier 2005
    Messages
    216
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 216
    Points : 237
    Points
    237
    Par défaut
    Tu prends la main juste après un bootloader (grub, ...) ? Huhu quelle joie

    Moi je m'étais amusé à faire des trucs qui prennaient la main juste après le BIOS, sur le secteur de boot d'une disquette, c'était marrant, mais on débarque en mode réel à ce moment là

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Problème de linker avec SDL_Image
    Par Shugo78 dans le forum SDL
    Réponses: 7
    Dernier message: 25/03/2012, 23h10
  2. problème de linker avec bibliothèque PTHREAD
    Par krossark dans le forum Bibliothèques
    Réponses: 1
    Dernier message: 28/01/2010, 14h58
  3. Réponses: 10
    Dernier message: 17/08/2009, 12h39
  4. Problèmes de versions avec Xalan, Xerces et Java
    Par honeyz dans le forum XML/XSL et SOAP
    Réponses: 4
    Dernier message: 05/06/2003, 10h18
  5. [Debutant] Problème du linker [Dev-c++4]
    Par Macdir dans le forum Dev-C++
    Réponses: 3
    Dernier message: 30/05/2003, 20h50

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