Changeset 59

Show
Ignore:
Timestamp:
12/01/05 23:22:51 (3 years ago)
Author:
pragma
Message:

Simple linker and sundry fixes

- Added Dead-simple linker to source tree
- Added Build scripts to assist with building the various tests in the test suite
- Moved test code out of root and into /test
- Added Don's enhancements for compile-time signature generation!!

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/ddl/DynamicLibrary.d

    r16 r59  
    2727private import ddl.ExportSymbol; 
    2828private import ddl.DynamicModule; 
     29private import ddl.Mangle; 
    2930 
    30 interface DynamicLibrary{ 
     31abstract class DynamicLibrary{ 
    3132    public ExportSymbol[] getExports(); 
    3233    public ExportSymbol getExport(char[] name); 
    3334    public DynamicModule[] getModules(); 
     35     
     36    public void* getExportAddress(char[] name){ 
     37        return this.getExport(name).address; 
     38    } 
     39     
     40    template getField(T, char[] name) 
     41    { 
     42        T getField() { return cast(T)getExportAddress("_D" ~ mangleText!(name) ~ mangleType!(T)); } 
     43    } 
     44     
     45    template getFunction(RetT, char [] name) 
     46    { 
     47       RetT function() getFunction() { return cast(RetT function() )getExportAddress("_D" ~ mangleText!(name) ~ "F" ~ "Z" ~ mangleType!(RetT)); } 
     48    } 
     49     
     50    template getFunction(RetT, char [] name, P1) 
     51    { 
     52       RetT function(P1) getFunction() { return cast(RetT function(P1))getExportAddress("_D" ~ mangleText!(name) ~ "F" ~ mangleType!(P1) ~ "Z" ~ mangleType!(RetT)); 
     53       } 
     54    } 
     55     
     56    template getFunction(RetT, char [] name, P1, P2) 
     57    { 
     58       RetT function(P1, P2) getFunction() { return cast(RetT function(P1, P2))getExportAddress("_D" ~ 
     59       mangleText!(name) ~ "F" ~ mangleType!(P1) ~ mangleType!(P2) ~ "Z" ~ mangleType!(RetT)); 
     60       } 
     61    }    
    3462} 
  • trunk/ddl/DynamicModule.d

    r18 r59  
    2525module ddl.DynamicModule; 
    2626 
     27/** 
     28    Authors: Eric Anderton 
     29    License: BSD Derivative (see source for details) 
     30    Copyright: 2005 Eric Anderton 
     31*/ 
     32//TODO: change so that a module yields what modules namespaces it depends on, if possible. 
     33 
    2734private import ddl.ExportSymbol; 
    2835 
    29 interface DynamicModule{ 
     36/**  
     37    Represents a binary module within DDL. 
     38     
     39    Once a module is loaded, it is techncially not usable until all of its internal fixups 
     40    and external dependencies are resolved.  Resolution is performed via the resolveDependency and  
     41    resolveDependencies methods.   
     42*/ 
     43//TODO: add a way to delay the actual resolution to a separate call, as to optimize the linker 
     44abstract class DynamicModule{ 
     45     
     46    /**  
     47        Returns the name of the module. 
     48     
     49        While the result of getName() is largely compiler dependent for .asm or .c  
     50        based binary files, D compilers reliably use the file name with the '.d' file extension 
     51        for the name of the module. 
     52     
     53        Returns: the module's name 
     54    */ 
    3055    public char[] getName(); 
     56     
     57    /**  
     58        The behavior of getDependencies is somewhat obtuse: it will return only what dependencies 
     59        it presently needs in order to be resolved.  Should the module be completely resolved, 
     60        getDependencies will return null; 
     61         
     62        Returns: an array of symbols the module depends upon.        
     63         
     64        See_Also: 
     65            isResolved 
     66    */ 
    3167    public char[][] getDependencies(); 
     68     
     69    /**  
     70        Attempts to resolve a single dependency that the module may have. 
     71         
     72        Should the dependency not exist, no effect takes place.  This lazy behavior is done to help 
     73        ease runtine linking by reducing the number of checks and exceptions involved in the process. 
     74         
     75        Determining the sucess of resolving all of the module's dependencies is determined via isResolved. 
     76         
     77        Params: 
     78            x = the name of the symbol to resolve 
     79            address = the address of the external symbol 
     80    */ 
    3281    public void resolveDependency(char[] name,void* address); 
     82     
     83    /**  
     84        Attempts to resolve a single dependency that the module may have. 
     85         
     86        Should the dependency not exist, no effect takes place.  This lazy behavior is done to help 
     87        ease runtine linking by reducing the number of checks and exceptions involved in the process. 
     88         
     89        Determining the sucess of resolving all of the module's dependencies is determined via isResolved. 
     90         
     91        Params: 
     92            sym = an export to mate with a dependency in this module 
     93    */ 
     94    public void resolveDependency(ExportSymbol sym){ 
     95        this.resolveDependency(sym.name,sym.address); 
     96    } 
     97     
     98    /** 
     99        Resolves a set of dependencies that the module may have. 
     100         
     101        Similar to resolveDependency, this method attempts to resolve a series of symbols provided 
     102        in the array 'exports'.  This is provided to allow for symmetry between modules so that  
     103        resolving dependencies on a module-by-module basis is simple to perform. 
     104         
     105        Examples: 
     106        --- 
     107        DynamicModule a,b; 
     108        a.resolveDependencies(b.getExports); // attempt to satisfy a's dependencies via b's exports 
     109        --- 
     110         
     111        Params: 
     112            exports = an array of exports as provided from an external source, such as another DynamicModule 
     113        See_Also: 
     114            getExports 
     115    */ 
    33116    public void resolveDependencies(ExportSymbol[] exports); 
     117     
     118    /** 
     119        Returns the set of all exports for the module. 
     120    */ 
    34121    public ExportSymbol[] getExports(); 
     122     
     123    /** 
     124        Gets a specific export by name.  If the export does not exist, the method returns ExportSymbol.init. 
     125    */ 
    35126    public ExportSymbol getExport(char[] name); 
    36     public bit isResolved(); // do we have any exports left to resolve? 
     127     
     128    /** 
     129        Returns the current resolution state of the module. 
     130         
     131        Generally speaking, isResolved is false if there are still external symbols (dependencies to  
     132        resolve.  If all these dependencies are resolved, then isResolved returns true. 
     133         
     134        It is ill-advised to attempt to use any symbols returned from a DynamicModule in an interactive 
     135        way (binding to functions and so-forth) if the module is not completely resolved.  To do otherwise 
     136        is undefined and could easily result in a protection-fault/segmentation-fault. 
     137    */ 
     138    public bit isResolved();  
     139     
     140    /** 
     141        Determines if the module is being linked. 
     142         
     143        This field determines the current link state of the module. 
     144        It is used exclusively during link procedures as a stop-gap against revisiting the same module 
     145        during a full link. 
     146         
     147        If true, the module is being linked.  If false, the module is not being linked. 
     148    */ 
     149    public bit isLinking; 
    37150} 
    38151 
  • trunk/ddl/Linker.d

    r18 r59  
    2525module ddl.Linker; 
    2626 
    27 private import ddl.CachedLoader; 
     27/** 
     28    Authors: Eric Anderton 
     29    License: BSD Derivative (see source for details) 
     30    Copyright: 2005 Eric Anderton 
     31*/ 
     32 
     33//private import ddl.CachedLoader; 
    2834private import ddl.ExportSymbol; 
    2935private import ddl.DynamicLibrary; 
    3036private import ddl.DynamicModule; 
    3137private import ddl.LibrarySearchPath; 
    32 private import ddl.LibraryValidator; 
    33  
    34 class Linker : CachedLoader{ 
     38//private import ddl.LibraryValidator; 
     39private import ddl.Demangle; 
     40 
     41private import std.stdio; 
     42private import std.moduleinit; // used for ModuleInfo 
     43 
     44/** 
     45    Exception class used exclusively by the Linker. 
     46     
     47    LinkExceptions are generated when the linker cannot resolve a module during the linking process. 
     48*/ 
     49class LinkException : Exception{ 
     50    DynamicModule mod; 
     51     
     52    /** 
     53        Module that prompted the link exception. 
     54    */ 
     55    DynamicModule reason(){ 
     56        return this.mod; 
     57    } 
     58     
     59    /** 
     60        Default constructor. 
     61         
     62        Params: 
     63            reason = the module that prompts the exception 
     64    */ 
     65    public this(DynamicModule reason){ 
     66        super("LinkException: '" ~ reason.getName ~ "'"); 
     67        this.mod = reason; 
     68    } 
     69
     70 
     71 
     72/** 
     73    General-Purpose runtime linker for DDL. 
     74*/ 
     75class Linker{    
     76    /**  
     77        Library list for libraries used for linking. 
     78         
     79        The order of insertion into the library list is used as a priority scheme 
     80        when attempting to link new modules into the runtime.  The first library  
     81        added to the linker should be the current in-situ library, should linking 
     82        to classes and types in the current runtime be a requirement.  In any case 
     83        the next candidates for addition to the linker should be the runtime libraries 
     84        in no particular order. 
     85         
     86        The linker will attept to link against the first library first, and so on 
     87        down the list. 
     88    */ 
     89    public DynamicLibrary[] libraries; 
     90     
     91    /**  
     92        Default constructor. 
     93    */ 
    3594    public this(){ 
    36         super(); 
    37     } 
    38  
    39     public this(LibrarySearchPath searchPath){ 
    40         super(searchPath); 
    41     } 
    42      
    43     public this(LibrarySearchPath searchPath,LibraryValidator validator){ 
    44         super(searchPath,validator); 
    45     } 
    46      
    47     /** Overrides default behavior of just pulling in the library from the parent. 
    48         The library is loaded and its publics are serviced to all the other libs. 
    49         Then, the dependencies are gathered from the cache and fixed up. 
    50         Finally the library is returned. 
    51          
    52         TODO: this is patently non-threadsafe. 
    53         TODO: enhance this with namespace-based scoping and searching 
    54     */ 
    55     protected DynamicLibrary loadNewLibrary(char[] filename){ 
    56         DynamicLibrary newLib = super.loadNewLibrary(filename); 
    57          
    58         foreach(DynamicModule newMod; newLib.getModules()){ 
    59             foreach(DynamicLibrary oldLib; super.cache){ 
    60                 foreach(DynamicModule oldMod; oldLib.getModules()){ 
    61                     if(!oldMod.isResolved()){ 
    62                         oldMod.resolveDependencies(newMod.getExports()); 
    63                     } 
    64                     if(!newMod.isResolved()){ 
    65                         newMod.resolveDependencies(oldMod.getExports()); 
     95        // do nothing 
     96    } 
     97     
     98    /** 
     99        Adds a library to the linker to be used during link operations. 
     100         
     101        Modules are included into the internal cross-reference only if they are D modules. 
     102    */ 
     103    void add(DynamicLibrary lib){ 
     104        foreach(DynamicModule mod; lib.getModules){ 
     105            writefln("add: %s",mod.getName); 
     106        } 
     107        libraries ~= lib; 
     108    } 
     109     
     110    /** 
     111        Initalizes a ModuleInfo instance from a DynamicModule. 
     112    */ 
     113    protected void initModule(ModuleInfo m, int skip){ 
     114        if(!m) return; 
     115        if (m.flags & MIctordone) return; 
     116         
     117        debug printf("Module: %.*s %0.8X\n",m.name,m); 
     118        if (m.ctor || m.dtor) 
     119        { 
     120            if (m.flags & MIctorstart) 
     121            {   if (skip) 
     122                return; 
     123            throw new ModuleCtorError(m); 
     124            } 
     125            m.flags |= MIctorstart; 
     126            foreach(ModuleInfo imported; m.importedModules){ 
     127                initModule(imported,0); 
     128            } 
     129            if (m.ctor) 
     130            (*m.ctor)(); 
     131            m.flags &= ~MIctorstart; 
     132            m.flags |= MIctordone; 
     133     
     134            //TODO: Now that construction is done, register the destructor 
     135        } 
     136        else 
     137        { 
     138            m.flags |= MIctordone; 
     139            foreach(ModuleInfo imported; m.importedModules){ 
     140                initModule(imported,1); 
     141            } 
     142        }     
     143    } 
     144     
     145    /** 
     146        Links a module against the linker's internal cross-reference. 
     147         
     148        This implementation performs a long search of modules, then discrete symbols in the 
     149        cross-reference. 
     150    */ 
     151    public void link(DynamicModule mod){ 
     152        //protect against infinite recursion here by returning early 
     153        //by this, we count on the module being resolved further up the call stack 
     154        if(mod.isLinking) return; 
     155         
     156        mod.isLinking = true; 
     157         
     158        foreach(char[] dep; mod.getDependencies){ 
     159            ExportSymbol sym = ExportSymbol.init; 
     160            foreach(DynamicLibrary lib; this.libraries){ 
     161                foreach(DynamicModule libMod; lib.getModules){ 
     162                    sym = libMod.getExport(dep); 
     163                    if(sym != ExportSymbol.init){ 
     164                        if(!libMod.isResolved()){ 
     165                            this.link(libMod); 
     166                        } 
     167                        mod.resolveDependency(sym); 
     168                        goto nextDep; // why keep looping? get the heck out -- we're done! 
    66169                    } 
    67170                } 
    68171            } 
    69         } 
    70          
    71         return newLib; // return the new library so it may be added to the cache by the superclass 
     172            nextDep: 
     173            if(sym == ExportSymbol.init){ 
     174                writefln("cannot find %s",dep); 
     175            } 
     176        } 
     177        //TODO: possible mod.resolveInternals() call here. 
     178        mod.isLinking = false; 
     179         
     180        if(!mod.isResolved()){ 
     181            throw new LinkException(mod); 
     182        } 
     183         
     184        // dig up the ModuleInfo (if applicable) and initalize it! 
     185        foreach(ExportSymbol sym; mod.getExports){ 
     186            if(getSymbolType(sym.name) == SymbolType.ModuleInfo){ 
     187                // found it, now get it and run the constructor 
     188                ModuleInfo moduleInfo = cast(ModuleInfo)(sym.address); 
     189                initModule(moduleInfo,0); 
     190            } 
     191        } 
     192    } 
     193     
     194    /** 
     195        Links a library against the linker's internal cross-reference. 
     196         
     197        There is a subtle difference between linking a lib and linking a lib that has been 
     198        added to the cross-reference.  If every module in the lib is merely dependent upon 
     199        modules that exist in the cross-reference already, then just calling link will do  
     200        the task.  Otherwise, the lib should be added to the cross-reference first, before 
     201        proceeding with the actual link. 
     202         
     203        Exmaples: 
     204        --- 
     205        DynamicLibrary lib; 
     206        Linker linker; 
     207         
     208        linker.add(lib); // add to xref first 
     209        linker.link(lib); // link in the library and its aggregate modules 
     210        --- 
     211    */ 
     212    public void link(DynamicLibrary lib){ 
     213        foreach(DynamicModule mod; lib.getModules){ 
     214            this.link(mod); 
     215        } 
    72216    } 
    73217} 
  • trunk/ddl/insitu/InSituModule.d

    r27 r59  
    6161     
    6262    public ExportSymbol getExport(char[] name){ 
    63         return exports[name]; 
     63        if(name in exports) return exports[name]; 
     64        else return ExportSymbol.init; 
    6465    } 
    6566     
  • trunk/ddl/omf/OMFModule.d

    r46 r59  
    7979     
    8080    public ExportSymbol getExport(char[] name){ 
    81         return exports[name]; 
     81        if(name in exports) return exports[name]; 
     82        else return ExportSymbol.init; 
    8283    } 
    8384