home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <ctype.h>
- #include "tool.h"
- #include "link.h"
- #include <sys/types.h>
- #include <fcntl.h>
- #include <unistd.h>
-
- #define ALLOC_MODULE 5000
-
- /*
- * Check if the module is an a.out module, so that we can skip
- * the first '_'. We now use a unified ELF-like symbol table format
- */
- static int is_a_out(const char *objname) // 1 == a.out, 0 == ELF
- {
- int fd;
- char buf[4];
- int a_out = 1; //if open fails, the following call to mod_open fails too
-
- if ((fd = open(objname, O_RDONLY)) > 0) {
- if (read(fd, buf, 4) == 4) {
- if (buf[0] == 0177 && strncmp(buf +1, "ELF", 3) == 0)
- a_out = 0;
- }
- close(fd);
- }
-
- return a_out;
- }
-
- /*
- Ouvre le fichier et retourne NULL si erreur.
- */
- static FILE *module_open (const char *objname)
- {
- FILE *ret = NULL;
- struct stat buf;
- if (stat (objname,&buf) != -1){
- char cmd[300];
- sprintf (cmd,"nm -pg %s",objname);
- ret = popen_err (cmd,"r",0);
- }else{
- depmod_error ("%s does not exist",objname);
- }
- return ret;
- }
- /*
- Gère la liste de tous les modules rencontré durant le link
- */
- PUBLIC MODULES::MODULES()
- {
- /* #Spécification: librairies / nombre maximum
- Un nombre maximum de 255 librairie est permis pour le link
- */
- tblibs = (char**)malloc_err (255*sizeof(char*),1);
- nblib = 0;
- tbmod = (MODULE*)malloc_err (ALLOC_MODULE*sizeof(MODULE),1);
- nbmod = 0;
- }
-
- /*
- Finalise l'information sur un module.
- */
- PRIVATE void MODULES::setmod (
- MODULE *mod,
- SYMBOL *tbpub[],
- int nbpub,
- SYMBOL *tbext[],
- int nbext,
- int module_requis)
- {
- mod->is_load = module_requis;
- mod->pub.nb = nbpub;
- mod->ext.nb = nbext;
- if (nbpub > 0){
- int size = nbpub*sizeof(SYMBOL*);
- mod->pub.tb = (SYMBOL**)malloc_err(size,1);
- memcpy (mod->pub.tb,tbpub,size);
- }else{
- mod->pub.tb = NULL;
- }
- if (nbext > 0){
- int size = nbext*sizeof(SYMBOL*);
- mod->ext.tb = (SYMBOL**)malloc_err(size,1);
- memcpy (mod->ext.tb,tbext,size);
- if (module_requis){
- SYMBOL **ptext = mod->ext.tb;
- for (int i=0; i<nbext; i++,ptext++) (*ptext)->requis = 1;
- }
- }else{
- mod->ext.tb = NULL;
- }
- }
- /*
- Create a module entry in the list of module.
- This module generally do not is not related to any real file.
- */
-
- PUBLIC MODULE *MODULES::setdummy (const char *name)
- {
- MODULE *mod = tbmod+nbmod++;
- mod->name = alloctxt_add (name);
- mod->lib = -1;
- mod->is_load = 0;
- mod->pub.nb = mod->ext.nb = 0;
- mod->ext.tb = NULL;
- mod->pub.tb = NULL;
- return mod;
- }
- /*
- Lit les symboles d'un objet et enregistre dans syms
- Retourne -1 si erreur.
- */
- PUBLIC int MODULES::loadobj(SYMBOLS &syms, const char *objname)
- {
- int ret = -1;
- int a_out = is_a_out(objname); // 1 == a.out, 0 == ELF
- FILE *fin = module_open (objname);
- if (fin != NULL){
- MODULE *mod = tbmod+nbmod++;
- ret = 0;
- mod->name = alloctxt_add (objname);
- mod->lib = -1;
- SYMBOL *tbext[5000];
- int nbext = 0;
- SYMBOL *tbpub[5000];
- int nbpub = 0;
- int module_requis=0;
- char rbuf[200];
- while (fgets(rbuf,sizeof(rbuf)-1,fin)!=NULL){
- char buf[200];
- str_strip (rbuf,buf);
- // skip leading '_' for a.out modules
- char *name = buf+11 + a_out;
- if (buf[0] == ' '){
- tbext[nbext++] = syms.add (name,NULL,SYM_REQUIS
- ,module_requis,0);
- }else if (isdigit(buf[0])){
- tbpub[nbpub++] = syms.add (name,mod,SYM_DEFINI
- ,module_requis,buf[9] == 'C');
- }else{
- break;
- }
- }
- pclose (fin);
- setmod (mod,tbpub,nbpub,tbext,nbext,1);
- }
- return ret;
- }
-
- /*
- Lit les symboles d'un objet et enregistre dans syms
- Retourne -1 si erreur.
- */
- PUBLIC int MODULES::loadlib(SYMBOLS &syms, const char *libname)
- {
- int ret = -1;
- FILE *fin = module_open (libname);
- if (fin != NULL){
- int nolib = nblib;
- tblibs[nblib++] = alloctxt_add (libname);
- char buf[200];
- ret = 0;
- int module_requis = 0;
- MODULE *mod = NULL;
- SYMBOL *tbext[5000];
- int nbext = 0;
- SYMBOL *tbpub[5000];
- int nbpub = 0;
- while (fgets(buf,sizeof(buf)-1,fin)!=NULL){
- str_strip (buf,buf);
- char *name = buf+11;
- if (buf[0] == ' '){
- tbext[nbext++] = syms.add (name,NULL,SYM_PASUTIL,module_requis,0);
- }else{
- int len = strlen(buf);
- if (len > 0){
- if (buf[len-1] == ':'){
- // On commence un nouveau module
- if (nbpub + nbext > 0){
- setmod (mod,tbpub,nbpub,tbext,nbext,module_requis);
- }
- mod = tbmod+nbmod++;
- mod->name = alloctxt_add (buf);
- mod->lib = nolib;
- mod->is_load = 0;
- module_requis = 0;
- nbpub = 0;
- nbext = 0;
- }else if (isdigit(buf[0])){
- tbpub[nbpub++] = syms.add (name,mod,SYM_DEFINI
- ,module_requis,buf[9] == 'C');
- }else{
- break;
- }
- }
- }
- }
- if (nbpub + nbext > 0){
- setmod (mod,tbpub,nbpub,tbext,nbext,module_requis);
- }
- pclose (fin);
- }
- return ret;
-
- }
-
- /*
- Trouve les symboles qui doivent être requis d'avance pour eviter un
- link multi-passe.
-
- Retourne le nombre de passe requise.
- */
- PUBLIC int MODULES::multipass ()
- {
- int ret = 0;
- int trouve;
- do {
- ret++;
- trouve = 0;
- MODULE *ptmod = tbmod;
- for (int i=0; i<nbmod; i++, ptmod++){
- if (!ptmod->is_load){
- /* #Spécification: etrangeté
- Pour fabriquer la table de résolution évitant un
- link multi-passe, on doit recueillir un symbole
- par module qui ne serait pas chargé dès la première
- passe.
-
- Lorsqu'un module est chargé par ccld, si au moins
- un de ses symboles publiques est déjà requis par
- un module précédant lui-même implicitement requis,
- alors ce module sera aussi requis en une passe.
-
- A la fin, les modules non-requis, mais contenant
- des symboles requis sont forcés. Les symboles
- externes de ce module deviennent requis (forceant
- probablement d'autre modules).
-
- Pour "forcer" un module, on fabrique un source C
- temporaire qui référencera un des symboles publiques
- du module.
-
- Une étrangeté: On essai de ne pas choisir de symbole
- publique de type "common" parce qu'il ne semble
- pas très apte à "forcer" le module.
- */
- SYMBOL **ptpub = ptmod->pub.tb;
- int nbpub = ptmod->pub.nb;
- for (int p=0; p<nbpub; p++, ptpub++){
- if ((*ptpub)->requis){
- // Au moins un public est requis. Donc tous les externes
- // le sont aussi.
- ptmod->is_load = 1;
- trouve = 1;
- // Recherche le premier symbole non common !!!
- ptpub = ptmod->pub.tb;
- for (p = 0; p<nbpub; p++, ptpub++){
- if (!(*ptpub)->is_common){
- (*ptpub)->force = 1;
- break;
- }
- }
- if (p == nbpub){
- // Il n'y a que des common dans ce module
- // on force le premier.
- ptmod->pub.tb[0]->force = 1;
- }
- SYMBOL **ptext = ptmod->ext.tb;
- int nbext = ptmod->ext.nb;
- for (int e=0; e<nbext; e++, ptext++){
- (*ptext)->requis = 1;
- }
- break;
- }
- }
- }
- }
- }while (trouve == 1);
- return ret;
- }
- /*
- Affiche la liste des modules qui necessite un symbole (indefini).
- */
- PUBLIC void MODULES::showundef (SYMBOL *undef, FILE *fout)
- {
- MODULE *ptmod = tbmod;
- int nb = 0;
- for (int i=0; i<nbmod; i++, ptmod++){
- if (ptmod->is_load){
- SYMBOL **ptext = ptmod->ext.tb;
- int nbext = ptmod->ext.nb;
- for (int e=0; e<nbext; e++, ptext++){
- if (*ptext == undef){
- if (nb == 0){
- fprintf (fout,"\t%s\n",undef->name);
- nb = 1;
- }
- if (ptmod->lib == -1){
- fprintf (fout,"\t %s\n",ptmod->name);
- }else{
- fprintf (fout,"\t %s(%s)\n",ptmod->name
- ,tblibs[ptmod->lib]);
- }
- break;
- }
- }
- }
- }
- }
- /*
- Affiche la liste des symboles non définies.
- Retourne le nombre trouvé ou 0 si ok.
- */
- PUBLIC int MODULES::findundef (FILE *fout)
- {
- MODULE *ptmod = tbmod;
- int ret = 0;
- for (int i=0; i<nbmod; i++, ptmod++){
- if (ptmod->is_load){
- SYMBOL **ptext = ptmod->ext.tb;
- int nbext = ptmod->ext.nb;
- for (int e=0; e<nbext; e++, ptext++){
- if (!(*ptext)->defini){
- if (ret == 0){
- fprintf (fout,"Undefined symbols:\n");
- }
- showundef (*ptext,fout);
- (*ptext)->defini = 1; // Evite de rementionner
- // le symbole
- ret++;
- }
- }
- }
- }
- return ret;
- }
-
- /*
- Affiche la liste des modules qui seront inclus dans l'exécutable
- Retourne le nombre de modules trouvés.
- */
- PUBLIC int MODULES::showload (FILE *fout)
- {
- MODULE *ptmod = tbmod;
- int ret = 0;
- for (int i=0; i<nbmod; i++, ptmod++){
- if (ptmod->is_load){
- ret++;
- fprintf (fout,"%s ",ptmod->name);
- }
- }
- if (ret) fprintf (fout,"\n");
- return ret;
- }
-
- /*
- Affiche la liste de tous les modules en mémoire. Utilisé pour débug
- */
- PUBLIC void MODULES::showall (FILE *fout)
- {
- MODULE *ptmod = tbmod;
- for (int i=0; i<nbmod; i++, ptmod++){
- fprintf (fout,"%s %d\n",ptmod->name,ptmod->is_load);
- SYMBOL **ptpub = ptmod->pub.tb;
- int nbpub = ptmod->pub.nb;
- for (int e=0; e<nbpub; e++, ptpub++){
- SYMBOL *ptsym = *ptpub;
- fprintf (fout,"\tT %s %d %d %d %d %d\n",ptsym->name,ptsym->requis
- ,ptsym->defini,ptsym->vue_avant
- ,ptsym->is_common,ptsym->force);
- }
- SYMBOL **ptext = ptmod->ext.tb;
- int nbext = ptmod->ext.nb;
- for (e=0; e<nbext; e++, ptext++){
- fprintf (fout,"\tU %s %d\n",(*ptext)->name,(*ptext)->defini);
- }
- }
- }
-
- #ifdef TEST
-
- int main (int argc, char *argv[])
- {
- if (argc > 1){
- SYMBOLS syms;
- MODULES mods;
- for (int i=1; i<argc; i++){
- char *arg = argv[i];
- char ext[MAXSIZ_EXTENSION];
- file_baseext (arg,NULL,ext);
- if (strcmp(ext,"a")==0){
- mods.loadlib (syms,arg);
- }else{
- mods.loadobj (syms,arg);
- }
- }
- int pass = mods.multipass();
- printf ("Nombre de passe requise = %d\n",pass);
- int undef = mods.findundef (stdout);
- printf ("Nombre de undef %d\n",undef);
- char *tb[10000];
- int nbforce = syms.findforce (tb,10000);
- printf ("nbforce = %d\n",nbforce);
- int nbload = mods.showload (stdout);
- printf ("nbload = %d\n",nbload);
- //syms.dump(stdout);
- }
- return 0;
- }
-
- #endif
-
-