/* -------------------------------------------------------------
 *         assembler.c
 *         FM 1er avril 2003
 *    
 *         Apres la phase d'analyse syntaxique minimale realisee
 *         par Analyse(), verifications contextuelles et production
 *         du fichier objet au format ELF
 *
 * Fournit la fonction main
 * -------------------------------------------------------------
 */
#include <stdio.h>  
 
#include  "AA.h"
#include  "AnalyseSynt.h"
#include  "importelf.h"
 
 
#include <fcntl.h>  
#include <stdlib.h>  
#include <elf.h>
#include <string.h>  
#include <limits.h>  
 
#include  <sys/types.h>
#include  <sys/stat.h>
 
 
/*#include  <string.h>
#include  <errno.h>*/
 
 
/* Tables pour VerifInst  
 * -----------------------
 */
 
static char *tableNomsRegs32 [] = {
 "%eax",  
 "%ecx",
 "%edx",
 "%ebx",
 "%esp",
 "%ebp",
 "%esi",
 "%edi",
 " "  
} ;
 
static char *tableNomsRegs16 [] = {
 "%ax",    
 "%cx",
 "%dx",
 "%bx",
 "%sp",
 "%bp",
 "%si",
 "%di",
 " "
} ;
 
static char *tableNomsRegs8 [] = {
 "%al",    
 "%cl",
 "%dl",
 "%bl",
 "%ah",  
 "%ch",
 "%dh",
 "%bh",
 " "  
} ;
 
 
 static char *tableInstructions2ParB [] = {
 "addb",
 "andb",
 "cmpb",
 "movb",
 "orb",
 "subb",
 "xorb",
 " "
} ;
 
static char *tableInstructions2ParW [] = {
 "addw",
 "andw",
 "cmpw",
 "movw",
 "orw",
 "subw",
 "xorw",
 " "
} ;
 
static char *tableInstructions2ParL [] = {
 "addl",
 "andl",
 "cmpl",
 "movl",
 "orl",
 "subl",
 "xorl",
 " "
} ;
 
static char *tableSautCond [] = {
 "ja",
 "jae",
 "jb",
 "jbe",
 "je",
 "jg",
 "jge",
 "jl",
 "jle",
 "jne",
 " "
} ;
 
 
   
 
/* Types pour ELF  
 * --------------
 */
typedef struct {  
        Elf_Scn  *TextSection ;
        Elf_Scn  *DataSection ;
        Elf_Scn  *BssSection ;
        Elf_Scn  *SymbolTable ;
        Elf_Scn  *StringTable ;
        Elf_Scn  *RelocTextSection ;
        Elf_Scn  *RelocDataSection ;
    } SectionDescriptors ;
 
    typedef struct {
        int     TextNameIndex ;
        int     DataNameIndex ;
        int     BssNameIndex ;
        int     SymbolTableNameIndex ;
        int     StringTableNameIndex ;
        int     RelocTextNameIndex ;
        int     RelocDataNameIndex ;
    } NameIndexes ;
 
 
 
/* Pre-declarations des procedures et fonctions  
 * --------------------------------------------
 */
static int   Verif      (Elem *, int) ;
static void  Decoration (Elem *, int) ;  
static void  Remplir_Listing (Elem *, int, FILE *) ;
static void  GenererObjet    (Elf *) ;
static void  GenerateHeader (Elf *, SectionDescriptors *, NameIndexes *) ;
static void  CreateTableOfSectionNames (Elf *, NameIndexes *) ;
static void  GenerateTextAndReloc  (Elf *, Elf_Scn *, Elf_Scn *, int , int );
 
 
static  void    GenerateTextAndReloc
        (Elf *, Elf_Scn *, Elf_Scn *, int , int );
static  void    GenerateDataAndReloc
        (Elf *, Elf_Scn *, Elf_Scn *, int , int ) ;
static  void    GenerateBss     (Elf *, Elf_Scn *, int )  ;
static  void    GenerateSymbTab (Elf *, Elf_Scn *, int )  ;
static  void    GenerateCharTab (Elf *, Elf_Scn *, int )  ;
 
static  void    SetSHDR (                    Elf32_Shdr *shdr,
                     Elf32_Word sh_name,    /* section name */
                     Elf32_Word sh_type,    /* SH_... */
                     Elf32_Word sh_flags,   /* SHF_... */
                     Elf32_Addr sh_addr,    /* virtual address */
                     Elf32_Off  sh_offset,  /* file offset */
                     Elf32_Word sh_size,    /* section size */
                     Elf32_Word sh_link,    /* misc info */
                     Elf32_Word sh_info,    /* misc info */
                     Elf32_Word sh_addralign,   /* memory alignment */
                     Elf32_Word sh_entsize  /* entry size if table */
                )   ;    
 
static void SetDATA (Elf_Data   *, Elf_Type, size_t, off_t, size_t);
 
static void SetSYMBOL (Elf32_Sym *, int, Elf32_Word,  
                       Elf32_Addr, unsigned char, Elf32_Half) ;
 
/* ---------------------------------------------------------------
 * SetDATA  
 * - Installation d'un bloc de donnees du format ELF  
 * ---------------------------------------------------------------  
 */
static void SetDATA (Elf_Data   *data,  
                     Elf_Type   d_type,
                     size_t     d_size,
                     off_t      d_off,
                     size_t     d_align)
{
  data->d_type = d_type ;
  data->d_size = d_size ;
  data->d_off = d_off ;
  data->d_align =  d_align ;
  data->d_version = EV_CURRENT  ;
  if (d_size)  
 data->d_buf = malloc ( d_size);  
  else  
 data->d_buf = NULL ;
}  
/* ---------------------------------------------------------------
 * SetSYMBOL
 * ---------------------------------------------------------------  
 */
static void SetSYMBOL (Elf32_Sym *psymb, int index, Elf32_Word nameindex,  
                       Elf32_Addr value, unsigned char info, Elf32_Half sectionindex)  
{  
  (psymb+index)->st_name  = nameindex ;
  (psymb+index)->st_value = value ;
  (psymb+index)->st_size  = 0 ;
  (psymb+index)->st_info  = info ;
  (psymb+index)->st_other = 0 ;
  (psymb+index)->st_shndx = sectionindex;
}
 
/* ---------------------------------------------------------------
 * SetSHDR
 * ---------------------------------------------------------------  
 */
static void SetSHDR (    
                     Elf32_Shdr *shdr,
                     Elf32_Word sh_name,    /* section name */
                     Elf32_Word sh_type,    /* SHT_... */
                     Elf32_Word sh_flags,   /* SHF_... */
                     Elf32_Addr sh_addr,    /* virtual address */
                     Elf32_Off  sh_offset,  /* file offset */
                     Elf32_Word sh_size,    /* section size */
                     Elf32_Word sh_link,    /* misc info */
                     Elf32_Word sh_info,    /* misc info */
                     Elf32_Word sh_addralign,   /* memory alignment */
                     Elf32_Word sh_entsize  /* entry size if table */
)
{
  shdr->sh_name = sh_name ;  
  shdr->sh_type = sh_type ;
  shdr->sh_flags =  sh_flags;
  shdr->sh_addr = sh_addr ;
  shdr->sh_offset =sh_offset ;
  shdr->sh_size = sh_size;
  shdr->sh_link = sh_link ;
  shdr->sh_info = sh_info ;
  shdr->sh_addralign = sh_addralign;
  shdr->sh_entsize = sh_entsize ;
}
/* ---------------------------------------------------------------
 * main - assembleur  
 * ---------------------------------------------------------------  
 */
int  main (int argc, char *argv[]) {
 
FILE  *inputf ;      /* descripteur de fichier d'entree */
int   result_analyse ;      /* resultat de la premiere phase d'analyse. 0 si ok */
int   result_verif   ;      /* resultat de la phase d'analyse contextuelle.
                            0 si ok. */
FILE  *p_fd_listing ;       /* descripteur du listing de sortie */
int   fd_object ;           /* descripteur de fichier de sortie */
int   fd_listing        ;    /* descripteur du fichier de listing */
char  nom_listing [100] ;    /* nom du fichier contenant le listing d assemblage */
char  nom_out [100] ;        /* nom du fichier de sortie */
Elf   *elf ;                 /* descripteur du fichier ELF de sortie */
int   modif_fich_sortie ;    /* booleen modifie par la presence de l option -o */
int   trace          ;    /* booleen modifie par la presence de l option -v */
 
/* sdd interne a remplir par analyse et a retravailler ensuite */
 static Elem LeProg [MAX_LIGNES_LOG] ;
 int  nbLigneLog ;  
 
 
 
/* -----------------------------------------------------------------------------------
 * Analyse des arguments de la ligne de commande
 * Possibilite d option
 * -v : pour des informations sur le deroulement du programme
 * -o <nom> : pour choisir le nom du fichier de sortie
 * -----------------------------------------------------------------------------------
 */
 modif_fich_sortie = 0 ;
 trace = 0 ;
 
 switch (argc) {
 	case 2 : break ;
   	sprintf(nom_out, "%s.o", argv[1]) ;
 	case 3 : if (!strcmp (argv[2], "-v" )) {
   	trace = 1 ;
   	sprintf(nom_out, "%s.o", argv[1]) ;
   	break ;  
    }
    else {
   	printf ("\n%s : option invalide : %s\n\n",  
   	argv[0], argv [2]);
   	exit (1) ;
    }
 	case 4 : if (!strcmp (argv[2], "-o" )) {
   	sprintf(nom_out, "%s.o", argv[3]) ;
   	break ;  
    }
    else {
   	printf ("\n%s : option invalide : %s\n\n",  
   	argv[0], argv [2]);
   	exit (1) ;
    }
 	default : printf ("\n%s : nombre de parametres de commande incorrect \n\n",
     argv[0]) ;
     exit (1) ;
 }
 
 if ((inputf = fopen(argv[1], "r" )) == NULL) {
   	printf("%s : impossible d'ouvrir : %s\n", argv[0], argv[1]);
   	exit(1);
 }
 
 if (trace)
 	printf  
("\n************************************************************
* Verification de la ligne de commande achevee avec succes *
************************************************************ \n\n" ) ;  
 
 
 
/* -----------------------------------------------------------------------------------
 * Analyse - phase 1 : remplit les structures de donnees de AA.h
 * Arret a la premiere erreur detectee
 * On produira tout de meme un listing avec le fichier incomplet
 * par contre pas de fichier binaire relogeable
 * -----------------------------------------------------------------------------------
 */
 result_analyse = Analyse (inputf, LeProg, &nbLigneLog) ;
 if (result_analyse != 0)  
 	printf ("\n%s : erreur de syntaxe - poursuite \n\n",
 	argv[0]) ;
 
 close (inputf) ;
 
 	if (trace)
 	printf  
("\n****************************
* Analyse lexicale achevee *
**************************** \n\n" ) ;
 
 
 
/* -----------------------------------------------------------------------------------
 * Analyse - phase 2 : verifications contextuelles
 * pas de double definition d etiquette, modes d adressage autorises
 * taille demandee positive pour reservations non initialisees
 * taille de zone reservee suffisante pour stocker une donnee initialisante
 * borne d alignement positive
 * -----------------------------------------------------------------------------------
 */
 
 result_verif = Verif (LeProg, nbLigneLog) ;
 if (result_verif != 0)  
 	printf ("\n%s : erreur de syntaxe contextuelle - poursuite \n\n",
 	argv[0]) ;
 
 	if (trace)
 	printf  
("\n****************************************
* Verifications contextuelles achevees *
**************************************** \n\n" ) ;
 
 
 
 
/* Enrichissement de la structure de donnees
 * calcul des valeurs et des zones de def des symboles,...  
 * ----------------------------------------------------
 */
 
 Decoration (LeProg, nbLigneLog) ;
 
 
 
 
 
/* -----------------------------------------------------------------------------------
 * Production du listing d assemblage
 * -----------------------------------------------------------------------------------
 */
 
 sprintf (nom_listing, "%s.l", inputf) ;
 
 /* ouverture d un fichier de listing en ecriture */
 unlink (nom_listing) ;
 p_fd_listing = fopen (nom_listing, "w" ) ;
 
 if (fd_listing == -1) {
 	perror ("Kerala(linux-pentium)" ) ;
 	exit (1) ;
 }
 fchmod (fd_listing, S_IRUSR|S_IWUSR) ;
 
 Remplir_Listing (LeProg, nbLigneLog, p_fd_listing) ;
 
 
 
/* Generation de code =
 * production du fichier ELF  
 * -------------------------
 */
 
 sprintf (nom_out, "out.o" ) ;
 
 /* ouverture d'un fichier ELF en ecriture */
 unlink (nom_out);  
    fd_object = open(nom_out, O_WRONLY|O_CREAT|O_TRUNC) ;  
 
    if (fd_object == -1) {
        perror ("Kerala(linux-pentium)" ) ;
        exit(1);  
    }
    fchmod (fd_object, S_IRUSR|S_IWUSR);
 
    /* coordinate versions of the ELF library */
    (void) elf_version(EV_CURRENT);
 
    /* Obtain the ELF descriptor */
    if ((elf = elf_begin(fd_object, ELF_C_WRITE, NULL)) == NULL)
     exit(1);
 
 GenererObjet (elf) ;
 
    elf_update (elf,ELF_C_WRITE) ;
    elf_end (elf);  
    close (fd_object) ;
 
 
}
 
 
/* pre-declarations - voir ci-dessous */
static int VerifInst (Elem) ;
static int VerifReservInit(Elem) ;
 
 
/* Fonctions tests */
 
int EstReg32 (char *nom) {
 int i ;
 for (i = 0; ; i++) {
 	if (!strcmp (" ", tableNomsRegs32 [i]))
   break ;
 	if (!strcmp (nom, tableNomsRegs32 [i]))
   return 1 ;
 }
 return 0 ;
}
 
int EstReg16 (char *nom) {
 int i ;
 for (i = 0; ; i++) {
 	if (!strcmp (" ", tableNomsRegs16 [i]))
   break ;
 	if (!strcmp (nom, tableNomsRegs16 [i]))
   return 1 ;
 }
 return 0 ;
}
 
int EstReg8 (char *nom) {
 int i ;
 for (i = 0; ; i++) {
 	if (!strcmp (" ", tableNomsRegs8 [i]))
   break ;
 	if (!strcmp (nom, tableNomsRegs8 [i]))
   return 1 ;
 }
 return 0 ;
}
 
int EstValImm8 (long val) {
 if ((val < SHRT_MIN ) || (val > USHRT_MAX ))
 	return 0;
 else return 1;
}
 
int EstValImm16 (long val) {
 if ((val < INT_MIN) || (val > UINT_MAX))
 	return 0;
 else return 1;
}
 
int EstValSigne8 (long val){
if ((val < SHRT_MIN ) || (val > SHRT_MAX ))
 	return 0;
 else return 1;
}
 
/* ------------------------------------------------------------------------  
*/
 
int EstInst2ParB (char *nom) {
 int i ;
 for (i = 0; ; i++) {
 	if (!strcmp (" ", tableInstructions2ParB [i]))
   break ;
 	if (!strcmp (nom, tableInstructions2ParB [i]))
   return 1 ;
 }
 return 0 ;
}
 
int EstInst2ParW (char *nom) {
 int i ;
 for (i = 0; ; i++) {
 	if (!strcmp (" ", tableInstructions2ParW [i]))
   break ;
 	if (!strcmp (nom, tableInstructions2ParW [i]))
   return 1 ;
 }
 return 0 ;
}
 
int EstInst2ParL (char *nom) {
 int i ;
 for (i = 0; ; i++) {
 	if (!strcmp (" ", tableInstructions2ParL [i]))
   break ;
 	if (!strcmp (nom, tableInstructions2ParL [i]))
   return 1 ;
 }
 return 0 ;
}
 
int EstSautCond (char *nom) {
 int i ;
 for (i = 0; ; i++) {
 	if (!strcmp (" ", tableSautCond [i]))
   break ;
 	if (!strcmp (nom, tableSautCond [i]))
   return 1 ;
 }
 return 0 ;
}
 
/* --------------------------------------------------------------------------------------------------  
*/
 
/* predeclarations */
int EstModeAdInst2ParB (NatParam, Param, NatParam, Param) ;
int EstModeAdInst2parW (NatParam, Param, NatParam, Param) ;
int EstModeAdInst2parL (NatParam, Param, NatParam, Param) ;
 
int EstModeAdInst2ParB (NatParam natp0, Param p0, NatParam natp1, Param p1) {
  switch (natp0) {
  case P_NOMREG      :
    if (EstReg8(p0.u.nomreg)&&(((natp1 == P_NOMREG)&&EstReg8(p1.u.nomreg)) || ((natp1==P_INDIR)&&(p1.u.indir.nbreg == 1)) ||  
       	((natp1==P_INDEX_INDIR)&&(p1.u.index_indir.nbreg == 1)) || (natp1==P_NOMBRE)  || (natp1==P_ETIQUETTE)))
      return 1;
  case P_DOLLAR_NB   :
    if (EstValImm8(p0.u.dollar_nb)&&(((natp1 == P_NOMREG)&&EstReg8(p1.u.nomreg)) || ((natp1==P_INDIR)&&(p1.u.indir.nbreg == 1)) ||  
           ((natp1==P_INDEX_INDIR)&&(p1.u.index_indir.nbreg == 1)) || (natp1==P_NOMBRE)  || (natp1==P_ETIQUETTE)))
      return 1;
  case P_DOLLAR_ETIQ :
    if (((natp1 == P_NOMREG)&&EstReg8(p1.u.nomreg)) || ((natp1==P_INDIR)&&(p1.u.indir.nbreg == 1)) ||  
     ((natp1==P_INDEX_INDIR)&&(p1.u.index_indir.nbreg == 1)) || (natp1==P_NOMBRE)  || (natp1==P_ETIQUETTE))
      return 1;
  case P_INDIR       :
    if ((p0.u.indir.nbreg == 1)&&((natp1==P_NOMREG) && (EstReg8(p1.u.nomreg))))
      return 1;
  case P_INDEX_INDIR :
    if ((p0.u.index_indir.nbreg == 1)&&((natp1==P_NOMREG) && (EstReg8(p1.u.nomreg))))
      return 1;
  case P_NOMBRE      :
  case P_ETIQUETTE   :
    if ((natp1==P_NOMREG) && (EstReg8(p1.u.nomreg)))
      return 1;
  default:
    return 0 ;
  }
}
   
 
int EstModeAdInst2parW (NatParam natp0, Param p0, NatParam natp1, Param p1) {
  switch (natp0) {
  case P_NOMREG      :
    if (EstReg16(p0.u.nomreg)&&(((natp1 == P_NOMREG)&&EstReg16(p1.u.nomreg)) || ((natp1==P_INDIR)&&(p1.u.indir.nbreg == 1)) ||  
       	((natp1==P_INDEX_INDIR)&&(p1.u.index_indir.nbreg == 1)) || (natp1==P_NOMBRE)  || (natp1==P_ETIQUETTE)))
      return 1;
  case P_DOLLAR_NB   :
    if (EstValImm16(p0.u.dollar_nb)&&(((natp1 == P_NOMREG)&&EstReg16(p1.u.nomreg)) || ((natp1==P_INDIR)&&(p1.u.indir.nbreg == 1)) ||  
           ((natp1==P_INDEX_INDIR)&&(p1.u.index_indir.nbreg == 1)) || (natp1==P_NOMBRE)  || (natp1==P_ETIQUETTE)))
      return 1;
  case P_DOLLAR_ETIQ :
    if (((natp1 == P_NOMREG)&&EstReg16(p1.u.nomreg)) || ((natp1==P_INDIR)&&(p1.u.indir.nbreg == 1)) ||  
     ((natp1==P_INDEX_INDIR)&&(p1.u.index_indir.nbreg == 1)) || (natp1==P_NOMBRE)  || (natp1==P_ETIQUETTE))
      return 1;
  case P_INDIR       :
    if ((p0.u.indir.nbreg == 1)&&((natp1==P_NOMREG) && (EstReg16(p1.u.nomreg))))
      return 1;
  case P_INDEX_INDIR :
    if ((p0.u.index_indir.nbreg == 1)&&((natp1==P_NOMREG) && (EstReg16(p1.u.nomreg))))
      return 1;
  case P_NOMBRE      :
  case P_ETIQUETTE   :
    if ((natp1==P_NOMREG) && (EstReg16(p1.u.nomreg)))
      return 1;
  default:
    return 0 ;
  }
}
   
 
 
int EstModeAdInst2parL (NatParam natp0, Param p0, NatParam natp1, Param p1) {
  switch (natp0) {
  case P_NOMREG      :
    if (EstReg32(p0.u.nomreg)&&(((natp1 == P_NOMREG)&&EstReg32(p1.u.nomreg)) || ((natp1==P_INDIR)&&(p1.u.indir.nbreg == 1)) ||  
       	((natp1==P_INDEX_INDIR)&&(p1.u.index_indir.nbreg == 1)) || (natp1==P_NOMBRE)  || (natp1==P_ETIQUETTE)))
      return 1;
  case P_DOLLAR_NB   :
    if (((natp1 == P_NOMREG)&&EstReg32(p1.u.nomreg)) || ((natp1==P_INDIR)&&(p1.u.indir.nbreg == 1)) ||  
     ((natp1==P_INDEX_INDIR)&&(p1.u.index_indir.nbreg == 1)) || (natp1==P_NOMBRE)  || (natp1==P_ETIQUETTE))
      return 1;
  case P_DOLLAR_ETIQ :
    if (((natp1 == P_NOMREG)&&EstReg32(p1.u.nomreg)) || ((natp1==P_INDIR)&&(p1.u.indir.nbreg == 1)) ||  
     ((natp1==P_INDEX_INDIR)&&(p1.u.index_indir.nbreg == 1)) || (natp1==P_NOMBRE)  || (natp1==P_ETIQUETTE))
      return 1;
  case P_INDIR       :
    if ((p0.u.indir.nbreg == 1)&&((natp1==P_NOMREG) && (EstReg32(p1.u.nomreg))))
      return 1;
  case P_INDEX_INDIR :
    if ((p0.u.index_indir.nbreg == 1)&&((natp1==P_NOMREG) && (EstReg32(p1.u.nomreg))))
      return 1;
  case P_NOMBRE      :
  case P_ETIQUETTE   :
    if ((natp1==P_NOMREG) && (EstReg32(p1.u.nomreg)))
      return 1;
  default:
    return 0 ;
  }
}
   
 int EstModeAdLea (NatParam natp0, Param p0, NatParam natp1, Param p1){
   if (natp1==P_NOMREG){
     switch(natp0) {
     case P_INDIR :
       if (((p0.u.indir.nbreg == 1)&&(EstReg32(p0.u.indir.nomreg1)))&&
         ((natp1 == P_NOMREG)&&EstReg32(p1.u.indir.nomreg1)))
  return 1;
     case P_INDEX_INDIR :
       if (((p0.u.index_indir.nbreg == 1)&&EstReg32(p0.u.index_indir.nomreg1))&&
         ((natp1 == P_NOMREG)&&EstReg32(p1.u.indir.nomreg1)))
  return 1;
     case P_NOMBRE :
     case P_ETIQUETTE :
       if ((natp1==P_NOMREG) && (EstReg32(p1.u.nomreg)))  
         return 1;
     default :
       return 0;
     }
   }
 }
 
 int EstModeAdPopw (NatParam natp0, Param p0){
   switch(natp0) {
   case P_INDIR :
       if ((p0.u.indir.nbreg == 1)&&(EstReg32(p0.u.indir.nomreg1)))
  return 1;
   case P_INDEX_INDIR :
     if ((p0.u.index_indir.nbreg == 1)&&EstReg32(p0.u.index_indir.nomreg1))
       return 1;
   case P_NOMBRE :
   case P_ETIQUETTE :
     return 1;
   case P_NOMREG :
     if (EstReg16(p0.u.nomreg))
       return 1;
   default :
     return 0;
   }
 }
 
 
 
 
on va arreter la 
 
 ---------------
			
Les accents sont en option... j'ai un clavier qwertz.