home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / a / bin / modules-.2 / modules- / modules-1.2.8 / depmod / module.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-30  |  9.6 KB  |  417 lines

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <sys/stat.h>
  4. #include <ctype.h>
  5. #include "tool.h"
  6. #include "link.h"
  7. #include <sys/types.h>
  8. #include <fcntl.h>
  9. #include <unistd.h>
  10.  
  11. #define ALLOC_MODULE    5000
  12.  
  13.  /*
  14.   * Check if the module is an a.out module, so that we can skip
  15.   * the first '_'. We now use a unified ELF-like symbol table format
  16.   */
  17. static int is_a_out(const char *objname) // 1 == a.out, 0 == ELF
  18. {
  19.     int fd;
  20.     char buf[4];
  21.     int a_out = 1; //if open fails, the following call to mod_open fails too
  22.  
  23.     if ((fd = open(objname, O_RDONLY)) > 0) {
  24.         if (read(fd, buf, 4) == 4) {
  25.             if (buf[0] == 0177 && strncmp(buf +1, "ELF", 3) == 0)
  26.                 a_out = 0;
  27.         }
  28.         close(fd);
  29.     }
  30.  
  31.     return a_out;
  32. }
  33.  
  34. /*
  35.     Ouvre le fichier et retourne NULL si erreur.
  36. */
  37. static FILE *module_open (const char *objname)
  38. {
  39.     FILE *ret = NULL;
  40.     struct stat buf;
  41.     if (stat (objname,&buf) != -1){
  42.         char cmd[300];
  43.         sprintf (cmd,"nm -pg %s",objname);
  44.         ret = popen_err (cmd,"r",0);
  45.     }else{
  46.         depmod_error ("%s does not exist",objname);
  47.     }
  48.     return ret;
  49. }
  50. /*
  51.     Gère la liste de tous les modules rencontré durant le link
  52. */
  53. PUBLIC MODULES::MODULES()
  54. {
  55.     /* #Spécification: librairies / nombre maximum
  56.         Un nombre maximum de 255 librairie est permis pour le link
  57.     */
  58.     tblibs = (char**)malloc_err (255*sizeof(char*),1);
  59.     nblib = 0;
  60.     tbmod = (MODULE*)malloc_err (ALLOC_MODULE*sizeof(MODULE),1);
  61.     nbmod = 0;
  62. }
  63.  
  64. /*
  65.     Finalise l'information sur un module.
  66. */
  67. PRIVATE void MODULES::setmod (
  68.     MODULE *mod,
  69.     SYMBOL *tbpub[],
  70.     int nbpub,
  71.     SYMBOL *tbext[],
  72.     int nbext,
  73.     int module_requis)
  74. {
  75.     mod->is_load = module_requis;
  76.     mod->pub.nb = nbpub;
  77.     mod->ext.nb = nbext;
  78.     if (nbpub > 0){
  79.         int size = nbpub*sizeof(SYMBOL*);
  80.         mod->pub.tb = (SYMBOL**)malloc_err(size,1);
  81.         memcpy (mod->pub.tb,tbpub,size);
  82.     }else{
  83.         mod->pub.tb = NULL;
  84.     }
  85.     if (nbext > 0){
  86.         int size = nbext*sizeof(SYMBOL*);
  87.         mod->ext.tb = (SYMBOL**)malloc_err(size,1);
  88.         memcpy (mod->ext.tb,tbext,size);
  89.         if (module_requis){
  90.             SYMBOL **ptext = mod->ext.tb;
  91.             for (int i=0; i<nbext; i++,ptext++) (*ptext)->requis = 1;
  92.         }
  93.     }else{
  94.         mod->ext.tb = NULL;
  95.     }
  96. }
  97. /*
  98.     Create a module entry in the list of module.
  99.     This module generally do not is not related to any real file.
  100. */
  101.  
  102. PUBLIC MODULE *MODULES::setdummy (const char *name)
  103. {
  104.     MODULE *mod = tbmod+nbmod++;
  105.      mod->name = alloctxt_add (name);
  106.     mod->lib = -1;
  107.     mod->is_load = 0;
  108.     mod->pub.nb = mod->ext.nb = 0;
  109.     mod->ext.tb = NULL;
  110.     mod->pub.tb = NULL;
  111.     return mod;
  112. }
  113. /*
  114.     Lit les symboles d'un objet et enregistre dans syms
  115.     Retourne -1 si erreur.
  116. */
  117. PUBLIC int MODULES::loadobj(SYMBOLS &syms, const char *objname)
  118. {
  119.     int ret = -1;
  120.     int a_out = is_a_out(objname); // 1 == a.out, 0 == ELF
  121.     FILE *fin = module_open (objname);
  122.     if (fin != NULL){
  123.         MODULE *mod = tbmod+nbmod++;
  124.         ret = 0;
  125.          mod->name = alloctxt_add (objname);
  126.         mod->lib = -1;
  127.         SYMBOL *tbext[5000];
  128.         int nbext = 0;
  129.         SYMBOL *tbpub[5000];
  130.         int nbpub = 0;
  131.         int module_requis=0;
  132.         char rbuf[200];
  133.         while (fgets(rbuf,sizeof(rbuf)-1,fin)!=NULL){
  134.             char buf[200];
  135.             str_strip (rbuf,buf);
  136.             // skip leading '_' for a.out modules
  137.             char *name = buf+11 + a_out;
  138.             if (buf[0] == ' '){
  139.                 tbext[nbext++] = syms.add (name,NULL,SYM_REQUIS
  140.                     ,module_requis,0);
  141.             }else if (isdigit(buf[0])){
  142.                 tbpub[nbpub++] = syms.add (name,mod,SYM_DEFINI
  143.                     ,module_requis,buf[9] == 'C');
  144.             }else{
  145.                 break;
  146.             }
  147.         }
  148.         pclose (fin);
  149.         setmod (mod,tbpub,nbpub,tbext,nbext,1);
  150.     }
  151.     return ret;
  152. }
  153.  
  154. /*
  155.     Lit les symboles d'un objet et enregistre dans syms
  156.     Retourne -1 si erreur.
  157. */
  158. PUBLIC int MODULES::loadlib(SYMBOLS &syms, const char *libname)
  159. {
  160.     int ret = -1;
  161.     FILE *fin = module_open (libname);
  162.     if (fin != NULL){
  163.         int nolib = nblib;
  164.         tblibs[nblib++] = alloctxt_add (libname);
  165.         char buf[200];
  166.         ret = 0;
  167.         int module_requis = 0;
  168.         MODULE *mod = NULL;
  169.         SYMBOL *tbext[5000];
  170.         int nbext = 0;
  171.         SYMBOL *tbpub[5000];
  172.         int nbpub = 0;
  173.         while (fgets(buf,sizeof(buf)-1,fin)!=NULL){
  174.             str_strip (buf,buf);
  175.             char *name = buf+11;
  176.             if (buf[0] == ' '){
  177.                 tbext[nbext++] = syms.add (name,NULL,SYM_PASUTIL,module_requis,0);
  178.             }else{
  179.                 int len = strlen(buf);
  180.                 if (len > 0){
  181.                     if (buf[len-1] == ':'){
  182.                         // On commence un nouveau module
  183.                         if (nbpub + nbext > 0){
  184.                             setmod (mod,tbpub,nbpub,tbext,nbext,module_requis);
  185.                         }
  186.                         mod = tbmod+nbmod++;
  187.                          mod->name = alloctxt_add (buf);
  188.                         mod->lib = nolib;
  189.                         mod->is_load = 0;
  190.                         module_requis = 0;
  191.                         nbpub = 0;
  192.                         nbext = 0;
  193.                     }else if (isdigit(buf[0])){
  194.                         tbpub[nbpub++] = syms.add (name,mod,SYM_DEFINI
  195.                             ,module_requis,buf[9] == 'C');
  196.                     }else{
  197.                         break;
  198.                     }
  199.                 }
  200.             }
  201.         }
  202.         if (nbpub + nbext > 0){
  203.             setmod (mod,tbpub,nbpub,tbext,nbext,module_requis);
  204.         }
  205.         pclose (fin);
  206.     }
  207.     return ret;
  208.     
  209. }
  210.  
  211. /*
  212.     Trouve les symboles qui doivent être requis d'avance pour eviter un
  213.     link multi-passe.
  214.  
  215.     Retourne le nombre de passe requise.
  216. */
  217. PUBLIC int MODULES::multipass ()
  218. {
  219.     int ret = 0;
  220.     int trouve;
  221.     do {
  222.         ret++;
  223.         trouve = 0;
  224.         MODULE *ptmod = tbmod;
  225.         for (int i=0; i<nbmod; i++, ptmod++){
  226.             if (!ptmod->is_load){
  227.                 /* #Spécification: etrangeté
  228.                     Pour fabriquer la table de résolution évitant un
  229.                     link multi-passe, on doit recueillir un symbole
  230.                     par module qui ne serait pas chargé dès la première
  231.                     passe.
  232.  
  233.                     Lorsqu'un module est chargé par ccld, si au moins
  234.                     un de ses symboles publiques est déjà requis par
  235.                     un module précédant lui-même implicitement requis,
  236.                     alors ce module sera aussi requis en une passe.
  237.  
  238.                     A la fin, les modules non-requis, mais contenant
  239.                     des symboles requis sont forcés. Les symboles
  240.                     externes de ce module deviennent requis (forceant
  241.                     probablement d'autre modules).
  242.  
  243.                     Pour "forcer" un module, on fabrique un source C
  244.                     temporaire qui référencera un des symboles publiques
  245.                     du module.
  246.  
  247.                     Une étrangeté: On essai de ne pas choisir de symbole
  248.                     publique de type "common" parce qu'il ne semble
  249.                     pas très apte à "forcer" le module.
  250.                 */
  251.                 SYMBOL **ptpub = ptmod->pub.tb;
  252.                 int nbpub = ptmod->pub.nb;
  253.                 for (int p=0; p<nbpub; p++, ptpub++){
  254.                     if ((*ptpub)->requis){
  255.                         // Au moins un public est requis. Donc tous les externes
  256.                         // le sont aussi.
  257.                         ptmod->is_load = 1;
  258.                         trouve = 1;
  259.                         // Recherche le premier symbole non common !!!
  260.                         ptpub = ptmod->pub.tb;
  261.                         for (p = 0; p<nbpub; p++, ptpub++){
  262.                             if (!(*ptpub)->is_common){
  263.                                 (*ptpub)->force = 1;
  264.                                 break;
  265.                             }
  266.                         }
  267.                         if (p == nbpub){
  268.                             // Il n'y a que des common dans ce module
  269.                             // on force le premier.
  270.                             ptmod->pub.tb[0]->force = 1;
  271.                         }
  272.                         SYMBOL **ptext = ptmod->ext.tb;
  273.                         int nbext = ptmod->ext.nb;
  274.                         for (int e=0; e<nbext; e++, ptext++){
  275.                             (*ptext)->requis = 1;
  276.                         }
  277.                         break;
  278.                     }
  279.                 }
  280.             }
  281.         }
  282.     }while (trouve == 1);
  283.     return ret;
  284. }
  285. /*
  286.     Affiche la liste des modules qui necessite un symbole (indefini).
  287. */
  288. PUBLIC void MODULES::showundef (SYMBOL *undef, FILE *fout)
  289. {
  290.     MODULE *ptmod = tbmod;
  291.     int nb = 0;
  292.     for (int i=0; i<nbmod; i++, ptmod++){
  293.         if (ptmod->is_load){
  294.             SYMBOL **ptext = ptmod->ext.tb;
  295.             int nbext = ptmod->ext.nb;
  296.             for (int e=0; e<nbext; e++, ptext++){
  297.                 if (*ptext == undef){
  298.                     if (nb == 0){
  299.                         fprintf (fout,"\t%s\n",undef->name);
  300.                         nb = 1;
  301.                     }
  302.                     if (ptmod->lib == -1){
  303.                         fprintf (fout,"\t    %s\n",ptmod->name);
  304.                     }else{
  305.                         fprintf (fout,"\t    %s(%s)\n",ptmod->name
  306.                             ,tblibs[ptmod->lib]);
  307.                     }
  308.                     break;
  309.                 }
  310.             }
  311.         }
  312.     }
  313. }
  314. /*
  315.     Affiche la liste des symboles non définies.
  316.     Retourne le nombre trouvé ou 0 si ok.
  317. */
  318. PUBLIC int MODULES::findundef (FILE *fout)
  319. {
  320.     MODULE *ptmod = tbmod;
  321.     int ret = 0;
  322.     for (int i=0; i<nbmod; i++, ptmod++){
  323.         if (ptmod->is_load){
  324.             SYMBOL **ptext = ptmod->ext.tb;
  325.             int nbext = ptmod->ext.nb;
  326.             for (int e=0; e<nbext; e++, ptext++){
  327.                 if (!(*ptext)->defini){
  328.                     if (ret == 0){
  329.                         fprintf (fout,"Undefined symbols:\n");
  330.                     }
  331.                     showundef (*ptext,fout);
  332.                     (*ptext)->defini = 1;    // Evite de rementionner
  333.                                             // le symbole
  334.                     ret++;
  335.                 }
  336.             }
  337.         }
  338.     }
  339.     return ret;
  340. }
  341.  
  342. /*
  343.     Affiche la liste des modules qui seront inclus dans l'exécutable
  344.     Retourne le nombre de modules trouvés.
  345. */
  346. PUBLIC int MODULES::showload (FILE *fout)
  347. {
  348.     MODULE *ptmod = tbmod;
  349.     int ret = 0;
  350.     for (int i=0; i<nbmod; i++, ptmod++){
  351.         if (ptmod->is_load){
  352.             ret++;
  353.             fprintf (fout,"%s ",ptmod->name);
  354.         }
  355.     }
  356.     if (ret) fprintf (fout,"\n");
  357.     return ret;
  358. }
  359.  
  360. /*
  361.     Affiche la liste de tous les modules en mémoire. Utilisé pour débug
  362. */
  363. PUBLIC void MODULES::showall (FILE *fout)
  364. {
  365.     MODULE *ptmod = tbmod;
  366.     for (int i=0; i<nbmod; i++, ptmod++){
  367.         fprintf (fout,"%s %d\n",ptmod->name,ptmod->is_load);
  368.         SYMBOL **ptpub = ptmod->pub.tb;
  369.         int nbpub = ptmod->pub.nb;
  370.         for (int e=0; e<nbpub; e++, ptpub++){
  371.             SYMBOL *ptsym = *ptpub;
  372.             fprintf (fout,"\tT %s %d %d %d %d %d\n",ptsym->name,ptsym->requis
  373.                 ,ptsym->defini,ptsym->vue_avant
  374.                 ,ptsym->is_common,ptsym->force);
  375.         }
  376.         SYMBOL **ptext = ptmod->ext.tb;
  377.         int nbext = ptmod->ext.nb;
  378.         for (e=0; e<nbext; e++, ptext++){
  379.             fprintf (fout,"\tU %s %d\n",(*ptext)->name,(*ptext)->defini);
  380.         }
  381.     }
  382. }
  383.  
  384. #ifdef TEST
  385.  
  386. int main (int argc, char *argv[])
  387. {
  388.     if (argc > 1){
  389.         SYMBOLS syms;
  390.         MODULES mods;
  391.         for (int i=1; i<argc; i++){
  392.             char *arg = argv[i];
  393.             char ext[MAXSIZ_EXTENSION];
  394.             file_baseext (arg,NULL,ext);
  395.             if (strcmp(ext,"a")==0){
  396.                 mods.loadlib (syms,arg);
  397.             }else{
  398.                 mods.loadobj (syms,arg);
  399.             }
  400.         }
  401.         int pass = mods.multipass();
  402.         printf ("Nombre de passe requise = %d\n",pass);
  403.         int undef = mods.findundef (stdout);
  404.         printf ("Nombre de undef %d\n",undef);
  405.         char *tb[10000];
  406.         int nbforce = syms.findforce (tb,10000);
  407.         printf ("nbforce = %d\n",nbforce);
  408.         int nbload = mods.showload (stdout);
  409.         printf ("nbload = %d\n",nbload);
  410.         //syms.dump(stdout);
  411.     }
  412.     return 0;
  413. }
  414.  
  415. #endif
  416.  
  417.