Announcement

Collapse
No announcement yet.

Real World Small DLL ?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Real World Small DLL ?

    I have started a new topic as the last one was getting a bit long.
    Phillipe was kind enough to build a test piece in what I think was
    Microsoft C/C++ to compare the compiled size against a PowerBASIC and MASM
    DLL.

    Both Eric and Phillipe expressed some doubt that DLLs built at there
    minimum size were any use as an indicator to the efficiency of the
    compiler used and that "real world" examples would probably expand at much
    the same rate.

    What follows is a DLL written in PowerBASIC that uses API file IO, it has
    initialised the PowerBASIC string engine and has an encryption function
    written in inline asm, things that PowerBASIC can mix with ease.

    With thanks to Eric for the piece of genius about the wrapper functions in
    the win32api.inc file, the minimum DLL size built at 4608 bytes. The
    following DLL code builds at 6144 bytes excluding the same set of wrappers
    which is roughly 1500 bytes of code added for initialising the string
    engine in PowerBASIC, the API calls and the inline asm function.

    The DLL has a single callable function that opens a file, encrypts it and
    writes it back to disk. The encryption technique is an XOR type that uses
    a variable length key as the source of the XOR extra byte and it reads the
    key in ascending order until it reaches the end and then it returns to the
    beginning and does it again.

    Call it once with a key text of any length and it will encrypt the file,
    call it again with the identical key and it will restore the file to
    original. I would not keep state secrets encrypted with this technique but
    it will stop all but the very serious encryption cracker.

    Regards,

    [email protected]

    Code:
      
    The DECLARATION for the DLL function is as follows,
      
        DECLARE FUNCTION EncryptFile lib "encrypt.dll" ALIAS "EncryptFile" _
                                         (ByVal lpszSourceFile as LONG, _
                                          ByVal lpszDestFile   as LONG) as LONG
      
    Call it in the calling application as follows,
      
        fName$   = "test.txt"
        
        KeyText$ = "You can make this key text any length you like"+ _
                   "The longer the better as it makes the combinations"+ _
                   "harder to brute force crack."
        
        EncryptFile ByVal StrPtr(fName$),ByVal StrPtr(KeyText$)
      
        The DLL code is as follows,
      
        NOTE: The line "%Small = 1" is a conditional compile statement to exclude
        the wrapper functions in win32api.inc.
      
      ' ###########################################################################
      
          #COMPILE DLL
      
          GLOBAL DLLinstance as LONG      ' the DLLs instance handle
      
          %Small = 1
      
        ' -----------------------------------
        ' set correct paths for include files
        ' -----------------------------------
      
          #INCLUDE "d:\pb6\winapi\win32api.inc"
      
          DECLARE FUNCTION SysAllocStringByteLen LIB _
                           "OLEAUT32.DLL" ALIAS "SysAllocStringByteLen" _
                           (BYVAL p1 as LONG,BYVAL p2 as LONG) as LONG
      
          DECLARE FUNCTION SysFreeString LIB "OLEAUT32.DLL" _
                           ALIAS "SysFreeString"(BYVAL p1 as LONG) as LONG
      
          DECLARE FUNCTION XorString(bString$,KeyString$) as STRING
      
      ' ###########################################################################
      
      FUNCTION LibMain(BYVAL hInst    AS LONG, _
                       BYVAL Reason   AS LONG, _
                       BYVAL Reserved AS LONG) EXPORT AS LONG
      
          DLLinstance = hInst
      
          FUNCTION = 1
      
      END FUNCTION
      
      ' ###########################################################################
      
      FUNCTION EncryptFile ALIAS "EncryptFile"(ByVal lpszDiskFile as LONG, _
                                  ByVal lpszKeyText  as LONG) EXPORT as LONG
      
          #REGISTER NONE
      
          LOCAL hFile   as LONG
          LOCAL lFile   as LONG
          LOCAL bytes   as LONG
          LOCAL hBuffer as LONG
          LOCAL pbString$
          LOCAL KeyString$
      
          hFile = CreateFile(ByVal lpszDiskFile,%GENERIC_READ or %GENERIC_WRITE, _
                             %FILE_SHARE_READ,ByVal %NULL,%OPEN_EXISTING, _
                             %FILE_ATTRIBUTE_NORMAL,ByVal %NULL)
      
          lFile = GetFileSize(hFile,ByVal %NULL)
      
          dest$ = space$(lFile)
          dst&  = strptr(dest$)
      
          hBuffer = SysAllocStringByteLen(0,lFile)
      
          ReadFile hFile,ByVal hBuffer,lFile,ByVal VarPtr(bytes),ByVal %NULL
      
          ! mov eax, hBuffer
          ! mov pbString$, eax
      
          ! mov eax, lpszKeyText
          ! mov KeyString$, eax
      
          pbString$ = XorString(pbString$,KeyString$)
      
          SetFilePointer hFile,0,ByVal %NULL,%FILE_BEGIN
          WriteFile hFile,ByVal StrPtr(pbString$),lFile,ByVal VarPtr(bytes),ByVal %NULL
      
          SysFreeString hBuffer
          CloseHandle hFile
      
          FUNCTION = 0
      
      END FUNCTION
      
      ' ###########################################################################
      
      FUNCTION XorString(bString$,KeyString$) as STRING
      
          #REGISTER NONE
      
          LOCAL ln   as LONG
          LOCAL src  as LONG
          LOCAL lpBt as LONG
          LOCAL pcnt as LONG
          LOCAL bvar as BYTE
      
          lpBt = StrPtr(KeyString$)   ' get starting address of key string
          pcnt = lpBt                 ' copy it to another variable
      
          ! mov esi, lpBt
          ! mov al,[esi]
          ! mov bvar, al      ; put 1st byte in bvar
      
          ln  = len(bString$)
          src = StrPtr(bString$)
      
          ! mov ecx, ln
          ! mov esi, src
          ! mov edi, src
      
        xsSt:
          ! mov al,[esi]      ; copy 1st byte of source into al
          ! inc esi
          
          ! xor al, bvar      ; xor al with next byte in bvar
      
          ! push eax
          ! push esi
      
        ' ====== This code gets the next byte in the key string ======
        '        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          ! inc pcnt          ; increment byte address
          ! mov esi, pcnt     ; put it in esi
          ! mov al,[esi]
          ! inc esi
          ! cmp al, 0         ; see if its zero
          ! jne xsNxt         ; if not, jump over next code
      
          ! mov edx, lpBt     ; if al = 0
          ! mov pcnt, edx     ; reset pcnt to ariginal address
          ! mov esi, pcnt     ; put original address in esi
          ! mov al,[esi]
          ! inc esi
      
        xsNxt:
          ! mov bvar, al
        ' ============================================================
      
          ! pop esi
          ! pop eax
      
          ! mov [edi], al
          ! inc edi
      
          ! dec ecx
          ! cmp ecx, 0
          ! jne xsSt
          
          FUNCTION = bString$
      
      END FUNCTION
      
      ' ###########################################################################
    hutch at movsd dot com
    The MASM Forum

    www.masm32.com

  • #2
    One quick note about "test resolution" for anybody that is comparing DLL sizes... You'll find that many compilers -- including PB/DLL and (apparently) C++ -- create DLL files that are always multiples of 512 bytes. You can very often add code to a DLL without increasing its size, until a certain threshhold is reached and the size jumps 512 bytes. So if one DLL is one byte below the threshhold and another is one byte over, that two-byte difference in actual code efficiency will show up as a 1k difference in the DLL sizes.

    The larger the DLLs that are tested, the more accurate and meaningful the test results.

    (As a side note, this "resolution" factor is also very important when you are trying to compare the size of two different functions in the same language, for example when you are trying to decide between two different coding techniques. The resulting EXE or DLL files may be the same size, but that doesn't mean the test code is the same size. And a difference of 512 bytes in the files might only indicate a one-byte difference in the code size.)

    Back to comparing languages... The problem is, the larger the DLLs, the more divergent the code, since the techniques that are used will be increasingly different. In the end, IMO, this isn't necessarily something that can be measured accurately... It's more a function of "I can accomplish X with compiler Y and my total executable/distributable size is Z, and it runs at speed W".

    The efficiency of a compiler is also (IMO) a function of "it took me A hours to write it, B hours to debug it, and it will take me C hours to modify it a year from now", and those numbers will also be different for PB/CC, C++, and MASM, depending on the area(s) of expertise of the coder.

    A long time ago I wrote "saying that good programs can only be written in C is like saying that good poetry can only be written in Russian". When you are comparing two languages, your level of expertise with the language may be the largest factor that determines what you can accomplish. Even if MASM creates the smallest and fastest files, if you can't "speak" MASM very well, it would not be a good choice for your "poetry".

    But the comparisons are very interesting...

    -- Eric


    ------------------
    Perfect Sync: Perfect Sync Development Tools
    Email: mailto:[email protected][email protected]</A>



    [This message has been edited by Eric Pearson (edited March 18, 2000).]
    "Not my circus, not my monkeys."

    Comment


    • #3
      Hutch,
      The following Visual C++ Ver. 1.5 code was written first. Some time after, I received my PBDLL ver. 1.5 upgrade
      and just for fun, decided to translate to PBDLL. The compiled size results are as follows:

      Visual C version:15,852 BYTES (No debug -- release! version.)

      PBDLL Version: 5130 BYTES!

      Comments: I have observed a 3:1 size ratio every time I have compiled functionaly identical code between VC and
      PBDLL. I have not taken any pains to benchmark speed differences since both dlls can hit the a/d board as
      fast as I need. I thought this might be of particular interest in this discussion since in both cases
      I was using the compilers as "Wrappers" for inline assembly.

      Note: While both versions are 16 bit, I found the same 3:1 size difference after translating
      Protoview's ANSI C DataTable demo using PBDLL 6.0. As Eric Pearson pointed out, the inclusion of the
      win32api.inc increases the compiled size of of the PBDLL code but in the DataTable ANSI C and PBDLL 6.0
      both had the windows include files. It would appear the additional overhead compiles with the same 3:1 ratio.

      Scott

      Code:
      /* =======================================================================
      SDHLMJ.C   Dynamic link library for XXXXXXXX  A/D board.
      		   
      	   Written by Scott Hauser    October - 1995
      ========================================================================*/		   
      
      #include <windows.h>
      
      /* WINAPI PROTOTYPES */
      int CALLBACK LibMain(HANDLE hLibInst, WORD wDataSeg, 
      						WORD cbHeapSize, LPSTR lpszCmdLine);
      
      int CALLBACK WEP(int bSystemExit);
      
      /*************************************************************************
      
      	EXPORTED FUNCTIONS:
      		
      		0= EnableTBC(void)
      			
      		1= ShortCaps(void)
      		
      		2= TBC_Board(int cntrlMode, int TheCode)
      		
      		3= IntegrateTBC(int cxTime, int bxTime)
      		
      		4= CalibratePC_Timer() - Calibrates A/D short time for Integration
      		
      		5= ShortTimer(int intTime,int cxValue, int bxValue) 
      		
      		6= IntTBC(int cxTime, int bxTime) -- in case there are only 16 caps
      		
      		7= Read& = Convert(int Chan) -- One Shot convert routine
      		
      		8= WakeUp(void) -- Call this function to load the dll so other calls
      						   dont wait for dll to load...
      		
      		9= Cnvrt_32(long *Data, int nSize) 
      		
      	   10= TBC_Idle(void) -- shuts down TBC board when not in use
      	   
      		
      ************************************************************************/
      
      /* ~~~~~~~~~~~~~~TBC BOARD PROTOTYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
      
      int WINAPI EnableTBC(void);
      int WINAPI ShortCaps(void);
      int	WINAPI TBC_Board(int cntrlMode, int TheCode);
      int	WINAPI IntegrateTBC(int cxTime, int bxTime);
      int	WINAPI CalibratePC_Timer(int cxTime,int bxTime,int actTime);
      int WINAPI ShortTimer(int intTime,int cxValue, int bxValue);
      int	WINAPI IntTBC(int cxTime, int bxTime);
      int WINAPI TBCConvert(void);
      int WINAPI WakeUp(void);
      void __export __loadds WINAPI Cnvrt_32(long *Data,int nSize);
      void setBank1(void);
      void setBank2(void);
      unsigned int Do_Bank1(void);
      unsigned int Do_Bank2(void);
      void WINAPI TBC_Idle(void);
      
      /* =============== WINDOWS FUNCTIONS BEGIN HERE ======================= */
      
      int CALLBACK LibMain(HANDLE hLibInst,  WORD wDataSeg, 
      								WORD cbHeapSize, LPSTR lpszCmdLine)
      {
      	return TRUE;
      }
      
      int CALLBACK  WEP(int bSystemExit)
      {
      	return TRUE;
      }
      
      
      /* ================== TBC BOARD STUFF BEGINS HERE ===================== */
      
      /*<0>*/
      int WINAPI EnableTBC(void)
      {
      	__asm{
      				MOV	AL,128
      				MOV	DX,0717h
      				OUT DX,AL
      		}
      	return 0;
      }
      				
      /*<1>*/
      int WINAPI ShortCaps(void)
      {
      	__asm{
      				MOV	DX,0714h
      				MOV	AL,00000111b
      				OUT	DX,AL
      				
      				MOV AL,90
      			L1:	DEC Al
      				JNZ L1
      				
      				MOV	DX,0714h
      				MOV	AL,00100111B
      				OUT	DX,AL
      				
      				MOV AL,90
      			L2:	DEC	AL
      				JNZ L2
      				
      		}
      	return 0;
      }
      
      /*<2>*/						
      int	WINAPI TBC_Board(int cntrlMode, int TheCode)
      {   
      	__asm{
      				MOV	AX,TheCode    
      				MOV	DX,cntrlMode  
      				OUT	DX,AL
      		  }		 
      	return 0;
      }
      
      /*<3>*/ 
      int	WINAPI IntegrateTBC(int cxTime, int bxTime)
      {
      	__asm{
      				CLI
      				MOV AX,0
      				MOV DX,0714h
      				MOV	Al,10110000B
      				OUT	DX,AL
      				
      		    	MOV	CX,cxTime
      		Time2:	MOV BX,bxTime
      		Time3:	DEC	BX
      				JNZ Time3
      				LOOP Time2
      				
      				MOV AL,0
      				MOV	DX,0714h
      				MOV	AL,10010000B  /*connect bank 0 */
      				OUT	DX,AL
      				
      				MOV AL,0
      				MOV	DX,0714h
      				MOV	AL,11000000B
      				OUT DX,AL
      				STI
      		}
      	return 0;												
      }
      
      /*<4>*/
      int	WINAPI CalibratePC_Timer(int cxTime,int bxTime,int actTime)
      {     __asm{    
      				
      				MOV AX,actTime
      	 	DELAY1: MOV CX,cxTime
      		DELAY2: MOV BX,bxTime  ;NUMBER  TO MAKE 1 SECOND PER AX
      		DELAY3: DEC BX      
      	  			JNZ     DELAY3
      	  			LOOP    DELAY2
      	  			DEC     AX
      	  			JNZ     DELAY1
      	  		}
        return 0;
      }
      
      /*<5>*/
      int WINAPI ShortTimer(int intTime,int cxValue, int bxValue) 
      {  
      	__asm{
      		        MOV AX,intTime
      	 	DELAY1: MOV CX,cxValue
      		DELAY2: MOV BX,bxValue  ;NUMBER  TO MAKE 
      		DELAY3: DEC BX          ;1 SECOND PER AX
      	  			JNZ     DELAY3
      	  			LOOP    DELAY2
      	  			DEC     AX
      	  			JNZ     DELAY1
      		}
      	return 0;
      	}
      
      /*<6>*/
      int	WINAPI IntTBC(int cxTime, int bxTime)
      {
      	__asm{
      				CLI
      				MOV AX,0
      				MOV DX,0714h
      				MOV	Al,10010000B
      				OUT	DX,AL
      				
      		    	MOV	CX,cxTime
      		Time2:	MOV BX,bxTime
      		Time3:	DEC	BX
      				JNZ Time3
      				LOOP Time2
      				
      				MOV AL,0
      				MOV	DX,0714h
      				MOV	AL,11000000B
      				OUT DX,AL
      				STI
      		}
      	return 0;												
      }
      
      /*<7>*/
      int WINAPI TBCConvert(void)
      {
         
      	__asm{
      				MOV DX,0716H
      				MOV AL,0
      				OUT	DX,AL
      				
      				MOV DX,0714h
      		Cnvted:	IN	AL,DX
      				TEST AL,80H
      				JNS	Cnvted
      				
      				MOV DX,0716h
      				IN	AL,DX
      				MOV	AH,AL
      				MOV DX,0715h
      				IN 	AL,DX
      		}
      							
      }
      
      /*<8>*/     
      int WINAPI WakeUp(void)
      {
      	return 0;
      }
      
      /*<9>*/
      void __export __loadds WINAPI Cnvrt_32(long *Data, int nSize)
      {
      int i;
      unsigned int chRead;
      
            /*  call TBCboard bank 1 here */
            setBank1();
          for(i=0;i<(nSize/2);i++)
      		{   
      		chRead=0;
      		chRead = Do_Bank1();
      		if(chRead==0xFFFF)
      			Data[i]=-1;
      		else	 
      	    	Data[i]=Data[i]+chRead;
      	}
      	 
      	 /*  call TBCboard bank 2 here */
      	 setBank2();
      	for(i=(nSize/2);i<nSize;i++)
      	{
      		chRead=0;
      		chRead = Do_Bank2();
      		if(chRead==0xFFFF)
      			Data[i]=-1;
      		else	 
      			Data[i]=Data[i]+chRead;
      	}	
      }
      void setBank1(void)
      {
      	__asm{
      			MOV		AL,0
      			MOV		DX,0715h    /*CHANNEL*/
      			OUT		DX,AL
      			
      			MOV		AL,11000000B    
      			MOV		DX,0714h    /*CONTROL*/
      			OUT		DX,AL
      		}
      }
      			
      unsigned int Do_Bank1(void)
      {  unsigned int chRead;
      	chRead=0;
      	__asm{				
      			MOV		DX,0716h    /*CONVERT*/
      			MOV		AL,0
      			OUT		DX,AL
      			
      			MOV		DX,0714h    /*STATUS */
      	NotDone: IN		AL,DX
      			TEST	AL,080h
      			JNS		NotDone
      			
      			MOV		DX,0716h	/*Address for HiByte  */
      			IN		AL,DX
      			MOV		AH,AL
      		    MOV		DX,0715h 	/* Address for LoByte */
      			IN		AL,DX
      			MOV		chRead,AX	/*C __asm Quirk, see below */
      		} 
      	
      	return chRead;  /* this isn't required for a one shot conversion call
                          from VB, but needs to be here if called by Cnvrt_32*/
      					
      }
      void setBank2(void)
      {		
      	__asm{
      			MOV		DX,0715h     /*CHANNEL*/
      			MOV		AL,0
      			OUT 	DX,AL
      			
      			MOV		AL,11110000B    
      			MOV		DX,0714h     /*CONTROL*/
      			OUT		DX,AL
              }
      }
              	
      unsigned int Do_Bank2(void)
      {  unsigned int chRead;
      	chRead=0;
      	__asm{  
      			
      			MOV		DX,0716h     /*CONVERT*/
      			MOV		AL,0
      			OUT		DX,AL
      			
      			MOV		DX,0714h     /*STATUS*/
      	NotDone: IN		AL,DX
      			TEST	AL,080h
      			JNS		NotDone
      			
      			MOV		DX,0716h	/*Address for HiByte  */
      			IN		AL,DX
      			MOV		AH,AL
      		    MOV		DX,0715h 	/* Address for LoByte */
      			IN		AL,DX
      			MOV		chRead,AX	/*C __asm Quirk, see below */
      		} 
      	
      	return chRead;  /* this isn't required for a one shot conversion call
                          from VB, but needs to be here if called by Cnvrt_32*/
      					
      }
      
      /*<10>*/
      void WINAPI TBC_Idle(void)
      {
      	__asm{	
      			MOV		AL,0111000B
      			MOV		DX,0714h  
      			OUT		DX,AL
      		}
      	
      }
      
      '=================== PowerBasic Version Starts here...=================================
      
      '=======================================================================
      '    SDHLMJ.BAS
      '    Dynamic link library for TBC A/D board.
      '                   
      '                by Scott Hauser Original was  C++ Code
      '                     October - 1995
      '
      '   Converted to PBDLL CODE  Scott Hauser September - 1996
      '========================================================================                 
      
      $COMPILE DLL
      $DIM ALL
      
      '==================== Control Stuff   EQUATES ===========================
      
      %BASE   = &H0710  ' Base Address
      
                        'Write Locations
      %CONTROL = %BASE + 4  
      %CHANNEL = %BASE + 5
      %CONVERT = %BASE + 6
      %ENABLE  = %BASE + 7
      
                        'Read Locations
      %STATUS  = %BASE + 4
      %LOBYTE  = %BASE + 5
      %HIBYTE  = %BASE + 6
      
      '========================================================================
      
      ' Insert LibMain and Wep Functions here
      
      '________________________________________________________________________
      
        DECLARE FUNCTION Do_Bank1() AS WORD
        DECLARE FUNCTION Do_Bank2() AS WORD
      
      Function EnableTBC() EXPORT AS INTEGER
       ! MOV  AL,128
       ! MOV  DX,%ENABLE
       ! OUT  DX,AL
        EnableTBC = -1
      END FUNCTION
      
      Function ShortCaps() EXPORT AS INTEGER
           ! MOV DX,%CONTROL
           ! MOV AL,&B00000111
           ! OUT DX,AL
           ! MOV AL,90
      L1:
           ! DEC AL
           ! JNZ L1
           ! MOV DX,%CONTROL
           ! MOV AL,&B00100111
           ! OUT DX,AL
           ! MOV AL,90
      L2:
           ! DEC AL
           ! JNZ L2
      END FUNCTION
      
      Function TBC_Board(ByVal cntrlMode AS Integer,_
                         ByVal TheCode AS Integer) EXPORT AS INTEGER
          ! MOV  AX,TheCode    
          ! MOV  DX,cntrlMode  
          ! OUT  DX,AL
      END FUNCTION
      
      FUNCTION IntegrateTBC(ByVal cxTime AS Integer,_
                            ByVal bxTime AS Integer) EXPORT AS INTEGER
            ! CLI
            ! MOV  AX,0
            ! MOV  DX,%CONTROL
            ! MOV  Al,&B10110000
            ! OUT  DX,AL
            ! MOV  CX,cxTime
      Time2:
            ! MOV  BX,bxTime
      Time3:
            ! DEC  BX
            ! JNZ  Time3
            ! LOOP Time2
            ! MOV  AL,0
            ! MOV  DX,%CONTROL
            ! MOV  AL,&B10010000  ;connect bank 0 
            ! OUT  DX,AL
            ! MOV  AL,0
            ! MOV  DX,%CONTROL
            ! MOV  AL,&B11000000
            ! OUT  DX,AL
            ! STI
      END FUNCTION
      
      FUNCTION CalibratePC_Timer(ByVal cxTime AS Integer,_
                                 ByVal bxTime AS Integer,_
                                 ByVal actTime AS Integer) EXPORT AS INTEGER
              ! MOV  AX,actTime
      DELAY1:
              ! MOV  CX,cxTime
      DELAY2:
              ! MOV  BX,bxTime  ;NUMBER  TO MAKE 1 SECOND PER AX
      DELAY3:
              ! DEC  BX
              ! JNZ  DELAY3
              ! LOOP DELAY2
              ! DEC  AX
              ! JNZ  DELAY1
      END FUNCTION
      
      FUNCTION ShortTimer(ByVal intTime AS Integer,_
                          ByVal cxValue AS Integer,_
                          ByVal bxValue AS Integer) AS Integer
              ! MOV  AX,intTime
      DELY1:
              ! MOV  CX,cxValue
      DELY2:
              ! MOV  BX,bxValue  ;NUMBER  TO MAKE
      DELY3:
              ! DEC  BX          ;1 SECOND PER AX
              ! JNZ  DELY3
              ! LOOP DELY2
              ! DEC  AX
              ! JNZ  DELY1
      END FUNCTION
      
      FUNCTION IntTBC(ByVal cxTime AS Integer,_
                      ByVal bxTime AS Integer) AS Integer
             ! CLI
             ! MOV AX,0
             ! MOV DX,%CONTROL
             ! MOV Al,&B10010000
             ! OUT DX,AL
             ! MOV CX,cxTime
      Tim2:
             ! MOV BX,bxTime
      Tim3:
             ! DEC BX
             ! JNZ Tim3
             ! LOOP Tim2
             ! MOV AL,0
             ! MOV DX,%CONTROL
             ! MOV AL,&B11000000
             ! OUT DX,AL
             ! STI
      END FUNCTION
      
      FUNCTION TBCConvert() AS Integer
             ! MOV DX,%CONVERT
             ! MOV AL,0
             ! OUT DX,AL
             ! MOV DX,%STATUS
      Cnvted:
             ! IN  AL,DX
             ! TEST AL,&H80
             ! JNS Cnvted
             ! MOV DX,%HIBYTE
             ! IN  AL,DX
             ! MOV AH,AL
             ! MOV DX,%LOBYTE
             ! IN  AL,DX
      END FUNCTION
      
      FUNCTION WakeUp() AS Integer
        Wakeup = -1
      END FUNCTION
      
      FUNCTION Cnvrt_32(ByVal gData AS DWORD,_
                        ByVal nSize AS Integer) EXPORT AS Integer
      
        DIM Data AS DWORD PTR
        DIM chRead AS WORD
        DIM i AS Integer
      
        Data = gData
         'call TBCboard bank 1 here 
      
         CALL setBank1()
         For i = 0 to (nSize/2)
           chRead = 0
           chRead = Do_Bank1() 
           If chRead = &HFFFF Then
            @Data[i] = -1
           Else     
             @Data[i] = @Data[i] + chRead
           End If
         Next
      
         '  call TBCboard bank 2 here
      
          CALL setBank2()
          For i =(nSize/2) To nSize
            chRead = 0
            chRead = Do_Bank2()
              If chRead = &HFFFF Then
                @Data[i] = -1
              Else     
                @Data[i] = @Data[i] + chRead
              End If
          Next
      End FUNCTION
      
      Sub setBank1()
               ! MOV AL,0
               ! MOV DX,%CHANNEL
               ! OUT DX,AL
               ! MOV AL,&B11000000
               ! MOV DX,%CONTROL
               ! OUT DX,AL
      End Sub
      
      FUNCTION Do_Bank1() AS WORD
        Dim chRead as WORD
          chRead=0
               ! MOV DX,%CONVERT
               ! MOV AL,0
               ! OUT DX,AL
               ! MOV DX,%STATUS
      NotDone:
               ! IN AL,DX
               ! TEST AL,&H080
               ! JNS NotDone
               ! MOV DX,%HIBYTE
               ! IN  AL,DX
               ! MOV AH,AL
               ! MOV DX,%LOBYTE
               ! IN  AL,DX
               ! MOV chRead,AX       
        Do_Bank1 = chRead  
      END FUNCTION
      
      SUB setBank2()
               ! MOV DX,%CHANNEL
               ! MOV AL,0
               ! OUT DX,AL
               ! MOV AL,&B11110000
               ! MOV DX,%CONTROL
               ! OUT DX,AL
      END SUB
              	
      FUNCTION Do_Bank2() AS WORD
      Dim chRead AS WORD
              chRead=0
               ! MOV DX,%CONVERT
               ! MOV AL,0
               ! OUT DX,AL
               ! MOV DX,%STATUS
      NotDon2:
               ! IN  AL,DX
               ! TEST AL,&H080
               ! JNS  NotDon2
               ! MOV  DX,%HIBYTE
               ! IN   AL,DX
               ! MOV  AH,AL
               ! MOV  DX,%LOBYTE
               ! IN   AL,DX
               ! MOV  chRead,AX 
      	
               Do_Bank2 =  chRead
      END FUNCTION
      
      
      Sub TBC_Idle()
        ! MOV AL,&B0111000
        ! MOV DX,%CONTROL
        ! OUT DX,AL
      End Sub


      ------------------
      The most exasperating part of the "rat race" is how often the rats are in the lead!

      Comment


      • #4

        I had much the same observation as Scott after Visual C++ version 1. It
        would build a standard API from end at about 4k but the MFC stuff that was
        just being introduced at the time produced balloons in comparison. I
        always used to build the SDK example and with a C version of an MDI text
        editor, it would build at about 28k. I built the MFC version and it ended
        up at about 80k.

        Where the C libraries for Visual C++ version 1 were very good and produced
        at that time, minimum size binary code, the later version just kept
        getting bigger for no functionality increase. In the larger context, terms
        such as speed, size and code optimisation are now just advertising hype
        for tools that produce oversized code. I voted with my feet and abandoned
        the C/C++ product.

        If there has been one aspect of programming that has annoyed me over time,
        it has been the patronising nonsense I have heard from the older brigade
        of C/C++ programmers about dialects of basic. "You mean you write in
        Bay-Sick !". When you connect that the only runtime DLLs are the ones you
        write yourself, you get a funny type of silence. Offer to improve the
        performance of there programs with some PowerBASIC DLLs and the conversation
        starts to get hostile.

        Like many people, I have written in ASM, Basic & C from the old days in
        DOS. In those days you wrote in C to get the grunt, ASM modules to
        actually make it go fast and Basic if you needed to write something in a
        hurry that worked well. It was my experience from working with the basic
        guys that they had to often do very difficult things in underpowered
        languages which displayed a lot more ability than many of their critics.

        The two objective measures are size and speed, something that does not win
        you any friends when egos are at stake but it sure shut the patronising
        nonsense up. The PowerBASIC compilers do perform where it matters in the
        areas of size and speed and the numbers prove it.

        I have never minded sharing this particular piece of humour with the
        thousands of other PowerBASIC programmers who routinely pop out the DLLs
        they need with indifference to the patronising nonsense that still
        occasionally surfaces. Basic programmers are usually a pragmatic bunch
        and most have had to output reasonably large amounts of code over time so
        ignoring some flack and delivering the goods on time is reasonably normal.

        Regards,

        [email protected]

        ------------------
        hutch at movsd dot com
        The MASM Forum

        www.masm32.com

        Comment


        • #5
          <<Steve,
          <<What follows is a DLL written in PowerBASIC that uses API file IO, it has
          <<initialised the PowerBASIC string engine and has an encryption function
          <<written in inline asm, things that PowerBASIC can mix with ease.
          I am not sure that the code you have posted is really appropriate
          to evaluate the speed/size differences between PB, C, C++ because
          it is made of Win32 API calls and pure assembly language, which can be directly inserted in C/C++ code:

          ! mov eax, hBuffer
          ! mov pbString$, eax

          will translate to:

          _asm
          {
          mov eax, hBuffer
          mov pbString, eax
          }

          Eric, I fully agree with you. Size and speed are only some of the aspects to consider when choosing a development tool for a given task. I would also mention:
          - the debugging, profiling, intrumenting capabilities of the tool
          - the ease of use of external software resources: COM components, LIB/OBJ files,
          - its capability to produce all types of DLLs, EXEs (GUI and console), LIBs, COM components ...
          - its integration with team development and version control tools
          - ...

          Scott,
          <<Visual C version:15,852 BYTES (No debug -- release! version.)
          <<
          <<PBDLL Version: 5130 BYTES!
          <<
          <<Comments: I have observed a 3:1 size ratio every time I have compiled functionaly identical code between VC and
          <<PBDLL. I have not taken any pains to benchmark speed differences since both dlls can hit the a/d board as
          <<fast as I need. I thought this might be of particular interest in this discussion since in both cases
          <<I was using the compilers as "Wrappers" for inline assembly.
          I have personnaly found a 5:1 ratio between VC++ and PB/DLL,
          and someone else could even prove a 2:1 one between MASM and PB/DLL <bg>.

          More seriously, the figure you mention only prove that the minimum overhead of a C/C++ DLL is between
          10 and 25 Kb bigger than with PB/DLL.

          Our DV32 for PB/DLL engine is a C++ DLL made of 10.000 lines of code, and its final size
          (without needing any extra DLL) is only 81 920 bytes.


          Philippe


          ------------------

          Comment


          • #6
            Perhap I have missed something here in what constitutes a comparison, I
            get to write a lot of code that looks very much like the small DLL that I
            posted, mixed ASM, Basic & API code. Now I wonder what the comparison is
            supposed to be if API calls and inline ASM are not considered to be a
            comparison.

            The notion of ratio is not what has so far been tested with the minimum
            size start up code, its what the compiler adds to the EXE/DLL before you
            start. The example you built with the same code in C/C++ was about 28k,
            the PowerBASIC DLL with Eric's piece of genius built at 4608 bytes and the
            MASM DLL was about 2.5k. I included the MASM DLL example because it shows
            that the PowerBASIC compiler delivers in the MASM end of the market in
            terms of size, not the C++ end of the market.

            Now my problem is this, what is the size threshold where PowerBASIC DLLs
            catch up to a C++ DLL, I suggest that there is not one as it is capable
            of delivering the type of code that myself and many other programmers
            write up to whatever size and complexity you like.

            The comparison with MASM code is a reasonable one as MASM code is bare
            bones stuff where you really do get what you write. It comes with no
            runtime functions at all so you must construct your code purely from API
            calls and ASM mnemonics yet it does build and it does run if you write it
            correctly.

            Writing PowerBASIC low level code is a lot easier and faster yet it
            still delivers DLLs that are a lot closer to the MASM size than the
            C++ size because among other things, it does not have the option to do
            it in a lazy or sloppy way.

            If there is one point we do have in agreement, its the lack of static
            libraries and compiler support for the COM interface in the current
            version of PowerBASIC. Where C rather than C++ used to have a vast array
            of aftermarket libraries that could be used to further extend the capacity
            of the language, currently PowerBASIC does not and I consider that a
            weakness.

            While most have found their way around it by having pre-written blocks of
            code available which they either INCLUDE or paste into their source, the
            capacity to build libraries like MASM, C, C++, Pascal and of course most
            of the older DOS languages is one that is needed in PowerBASIC.

            Sinse I have bothered to decompile PowerBASIC EXE files from time to time
            to see what Bob Zale is doing with his asm, I have a reasonable good idea
            of what the difference is between a MASM EXE and a PowerBASIC EXE and it
            is mainly related to the support for dynamic string allocation and
            deallocation which accounts for the about 2k difference.

            What I don't know is why a modern C/C++ compiler produces a DLL that is
            about 26k bigger than a MASM DLL. I think it is fair to say that you get
            more than you write when you get results that bad. Now taking a slightly
            tongue in cheek approach to the mysterious 26k that is not accounted for,
            I can imagine such things as the code for making a net connection to see
            if your product is registered in the manufacturers database, checking the
            registry for hot copies of win 9x/NT or any other non-sense you can
            imagine.

            As long as I can get compilers that don't slap 26k of junk on the front
            of a DLL/EXE file, I will keep using them as both size and speed are
            important factors in the type of code that I write.

            Now as far as support tools, I grew up in the generation of Codeview
            debuggers with MASM and Microsoft C in DOS but I am much of the view that
            high level language debuggers are not all that much use. In DOS C, you had
            a reasonable good translation to the ASM listing for the stepping but with
            most of the later high level languages, that relationship has been dead
            for a long time.

            The leading edge debugger for 32 bit windows code in NuMega's softice but
            I have found from playing with one of the demo versions that was available
            in England a couple of years ago that stepping through asm that I have
            written myself or stepping through the internals of system DLLs is not a
            lot of use.

            My own approach to speed testing is a very primitive one, I look for real
            time testing of algorithms over very larger samples to cover the vagueries
            related to ring 3 access profiling. Intel Vtune is a very nice toy but I
            find it hard to justify the high cost when the method I use does the job
            well.

            Regards,

            [email protected]

            ------------------
            hutch at movsd dot com
            The MASM Forum

            www.masm32.com

            Comment


            • #7
              Code:
              Hi Philippe,
              
                  >>More seriously, the figure you mention only prove that the minimum overhead of a C/C++ DLL is between
                  >>10 and 25 Kb bigger than with PB/DLL.
              
              No I do not think it does.  Actually, Keith Waters did much of the work for us already. His data suggests
              I am incorrect in my ratio observation 3:1 as a flat factor. His data also suggests it is not a minimum 
              overhead of 10 to 25 kb either. Perhaps the linker in VC 1.X doesn't strip un-needed code as well as it could.
              That would be in Bob Zale's area of expertise to comment.  
              
              His data does suggest that when Bob Zale decides to implement some of the features such as com etc., it will
              more than likely be more efficient than any of the current offerings.
              
              Scott
              
                          Program name    PB/DLL  C/C++  (C % Larger)
              Chapter 2   HELLOWIN EXE    6,656   16,896  254%
              Chapter 3   SYSMETS1 EXE    15,872  19,968  126%
                          SYSMETS2 EXE    17,408  20,992  121%
                          SYSMETS3 EXE    18,944  21,504  114%
              Chapter 4   BEZIER   EXE    8,192   17,408  213%
                          CLOVER   EXE    9,728   41,472  426%
                          DEVCAPS1 EXE    12,288  18,432  150%
                          EMF1(1)  EXE    8,192   16,896  206%
                          ENDJOIN  EXE    8,192   17,408  213%
                          JUSTIFY1 EXE    12,288  39,936  325%
                          LINEDEMO EXE    7,168   16,896  236%
                          METAFILE EXE    8,192   17,920  219%
                          RANDRECT EXE    7,168   16,896  236%
                          SCRAMBLE EXE    7,680   16,896  220%
                          SINEWAVE EXE    8,192   39,424  481%
                          WHATSIZE EXE    9,728   21,504  221%
              Chapter 5   KEYLOOK  EXE    11,264  18,432  164%
                          SYSMETS3 EXE(2) 18,944  22,016  116%
                          TYPER    EXE    9,728   20,480  211%
              Chapter 6   BLOKOUT1 EXE    7,168   17,408  243%
                          BLOKOUT2 EXE    8,192   17,408  213%
                          CHECKER1 EXE    7,680   17,408  227%
                          CHECKER2 EXE    8,704   17,920  206%
                          CHECKER3 EXE    8,704   17,408  200%
                          CONNECT  EXE    7,680   17,408  227%
              Chapter 7   ANACLOCK EXE    12,288  46,592  379%
                          BEEPER1  EXE    7,168   16,896  236%
                          BEEPER2  EXE    7,168   16,896  236%
                          BOUNCE   EXE    8,192   18,432  225%
                          DIGCLOCK EXE    8,192   25,088  306%
              Chapter 8   BTNLOOK  EXE    13,312  17,920  135%
                          COLORS1  EXE    12,288  19,456  158%
                          ENVIRON  EXE    8,192   19,968  244%
                          HEAD     EXE    10,240  20,480  200%
                          OWNERDRW EXE    10,240  18,944  185%
                          POPPAD1  EXE    6,656   16,896  254%
              Chapter 9   POEPOEM  EXE    10,752  20,992  195%
                          RESOURC1 EXE    8,192   17,920  219%
                          RESOURC2 EXE    8,704   18,432  212%
              Chapter 10  GRAFMENU EXE    12,288  21,504  175%
                          MENUDEMO EXE    10,752  18,944  176%
                          NOPOPUPS EXE    8,192   18,432  225%
                          POORMENU EXE    7,168   17,408  243%
                          POPMENU  EXE    8,704   18,944  218%
                          POPPAD2  EXE    10,240  19,968  195%
              Chapter 11  ABOUT1   EXE    8,192   17,920  219%
                          ABOUT2   EXE    10,240  20,480  200%
                          ABOUT3   EXE    10,752  18,944  176%
                          COLORS2  EXE    9,216   17,920  194%
                          COLORS3  EXE    10,240  15,872  155%
                          HEXCALC  EXE    13,312  20,992  158%
                          POPPAD   EXE    23,040  31,232  136%
              Chapter 12  GADGETS  EXE    57,856  38,400  66%
                          PROPERTY EXE    35,840  31,232  87%
              Chapter 14  BIGJOB1  EXE    10,240  43,008  420%
                          BIGJOB2  EXE    10,752  43,008  400%
                          MULTI1   EXE    13,312  35,840  269%
                          MULTI2   EXE    13,824  38,400  278%
                          RNDRCTMT EXE    7,680   19,968  260%
              Chapter 15  DEVCAPS2 EXE    27,136  28,672  106%
                          FORMFEED EXE    7,168   16,384  229%
                          POPPAD   EXE    25,088  33,792  135%
                          PRINT1   EXE    9,216   18,432  200%
                          PRINT2   EXE    9,216   18,944  206%
                          PRINT3   EXE    10,752  19,456  181%
                          PRINT4   EXE    10,752  20,480  190%
              Chapter 16  CLIPVIEW EXE    8,192   16,896  206%
              Chapter 17  DDEPOP1  EXE    24,064  45,056  187%
                          DDEPOP2  EXE    20,480  43,008  210%
                          SHOWPOP1 EXE    20,480  23,040  113%
                          SHOWPOP2 EXE    19,456  22,528  116%
              Chapter 18  MDIDEMO  EXE    15,360  22,528  147%
              Chapter 19  EDRTEST  EXE    6,656   16,896  254%
                          SHOWBIT  EXE    7,680   16,896  220%
                          STRPROG  EXE    9,728   19,456  200%
                                               
                                               Average=   212% larger than PB/DLL 
                                               Res ipsa loquitar (The thing speaks for itself)
              ------------------
              The most exasperating part of the "rat race" is how often the rats are in the lead!

              Comment


              • #8
                Hi

                I tested a minimal dll using the C compiler I use when I do C work (not often these days since PB is my compiler of choice 8-) and got the following figures:

                tested with lcc-32:

                including <windows.h>: 5632 bytes (same size as minimum PBDLL with WIN32API.inc!)
                without <windows.h>: 5120 bytes (a tad larger than PBDLL)

                The executables produced by lcc-32 are in general quite a bit smaller than VC++ produced ones, however VC++ definitely has an edge on speed.

                PBDLL is both great on size and speed - however, it is possible to produce compact dlls with VC++, it just needs a bit more work and generally won't come close to PB.

                Cheers

                Florent


                [This message has been edited by Florent Heyworth (edited March 19, 2000).]

                Comment


                • #9
                  Scott,

                  <<No I do not think it does. Actually, Keith Waters did much of the work for us already.
                  <<His data suggests I am incorrect in my ratio observation 3:1 as a flat factor.
                  <<His data also suggests it is not a minimum overhead of 10 to 25 kb either.
                  <<Perhaps the linker in VC 1.X doesn't strip un-needed code as well as it could.
                  <<That would be in Bob Zale's area of expertise to comment.
                  I totally disagree with your analyzis: all the figures you give correspond EXEs smaller than 60Kb.
                  In that size range, the fixed cost due to the minimum runtime has a huge impact on the percentage
                  based comparisons:
                  <<10,240 43,008 420% delta=33Kb
                  making them meaningless.

                  It even happens than the PB/DLL EXEs are up to 150% BIGGER than their C++ counterpart:
                  <<Chapter 12 GADGETS EXE 57,856 38,400 66%
                  << PROPERTY EXE 35,840 31,232 87%

                  I would rather compare the size of programs made of 1000, 5000, 10000 lines of code,
                  corresponding to the real world.

                  <<His data does suggest that when Bob Zale decides to implement some of the features such as com etc.,
                  <<it willmore than likely be more efficient than any of the current offerings.
                  Given the complexity of the technology, the size of the COM components produced by a future PB
                  version will certianly not be your first concern. Also, as far as the size of the COM components
                  is concerned, it will be very hard to beat ATL 3.0.

                  Philippe


                  ------------------

                  Comment


                  • #10
                    > It even happens than the PB/DLL EXEs are up
                    > to 150% BIGGER than their C++ counterpart:
                    <<Chapter 12 GADGETS EXE 57,856 38,400 66%

                    Percentages stated in this way are misleading. I believe that you mean "50% bigger" not 150%. All of the numbers in Scott's analysis are also skewed... Perhaps subtracting 100 from the % number would give a better picture...

                    Code:
                    Chapter 12 GADGETS EXE 57,856 38,400 -44% (meaning that PB/DLL produces a larger file in this case)
                    So the bottom line is more like 112% not 212%.

                    -- Eric


                    ------------------
                    Perfect Sync: Perfect Sync Development Tools
                    Email: mailto:[email protected][email protected]</A>



                    [This message has been edited by Eric Pearson (edited March 19, 2000).]
                    "Not my circus, not my monkeys."

                    Comment


                    • #11
                      Guys --
                      You compare 5Kb more or less.
                      Look in Task Manager. PB/DLL EXE even with one statement Msgbox wants more than 1 Mb as stack.

                      ------------------

                      Comment


                      • #12
                        Originally posted by Semen Matusovski:
                        Guys --
                        You compare 5Kb more or less.
                        Look in Task Manager. PB/DLL EXE even with one statement Msgbox wants more than 1 Mb as stack.
                        Isn't the 1 meg stack a Windows' default??

                        James



                        ------------------

                        Comment


                        • #13
                          Yessir!


                          ------------------
                          Lance
                          PowerBASIC Support
                          mailto:[email protected][email protected]</A>
                          Lance
                          mailto:[email protected]

                          Comment


                          • #14
                            Lance --
                            What means default ?
                            I don't know new formats of Exe, but in Windows 3.1 in NE structure (WinInfo) it was special field WORD stackSize.
                            Also I see that some (32-bit) modules require less.

                            For me, it looks that initial size of stack is defined in EXE-header. Or I'm wrong ?

                            ------------------

                            Comment


                            • #15
                              Florent has made a good point here, C compilers do not NEED to be big code
                              size producers, it just happens that most have turned into that. The speed
                              problem is probably related to the standard of runtime libraries used and
                              it has that sniff of multiport code.

                              I think Eric originally mentioned the 512 byte file alignment in
                              PowerBASIC which is also the same in MASM EXE files. MASM uses the DDK /
                              VC 5 linker that produces this file alignment but if you link it using the
                              VC 6 linker, the file blows out to 16k.

                              Apparently this is to offset the problems of loading very large programs
                              which are often produced by VC 6. Now I wonder if Phillipe has tried to
                              use the DDK / VC 5 linker to see of the program size drops by a measurable
                              amount because with a final DLL size of 80 odd k, he is clearly not relying
                              on paragraph alignment to get the speed of his code.

                              In reference to the stack usage of 32 bit PE files, James is correct here
                              in that the PE header has 2 areas respectively for "Stack reserve" and
                              "Stack Commit", roughly what a program needs to get going and what it
                              will use if it need it.

                              Now with Scott's list of EXE sizes, I think the numbers here speak
                              eloquently, simply by looking at the byte count, statistical theory will
                              not bridge the size gap and it needs to be understood that the C compiler
                              was a lot earlier version which produced smaller code than the current
                              ones.

                              I also agree with Scott with his comments on how COM is implemented, I
                              have seen code in MASM that manually codes the vtable and it is a joy to
                              behold in terms of complexity but it does come in at MASM size, not C++
                              size so if the interface is designed well, I have no doubt that it can
                              be done in a small and efficient way.

                              What I have not seen in this discussion so far is a way to produce
                              PowerBASIC size DLLs with another compiler and while it may be interesting
                              to ponder the virtue of building DLLs big enough to see what the threshold
                              could be for a PowerBASIC DLL to lose its obvious size advantage, it won't
                              stop that multitude of PowerBASIC programmers from routinely writing DLLs
                              that come in well under the size of their competitors.

                              Regards,

                              [email protected]

                              ------------------
                              hutch at movsd dot com
                              The MASM Forum

                              www.masm32.com

                              Comment

                              Working...
                              X